ipv4.c
上传用户:riyaled888
上传日期:2009-03-27
资源大小:7338k
文件大小:24k
源码类别:

多媒体

开发平台:

MultiPlatform

  1. /*****************************************************************************
  2.  * ipv4.c: IPv4 network abstraction layer
  3.  *****************************************************************************
  4.  * Copyright (C) 2001, 2002 VideoLAN
  5.  * $Id: ipv4.c 8907 2004-10-04 14:29:23Z gbazin $
  6.  *
  7.  * Authors: Christophe Massiot <massiot@via.ecp.fr>
  8.  *          Mathias Kretschmer <mathias@research.att.com>
  9.  *          Alexis de Lattre <alexis@via.ecp.fr>
  10.  *
  11.  * This program is free software; you can redistribute it and/or modify
  12.  * it under the terms of the GNU General Public License as published by
  13.  * the Free Software Foundation; either version 2 of the License, or
  14.  * (at your option) any later version.
  15.  *
  16.  * This program is distributed in the hope that it will be useful,
  17.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  18.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  19.  * GNU General Public License for more details.
  20.  *
  21.  * You should have received a copy of the GNU General Public License
  22.  * along with this program; if not, write to the Free Software
  23.  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
  24.  *****************************************************************************/
  25. /*****************************************************************************
  26.  * Preamble
  27.  *****************************************************************************/
  28. #include <stdlib.h>
  29. #include <string.h>
  30. #include <vlc/vlc.h>
  31. #include <errno.h>
  32. #ifdef HAVE_SYS_TYPES_H
  33. #   include <sys/types.h>
  34. #endif
  35. #ifdef HAVE_SYS_STAT_H
  36. #   include <sys/stat.h>
  37. #endif
  38. #ifdef HAVE_FCNTL_H
  39. #   include <fcntl.h>
  40. #endif
  41. #ifdef HAVE_UNISTD_H
  42. #   include <unistd.h>
  43. #endif
  44. #if defined( UNDER_CE )
  45. #   include <winsock.h>
  46. #   define close(fd) CloseHandle((HANDLE)fd)
  47. #elif defined( WIN32 )
  48. #   include <winsock2.h>
  49. #   include <ws2tcpip.h>
  50. #   define close closesocket
  51. #else
  52. #   include <netdb.h>                                         /* hostent ... */
  53. #   include <sys/socket.h>
  54. #   include <netinet/in.h>
  55. #   ifdef HAVE_ARPA_INET_H
  56. #       include <arpa/inet.h>                    /* inet_ntoa(), inet_aton() */
  57. #   endif
  58. #endif
  59. #include "network.h"
  60. #ifndef INADDR_ANY
  61. #   define INADDR_ANY  0x00000000
  62. #endif
  63. #ifndef INADDR_NONE
  64. #   define INADDR_NONE 0xFFFFFFFF
  65. #endif
  66. #ifndef IN_MULTICAST
  67. #   define IN_MULTICAST(a) IN_CLASSD(a)
  68. #endif
  69. #ifndef PF_INET
  70. #    define PF_INET AF_INET                                          /* BeOS */
  71. #endif
  72. /*****************************************************************************
  73.  * Local prototypes
  74.  *****************************************************************************/
  75. static int NetOpen( vlc_object_t * );
  76. /*****************************************************************************
  77.  * Module descriptor
  78.  *****************************************************************************/
  79. #define TIMEOUT_TEXT N_("TCP connection timeout in ms")
  80. #define TIMEOUT_LONGTEXT N_( 
  81.     "Allows you to modify the default TCP connection timeout. This " 
  82.     "value should be set in millisecond units." )
  83. vlc_module_begin();
  84.     set_description( _("IPv4 network abstraction layer") );
  85.     set_capability( "network", 50 );
  86.     set_callbacks( NetOpen, NULL );
  87.     add_integer( "ipv4-timeout", 5 * 1000, NULL, TIMEOUT_TEXT,
  88.                  TIMEOUT_LONGTEXT, VLC_TRUE );
  89. vlc_module_end();
  90. /*****************************************************************************
  91.  * BuildAddr: utility function to build a struct sockaddr_in
  92.  *****************************************************************************/
  93. static int BuildAddr( struct sockaddr_in * p_socket,
  94.                       const char * psz_address, int i_port )
  95. {
  96.     /* Reset struct */
  97.     memset( p_socket, 0, sizeof( struct sockaddr_in ) );
  98.     p_socket->sin_family = AF_INET;                                /* family */
  99.     p_socket->sin_port = htons( (uint16_t)i_port );
  100.     if( !*psz_address )
  101.     {
  102.         p_socket->sin_addr.s_addr = INADDR_ANY;
  103.     }
  104.     else
  105.     {
  106.         struct hostent    * p_hostent;
  107.         /* Try to convert address directly from in_addr - this will work if
  108.          * psz_address is dotted decimal. */
  109. #ifdef HAVE_ARPA_INET_H
  110.         if( !inet_aton( psz_address, &p_socket->sin_addr ) )
  111. #else
  112.         p_socket->sin_addr.s_addr = inet_addr( psz_address );
  113.         if( p_socket->sin_addr.s_addr == INADDR_NONE )
  114. #endif
  115.         {
  116.             /* We have a fqdn, try to find its address */
  117.             if ( (p_hostent = gethostbyname( psz_address )) == NULL )
  118.             {
  119.                 return( -1 );
  120.             }
  121.             /* Copy the first address of the host in the socket address */
  122.             memcpy( &p_socket->sin_addr, p_hostent->h_addr_list[0],
  123.                      p_hostent->h_length );
  124.         }
  125.     }
  126.     return( 0 );
  127. }
  128. /*****************************************************************************
  129.  * OpenUDP: open a UDP socket
  130.  *****************************************************************************
  131.  * psz_bind_addr, i_bind_port : address and port used for the bind()
  132.  *   system call. If psz_bind_addr == "", the socket is bound to
  133.  *   INADDR_ANY and broadcast reception is enabled. If i_bind_port == 0,
  134.  *   1234 is used. If psz_bind_addr is a multicast (class D) address,
  135.  *   join the multicast group.
  136.  * psz_server_addr, i_server_port : address and port used for the connect()
  137.  *   system call. It can avoid receiving packets from unauthorized IPs.
  138.  *   Its use leads to great confusion and is currently discouraged.
  139.  * This function returns -1 in case of error.
  140.  *****************************************************************************/
  141. static int OpenUDP( vlc_object_t * p_this, network_socket_t * p_socket )
  142. {
  143.     char * psz_bind_addr = p_socket->psz_bind_addr;
  144.     int i_bind_port = p_socket->i_bind_port;
  145.     char * psz_server_addr = p_socket->psz_server_addr;
  146.     int i_server_port = p_socket->i_server_port;
  147.     int i_handle, i_opt;
  148.     socklen_t i_opt_size;
  149.     struct sockaddr_in sock;
  150.     vlc_value_t val;
  151.     /* If IP_ADD_SOURCE_MEMBERSHIP is not defined in the headers
  152.        (because it's not in glibc for example), we have to define the
  153.        headers required for IGMPv3 here */
  154. #ifndef IP_ADD_SOURCE_MEMBERSHIP
  155.     #define IP_ADD_SOURCE_MEMBERSHIP  39
  156.     struct ip_mreq_source {
  157.         struct in_addr  imr_multiaddr;
  158.         struct in_addr  imr_interface;
  159.         struct in_addr  imr_sourceaddr;
  160.      };
  161. #endif
  162.     /* Open a SOCK_DGRAM (UDP) socket, in the AF_INET domain, automatic (0)
  163.      * protocol */
  164.     if( (i_handle = socket( AF_INET, SOCK_DGRAM, 0 )) == -1 )
  165.     {
  166. #if defined(WIN32) || defined(UNDER_CE)
  167.         msg_Warn( p_this, "cannot create socket (%i)", WSAGetLastError() );
  168. #else
  169.         msg_Warn( p_this, "cannot create socket (%s)", strerror(errno) );
  170. #endif
  171.         return( -1 );
  172.     }
  173.     /* We may want to reuse an already used socket */
  174.     i_opt = 1;
  175.     if( setsockopt( i_handle, SOL_SOCKET, SO_REUSEADDR,
  176.                     (void *) &i_opt, sizeof( i_opt ) ) == -1 )
  177.     {
  178. #if defined(WIN32) || defined(UNDER_CE)
  179.         msg_Warn( p_this, "cannot configure socket (SO_REUSEADDR: %i)",
  180.                   WSAGetLastError() );
  181. #else
  182.         msg_Warn( p_this, "cannot configure socket (SO_REUSEADDR: %s)",
  183.                           strerror(errno));
  184. #endif
  185.         close( i_handle );
  186.         return( -1 );
  187.     }
  188. #ifdef SO_REUSEPORT
  189.     i_opt = 1;
  190.     if( setsockopt( i_handle, SOL_SOCKET, SO_REUSEPORT,
  191.                     (void *) &i_opt, sizeof( i_opt ) ) == -1 )
  192.     {
  193.         msg_Warn( p_this, "cannot configure socket (SO_REUSEPORT)" );
  194.     }
  195. #endif
  196.     /* Increase the receive buffer size to 1/2MB (8Mb/s during 1/2s) to avoid
  197.      * packet loss caused by scheduling problems */
  198.     i_opt = 0x80000;
  199. #if !defined( SYS_BEOS )
  200.     if( setsockopt( i_handle, SOL_SOCKET, SO_RCVBUF, (void *) &i_opt, sizeof( i_opt ) ) == -1 )
  201.     {
  202. #if defined(WIN32) || defined(UNDER_CE)
  203.         msg_Dbg( p_this, "cannot configure socket (SO_RCVBUF: %i)",
  204.                  WSAGetLastError() );
  205. #else
  206.         msg_Dbg( p_this, "cannot configure socket (SO_RCVBUF: %s)",
  207.                           strerror(errno));
  208. #endif
  209.     }
  210. #endif
  211. #if !defined( SYS_BEOS )
  212.     /* Check if we really got what we have asked for, because Linux, etc.
  213.      * will silently limit the max buffer size to net.core.rmem_max which
  214.      * is typically only 65535 bytes */
  215.     i_opt = 0;
  216.     i_opt_size = sizeof( i_opt );
  217.     if( getsockopt( i_handle, SOL_SOCKET, SO_RCVBUF, (void*) &i_opt, &i_opt_size ) == -1 )
  218.     {
  219. #if defined(WIN32) || defined(UNDER_CE)
  220.         msg_Warn( p_this, "cannot query socket (SO_RCVBUF: %i)",
  221.                   WSAGetLastError() );
  222. #else
  223.         msg_Warn( p_this, "cannot query socket (SO_RCVBUF: %s)",
  224.                           strerror(errno) );
  225. #endif
  226.     }
  227.     else if( i_opt < 0x80000 )
  228.     {
  229.         msg_Dbg( p_this, "socket buffer size is 0x%x instead of 0x%x",
  230.                          i_opt, 0x80000 );
  231.     }
  232. #endif
  233.     /* Build the local socket */
  234. #if defined( WIN32 ) && !defined( UNDER_CE )
  235.     /* Under Win32 and for multicasting, we bind to INADDR_ANY,
  236.      * so let's call BuildAddr with "" instead of psz_bind_addr */
  237.     if( BuildAddr( &sock, IN_MULTICAST( ntohl( inet_addr(psz_bind_addr) ) ) ?
  238.                    "" : psz_bind_addr, i_bind_port ) == -1 )
  239. #else
  240.     if( BuildAddr( &sock, psz_bind_addr, i_bind_port ) == -1 )
  241. #endif
  242.     {
  243.         msg_Dbg( p_this, "could not build local address" );
  244.         close( i_handle );
  245.         return( -1 );
  246.     }
  247.     /* Bind it */
  248.     if( bind( i_handle, (struct sockaddr *)&sock, sizeof( sock ) ) < 0 )
  249.     {
  250. #if defined(WIN32) || defined(UNDER_CE)
  251.         msg_Warn( p_this, "cannot bind socket (%i)", WSAGetLastError() );
  252. #else
  253.         msg_Warn( p_this, "cannot bind socket (%s)", strerror(errno) );
  254. #endif
  255.         close( i_handle );
  256.         return( -1 );
  257.     }
  258. #if defined( WIN32 ) && !defined( UNDER_CE )
  259.     /* Restore the sock struct so we can spare a few #ifdef WIN32 later on */
  260.     if( IN_MULTICAST( ntohl( inet_addr(psz_bind_addr) ) ) )
  261.     {
  262.         if ( BuildAddr( &sock, psz_bind_addr, i_bind_port ) == -1 )
  263.         {
  264.             msg_Dbg( p_this, "could not build local address" );
  265.             close( i_handle );
  266.             return( -1 );
  267.         }
  268.     }
  269. #endif
  270. #if !defined( SYS_BEOS )
  271.     /* Allow broadcast reception if we bound on INADDR_ANY */
  272.     if( !*psz_bind_addr )
  273.     {
  274.         i_opt = 1;
  275.         if( setsockopt( i_handle, SOL_SOCKET, SO_BROADCAST, (void*) &i_opt, sizeof( i_opt ) ) == -1 )
  276.         {
  277. #if defined(WIN32) || defined(UNDER_CE)
  278.             msg_Warn( p_this, "cannot configure socket (SO_BROADCAST: %i)",
  279.                       WSAGetLastError() );
  280. #else
  281.             msg_Warn( p_this, "cannot configure socket (SO_BROADCAST: %s)",
  282.                        strerror(errno) );
  283. #endif
  284.         }
  285.     }
  286. #endif
  287. #if !defined( UNDER_CE ) && !defined( SYS_BEOS )
  288.     /* Join the multicast group if the socket is a multicast address */
  289.     if( IN_MULTICAST( ntohl(sock.sin_addr.s_addr) ) )
  290.     {
  291.         /* Determine interface to be used for multicast */
  292.         char * psz_if_addr = config_GetPsz( p_this, "iface-addr" );
  293.         /* If we have a source address, we use IP_ADD_SOURCE_MEMBERSHIP
  294.            so that IGMPv3 aware OSes running on IGMPv3 aware networks
  295.            will do an IGMPv3 query on the network */
  296.         if( *psz_server_addr )
  297.         {
  298.             struct ip_mreq_source imr;
  299.             imr.imr_multiaddr.s_addr = sock.sin_addr.s_addr;
  300.             imr.imr_sourceaddr.s_addr = inet_addr(psz_server_addr);
  301.             if( psz_if_addr != NULL && *psz_if_addr
  302.                 && inet_addr(psz_if_addr) != INADDR_NONE )
  303.             {
  304.                 imr.imr_interface.s_addr = inet_addr(psz_if_addr);
  305.             }
  306.             else
  307.             {
  308.                 imr.imr_interface.s_addr = INADDR_ANY;
  309.             }
  310.             if( psz_if_addr != NULL ) free( psz_if_addr );
  311.             msg_Dbg( p_this, "IP_ADD_SOURCE_MEMBERSHIP multicast request" );
  312.             /* Join Multicast group with source filter */
  313.             if( setsockopt( i_handle, IPPROTO_IP, IP_ADD_SOURCE_MEMBERSHIP,
  314.                          (char*)&imr,
  315.                          sizeof(struct ip_mreq_source) ) == -1 )
  316.             {
  317. #if defined(WIN32) || defined(UNDER_CE)
  318.                 msg_Err( p_this, "failed to join IP multicast group (%i)",
  319.                          WSAGetLastError() );
  320. #else
  321.                 msg_Err( p_this, "failed to join IP multicast group (%s)",
  322.                                   strerror(errno) );
  323. #endif
  324.                 msg_Err( p_this, "are you sure your OS supports IGMPv3?" );
  325.                 close( i_handle );
  326.                 return( -1 );
  327.             }
  328.          }
  329.          /* If there is no source address, we use IP_ADD_MEMBERSHIP */
  330.          else
  331.          {
  332.              struct ip_mreq imr;
  333.              imr.imr_multiaddr.s_addr = sock.sin_addr.s_addr;
  334.              if( psz_if_addr != NULL && *psz_if_addr
  335.                 && inet_addr(psz_if_addr) != INADDR_NONE )
  336.             {
  337.                 imr.imr_interface.s_addr = inet_addr(psz_if_addr);
  338.             }
  339.             else
  340.             {
  341.                 imr.imr_interface.s_addr = INADDR_ANY;
  342.             }
  343.             if( psz_if_addr != NULL ) free( psz_if_addr );
  344.             msg_Dbg( p_this, "IP_ADD_MEMBERSHIP multicast request" );
  345.             /* Join Multicast group without source filter */
  346.             if( setsockopt( i_handle, IPPROTO_IP, IP_ADD_MEMBERSHIP,
  347.                             (char*)&imr, sizeof(struct ip_mreq) ) == -1 )
  348.             {
  349. #if defined(WIN32) || defined(UNDER_CE)
  350.                 msg_Err( p_this, "failed to join IP multicast group (%i)",
  351.                          WSAGetLastError() );
  352. #else
  353.                 msg_Err( p_this, "failed to join IP multicast group (%s)",
  354.                                   strerror(errno) );
  355. #endif
  356.                 close( i_handle );
  357.                 return( -1 );
  358.             }
  359.          }
  360.     }
  361. #endif
  362.     if( *psz_server_addr )
  363.     {
  364.         /* Build socket for remote connection */
  365.         if ( BuildAddr( &sock, psz_server_addr, i_server_port ) == -1 )
  366.         {
  367.             msg_Warn( p_this, "cannot build remote address" );
  368.             close( i_handle );
  369.             return( -1 );
  370.         }
  371.         /* Connect the socket */
  372.         if( connect( i_handle, (struct sockaddr *) &sock,
  373.                      sizeof( sock ) ) == (-1) )
  374.         {
  375. #if defined(WIN32) || defined(UNDER_CE)
  376.             msg_Warn( p_this, "cannot connect socket (%i)", WSAGetLastError());
  377. #else
  378.             msg_Warn( p_this, "cannot connect socket (%s)", strerror(errno) );
  379. #endif
  380.             close( i_handle );
  381.             return( -1 );
  382.         }
  383. #if !defined( UNDER_CE ) && !defined( SYS_BEOS )
  384.         if( IN_MULTICAST( ntohl(inet_addr(psz_server_addr) ) ) )
  385.         {
  386.             /* set the time-to-live */
  387.             int i_ttl = p_socket->i_ttl;
  388.             unsigned char ttl;
  389.             if( i_ttl < 1 )
  390.             {
  391.                 if( var_Get( p_this, "ttl", &val ) != VLC_SUCCESS )
  392.                 {
  393.                     var_Create( p_this, "ttl",
  394.                                 VLC_VAR_INTEGER | VLC_VAR_DOINHERIT );
  395.                     var_Get( p_this, "ttl", &val );
  396.                 }
  397.                 i_ttl = val.i_int;
  398.             }
  399.             if( i_ttl < 1 ) i_ttl = 1;
  400.             ttl = (unsigned char) i_ttl;
  401.             /* There is some confusion in the world whether IP_MULTICAST_TTL 
  402.              * takes a byte or an int as an argument.
  403.              * BSD seems to indicate byte so we are going with that and use
  404.              * int as a fallback to be safe */
  405.             if( setsockopt( i_handle, IPPROTO_IP, IP_MULTICAST_TTL,
  406.                             &ttl, sizeof( ttl ) ) < 0 )
  407.             {
  408.                 msg_Dbg( p_this, "failed to set ttl (%s). Let's try it "
  409.                          "the integer way.", strerror(errno) );
  410.                 if( setsockopt( i_handle, IPPROTO_IP, IP_MULTICAST_TTL,
  411.                                 &i_ttl, sizeof( i_ttl ) ) <0 )
  412.                 {
  413.                     msg_Err( p_this, "failed to set ttl (%s)",
  414.                              strerror(errno) );
  415.                     close( i_handle );
  416.                     return( -1 );
  417.                 }
  418.             }
  419.         }
  420. #endif
  421.     }
  422.     p_socket->i_handle = i_handle;
  423.     if( var_Get( p_this, "mtu", &val ) != VLC_SUCCESS )
  424.     {
  425.         var_Create( p_this, "mtu", VLC_VAR_INTEGER | VLC_VAR_DOINHERIT );
  426.         var_Get( p_this, "mtu", &val );
  427.     }
  428.     p_socket->i_mtu = val.i_int;
  429.     return( 0 );
  430. }
  431. /*****************************************************************************
  432.  * SocketTCP: create a TCP socket
  433.  *****************************************************************************
  434.  * This function returns -1 in case of error.
  435.  *****************************************************************************/
  436. static int SocketTCP( vlc_object_t * p_this )
  437. {
  438.     int i_handle;
  439.     
  440.     /* Open a SOCK_STREAM (TCP) socket, in the PF_INET domain, automatic (0)
  441.      * protocol */
  442.     if( (i_handle = socket( PF_INET, SOCK_STREAM, 0 )) == -1 )
  443.     {
  444. #if defined(WIN32) || defined(UNDER_CE)
  445.         msg_Warn( p_this, "cannot create socket (%i)", WSAGetLastError() );
  446. #else
  447.         msg_Warn( p_this, "cannot create socket (%s)", strerror(errno) );
  448. #endif
  449.         return -1;
  450.     }
  451.     /* Set to non-blocking */
  452. #if defined( WIN32 ) || defined( UNDER_CE )
  453.     {
  454.         unsigned long i_dummy = 1;
  455.         if( ioctlsocket( i_handle, FIONBIO, &i_dummy ) != 0 )
  456.         {
  457.             msg_Err( p_this, "cannot set socket to non-blocking mode" );
  458.         }
  459.     }
  460. #else
  461.     {
  462.         int i_flags;
  463.         if( ( i_flags = fcntl( i_handle, F_GETFL, 0 ) ) < 0 ||
  464.             fcntl( i_handle, F_SETFL, i_flags | O_NONBLOCK ) < 0 )
  465.         {
  466.             msg_Err( p_this, "cannot set socket to non-blocking mode" );
  467.         }
  468.     }
  469. #endif
  470.     return i_handle;
  471. }
  472. /*****************************************************************************
  473.  * OpenTCP: open a TCP socket
  474.  *****************************************************************************
  475.  * psz_server_addr, i_server_port : address and port used for the connect()
  476.  *   system call. If i_server_port == 0, 80 is used.
  477.  * Other parameters are ignored.
  478.  * This function returns -1 in case of error.
  479.  *****************************************************************************/
  480. static int OpenTCP( vlc_object_t * p_this, network_socket_t * p_socket )
  481. {
  482.     char * psz_server_addr = p_socket->psz_server_addr;
  483.     int i_server_port = p_socket->i_server_port;
  484.     int i_handle;
  485.     struct sockaddr_in sock;
  486.     if( i_server_port == 0 )
  487.     {
  488.         i_server_port = 80;
  489.     }
  490.     if( (i_handle = SocketTCP( p_this )) == -1 )
  491.         return VLC_EGENERIC;
  492.     /* Build remote address */
  493.     if ( BuildAddr( &sock, psz_server_addr, i_server_port ) == -1 )
  494.     {
  495.         msg_Dbg( p_this, "could not build local address" );
  496.         goto error;
  497.     }
  498.     /* Connect the socket */
  499.     if( connect( i_handle, (struct sockaddr *) &sock, sizeof( sock ) ) == -1 )
  500.     {
  501. #if defined( WIN32 ) || defined( UNDER_CE )
  502.         if( WSAGetLastError() == WSAEWOULDBLOCK )
  503. #else
  504.         if( errno == EINPROGRESS )
  505. #endif
  506.         {
  507.             int i_ret, i_opt, i_opt_size = sizeof( i_opt ), i_max_count;
  508.             struct timeval timeout;
  509.             vlc_value_t val;
  510.             fd_set fds;
  511.             if( var_Get( p_this, "ipv4-timeout", &val ) != VLC_SUCCESS )
  512.             {
  513.                 var_Create( p_this, "ipv4-timeout",
  514.                             VLC_VAR_INTEGER | VLC_VAR_DOINHERIT );
  515.                 var_Get( p_this, "ipv4-timeout", &val );
  516.             }
  517.             i_max_count = val.i_int * 1000 / 100000 /* timeout.tv_usec */;
  518.             msg_Dbg( p_this, "connection in progress" );
  519.             do
  520.             {
  521.                 if( p_this->b_die || i_max_count <= 0 )
  522.                 {
  523.                     msg_Dbg( p_this, "connection aborted" );
  524.                     goto error;
  525.                 }
  526.                 i_max_count--;
  527.                 /* Initialize file descriptor set */
  528.                 FD_ZERO( &fds );
  529.                 FD_SET( i_handle, &fds );
  530.                 /* We'll wait 0.1 second if nothing happens */
  531.                 timeout.tv_sec = 0;
  532.                 timeout.tv_usec = 100000;
  533.             } while( ( i_ret = select( i_handle + 1, NULL, &fds, NULL,
  534.                                        &timeout ) ) == 0 ||
  535. #if defined( WIN32 ) || defined( UNDER_CE )
  536.                      ( i_ret < 0 && WSAGetLastError() == WSAEWOULDBLOCK ) );
  537. #else
  538.                      ( i_ret < 0 && errno == EINTR ) );
  539. #endif
  540.             if( i_ret < 0 )
  541.             {
  542.                 msg_Warn( p_this, "cannot connect socket (select failed)" );
  543.                 goto error;
  544.             }
  545. #if !defined( SYS_BEOS )
  546.             if( getsockopt( i_handle, SOL_SOCKET, SO_ERROR, (void*)&i_opt,
  547.                             &i_opt_size ) == -1 || i_opt != 0 )
  548.             {
  549.                 msg_Warn( p_this, "cannot connect socket (SO_ERROR)" );
  550.                 goto error;
  551.             }
  552. #endif
  553.         }
  554.         else
  555.         {
  556. #if defined(WIN32) || defined(UNDER_CE)
  557.             msg_Warn( p_this, "cannot connect socket (%i)", WSAGetLastError());
  558. #else
  559.             msg_Warn( p_this, "cannot connect socket (%s)", strerror(errno) );
  560. #endif
  561.             goto error;
  562.         }
  563.     }
  564.     p_socket->i_handle = i_handle;
  565.     p_socket->i_mtu = 0; /* There is no MTU notion in TCP */
  566.     return VLC_SUCCESS;
  567. error:
  568.     close( i_handle );
  569.     return VLC_EGENERIC;
  570. }
  571. /*****************************************************************************
  572.  * ListenTCP: open a TCP passive socket (server-side)
  573.  *****************************************************************************
  574.  * psz_server_addr, i_server_port : address and port used for the bind()
  575.  *   system call. If i_server_port == 0, 80 is used.
  576.  * Other parameters are ignored.
  577.  * This function returns -1 in case of error.
  578.  *****************************************************************************/
  579. static int ListenTCP( vlc_object_t * p_this, network_socket_t * p_socket )
  580. {
  581.     char * psz_server_addr = p_socket->psz_server_addr;
  582.     int i_server_port = p_socket->i_server_port;
  583.     int i_handle, i_dummy = 1;
  584.     struct sockaddr_in sock;
  585.     if( (i_handle = SocketTCP( p_this )) == -1 )
  586.         return VLC_EGENERIC;
  587.     if ( setsockopt( i_handle, SOL_SOCKET, SO_REUSEADDR,
  588.                 (void *)&i_dummy, sizeof( i_dummy ) ) == -1 )
  589.     {
  590.         msg_Warn( p_this, "cannot configure socket (SO_REUSEADDR)" );
  591.     }
  592.     /* Build remote address */
  593.     if ( BuildAddr( &sock, psz_server_addr, i_server_port ) == -1 )
  594.     {
  595.         msg_Dbg( p_this, "could not build local address" );
  596.         return VLC_EGENERIC;
  597.     }
  598.     
  599.     /* Bind the socket */
  600.     if( bind( i_handle, (struct sockaddr *) &sock, sizeof( sock )) == -1 )
  601.     {
  602. #if defined(WIN32) || defined(UNDER_CE)
  603.         msg_Err( p_this, "cannot bind socket (%i)", WSAGetLastError());
  604. #else
  605.         msg_Err( p_this, "cannot bind socket (%s)", strerror(errno) );
  606. #endif
  607.         goto error;
  608.     }
  609.  
  610.     /* Listen */
  611.     if( listen( i_handle, 100 ) == -1 )
  612.     {
  613. #if defined(WIN32) || defined(UNDER_CE)
  614.         msg_Err( p_this, "cannot bring socket in listening mode (%i)",
  615.                  WSAGetLastError());
  616. #else
  617.         msg_Err( p_this, "cannot bring the socket in listening mode (%s)",
  618.                  strerror(errno) );
  619. #endif
  620.         goto error;
  621.     }
  622.     p_socket->i_handle = i_handle;
  623.     p_socket->i_mtu = 0; /* There is no MTU notion in TCP */
  624.     return VLC_SUCCESS;
  625. error:
  626.     close( i_handle );
  627.     return VLC_EGENERIC;
  628. }
  629. /*****************************************************************************
  630.  * NetOpen: wrapper around OpenUDP, ListenTCP and OpenTCP
  631.  *****************************************************************************/
  632. static int NetOpen( vlc_object_t * p_this )
  633. {
  634.     network_socket_t * p_socket = p_this->p_private;
  635.     if( p_socket->i_type == NETWORK_UDP )
  636.     {
  637.         return OpenUDP( p_this, p_socket );
  638.     }
  639.     else if( p_socket->i_type == NETWORK_TCP_PASSIVE )
  640.     {
  641.         return ListenTCP( p_this, p_socket );
  642.     }
  643.     else
  644.     {
  645.         return OpenTCP( p_this, p_socket );
  646.     }
  647. }