From b59991fc28eda66262830b386cae86c9cdecc1ab Mon Sep 17 00:00:00 2001 From: =?utf8?q?R=C3=A9mi=20Denis-Courmont?= Date: Sun, 22 May 2005 11:24:08 +0000 Subject: [PATCH] - Use the new vlc_getaddrinfo API - 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 | 96 +++++++- modules/control/rc.c | 31 ++- modules/control/telnet.c | 11 +- modules/misc/network/ipv4.c | 247 +------------------ modules/misc/network/ipv6.c | 262 ++------------------ src/libvlc.h | 7 + src/misc/net.c | 462 +++++++++++++++++++++++++++--------- 7 files changed, 489 insertions(+), 627 deletions(-) diff --git a/include/network.h b/include/network.h index f0893d45cb..4661d0f7ae 100644 --- a/include/network.h +++ b/include/network.h @@ -6,7 +6,7 @@ * * Authors: Christophe Massiot * Laurent Aimar - * Rémi Denis-Courmont + * Rémi Denis-Courmont * * 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 diff --git a/modules/control/rc.c b/modules/control/rc.c index 11a4a938fd..1cba2351eb 100644 --- a/modules/control/rc.c +++ b/modules/control/rc.c @@ -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 ); diff --git a/modules/control/telnet.c b/modules/control/telnet.c index e142c8b1c6..05b89946ba 100644 --- a/modules/control/telnet.c +++ b/modules/control/telnet.c @@ -1,7 +1,7 @@ /***************************************************************************** * telnet.c: VLM interface plugin ***************************************************************************** - * Copyright (C) 2000, 2001 VideoLAN + * Copyright (C) 2000-2005 VideoLAN * $Id$ * * Authors: Simon Latapie @@ -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; diff --git a/modules/misc/network/ipv4.c b/modules/misc/network/ipv4.c index 2338ed08c3..a258d741ab 100644 --- a/modules/misc/network/ipv4.c +++ b/modules/misc/network/ipv4.c @@ -1,7 +1,7 @@ /***************************************************************************** * ipv4.c: IPv4 network abstraction layer ***************************************************************************** - * Copyright (C) 2001, 2002 VideoLAN + * Copyright (C) 2001-2005 VideoLAN * $Id$ * * Authors: Christophe Massiot @@ -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 ); } diff --git a/modules/misc/network/ipv6.c b/modules/misc/network/ipv6.c index a9ab69399b..22cbef414c 100644 --- a/modules/misc/network/ipv6.c +++ b/modules/misc/network/ipv6.c @@ -1,7 +1,7 @@ /***************************************************************************** * ipv6.c: IPv6 network abstraction layer ***************************************************************************** - * Copyright (C) 2002 VideoLAN + * Copyright (C) 2002-2005 VideoLAN * $Id$ * * Authors: Alexis Guillard @@ -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 ); } diff --git a/src/libvlc.h b/src/libvlc.h index 48eff4bd3b..9ed561b9c3 100644 --- a/src/libvlc.h +++ b/src/libvlc.h @@ -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, diff --git a/src/misc/net.c b/src/misc/net.c index 94c3df0322..733b538004 100644 --- a/src/misc/net.c +++ b/src/misc/net.c @@ -1,10 +1,11 @@ /***************************************************************************** * net.c: ***************************************************************************** - * Copyright (C) 2004 VideoLAN + * Copyright (C) 2004-2005 VideoLAN * $Id$ * * Authors: Laurent Aimar + * Rémi Denis-Courmont * * 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: ***************************************************************************** -- 2.39.2