- Use the new vlc_getaddrinfo API
authorRémi Denis-Courmont <rem@videolan.org>
Sun, 22 May 2005 11:24:08 +0000 (11:24 +0000)
committerRémi Denis-Courmont <rem@videolan.org>
Sun, 22 May 2005 11:24:08 +0000 (11:24 +0000)
- Unduplicate TCP networking code (closes #101)
- Modify net_ListenTCP to support multiple listening sockets
- Update net_ListenTCP callers to the new API

include/network.h
modules/control/rc.c
modules/control/telnet.c
modules/misc/network/ipv4.c
modules/misc/network/ipv6.c
src/libvlc.h
src/misc/net.c

index f0893d4..4661d0f 100644 (file)
@@ -6,7 +6,7 @@
  *
  * Authors: Christophe Massiot <massiot@via.ecp.fr>
  *          Laurent Aimar <fenrir@via.ecp.fr>
- *          Rémi Denis-Courmont <courmisch # via.ecp.fr>
+ *          Rémi Denis-Courmont <rem # videolan.org>
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -31,8 +31,6 @@
  *****************************************************************************/
 struct network_socket_t
 {
-    unsigned int i_type;
-
     char * psz_bind_addr;
     int i_bind_port;
 
@@ -46,12 +44,6 @@ struct network_socket_t
     size_t i_mtu;
 };
 
-/* Socket types */
-#define NETWORK_UDP 1
-#define NETWORK_TCP 2
-#define NETWORK_TCP_PASSIVE 3
-
-
 typedef struct
 {
     char *psz_protocol;
@@ -277,22 +269,21 @@ static inline char *vlc_b64_encode( char *src )
     return ret;
 }
 
-VLC_EXPORT( int, net_ConvertIPv4, ( uint32_t *p_addr, const char * psz_address ) );
-
 /* Portable networking layer communication */
 #define net_OpenTCP(a, b, c) __net_OpenTCP(VLC_OBJECT(a), b, c)
 VLC_EXPORT( int, __net_OpenTCP, ( vlc_object_t *p_this, const char *psz_host, int i_port ) );
 
 #define net_ListenTCP(a, b, c) __net_ListenTCP(VLC_OBJECT(a), b, c)
-VLC_EXPORT( int, __net_ListenTCP, ( vlc_object_t *p_this, char *psz_localaddr, int i_port ) );
+VLC_EXPORT( int *, __net_ListenTCP, ( vlc_object_t *, const char *, int ) );
 
 #define net_Accept(a, b, c) __net_Accept(VLC_OBJECT(a), b, c)
-VLC_EXPORT( int, __net_Accept, ( vlc_object_t *p_this, int fd_listen, mtime_t i_wait ) );
+VLC_EXPORT( int, __net_Accept, ( vlc_object_t *, int *, mtime_t ) );
 
 #define net_OpenUDP(a, b, c, d, e ) __net_OpenUDP(VLC_OBJECT(a), b, c, d, e)
 VLC_EXPORT( int, __net_OpenUDP, ( vlc_object_t *p_this, char *psz_bind, int i_bind, char *psz_server, int i_server ) );
 
 VLC_EXPORT( void, net_Close, ( int fd ) );
+VLC_EXPORT( void, net_ListenClose, ( int *fd ) );
 
 
 /* Functions to read from or write to the networking layer */
@@ -323,4 +314,83 @@ VLC_EXPORT( int, net_Printf, ( vlc_object_t *p_this, int fd, v_socket_t *, const
 #define net_vaPrintf(a,b,c,d,e) __net_vaPrintf(VLC_OBJECT(a),b,c,d,e)
 VLC_EXPORT( int, __net_vaPrintf, ( vlc_object_t *p_this, int fd, v_socket_t *, const char *psz_fmt, va_list args ) );
 
+/* Portable network names/addresses resolution layer */
+
+/* GAI error codes */
+# ifndef EAI_BADFLAGS
+#  define EAI_BADFLAGS -1
+# endif
+# ifndef EAI_NONAME
+#  define EAI_NONAME -2
+# endif
+# ifndef EAI_AGAIN
+#  define EAI_AGAIN -3
+# endif
+# ifndef EAI_FAIL
+#  define EAI_FAIL -4
+# endif
+# ifndef EAI_NODATA
+#  define EAI_NODATA -5
+# endif
+# ifndef EAI_FAMILY
+#  define EAI_FAMILY -6
+# endif
+# ifndef EAI_SOCKTYPE
+#  define EAI_SOCKTYPE -7
+# endif
+# ifndef EAI_SERVICE
+#  define EAI_SERVICE -8
+# endif
+# ifndef EAI_ADDRFAMILY
+#  define EAI_ADDRFAMILY -9
+# endif
+# ifndef EAI_MEMORY
+#  define EAI_MEMORY -10
+# endif
+# ifndef EAI_SYSTEM
+#  define EAI_SYSTEM -11
+# endif
+
+
+# ifndef NI_MAXHOST
+#  define NI_MAXHOST 1025
+#  define NI_MAXSERV 32
+# endif
+
+# ifndef NI_NUMERICHOST
+#  define NI_NUMERICHOST 0x01
+#  define NI_NUMERICSERV 0x02
+#  define NI_NOFQDN      0x04
+#  define NI_NAMEREQD    0x08
+#  define NI_DGRAM       0x10
+# endif
+
+# ifndef HAVE_STRUCT_ADDRINFO
+struct addrinfo
+{
+    int ai_flags;
+    int ai_family;
+    int ai_socktype;
+    int ai_protocol;
+    size_t ai_addrlen;
+    struct sockaddr *ai_addr;
+    char *ai_canonname;
+    struct addrinfo *ai_next;
+};
+#  define AI_PASSIVE     1
+#  define AI_CANONNAME   2
+#  define AI_NUMERICHOST 4
+# endif /* if !HAVE_STRUCT_ADDRINFO */
+
+/*** libidn support ***/
+# ifndef AI_IDN
+#  define AI_IDN      0
+#  define AI_CANONIDN 0
+# endif
+
+VLC_EXPORT( const char *, vlc_gai_strerror, ( int ) );
+VLC_EXPORT( int, vlc_getnameinfo, ( vlc_object_t *, const struct sockaddr *, int, char *, int, char *, int, int ) );
+VLC_EXPORT( int, vlc_getaddrinfo, ( vlc_object_t *, const char *, const char *, const struct addrinfo *, struct addrinfo ** ) );
+VLC_EXPORT( void, vlc_freeaddrinfo, ( struct addrinfo * ) );
+
 #endif
index 11a4a93..1cba235 100644 (file)
@@ -92,7 +92,7 @@ static int  AudioConfig  ( vlc_object_t *, char const *,
 
 struct intf_sys_t
 {
-    int i_socket_listen;
+    int *pi_socket_listen;
     int i_socket;
     char *psz_unix_path;
 
@@ -173,7 +173,7 @@ static int Activate( vlc_object_t *p_this )
     intf_thread_t *p_intf = (intf_thread_t*)p_this;
     playlist_t *p_playlist;
     char *psz_host, *psz_unix_path;
-    int i_socket = -1;
+    int *pi_socket = NULL;
 
 #if defined(HAVE_ISATTY) && !defined(WIN32)
     /* Check that stdin is a TTY */
@@ -187,6 +187,8 @@ static int Activate( vlc_object_t *p_this )
     psz_unix_path = config_GetPsz( p_intf, "rc-unix" );
     if( psz_unix_path )
     {
+        int i_socket;
+
 #ifndef PF_LOCAL
         msg_Warn( p_intf, "your OS doesn't support filesystem sockets" );
         free( psz_unix_path );
@@ -227,10 +229,21 @@ static int Activate( vlc_object_t *p_this )
             net_Close( i_socket );
             return VLC_EGENERIC;
         }
+
+        /* FIXME: we need a core function to merge listening sockets sets */
+        pi_socket = calloc( 2, sizeof( int ) );
+        if( pi_socket == NULL )
+        {
+            free( psz_unix_path );
+            net_Close( i_socket );
+            return VLC_ENOMEM;
+        }
+        pi_socket[0] = i_socket;
+        pi_socket[1] = -1;
 #endif
     }
 
-    if( ( i_socket == -1) &&
+    if( ( pi_socket == NULL ) &&
         ( psz_host = config_GetPsz( p_intf, "rc-host" ) ) != NULL )
     {
         vlc_url_t url;
@@ -239,7 +252,8 @@ static int Activate( vlc_object_t *p_this )
 
         msg_Dbg( p_intf, "base %s port %d", url.psz_host, url.i_port );
 
-        if( (i_socket = net_ListenTCP(p_this, url.psz_host, url.i_port)) == -1)
+        pi_socket = net_ListenTCP(p_this, url.psz_host, url.i_port);
+        if( pi_socket == NULL )
         {
             msg_Warn( p_intf, "can't listen to %s port %i",
                       url.psz_host, url.i_port );
@@ -259,7 +273,7 @@ static int Activate( vlc_object_t *p_this )
         return VLC_ENOMEM;
     }
 
-    p_intf->p_sys->i_socket_listen = i_socket;
+    p_intf->p_sys->pi_socket_listen = pi_socket;
     p_intf->p_sys->i_socket = -1;
     p_intf->p_sys->psz_unix_path = psz_unix_path;
 
@@ -297,8 +311,7 @@ static void Deactivate( vlc_object_t *p_this )
 {
     intf_thread_t *p_intf = (intf_thread_t*)p_this;
 
-    if( p_intf->p_sys->i_socket_listen != -1 )
-        net_Close( p_intf->p_sys->i_socket_listen );
+    net_ListenClose( p_intf->p_sys->pi_socket_listen );
     if( p_intf->p_sys->i_socket != -1 )
         net_Close( p_intf->p_sys->i_socket );
     if( p_intf->p_sys->psz_unix_path != NULL )
@@ -477,11 +490,11 @@ static void Run( intf_thread_t *p_intf )
         char *psz_cmd, *psz_arg;
         vlc_bool_t b_complete;
 
-        if( p_intf->p_sys->i_socket_listen != - 1 &&
+        if( p_intf->p_sys->pi_socket_listen != NULL &&
             p_intf->p_sys->i_socket == -1 )
         {
             p_intf->p_sys->i_socket =
-                net_Accept( p_intf, p_intf->p_sys->i_socket_listen, 0 );
+                net_Accept( p_intf, p_intf->p_sys->pi_socket_listen, 0 );
         }
 
         b_complete = ReadCommand( p_intf, p_buffer, &i_size );
index e142c8b..05b8994 100644 (file)
@@ -1,7 +1,7 @@
 /*****************************************************************************
  * telnet.c: VLM interface plugin
  *****************************************************************************
- * Copyright (C) 2000, 2001 VideoLAN
+ * Copyright (C) 2000-2005 VideoLAN
  * $Id$
  *
  * Authors: Simon Latapie <garf@videolan.org>
@@ -120,7 +120,7 @@ struct intf_sys_t
 {
    telnet_client_t **clients;
    int             i_clients;
-   int             fd;
+   int             *pi_fd;
    vlm_t           *mediatheque;
 };
 
@@ -144,7 +144,8 @@ static int Open( vlc_object_t *p_this )
     i_telnetport = config_GetInt( p_intf, "telnet-port" );
 
     p_intf->p_sys = malloc( sizeof( intf_sys_t ) );
-    if( ( p_intf->p_sys->fd = net_ListenTCP( p_intf , "", i_telnetport ) ) < 0 )
+    if( ( p_intf->p_sys->pi_fd = net_ListenTCP( p_intf , "", i_telnetport ) )
+                == NULL )
     {
         msg_Err( p_intf, "cannot listen for telnet" );
         free( p_intf->p_sys );
@@ -178,7 +179,7 @@ static void Close( vlc_object_t *p_this )
     }
     if( p_sys->clients != NULL ) free( p_sys->clients );
 
-    net_Close( p_sys->fd );
+    net_ListenClose( p_sys->pi_fd );
 
     vlm_Delete( p_sys->mediatheque );
 
@@ -203,7 +204,7 @@ static void Run( intf_thread_t *p_intf )
         int    i_ret, i_len, fd, i;
 
         /* if a new client wants to communicate */
-        fd = net_Accept( p_intf, p_sys->fd, p_sys->i_clients > 0 ? 0 : -1 );
+        fd = net_Accept( p_intf, p_sys->pi_fd, p_sys->i_clients > 0 ? 0 : -1 );
         if( fd > 0 )
         {
             telnet_client_t *cl;
index 2338ed0..a258d74 100644 (file)
@@ -1,7 +1,7 @@
 /*****************************************************************************
  * ipv4.c: IPv4 network abstraction layer
  *****************************************************************************
- * Copyright (C) 2001, 2002 VideoLAN
+ * Copyright (C) 2001-2005 VideoLAN
  * $Id$
  *
  * Authors: Christophe Massiot <massiot@via.ecp.fr>
@@ -92,11 +92,6 @@ static int NetOpen( vlc_object_t * );
 /*****************************************************************************
  * Module descriptor
  *****************************************************************************/
-#define TIMEOUT_TEXT N_("TCP connection timeout in ms")
-#define TIMEOUT_LONGTEXT N_( \
-    "Allows you to modify the default TCP connection timeout. This " \
-    "value should be set in millisecond units." )
-
 #define MIFACE_TEXT N_("Multicast output interface")
 #define MIFACE_LONGTEXT N_( \
     "Indicate here the multicast output interface. " \
@@ -106,9 +101,6 @@ vlc_module_begin();
     set_description( _("IPv4 network abstraction layer") );
     set_capability( "network", 50 );
     set_callbacks( NetOpen, NULL );
-
-    add_integer( "ipv4-timeout", 5 * 1000, NULL, TIMEOUT_TEXT,
-                 TIMEOUT_LONGTEXT, VLC_TRUE );
     add_string( "miface-addr", NULL, NULL, MIFACE_TEXT, MIFACE_LONGTEXT, VLC_TRUE );
 vlc_module_end();
 
@@ -501,230 +493,6 @@ static int OpenUDP( vlc_object_t * p_this, network_socket_t * p_socket )
     return( 0 );
 }
 
-/*****************************************************************************
- * SocketTCP: create a TCP socket
- *****************************************************************************
- * This function returns -1 in case of error.
- *****************************************************************************/
-static int SocketTCP( vlc_object_t * p_this )
-{
-    int i_handle;
-    
-    /* Open a SOCK_STREAM (TCP) socket, in the PF_INET domain, automatic (0)
-     * protocol */
-    if( (i_handle = socket( PF_INET, SOCK_STREAM, 0 )) == -1 )
-    {
-#if defined(WIN32) || defined(UNDER_CE)
-        msg_Warn( p_this, "cannot create socket (%i)", WSAGetLastError() );
-#else
-        msg_Warn( p_this, "cannot create socket (%s)", strerror(errno) );
-#endif
-        return -1;
-    }
-
-    /* Set to non-blocking */
-#if defined( WIN32 ) || defined( UNDER_CE )
-    {
-        unsigned long i_dummy = 1;
-        if( ioctlsocket( i_handle, FIONBIO, &i_dummy ) != 0 )
-        {
-            msg_Err( p_this, "cannot set socket to non-blocking mode" );
-        }
-    }
-#else
-    {
-        int i_flags;
-        if( ( i_flags = fcntl( i_handle, F_GETFL, 0 ) ) < 0 ||
-            fcntl( i_handle, F_SETFL, i_flags | O_NONBLOCK ) < 0 )
-        {
-            msg_Err( p_this, "cannot set socket to non-blocking mode" );
-        }
-    }
-#endif
-
-    return i_handle;
-}
-
-/*****************************************************************************
- * OpenTCP: open a TCP socket
- *****************************************************************************
- * psz_server_addr, i_server_port : address and port used for the connect()
- *   system call. If i_server_port == 0, 80 is used.
- * Other parameters are ignored.
- * This function returns -1 in case of error.
- *****************************************************************************/
-static int OpenTCP( vlc_object_t * p_this, network_socket_t * p_socket )
-{
-    char * psz_server_addr = p_socket->psz_server_addr;
-    int i_server_port = p_socket->i_server_port;
-
-    int i_handle;
-    struct sockaddr_in sock;
-
-    if( i_server_port == 0 )
-    {
-        i_server_port = 80;
-    }
-
-    if( (i_handle = SocketTCP( p_this )) == -1 )
-        return VLC_EGENERIC;
-
-    /* Build remote address */
-    if ( BuildAddr( &sock, psz_server_addr, i_server_port ) == -1 )
-    {
-        msg_Dbg( p_this, "could not build local address" );
-        goto error;
-    }
-
-    /* Connect the socket */
-    if( connect( i_handle, (struct sockaddr *) &sock, sizeof( sock ) ) == -1 )
-    {
-#if defined( WIN32 ) || defined( UNDER_CE )
-        if( WSAGetLastError() == WSAEWOULDBLOCK )
-#else
-        if( errno == EINPROGRESS )
-#endif
-        {
-            int i_ret, i_opt, i_opt_size = sizeof( i_opt ), i_max_count;
-            struct timeval timeout;
-            vlc_value_t val;
-            fd_set fds;
-
-            if( var_Get( p_this, "ipv4-timeout", &val ) != VLC_SUCCESS )
-            {
-                var_Create( p_this, "ipv4-timeout",
-                            VLC_VAR_INTEGER | VLC_VAR_DOINHERIT );
-                var_Get( p_this, "ipv4-timeout", &val );
-            }
-            i_max_count = val.i_int * 1000 / 100000 /* timeout.tv_usec */;
-
-            msg_Dbg( p_this, "connection in progress" );
-            do
-            {
-                if( p_this->b_die || i_max_count <= 0 )
-                {
-                    msg_Dbg( p_this, "connection aborted" );
-                    goto error;
-                }
-
-                i_max_count--;
-
-                /* Initialize file descriptor set */
-                FD_ZERO( &fds );
-                FD_SET( i_handle, &fds );
-
-                /* We'll wait 0.1 second if nothing happens */
-                timeout.tv_sec = 0;
-                timeout.tv_usec = 100000;
-
-            } while( ( i_ret = select( i_handle + 1, NULL, &fds, NULL,
-                                       &timeout ) ) == 0 ||
-#if defined( WIN32 ) || defined( UNDER_CE )
-                     ( i_ret < 0 && WSAGetLastError() == WSAEWOULDBLOCK ) );
-#else
-                     ( i_ret < 0 && errno == EINTR ) );
-#endif
-
-            if( i_ret < 0 )
-            {
-                msg_Warn( p_this, "cannot connect socket (select failed)" );
-                goto error;
-            }
-
-#if !defined( SYS_BEOS ) && !defined( UNDER_CE )
-            if( getsockopt( i_handle, SOL_SOCKET, SO_ERROR, (void*)&i_opt,
-                            &i_opt_size ) == -1 || i_opt != 0 )
-            {
-                msg_Warn( p_this, "cannot connect socket (SO_ERROR)" );
-                goto error;
-            }
-#endif
-        }
-        else
-        {
-#if defined(WIN32) || defined(UNDER_CE)
-            msg_Warn( p_this, "cannot connect socket (%i)", WSAGetLastError());
-#else
-            msg_Warn( p_this, "cannot connect socket (%s)", strerror(errno) );
-#endif
-            goto error;
-        }
-    }
-
-    p_socket->i_handle = i_handle;
-    p_socket->i_mtu = 0; /* There is no MTU notion in TCP */
-    return VLC_SUCCESS;
-
-error:
-    close( i_handle );
-    return VLC_EGENERIC;
-}
-
-/*****************************************************************************
- * ListenTCP: open a TCP passive socket (server-side)
- *****************************************************************************
- * psz_server_addr, i_server_port : address and port used for the bind()
- *   system call. If i_server_port == 0, 80 is used.
- * Other parameters are ignored.
- * This function returns -1 in case of error.
- *****************************************************************************/
-static int ListenTCP( vlc_object_t * p_this, network_socket_t * p_socket )
-{
-    char * psz_server_addr = p_socket->psz_server_addr;
-    int i_server_port = p_socket->i_server_port;
-
-    int i_handle, i_dummy = 1;
-    struct sockaddr_in sock;
-
-    if( (i_handle = SocketTCP( p_this )) == -1 )
-        return VLC_EGENERIC;
-
-    if ( setsockopt( i_handle, SOL_SOCKET, SO_REUSEADDR,
-                (void *)&i_dummy, sizeof( i_dummy ) ) == -1 )
-    {
-        msg_Warn( p_this, "cannot configure socket (SO_REUSEADDR)" );
-    }
-
-    /* Build remote address */
-    if ( BuildAddr( &sock, psz_server_addr, i_server_port ) == -1 )
-    {
-        msg_Dbg( p_this, "could not build local address" );
-        return VLC_EGENERIC;
-    }
-    
-    /* Bind the socket */
-    if( bind( i_handle, (struct sockaddr *) &sock, sizeof( sock )) == -1 )
-    {
-#if defined(WIN32) || defined(UNDER_CE)
-        msg_Err( p_this, "cannot bind socket (%i)", WSAGetLastError());
-#else
-        msg_Err( p_this, "cannot bind socket (%s)", strerror(errno) );
-#endif
-        goto error;
-    }
-    /* Listen */
-    if( listen( i_handle, 100 ) == -1 )
-    {
-#if defined(WIN32) || defined(UNDER_CE)
-        msg_Err( p_this, "cannot bring socket in listening mode (%i)",
-                 WSAGetLastError());
-#else
-        msg_Err( p_this, "cannot bring the socket in listening mode (%s)",
-                 strerror(errno) );
-#endif
-        goto error;
-    }
-
-    p_socket->i_handle = i_handle;
-    p_socket->i_mtu = 0; /* There is no MTU notion in TCP */
-    return VLC_SUCCESS;
-
-error:
-    close( i_handle );
-    return VLC_EGENERIC;
-}
-
 /*****************************************************************************
  * NetOpen: wrapper around OpenUDP, ListenTCP and OpenTCP
  *****************************************************************************/
@@ -732,16 +500,5 @@ static int NetOpen( vlc_object_t * p_this )
 {
     network_socket_t * p_socket = p_this->p_private;
 
-    if( p_socket->i_type == NETWORK_UDP )
-    {
-        return OpenUDP( p_this, p_socket );
-    }
-    else if( p_socket->i_type == NETWORK_TCP_PASSIVE )
-    {
-        return ListenTCP( p_this, p_socket );
-    }
-    else
-    {
-        return OpenTCP( p_this, p_socket );
-    }
+    return OpenUDP( p_this, p_socket );
 }
index a9ab693..22cbef4 100644 (file)
@@ -1,7 +1,7 @@
 /*****************************************************************************
  * ipv6.c: IPv6 network abstraction layer
  *****************************************************************************
- * Copyright (C) 2002 VideoLAN
+ * Copyright (C) 2002-2005 VideoLAN
  * $Id$
  *
  * Authors: Alexis Guillard <alexis.guillard@bt.com>
@@ -260,6 +260,19 @@ static int OpenUDP( vlc_object_t * p_this, network_socket_t * p_socket )
         return( -1 );
     }
 
+#ifdef WIN32
+# ifdef IPV6_PROTECTION_LEVEL
+        if( ptr->ai_family == PF_INET6 )
+        {
+            i_val = PROTECTION_LEVEL_UNRESTRICTED;
+            setsockopt( fd, IPPROTO_IPV6, IPV6_PROTECTION_LEVEL, &i_val,
+                        sizeof( i_val ) );
+        }
+# else
+#  warning You are using outdated headers for Winsock !
+# endif
+#endif
+
     /* We may want to reuse an already used socket */
     i_opt = 1;
     if( setsockopt( i_handle, SOL_SOCKET, SO_REUSEADDR,
@@ -403,12 +416,8 @@ static int OpenUDP( vlc_object_t * p_this, network_socket_t * p_socket )
                 if( setsockopt( i_handle, IPPROTO_IPV6, IPV6_MULTICAST_HOPS,
                                 (void *)&ttl, sizeof( ttl ) ) < 0 )
                 {
-#ifdef HAVE_ERRNO_H
                     msg_Err( p_this, "failed to set multicast ttl (%s)",
                              strerror(errno) );
-#else
-                    msg_Err( p_this, "failed to set multicast ttl" );
-#endif
                 }
             }
             else
@@ -417,12 +426,8 @@ static int OpenUDP( vlc_object_t * p_this, network_socket_t * p_socket )
                 if( setsockopt( i_handle, IPPROTO_IPV6, IPV6_UNICAST_HOPS,
                                 (void *)&ttl, sizeof( ttl ) ) < 0 )
                 {
-#ifdef HAVE_ERRNO_H
                     msg_Err( p_this, "failed to set unicast ttl (%s)",
                               strerror(errno) );
-#else
-                    msg_Err( p_this, "failed to set unicast ttl" );
-#endif
                 }
             }
         }
@@ -437,232 +442,6 @@ static int OpenUDP( vlc_object_t * p_this, network_socket_t * p_socket )
     return( 0 );
 }
 
-/*****************************************************************************
- * SocketTCP: create a TCP socket
- *****************************************************************************
- * This function returns -1 in case of error.
- *****************************************************************************/
-static int SocketTCP( vlc_object_t * p_this )
-{
-    int i_handle;
-    
-    /* Open a SOCK_STREAM (TCP) socket, in the PF_INET6 domain, automatic (0)
-     * protocol */
-    if( (i_handle = socket( PF_INET6, SOCK_STREAM, 0 )) == -1 )
-    {
-#ifdef HAVE_ERRNO_H
-        msg_Warn( p_this, "cannot create socket (%s)", strerror(errno) );
-#else
-        msg_Warn( p_this, "cannot create socket" );
-#endif
-        return -1;
-    }
-
-    /* Set to non-blocking */
-#if defined( WIN32 ) || defined( UNDER_CE )
-    {
-        unsigned long i_dummy = 1;
-        if( ioctlsocket( i_handle, FIONBIO, &i_dummy ) != 0 )
-        {
-            msg_Err( p_this, "cannot set socket to non-blocking mode" );
-        }
-    }
-#elif defined( HAVE_ERRNO_H )
-    {
-        int i_flags;
-        if( ( i_flags = fcntl( i_handle, F_GETFL, 0 ) ) < 0 ||
-            fcntl( i_handle, F_SETFL, i_flags | O_NONBLOCK ) < 0 )
-        {
-            msg_Err( p_this, "cannot set socket to non-blocking mode" );
-        }
-    }
-#endif
-
-    return i_handle;
-}
-
-/*****************************************************************************
- * OpenTCP: open a TCP socket
- *****************************************************************************
- * psz_server_addr, i_server_port : address and port used for the connect()
- *   system call. If i_server_port == 0, 80 is used.
- * Other parameters are ignored.
- * This function returns -1 in case of error.
- *****************************************************************************/
-static int OpenTCP( vlc_object_t * p_this, network_socket_t * p_socket )
-{
-    char * psz_server_addr = p_socket->psz_server_addr;
-    int i_server_port = p_socket->i_server_port;
-
-    int i_handle;
-    struct sockaddr_in6 sock;
-
-    if( i_server_port == 0 )
-    {
-        i_server_port = 80;
-    }
-
-    if( (i_handle = SocketTCP( p_this )) == -1 )
-        return VLC_EGENERIC;
-
-    /* Build remote address */
-    if ( BuildAddr( p_this, &sock, psz_server_addr, i_server_port ) == -1 )
-        goto error;
-
-    /* Connect the socket */
-    if( connect( i_handle, (struct sockaddr *) &sock, sizeof( sock ) ) == -1 )
-    {
-#if defined( WIN32 ) || defined( UNDER_CE )
-        if( WSAGetLastError() == WSAEWOULDBLOCK )
-#elif defined( HAVE_ERRNO_H )
-        if( errno == EINPROGRESS )
-#else
-        if( 0 )
-#endif
-        {
-            int i_ret, i_opt, i_opt_size = sizeof( i_opt ), i_max_count;
-            struct timeval timeout;
-            vlc_value_t val;
-            fd_set fds;
-
-            /* FIXME: There is no ipv6-timeout option, so we use ipv4-timeout
-             * instead */
-            if( !var_Type( p_this, "ipv4-timeout" ) )
-            {
-                var_Create( p_this, "ipv4-timeout",
-                            VLC_VAR_INTEGER | VLC_VAR_DOINHERIT );
-            }
-            var_Get( p_this, "ipv4-timeout", &val );
-            i_max_count = val.i_int * 1000 / 100000 /* timeout.tv_usec */;
-
-            msg_Dbg( p_this, "connection in progress" );
-            do
-            {
-                if( p_this->b_die || i_max_count <= 0 )
-                {
-                    msg_Dbg( p_this, "connection aborted" );
-                    goto error;
-                }
-
-                i_max_count--;
-
-                /* Initialize file descriptor set */
-                FD_ZERO( &fds );
-                FD_SET( i_handle, &fds );
-
-                /* We'll wait 0.1 second if nothing happens */
-                timeout.tv_sec = 0;
-                timeout.tv_usec = 100000;
-
-            } while( ( i_ret = select( i_handle + 1, NULL, &fds, NULL,
-                                       &timeout ) ) == 0 ||
-#if defined( WIN32 ) || defined( UNDER_CE )
-                     ( i_ret < 0 && WSAGetLastError() == WSAEWOULDBLOCK ) );
-#elif defined( HAVE_ERRNO_H )
-                     ( i_ret < 0 && errno == EINTR ) );
-#else
-                     ( i_ret < 0 ) );
-#endif
-
-            if( i_ret < 0 )
-            {
-                msg_Warn( p_this, "cannot connect socket (select failed)" );
-                goto error;
-            }
-
-#if !defined( SYS_BEOS )
-            if( getsockopt( i_handle, SOL_SOCKET, SO_ERROR, (void*)&i_opt,
-                            &i_opt_size ) == -1 || i_opt != 0 )
-            {
-                msg_Warn( p_this, "cannot connect socket (SO_ERROR)" );
-                goto error;
-            }
-#endif
-        }
-        else
-        {
-#if defined( HAVE_ERRNO_H )
-            msg_Warn( p_this, "cannot connect socket (%s)", strerror(errno) );
-#else
-            msg_Warn( p_this, "cannot connect socket" );
-#endif
-            goto error;
-        }
-    }
-
-    p_socket->i_handle = i_handle;
-    p_socket->i_mtu = 0; /* There is no MTU notion in TCP */
-    return VLC_SUCCESS;
-
-error:
-    close( i_handle );
-    return VLC_EGENERIC;
-}
-
-/*****************************************************************************
- * ListenTCP: open a TCP passive socket (server-side)
- *****************************************************************************
- * psz_server_addr, i_server_port : address and port used for the bind()
- *   system call. If i_server_port == 0, 80 is used.
- * Other parameters are ignored.
- * This function returns -1 in case of error.
- *****************************************************************************/
-static int ListenTCP( vlc_object_t * p_this, network_socket_t * p_socket )
-{
-    char * psz_server_addr = p_socket->psz_server_addr;
-    int i_server_port = p_socket->i_server_port;
-
-    int i_handle, i_dummy = 1;
-    struct sockaddr_in6 sock;
-
-    if( (i_handle = SocketTCP( p_this )) == -1 )
-        return VLC_EGENERIC;
-
-    if ( setsockopt( i_handle, SOL_SOCKET, SO_REUSEADDR,
-                (void *)&i_dummy, sizeof( i_dummy ) ) == -1 )
-    {
-        msg_Warn( p_this, "cannot configure socket (SO_REUSEADDR)" );
-    }
-
-    /* Build remote address */
-    if ( BuildAddr( p_this, &sock, psz_server_addr, i_server_port ) == -1 )
-    {
-        msg_Dbg( p_this, "could not build local address" );
-        return VLC_EGENERIC;
-    }
-    
-    /* Bind the socket */
-    if( bind( i_handle, (struct sockaddr *) &sock, sizeof( sock )) == -1 )
-    {
-#ifdef HAVE_ERRNO_H
-        msg_Err( p_this, "cannot bind socket (%s)", strerror(errno) );
-#else
-        msg_Err( p_this, "cannot bind socket" );
-#endif
-        goto error;
-    }
-    /* Listen */
-    if( listen( i_handle, 100 ) == -1 )
-    {
-#ifdef HAVE_ERRNO_H
-         msg_Err( p_this, "cannot bring the socket in listening mode (%s)",
-                  strerror(errno) );
-#else
-         msg_Err( p_this, "cannot bring the socket in listening mode" );
-#endif
-         goto error;
-    }
-
-    p_socket->i_handle = i_handle;
-    p_socket->i_mtu = 0; /* There is no MTU notion in TCP */
-    return VLC_SUCCESS;
-
-error:
-    close( i_handle );
-    return VLC_EGENERIC;
-}
-
 /*****************************************************************************
  * NetOpen: wrapper around OpenUDP, ListenTCP and OpenTCP
  *****************************************************************************/
@@ -670,16 +449,5 @@ static int NetOpen( vlc_object_t * p_this )
 {
     network_socket_t * p_socket = p_this->p_private;
 
-    if( p_socket->i_type == NETWORK_UDP )
-    {
-        return OpenUDP( p_this, p_socket );
-    }
-    else if( p_socket->i_type == NETWORK_TCP_PASSIVE )
-    {
-        return ListenTCP( p_this, p_socket );
-    }
-    else
-    {
-        return OpenTCP( p_this, p_socket );
-    }
+    return OpenUDP( p_this, p_socket );
 }
index 48eff4b..9ed561b 100644 (file)
@@ -463,6 +463,11 @@ static char *ppsz_clock_descriptions[] =
     "If you check this box, IPv4 will be used by default for all UDP and " \
     "HTTP connections.")
 
+#define TIMEOUT_TEXT N_("TCP connection timeout in ms")
+#define TIMEOUT_LONGTEXT N_( \
+    "Allows you to modify the default TCP connection timeout. This " \
+    "value should be set in millisecond units." )
+
 #define SOCKS_SERVER_TEXT N_("SOCKS server")
 #define SOCKS_SERVER_LONGTEXT N_( \
     "Allow you to specify a SOCKS server to use. It must be of the form " \
@@ -1089,6 +1094,8 @@ vlc_module_begin();
         change_short('6');
     add_bool( "ipv4", 0, NULL, IPV4_TEXT, IPV4_LONGTEXT, VLC_FALSE );
         change_short('4');
+    add_integer( "ipv4-timeout", 5 * 1000, NULL, TIMEOUT_TEXT,
+                 TIMEOUT_LONGTEXT, VLC_TRUE );
 
     set_section( N_( "Socks proxy") , NULL )
     add_string( "socks", NULL, NULL,
index 94c3df0..733b538 100644 (file)
@@ -1,10 +1,11 @@
 /*****************************************************************************
  * net.c:
  *****************************************************************************
- * Copyright (C) 2004 VideoLAN
+ * Copyright (C) 2004-2005 VideoLAN
  * $Id$
  *
  * Authors: Laurent Aimar <fenrir@videolan.org>
+ *          Rémi Denis-Courmont <rem # videolan.org>
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -122,193 +123,427 @@ int net_ConvertIPv4( uint32_t *p_addr, const char * psz_address )
  *****************************************************************************/
 int __net_OpenTCP( vlc_object_t *p_this, const char *psz_host, int i_port )
 {
-    vlc_value_t      val;
-    void            *private;
-
-    char            *psz_network = "";
-    network_socket_t sock;
-    module_t         *p_network;
-
-    /* Check if we have force ipv4 or ipv6 */
-    var_Create( p_this, "ipv4", VLC_VAR_BOOL | VLC_VAR_DOINHERIT );
-    var_Get( p_this, "ipv4", &val );
-    if( val.b_bool )
-    {
-        psz_network = "ipv4";
-    }
+    struct addrinfo hints, *res, *ptr;
+    const char      *psz_realhost;
+    char            *psz_realport, *psz_socks;
+    int             i_val, i_handle = -1;
 
-    var_Create( p_this, "ipv6", VLC_VAR_BOOL | VLC_VAR_DOINHERIT );
-    var_Get( p_this, "ipv6", &val );
-    if( val.b_bool )
-    {
-        psz_network = "ipv6";
-    }
+    if( ( i_port < 0 ) || ( i_port > 65535 ) )
+        return -1; /* I don't expect the next TCP version shortly */
+    if( i_port == 0 )
+        i_port = 80; /* historical VLC thing */
 
-    /* Prepare the network_socket_t structure */
-    sock.i_type = NETWORK_TCP;
-    sock.psz_bind_addr   = "";
-    sock.i_bind_port     = 0;
-    sock.i_ttl           = 0;
+    memset( &hints, 0, sizeof( hints ) );
+    hints.ai_socktype = SOCK_STREAM;
 
-    var_Create( p_this, "socks", VLC_VAR_STRING | VLC_VAR_DOINHERIT );
-    var_Get( p_this, "socks", &val );
-    if( *val.psz_string && *val.psz_string != ':' )
+    psz_socks = var_CreateGetString( p_this, "socks" );
+    if( *psz_socks && *psz_socks != ':' )
     {
-        char *psz = strchr( val.psz_string, ':' );
+        char *psz = strchr( psz_socks, ':' );
 
         if( psz )
             *psz++ = '\0';
 
-        sock.psz_server_addr = (char*)val.psz_string;
-        sock.i_server_port   = psz ? atoi( psz ) : 1080;
+        psz_realhost = psz_socks;
+        psz_realport = strdup( ( psz != NULL ) ? psz : "1080" );
 
-        msg_Dbg( p_this, "net: connecting to '%s:%d' for '%s:%d'",
-                 sock.psz_server_addr, sock.i_server_port,
-                 psz_host, i_port );
+        msg_Dbg( p_this, "net: connecting to '%s:%s' for '%s:%d'",
+                 psz_realhost, psz_realport, psz_host, i_port );
     }
     else
     {
-        sock.psz_server_addr = (char*)psz_host;
-        sock.i_server_port   = i_port;
-        msg_Dbg( p_this, "net: connecting to '%s:%d'", psz_host, i_port );
-    }
+        psz_realhost = psz_host;
+        psz_realport = malloc( 6 );
+        if( psz_realport == NULL )
+        {
+            free( psz_socks );
+            return -1;
+        }
 
+        sprintf( psz_realport, "%d", i_port );
+        msg_Dbg( p_this, "net: connecting to '%s:%s'", psz_realhost,
+                 psz_realport );
+    }
 
-    private = p_this->p_private;
-    p_this->p_private = (void*)&sock;
-    if( !( p_network = module_Need( p_this, "network", psz_network, 0 ) ) )
+    i_val = vlc_getaddrinfo( p_this, psz_realhost, psz_realport, &hints,
+                             &res );
+    free( psz_realport );
+    if( i_val )
     {
-        msg_Dbg( p_this, "net: connection to '%s:%d' failed",
-                 psz_host, i_port );
+        msg_Err( p_this, "cannot resolve '%s' : %s", psz_realhost,
+                 vlc_gai_strerror( i_val ) );
+        free( psz_socks );
         return -1;
     }
-    module_Unneed( p_this, p_network );
-    p_this->p_private = private;
 
-    if( *val.psz_string && *val.psz_string != ':' )
+    for( ptr = res; (ptr != NULL) && (i_handle == -1); ptr = ptr->ai_next )
+    {
+        int fd;
+
+        fd = socket( ptr->ai_family, ptr->ai_socktype, ptr->ai_protocol );
+        if( fd == -1 )
+        {
+#if defined(WIN32) || defined(UNDER_CE)
+            msg_Warn( p_this, "cannot create socket (%i)",
+                      WSAGetLastError() );
+#else
+            msg_Warn( p_this, "cannot create socket (%s)",
+                      strerror( errno ) );
+#endif
+            continue;
+        }
+
+
+        /* Set to non-blocking */
+#if defined( WIN32 ) || defined( UNDER_CE )
+        {
+            unsigned long i_dummy = 1;
+            if( ioctlsocket( fd, FIONBIO, &i_dummy ) != 0 )
+                msg_Err( p_this, "cannot set socket to non-blocking mode" );
+        }
+
+# ifdef IPV6_PROTECTION_LEVEL
+        if( ptr->ai_family == PF_INET6 )
+        {
+            i_val = PROTECTION_LEVEL_UNRESTRICTED;
+            setsockopt( fd, IPPROTO_IPV6, IPV6_PROTECTION_LEVEL, &i_val,
+                        sizeof( i_val ) );
+        }
+# else
+#  warning You are using outdated headers for Winsock !
+# endif
+#else
+        if( ( ( i_val = fcntl( fd, F_GETFL, 0 ) ) < 0 ) ||
+            ( fcntl( fd, F_SETFL, i_val | O_NONBLOCK ) < 0 ) )
+            msg_Err( p_this, "cannot set socket to non-blocking mode (%s)",
+                     strerror( errno ) );
+#endif
+
+        i_val = 1;
+        setsockopt( fd, SOL_SOCKET, SO_REUSEADDR, (void *)&i_val,
+                    sizeof( i_val ) );
+
+        if( connect( fd, ptr->ai_addr, ptr->ai_addrlen ) )
+        {
+            int i_val_size = sizeof( i_val ), i_max_count;
+            struct timeval tv;
+            vlc_value_t timeout;
+            fd_set fds;
+
+#if defined( WIN32 ) || defined( UNDER_CE )
+            if( WSAGetLastError() != WSAEWOULDBLOCK )
+            {
+                msg_Warn( p_this, "connection to %s:%d failed (%d)", psz_host,
+                          i_port, WSAGetLastError( ) );
+                net_Close( fd );
+                continue;
+            }
+#else
+            if( errno != EINPROGRESS )
+            {
+                msg_Warn( p_this, "connection to %s:%d : %s", psz_host,
+                          i_port, strerror( errno ) );
+                net_Close( fd );
+                continue;
+            }
+#endif
+
+            var_Create( p_this, "ipv4-timeout",
+                        VLC_VAR_INTEGER | VLC_VAR_DOINHERIT );
+            var_Get( p_this, "ipv4-timeout", &timeout );
+            i_max_count = timeout.i_int / 100;
+
+            msg_Dbg( p_this, "connection in progress" );
+            do
+            {
+                if( p_this->b_die )
+                {
+                    msg_Dbg( p_this, "connection aborted" );
+                    net_Close( fd );
+                    vlc_freeaddrinfo( res );
+                    free( psz_socks );
+                    return -1;
+                }
+                if( i_max_count <= 0 )
+                {
+                    msg_Dbg( p_this, "connection timed out" );
+                    net_Close( fd );
+                    continue;
+                }
+
+                i_max_count--;
+
+                /* Initialize file descriptor set */
+                FD_ZERO( &fds );
+                FD_SET( fd, &fds );
+
+                /* We'll wait 0.1 second if nothing happens */
+                tv.tv_sec = 0;
+                tv.tv_usec = 100000;
+
+                i_val = select( fd + 1, NULL, &fds, NULL, &tv );
+            }
+            while( ( i_val == 0 ) || ( ( i_val < 0 ) &&
+#if defined( WIN32 ) || defined( UNDER_CE )
+                            ( WSAGetLastError() == WSAEWOULDBLOCK )
+#else
+                            ( errno == EINTR )
+#endif
+                     ) );
+
+            if( i_val < 0 )
+            {
+                msg_Warn( p_this, "connection aborted (select failed)" );
+                net_Close( fd );
+                continue;
+            }
+
+#if !defined( SYS_BEOS ) && !defined( UNDER_CE )
+            if( getsockopt( fd, SOL_SOCKET, SO_ERROR, (void*)&i_val,
+                            &i_val_size ) == -1 || i_val != 0 )
+            {
+#ifdef WIN32
+                msg_Warn( p_this, "connection to %s:%d failed (%d)", psz_host,
+                          i_port, WSAGetLastError( ) );
+#else
+                msg_Warn( p_this, "connection to %s:%d : %s", psz_host,
+                          i_port, strerror( i_val ) );
+#endif
+                net_Close( fd );
+                continue;
+            }
+#endif
+        }
+        i_handle = fd; /* success! */
+    }
+    
+    vlc_freeaddrinfo( res );
+
+    if( *psz_socks && *psz_socks != ':' )
     {
         char *psz_user = var_CreateGetString( p_this, "socks-user" );
         char *psz_pwd  = var_CreateGetString( p_this, "socks-pwd" );
 
-        if( SocksHandshakeTCP( p_this, sock.i_handle, 5,
-                               psz_user, psz_pwd,
+        if( SocksHandshakeTCP( p_this, i_handle, 5, psz_user, psz_pwd,
                                psz_host, i_port ) )
         {
             msg_Err( p_this, "failed to use the SOCKS server" );
-            net_Close( sock.i_handle );
-            return -1;
+            net_Close( i_handle );
+            i_handle = -1;
         }
 
         free( psz_user );
         free( psz_pwd );
     }
-    free( val.psz_string );
+    free( psz_socks );
 
-    return sock.i_handle;
+    return i_handle;
 }
 
+
 /*****************************************************************************
  * __net_ListenTCP:
  *****************************************************************************
- * Open a TCP listening socket and return it
+ * Open TCP passive "listening" socket(s)
+ * This function returns NULL in case of error.
  *****************************************************************************/
-int __net_ListenTCP( vlc_object_t *p_this, char *psz_host, int i_port )
+int *__net_ListenTCP( vlc_object_t *p_this, const char *psz_host, int i_port )
 {
-    vlc_value_t      val;
-    void            *private;
+    struct addrinfo hints, *res, *ptr;
+    int             i_val, *pi_handles, i_size;
+    char            *psz_port;
 
-    char            *psz_network = "";
-    network_socket_t sock;
-    module_t         *p_network;
+    if( ( i_port < 0 ) || ( i_port > 65535 ) )
+        return NULL; /* I don't expect the next TCP version shortly */
+    if( i_port == 0 )
+        i_port = 80; /* historical VLC thing */
 
-    /* Check if we have force ipv4 or ipv6 */
-    var_Create( p_this, "ipv4", VLC_VAR_BOOL | VLC_VAR_DOINHERIT );
-    var_Get( p_this, "ipv4", &val );
-    if( val.b_bool )
-    {
-        psz_network = "ipv4";
-    }
+    memset( &hints, 0, sizeof( hints ) );
+    hints.ai_socktype = SOCK_STREAM;
+    hints.ai_flags = AI_PASSIVE;
 
-    var_Create( p_this, "ipv6", VLC_VAR_BOOL | VLC_VAR_DOINHERIT );
-    var_Get( p_this, "ipv6", &val );
-    if( val.b_bool )
+    psz_port = malloc( 6 );
+    if( psz_port == NULL )
+        return NULL;
+
+    sprintf( psz_port, "%d", i_port );
+    msg_Dbg( p_this, "net: listening to '%s:%s'", psz_host, psz_port );
+
+    i_val = vlc_getaddrinfo( p_this, psz_host, psz_port, &hints, &res );
+    free( psz_port );
+    if( i_val )
     {
-        psz_network = "ipv6";
+        msg_Err( p_this, "cannot resolve '%s' : %s", psz_host,
+                 vlc_gai_strerror( i_val ) );
+        return NULL;
     }
 
-    /* Prepare the network_socket_t structure */
-    sock.i_type = NETWORK_TCP_PASSIVE;
-    sock.psz_bind_addr   = "";
-    sock.i_bind_port     = 0;
-    sock.psz_server_addr = psz_host;
-    sock.i_server_port   = i_port;
-    sock.i_ttl           = 0;
+    pi_handles = NULL;
+    i_size = 1;
 
-    msg_Dbg( p_this, "net: listening to '%s:%d'", psz_host, i_port );
-    private = p_this->p_private;
-    p_this->p_private = (void*)&sock;
-    if( !( p_network = module_Need( p_this, "network", psz_network, 0 ) ) )
+    for( ptr = res; ptr != NULL; ptr = ptr->ai_next )
     {
-        msg_Dbg( p_this, "net: listening to '%s:%d' failed",
-                 psz_host, i_port );
-        return -1;
+        int fd, *newpi;
+
+        fd = socket( ptr->ai_family, ptr->ai_socktype, ptr->ai_protocol );
+        if( fd == -1 )
+        {
+#if defined(WIN32) || defined(UNDER_CE)
+            msg_Warn( p_this, "cannot create socket (%i)",
+                      WSAGetLastError() );
+#else
+            msg_Warn( p_this, "cannot create socket (%s)",
+                      strerror( errno ) );
+#endif
+            continue;
+        }
+
+        /* Set to non-blocking */
+#if defined( WIN32 ) || defined( UNDER_CE )
+        {
+            unsigned long i_dummy = 1;
+            if( ioctlsocket( fd, FIONBIO, &i_dummy ) != 0 )
+                msg_Err( p_this, "cannot set socket to non-blocking mode" );
+        }
+#else
+        if( ( ( i_val = fcntl( fd, F_GETFL, 0 ) ) < 0 ) ||
+            ( fcntl( fd, F_SETFL, i_val | O_NONBLOCK ) < 0 ) )
+            msg_Err( p_this, "cannot set socket to non-blocking mode (%s)",
+                     strerror( errno ) );
+#endif
+
+        i_val = 1;
+        setsockopt( fd, SOL_SOCKET, SO_REUSEADDR, (void *)&i_val,
+                    sizeof( i_val ) );
+
+        /* Bind the socket */
+        if( bind( fd, ptr->ai_addr, ptr->ai_addrlen ) )
+        {
+#if defined(WIN32) || defined(UNDER_CE)
+            msg_Warn( p_this, "cannot bind socket (%i)", WSAGetLastError( ) );
+#else
+            msg_Warn( p_this, "cannot bind socket (%s)", strerror( errno ) );
+#endif
+            net_Close( fd );
+            continue;
+        }
+        /* Listen */
+        if( listen( fd, 100 ) == -1 )
+        {
+#if defined(WIN32) || defined(UNDER_CE)
+            msg_Err( p_this, "cannot bring socket in listening mode (%i)",
+                     WSAGetLastError());
+#else
+            msg_Err( p_this, "cannot bring the socket in listening mode (%s)",
+                     strerror( errno ) );
+#endif
+            net_Close( fd );
+            continue;
+        }
+
+        newpi = (int *)realloc( pi_handles, (++i_size) * sizeof( int ) );
+        if( newpi == NULL )
+        {
+            net_Close( fd );
+            break;
+        }
+        else
+        {
+            newpi[i_size - 2] = fd;
+            if( pi_handles == NULL )
+                newpi[i_size - 1] = -1;
+            pi_handles = newpi;
+        }
     }
-    module_Unneed( p_this, p_network );
-    p_this->p_private = private;
+    
+    freeaddrinfo( res );
 
-    return sock.i_handle;
+    return pi_handles;
 }
 
 /*****************************************************************************
  * __net_Accept:
  *****************************************************************************
- * Accept a connection on a listening socket and return it
+ * Accept a connection on a set of listening sockets and return it
  *****************************************************************************/
-int __net_Accept( vlc_object_t *p_this, int fd, mtime_t i_wait )
+int __net_Accept( vlc_object_t *p_this, int *pi_fd, mtime_t i_wait )
 {
     vlc_bool_t b_die = p_this->b_die, b_block = (i_wait < 0);
-    struct timeval timeout;
-    fd_set fds_r, fds_e;
-    int i_ret;
 
     while( p_this->b_die == b_die )
     {
+        int i_val = -1, *pi, *pi_end;
+        struct timeval timeout;
+        fd_set fds_r, fds_e;
+
+        pi = pi_fd;
+
         /* Initialize file descriptor set */
         FD_ZERO( &fds_r );
-        FD_SET( fd, &fds_r );
         FD_ZERO( &fds_e );
-        FD_SET( fd, &fds_e );
+
+        for( pi = pi_fd; *pi != -1; pi++ )
+        {
+            int i_fd = *pi;
+
+            if( i_fd > i_val )
+                i_val = i_fd;
+
+            FD_SET( i_fd, &fds_r );
+            FD_SET( i_fd, &fds_e );
+        }
+        pi_end = pi;
 
         timeout.tv_sec = 0;
         timeout.tv_usec = b_block ? 500000 : i_wait;
 
-        i_ret = select(fd + 1, &fds_r, NULL, &fds_e, &timeout);
-        if( (i_ret < 0 && errno == EINTR) || i_ret == 0 )
+        i_val = select( i_val + 1, &fds_r, NULL, &fds_e, &timeout );
+        if( ( ( i_val < 0 ) && ( errno == EINTR ) ) || i_val == 0 )
         {
-            if( b_block ) continue;
-            else return -1;
+            if( b_block )
+                continue;
+            else
+                return -1;
         }
-        else if( i_ret < 0 )
+        else if( i_val < 0 )
         {
 #if defined(WIN32) || defined(UNDER_CE)
             msg_Err( p_this, "network select error (%i)", WSAGetLastError() );
 #else
-            msg_Err( p_this, "network select error (%s)", strerror(errno) );
+            msg_Err( p_this, "network select error (%s)", strerror( errno ) );
 #endif
             return -1;
         }
 
-        if( ( i_ret = accept( fd, 0, 0 ) ) <= 0 )
+        for( pi = pi_fd; *pi != -1; pi++ )
         {
+            int i_fd = *pi;
+
+            if( !FD_ISSET( i_fd, &fds_r ) && !FD_ISSET( i_fd, &fds_e ) )
+                continue;
+
+            i_val = accept( i_fd, NULL, 0 );
+            if( i_val < 0 )
+            {
 #if defined(WIN32) || defined(UNDER_CE)
-            msg_Err( p_this, "accept failed (%i)", WSAGetLastError() );
+                msg_Err( p_this, "accept failed (%i)", WSAGetLastError() );
 #else
-            msg_Err( p_this, "accept failed (%s)", strerror(errno) );
+                msg_Err( p_this, "accept failed (%s)", strerror( errno ) );
 #endif
-            return -1;
+            }
+            else
+            {
+                /*
+                 * This round-robin trick ensures that the first sockets in
+                 * pi_fd won't prevent the last ones from getting accept'ed.
+                 */
+                --pi_end;
+                memmove( pi, pi + 1, pi_end - pi );
+                *pi_end = i_fd;
+                return i_val;
+            }
         }
-
-        return i_ret;
     }
 
     return -1;
@@ -348,7 +583,6 @@ int __net_OpenUDP( vlc_object_t *p_this, char *psz_bind, int i_bind,
     if( psz_bind   == NULL ) psz_bind   = "";
 
     /* Prepare the network_socket_t structure */
-    sock.i_type = NETWORK_UDP;
     sock.psz_bind_addr   = psz_bind;
     sock.i_bind_port     = i_bind;
     sock.psz_server_addr = psz_server;
@@ -387,6 +621,18 @@ void net_Close( int fd )
 #endif
 }
 
+void net_ListenClose( int *pi_fd )
+{
+    if( pi_fd != NULL )
+    {
+        int *pi;
+
+        for( pi = pi_fd; *pi != -1; pi++ )
+            net_Close( *pi );
+        free( pi_fd );
+    }
+}
+
 /*****************************************************************************
  * __net_Read:
  *****************************************************************************