]> git.sesse.net Git - vlc/commitdiff
Sort out io.c
authorRémi Denis-Courmont <rem@videolan.org>
Mon, 5 Dec 2005 09:36:39 +0000 (09:36 +0000)
committerRémi Denis-Courmont <rem@videolan.org>
Mon, 5 Dec 2005 09:36:39 +0000 (09:36 +0000)
Makefile.am
src/network/io.c
src/network/tcp.c [new file with mode: 0644]
src/network/udp.c [new file with mode: 0644]

index e16a8ea2977b0c5143ebc40e9455dcafba4e19c0..6109e05645cadac722526546bf102d7ef1b36ef9 100644 (file)
@@ -435,10 +435,12 @@ SOURCES_libvlc_common = \
        src/osd/osd_parser.c \
        src/osd/osd_text.c \
        src/osd/osd_widgets.c \
+       src/network/getaddrinfo.c \
+       src/network/io.c \
+       src/network/tcp.c \
+       src/network/udp.c \
        src/network/httpd.c \
        src/network/tls.c \
-       src/network/io.c \
-       src/network/getaddrinfo.c \
        src/misc/charset.c \
        src/misc/md5.c \
        src/misc/mtime.c \
index 7106c08dad23e4ca03eeb097e1f8e7e1cb8d1cb5..93d9921466d5bfc0663e80130db574d766841c36 100644 (file)
@@ -1,5 +1,5 @@
 /*****************************************************************************
- * net.c:
+ * io.c: network I/O functions
  *****************************************************************************
  * Copyright (C) 2004-2005 the VideoLAN team
  * $Id$
 #   define INADDR_NONE 0xFFFFFFFF
 #endif
 
-static int SocksNegociate( vlc_object_t *, int fd, int i_socks_version,
-                           char *psz_socks_user, char *psz_socks_passwd );
-static int SocksHandshakeTCP( vlc_object_t *,
-                              int fd, int i_socks_version,
-                              char *psz_socks_user, char *psz_socks_passwd,
-                              const char *psz_host, int i_port );
-
-static int net_Socket( vlc_object_t *p_this, int i_family, int i_socktype,
-                       int i_protocol )
+int net_Socket( vlc_object_t *p_this, int i_family, int i_socktype,
+                int i_protocol )
 {
     int fd, i_val;
 
@@ -122,573 +115,6 @@ static int net_Socket( vlc_object_t *p_this, int i_family, int i_socktype,
     return fd;
 }
 
-/*****************************************************************************
- * __net_ConnectTCP:
- *****************************************************************************
- * Open a TCP connection and return a handle
- *****************************************************************************/
-int __net_ConnectTCP( vlc_object_t *p_this, const char *psz_host, int i_port )
-{
-    struct addrinfo hints, *res, *ptr;
-    const char      *psz_realhost;
-    char            *psz_socks;
-    int             i_realport, i_val, i_handle = -1;
-    vlc_bool_t      b_unreach = VLC_FALSE;
-
-    if( i_port == 0 )
-        i_port = 80; /* historical VLC thing */
-
-    memset( &hints, 0, sizeof( hints ) );
-    hints.ai_socktype = SOCK_STREAM;
-
-    psz_socks = var_CreateGetString( p_this, "socks" );
-    if( *psz_socks && *psz_socks != ':' )
-    {
-        char *psz = strchr( psz_socks, ':' );
-
-        if( psz )
-            *psz++ = '\0';
-
-        psz_realhost = psz_socks;
-        i_realport = ( psz != NULL ) ? atoi( psz ) : 1080;
-
-        msg_Dbg( p_this, "net: connecting to %s port %d for %s port %d",
-                 psz_realhost, i_realport, psz_host, i_port );
-    }
-    else
-    {
-        psz_realhost = psz_host;
-        i_realport = i_port;
-
-        msg_Dbg( p_this, "net: connecting to %s port %d", psz_realhost,
-                 i_realport );
-    }
-
-    i_val = vlc_getaddrinfo( p_this, psz_realhost, i_realport, &hints, &res );
-    if( i_val )
-    {
-        msg_Err( p_this, "cannot resolve %s port %d : %s", psz_realhost,
-                 i_realport, vlc_gai_strerror( i_val ) );
-        free( psz_socks );
-        return -1;
-    }
-
-    for( ptr = res; (ptr != NULL) && (i_handle == -1); ptr = ptr->ai_next )
-    {
-        int fd;
-
-        fd = net_Socket( p_this, ptr->ai_family, ptr->ai_socktype,
-                         ptr->ai_protocol );
-        if( fd == -1 )
-            continue;
-
-        if( connect( fd, ptr->ai_addr, ptr->ai_addrlen ) )
-        {
-            socklen_t i_val_size = sizeof( i_val );
-            div_t d;
-            struct timeval tv;
-            vlc_value_t timeout;
-
-#if defined( WIN32 ) || defined( UNDER_CE )
-            if( WSAGetLastError() != WSAEWOULDBLOCK )
-            {
-                if( WSAGetLastError () == WSAENETUNREACH )
-                    b_unreach = VLC_TRUE;
-                else
-                    msg_Warn( p_this, "connection to %s port %d failed (%d)",
-                              psz_host, i_port, WSAGetLastError( ) );
-                net_Close( fd );
-                continue;
-            }
-#else
-            if( errno != EINPROGRESS )
-            {
-                if( errno == ENETUNREACH )
-                    b_unreach = VLC_TRUE;
-                else
-                    msg_Warn( p_this, "connection to %s port %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 );
-            if( timeout.i_int < 0 )
-            {
-                msg_Err( p_this, "invalid negative value for ipv4-timeout" );
-                timeout.i_int = 0;
-            }
-            d = div( timeout.i_int, 100 );
-
-            msg_Dbg( p_this, "connection in progress" );
-            do
-            {
-                fd_set fds;
-
-                if( p_this->b_die )
-                {
-                    msg_Dbg( p_this, "connection aborted" );
-                    net_Close( fd );
-                    vlc_freeaddrinfo( res );
-                    free( psz_socks );
-                    return -1;
-                }
-
-                /* 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 = (d.quot > 0) ? 100000 : (1000 * d.rem);
-
-                i_val = select( fd + 1, NULL, &fds, NULL, &tv );
-
-                if( d.quot <= 0 )
-                {
-                    msg_Dbg( p_this, "connection timed out" );
-                    net_Close( fd );
-                    fd = -1;
-                    break;
-                }
-
-                d.quot--;
-            }
-            while( ( i_val == 0 ) || ( ( i_val < 0 ) &&
-#if defined( WIN32 ) || defined( UNDER_CE )
-                            ( WSAGetLastError() == WSAEWOULDBLOCK )
-#else
-                            ( errno == EINTR )
-#endif
-                     ) );
-
-            if( fd == -1 )
-                continue; /* timeout */
-
-            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 )
-            {
-                if( i_val == ENETUNREACH )
-                    b_unreach = VLC_TRUE;
-                else
-                {
-#ifdef WIN32
-                    msg_Warn( p_this, "connection to %s port %d failed (%d)",
-                              psz_host, i_port, WSAGetLastError( ) );
-#else
-                    msg_Warn( p_this, "connection to %s port %d : %s", psz_host,
-                              i_port, strerror( i_val ) );
-#endif
-                }
-                net_Close( fd );
-                continue;
-            }
-#endif
-        }
-        i_handle = fd; /* success! */
-    }
-
-    vlc_freeaddrinfo( res );
-
-    if( i_handle == -1 )
-    {
-        if( b_unreach )
-            msg_Err( p_this, "Host %s port %d is unreachable", psz_host,
-                     i_port );
-        return -1;
-    }
-
-    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, i_handle, 5, psz_user, psz_pwd,
-                               psz_host, i_port ) )
-        {
-            msg_Err( p_this, "failed to use the SOCKS server" );
-            net_Close( i_handle );
-            i_handle = -1;
-        }
-
-        free( psz_user );
-        free( psz_pwd );
-    }
-    free( psz_socks );
-
-    return i_handle;
-}
-
-
-/*****************************************************************************
- * __net_ListenTCP:
- *****************************************************************************
- * Open TCP passive "listening" socket(s)
- * This function returns NULL in case of error.
- *****************************************************************************/
-int *__net_ListenTCP( vlc_object_t *p_this, const char *psz_host, int i_port )
-{
-    struct addrinfo hints, *res, *ptr;
-    int             i_val, *pi_handles, i_size;
-
-    memset( &hints, 0, sizeof( hints ) );
-    hints.ai_socktype = SOCK_STREAM;
-    hints.ai_flags = AI_PASSIVE;
-
-    msg_Dbg( p_this, "net: listening to %s port %d", psz_host, i_port );
-
-    i_val = vlc_getaddrinfo( p_this, psz_host, i_port, &hints, &res );
-    if( i_val )
-    {
-        msg_Err( p_this, "cannot resolve %s port %d : %s", psz_host, i_port,
-                 vlc_gai_strerror( i_val ) );
-        return NULL;
-    }
-
-    pi_handles = NULL;
-    i_size = 1;
-
-    for( ptr = res; ptr != NULL; ptr = ptr->ai_next )
-    {
-        int fd, *newpi;
-
-        fd = net_Socket( p_this, ptr->ai_family, ptr->ai_socktype,
-                         ptr->ai_protocol );
-        if( fd == -1 )
-            continue;
-
-        /* 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;
-            pi_handles = newpi;
-        }
-    }
-
-    vlc_freeaddrinfo( res );
-
-    if( pi_handles != NULL )
-        pi_handles[i_size - 1] = -1;
-    return pi_handles;
-}
-
-/*****************************************************************************
- * __net_Accept:
- *****************************************************************************
- * Accept a connection on a set of listening sockets and return it
- *****************************************************************************/
-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);
-
-    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_ZERO( &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_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;
-        }
-        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 ) );
-#endif
-            return -1;
-        }
-
-        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() );
-#else
-                msg_Err( p_this, "accept failed (%s)", strerror( errno ) );
-#endif
-            }
-            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 -1;
-}
-
-
-/*****************************************************************************
- * __net_ConnectUDP:
- *****************************************************************************
- * Open a UDP socket to send data to a defined destination, with an optional
- * hop limit.
- *****************************************************************************/
-int __net_ConnectUDP( vlc_object_t *p_this, const char *psz_host, int i_port,
-                      int hlim )
-{
-    struct addrinfo hints, *res, *ptr;
-    int             i_val, i_handle = -1;
-    vlc_bool_t      b_unreach = VLC_FALSE;
-
-    if( i_port == 0 )
-        i_port = 1234; /* historical VLC thing */
-
-    memset( &hints, 0, sizeof( hints ) );
-    hints.ai_socktype = SOCK_DGRAM;
-
-    msg_Dbg( p_this, "net: connecting to %s port %d", psz_host, i_port );
-
-    i_val = vlc_getaddrinfo( p_this, psz_host, i_port, &hints, &res );
-    if( i_val )
-    {
-        msg_Err( p_this, "cannot resolve %s port %d : %s", psz_host, i_port,
-                 vlc_gai_strerror( i_val ) );
-        return -1;
-    }
-
-    for( ptr = res; ptr != NULL; ptr = ptr->ai_next )
-    {
-        int fd;
-
-        fd = net_Socket( p_this, ptr->ai_family, ptr->ai_socktype,
-                         ptr->ai_protocol );
-        if( fd == -1 )
-            continue;
-#if !defined( SYS_BEOS )
-        else
-        {
-            int i_val;
-
-            /* Increase the receive buffer size to 1/2MB (8Mb/s during 1/2s) to avoid
-            * packet loss caused by scheduling problems */
-            i_val = 0x80000;
-            setsockopt( i_handle, SOL_SOCKET, SO_RCVBUF, (void *)&i_val,
-                        sizeof( i_val ) );
-            i_val = 0x80000;
-            setsockopt( i_handle, SOL_SOCKET, SO_SNDBUF, (void *)&i_val,
-                        sizeof( i_val ) );
-        }
-#endif
-
-        if( connect( fd, ptr->ai_addr, ptr->ai_addrlen ) == 0 )
-        {
-            /* success */
-            i_handle = fd;
-            break;
-        }
-
-#if defined( WIN32 ) || defined( UNDER_CE )
-        if( WSAGetLastError () == WSAENETUNREACH )
-#else
-        if( errno == ENETUNREACH )
-#endif
-            b_unreach = VLC_TRUE;
-        else
-        {
-            msg_Warn( p_this, "%s port %d : %s", psz_host, i_port,
-                      strerror( errno ) );
-            net_Close( fd );
-            continue;
-        }
-    }
-
-    vlc_freeaddrinfo( res );
-
-    if( i_handle == -1 )
-    {
-        if( b_unreach )
-            msg_Err( p_this, "Host %s port %d is unreachable", psz_host,
-                     i_port );
-        return -1;
-    }
-
-    return i_handle;
-}
-
-/*****************************************************************************
- * __net_OpenUDP:
- *****************************************************************************
- * Open a UDP connection and return a handle
- *****************************************************************************/
-int __net_OpenUDP( vlc_object_t *p_this, const char *psz_bind, int i_bind,
-                   const char *psz_server, int i_server )
-{
-    vlc_value_t      v4, v6;
-    void            *private;
-    network_socket_t sock;
-    module_t         *p_network = NULL;
-
-    if( ( psz_server != NULL ) && ( psz_server[0] == '\0' ) )
-        msg_Warn( p_this, "calling net_OpenUDP with an explicit destination "
-                  "is obsolete - use net_ConnectUDP instead" );
-    if( i_server != 0 )
-        msg_Warn( p_this, "calling net_OpenUDP with an explicit destination "
-                  "port is obsolete - use __net_ConnectUDP instead" );
-
-    if( psz_server == NULL ) psz_server = "";
-    if( psz_bind == NULL ) psz_bind = "";
-
-    /* Prepare the network_socket_t structure */
-    sock.psz_bind_addr   = psz_bind;
-    sock.i_bind_port     = i_bind;
-    sock.psz_server_addr = psz_server;
-    sock.i_server_port   = i_server;
-    sock.i_ttl           = 0;
-    sock.v6only          = 0;
-    sock.i_handle        = -1;
-
-    msg_Dbg( p_this, "net: connecting to '[%s]:%d@[%s]:%d'",
-             psz_server, i_server, psz_bind, i_bind );
-
-    /* Check if we have force ipv4 or ipv6 */
-    var_Create( p_this, "ipv4", VLC_VAR_BOOL | VLC_VAR_DOINHERIT );
-    var_Get( p_this, "ipv4", &v4 );
-    var_Create( p_this, "ipv6", VLC_VAR_BOOL | VLC_VAR_DOINHERIT );
-    var_Get( p_this, "ipv6", &v6 );
-
-    if( !v4.b_bool )
-    {
-        if( v6.b_bool )
-            sock.v6only = 1;
-
-        /* try IPv6 first (unless IPv4 forced) */
-        private = p_this->p_private;
-        p_this->p_private = (void*)&sock;
-        p_network = module_Need( p_this, "network", "ipv6", VLC_TRUE );
-
-        if( p_network != NULL )
-            module_Unneed( p_this, p_network );
-
-        p_this->p_private = private;
-
-        /*
-         * Check if the IP stack can receive IPv4 packets on IPv6 sockets.
-         * If yes, then it is better to use the IPv6 socket.
-         * Otherwise, if we also get an IPv4, we have to choose, so we use
-         * IPv4 only.
-         */
-        if( ( sock.i_handle != -1 ) && ( ( sock.v6only == 0 ) || v6.b_bool ) )
-            return sock.i_handle;
-    }
-
-    if( !v6.b_bool )
-    {
-        int fd6 = sock.i_handle;
-
-        /* also try IPv4 (unless IPv6 forced) */
-        private = p_this->p_private;
-        p_this->p_private = (void*)&sock;
-        p_network = module_Need( p_this, "network", "ipv4", VLC_TRUE );
-
-        if( p_network != NULL )
-            module_Unneed( p_this, p_network );
-
-        p_this->p_private = private;
-
-        if( fd6 != -1 )
-        {
-            if( sock.i_handle != -1 )
-            {
-                msg_Warn( p_this, "net: lame IPv6/IPv4 dual-stack present. "
-                                  "Using only IPv4." );
-                net_Close( fd6 );
-            }
-            else
-                sock.i_handle = fd6;
-        }
-    }
-
-    if( sock.i_handle == -1 )
-        msg_Dbg( p_this, "net: connection to '[%s]:%d@[%s]:%d' failed",
-                psz_server, i_server, psz_bind, i_bind );
-
-    return sock.i_handle;
-}
 
 /*****************************************************************************
  * __net_Close:
@@ -706,18 +132,6 @@ 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:
  *****************************************************************************
@@ -1099,200 +513,6 @@ int __net_vaPrintf( vlc_object_t *p_this, int fd, v_socket_t *p_vs,
 }
 
 
-
-/*****************************************************************************
- * SocksNegociate:
- *****************************************************************************
- * Negociate authentication with a SOCKS server.
- *****************************************************************************/
-static int SocksNegociate( vlc_object_t *p_obj,
-                           int fd, int i_socks_version,
-                           char *psz_socks_user,
-                           char *psz_socks_passwd )
-{
-    uint8_t buffer[128+2*256];
-    int i_len;
-    vlc_bool_t b_auth = VLC_FALSE;
-
-    if( i_socks_version != 5 )
-        return VLC_SUCCESS;
-
-    /* We negociate authentication */
-
-    if( psz_socks_user && psz_socks_passwd &&
-        *psz_socks_user && *psz_socks_passwd )
-        b_auth = VLC_TRUE;
-
-    buffer[0] = i_socks_version;    /* SOCKS version */
-    if( b_auth )
-    {
-        buffer[1] = 2;                  /* Number of methods */
-        buffer[2] = 0x00;               /* - No auth required */
-        buffer[3] = 0x02;               /* - USer/Password */
-        i_len = 4;
-    }
-    else
-    {
-        buffer[1] = 1;                  /* Number of methods */
-        buffer[2] = 0x00;               /* - No auth required */
-        i_len = 3;
-    }
-
-    if( net_Write( p_obj, fd, NULL, buffer, i_len ) != i_len )
-        return VLC_EGENERIC;
-    if( net_Read( p_obj, fd, NULL, buffer, 2, VLC_TRUE ) != 2 )
-        return VLC_EGENERIC;
-
-    msg_Dbg( p_obj, "socks: v=%d method=%x", buffer[0], buffer[1] );
-
-    if( buffer[1] == 0x00 )
-    {
-        msg_Dbg( p_obj, "socks: no authentication required" );
-    }
-    else if( buffer[1] == 0x02 )
-    {
-        int i_len1 = __MIN( strlen(psz_socks_user), 255 );
-        int i_len2 = __MIN( strlen(psz_socks_passwd), 255 );
-        msg_Dbg( p_obj, "socks: username/password authentication" );
-
-        /* XXX: we don't support user/pwd > 255 (truncated)*/
-        buffer[0] = i_socks_version;        /* Version */
-        buffer[1] = i_len1;                 /* User length */
-        memcpy( &buffer[2], psz_socks_user, i_len1 );
-        buffer[2+i_len1] = i_len2;          /* Password length */
-        memcpy( &buffer[2+i_len1+1], psz_socks_passwd, i_len2 );
-
-        i_len = 3 + i_len1 + i_len2;
-
-        if( net_Write( p_obj, fd, NULL, buffer, i_len ) != i_len )
-            return VLC_EGENERIC;
-
-        if( net_Read( p_obj, fd, NULL, buffer, 2, VLC_TRUE ) != 2 )
-            return VLC_EGENERIC;
-
-        msg_Dbg( p_obj, "socks: v=%d status=%x", buffer[0], buffer[1] );
-        if( buffer[1] != 0x00 )
-        {
-            msg_Err( p_obj, "socks: authentication rejected" );
-            return VLC_EGENERIC;
-        }
-    }
-    else
-    {
-        if( b_auth )
-            msg_Err( p_obj, "socks: unsupported authentication method %x",
-                     buffer[0] );
-        else
-            msg_Err( p_obj, "socks: authentification needed" );
-        return VLC_EGENERIC;
-    }
-
-    return VLC_SUCCESS;
-}
-
-/*****************************************************************************
- * SocksHandshakeTCP:
- *****************************************************************************
- * Open a TCP connection using a SOCKS server and return a handle (RFC 1928)
- *****************************************************************************/
-static int SocksHandshakeTCP( vlc_object_t *p_obj,
-                              int fd,
-                              int i_socks_version,
-                              char *psz_socks_user, char *psz_socks_passwd,
-                              const char *psz_host, int i_port )
-{
-    uint8_t buffer[128+2*256];
-
-    if( i_socks_version != 4 && i_socks_version != 5 )
-    {
-        msg_Warn( p_obj, "invalid socks protocol version %d", i_socks_version );
-        i_socks_version = 5;
-    }
-
-    if( i_socks_version == 5 && 
-        SocksNegociate( p_obj, fd, i_socks_version,
-                        psz_socks_user, psz_socks_passwd ) )
-        return VLC_EGENERIC;
-
-    if( i_socks_version == 4 )
-    {
-        struct addrinfo hints = { 0 }, *p_res;
-
-        /* v4 only support ipv4 */
-        hints.ai_family = AF_INET;
-        if( vlc_getaddrinfo( p_obj, psz_host, 0, &hints, &p_res ) )
-            return VLC_EGENERIC;
-
-        buffer[0] = i_socks_version;
-        buffer[1] = 0x01;               /* CONNECT */
-        SetWBE( &buffer[2], i_port );   /* Port */
-        memcpy( &buffer[4],             /* Address */
-                &((struct sockaddr_in *)(p_res->ai_addr))->sin_addr, 4 );
-        vlc_freeaddrinfo( p_res );
-
-        buffer[8] = 0;                  /* Empty user id */
-
-        if( net_Write( p_obj, fd, NULL, buffer, 9 ) != 9 )
-            return VLC_EGENERIC;
-        if( net_Read( p_obj, fd, NULL, buffer, 8, VLC_TRUE ) != 8 )
-            return VLC_EGENERIC;
-
-        msg_Dbg( p_obj, "socks: v=%d cd=%d",
-                 buffer[0], buffer[1] );
-
-        if( buffer[1] != 90 )
-            return VLC_EGENERIC;
-    }
-    else if( i_socks_version == 5 )
-    {
-        int i_hlen = __MIN(strlen( psz_host ), 255);
-        int i_len;
-
-        buffer[0] = i_socks_version;    /* Version */
-        buffer[1] = 0x01;               /* Cmd: connect */
-        buffer[2] = 0x00;               /* Reserved */
-        buffer[3] = 3;                  /* ATYP: for now domainname */
-
-        buffer[4] = i_hlen;
-        memcpy( &buffer[5], psz_host, i_hlen );
-        SetWBE( &buffer[5+i_hlen], i_port );
-
-        i_len = 5 + i_hlen + 2;
-
-
-        if( net_Write( p_obj, fd, NULL, buffer, i_len ) != i_len )
-            return VLC_EGENERIC;
-
-        /* Read the header */
-        if( net_Read( p_obj, fd, NULL, buffer, 5, VLC_TRUE ) != 5 )
-            return VLC_EGENERIC;
-
-        msg_Dbg( p_obj, "socks: v=%d rep=%d atyp=%d",
-                 buffer[0], buffer[1], buffer[3] );
-
-        if( buffer[1] != 0x00 )
-        {
-            msg_Err( p_obj, "socks: CONNECT request failed\n" );
-            return VLC_EGENERIC;
-        }
-
-        /* Read the remaining bytes */
-        if( buffer[3] == 0x01 )
-            i_len = 4-1 + 2;
-        else if( buffer[3] == 0x03 )
-            i_len = buffer[4] + 2;
-        else if( buffer[3] == 0x04 )
-            i_len = 16-1+2;
-        else 
-            return VLC_EGENERIC;
-
-        if( net_Read( p_obj, fd, NULL, buffer, i_len, VLC_TRUE ) != i_len )
-            return VLC_EGENERIC;
-    }
-
-    return VLC_SUCCESS;
-}
-
 /*****************************************************************************
  * inet_pton replacement for obsolete and/or crap operating systems
  *****************************************************************************/
diff --git a/src/network/tcp.c b/src/network/tcp.c
new file mode 100644 (file)
index 0000000..a05db09
--- /dev/null
@@ -0,0 +1,637 @@
+/*****************************************************************************
+ * tcp.c:
+ *****************************************************************************
+ * Copyright (C) 2004-2005 the VideoLAN team
+ * $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
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
+ *****************************************************************************/
+
+/*****************************************************************************
+ * Preamble
+ *****************************************************************************/
+#include <stdlib.h>
+#include <vlc/vlc.h>
+
+#include <errno.h>
+
+#ifdef HAVE_FCNTL_H
+#   include <fcntl.h>
+#endif
+#ifdef HAVE_SYS_TIME_H
+#    include <sys/time.h>
+#endif
+#ifdef HAVE_UNISTD_H
+#   include <unistd.h>
+#endif
+
+#include "network.h"
+
+static int SocksNegociate( vlc_object_t *, int fd, int i_socks_version,
+                           char *psz_socks_user, char *psz_socks_passwd );
+static int SocksHandshakeTCP( vlc_object_t *,
+                              int fd, int i_socks_version,
+                              char *psz_socks_user, char *psz_socks_passwd,
+                              const char *psz_host, int i_port );
+extern int net_Socket( vlc_object_t *p_this, int i_family, int i_socktype,
+                       int i_protocol );
+
+/*****************************************************************************
+ * __net_ConnectTCP:
+ *****************************************************************************
+ * Open a TCP connection and return a handle
+ *****************************************************************************/
+int __net_ConnectTCP( vlc_object_t *p_this, const char *psz_host, int i_port )
+{
+    struct addrinfo hints, *res, *ptr;
+    const char      *psz_realhost;
+    char            *psz_socks;
+    int             i_realport, i_val, i_handle = -1;
+    vlc_bool_t      b_unreach = VLC_FALSE;
+
+    if( i_port == 0 )
+        i_port = 80; /* historical VLC thing */
+
+    memset( &hints, 0, sizeof( hints ) );
+    hints.ai_socktype = SOCK_STREAM;
+
+    psz_socks = var_CreateGetString( p_this, "socks" );
+    if( *psz_socks && *psz_socks != ':' )
+    {
+        char *psz = strchr( psz_socks, ':' );
+
+        if( psz )
+            *psz++ = '\0';
+
+        psz_realhost = psz_socks;
+        i_realport = ( psz != NULL ) ? atoi( psz ) : 1080;
+
+        msg_Dbg( p_this, "net: connecting to %s port %d for %s port %d",
+                 psz_realhost, i_realport, psz_host, i_port );
+    }
+    else
+    {
+        psz_realhost = psz_host;
+        i_realport = i_port;
+
+        msg_Dbg( p_this, "net: connecting to %s port %d", psz_realhost,
+                 i_realport );
+    }
+
+    i_val = vlc_getaddrinfo( p_this, psz_realhost, i_realport, &hints, &res );
+    if( i_val )
+    {
+        msg_Err( p_this, "cannot resolve %s port %d : %s", psz_realhost,
+                 i_realport, vlc_gai_strerror( i_val ) );
+        free( psz_socks );
+        return -1;
+    }
+
+    for( ptr = res; (ptr != NULL) && (i_handle == -1); ptr = ptr->ai_next )
+    {
+        int fd;
+
+        fd = net_Socket( p_this, ptr->ai_family, ptr->ai_socktype,
+                         ptr->ai_protocol );
+        if( fd == -1 )
+            continue;
+
+        if( connect( fd, ptr->ai_addr, ptr->ai_addrlen ) )
+        {
+            socklen_t i_val_size = sizeof( i_val );
+            div_t d;
+            struct timeval tv;
+            vlc_value_t timeout;
+
+#if defined( WIN32 ) || defined( UNDER_CE )
+            if( WSAGetLastError() != WSAEWOULDBLOCK )
+            {
+                if( WSAGetLastError () == WSAENETUNREACH )
+                    b_unreach = VLC_TRUE;
+                else
+                    msg_Warn( p_this, "connection to %s port %d failed (%d)",
+                              psz_host, i_port, WSAGetLastError( ) );
+                net_Close( fd );
+                continue;
+            }
+#else
+            if( errno != EINPROGRESS )
+            {
+                if( errno == ENETUNREACH )
+                    b_unreach = VLC_TRUE;
+                else
+                    msg_Warn( p_this, "connection to %s port %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 );
+            if( timeout.i_int < 0 )
+            {
+                msg_Err( p_this, "invalid negative value for ipv4-timeout" );
+                timeout.i_int = 0;
+            }
+            d = div( timeout.i_int, 100 );
+
+            msg_Dbg( p_this, "connection in progress" );
+            do
+            {
+                fd_set fds;
+
+                if( p_this->b_die )
+                {
+                    msg_Dbg( p_this, "connection aborted" );
+                    net_Close( fd );
+                    vlc_freeaddrinfo( res );
+                    free( psz_socks );
+                    return -1;
+                }
+
+                /* 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 = (d.quot > 0) ? 100000 : (1000 * d.rem);
+
+                i_val = select( fd + 1, NULL, &fds, NULL, &tv );
+
+                if( d.quot <= 0 )
+                {
+                    msg_Dbg( p_this, "connection timed out" );
+                    net_Close( fd );
+                    fd = -1;
+                    break;
+                }
+
+                d.quot--;
+            }
+            while( ( i_val == 0 ) || ( ( i_val < 0 ) &&
+#if defined( WIN32 ) || defined( UNDER_CE )
+                            ( WSAGetLastError() == WSAEWOULDBLOCK )
+#else
+                            ( errno == EINTR )
+#endif
+                     ) );
+
+            if( fd == -1 )
+                continue; /* timeout */
+
+            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 )
+            {
+                if( i_val == ENETUNREACH )
+                    b_unreach = VLC_TRUE;
+                else
+                {
+#ifdef WIN32
+                    msg_Warn( p_this, "connection to %s port %d failed (%d)",
+                              psz_host, i_port, WSAGetLastError( ) );
+#else
+                    msg_Warn( p_this, "connection to %s port %d : %s", psz_host,
+                              i_port, strerror( i_val ) );
+#endif
+                }
+                net_Close( fd );
+                continue;
+            }
+#endif
+        }
+        i_handle = fd; /* success! */
+    }
+
+    vlc_freeaddrinfo( res );
+
+    if( i_handle == -1 )
+    {
+        if( b_unreach )
+            msg_Err( p_this, "Host %s port %d is unreachable", psz_host,
+                     i_port );
+        return -1;
+    }
+
+    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, i_handle, 5, psz_user, psz_pwd,
+                               psz_host, i_port ) )
+        {
+            msg_Err( p_this, "failed to use the SOCKS server" );
+            net_Close( i_handle );
+            i_handle = -1;
+        }
+
+        free( psz_user );
+        free( psz_pwd );
+    }
+    free( psz_socks );
+
+    return i_handle;
+}
+
+
+/*****************************************************************************
+ * __net_ListenTCP:
+ *****************************************************************************
+ * Open TCP passive "listening" socket(s)
+ * This function returns NULL in case of error.
+ *****************************************************************************/
+int *__net_ListenTCP( vlc_object_t *p_this, const char *psz_host, int i_port )
+{
+    struct addrinfo hints, *res, *ptr;
+    int             i_val, *pi_handles, i_size;
+
+    memset( &hints, 0, sizeof( hints ) );
+    hints.ai_socktype = SOCK_STREAM;
+    hints.ai_flags = AI_PASSIVE;
+
+    msg_Dbg( p_this, "net: listening to %s port %d", psz_host, i_port );
+
+    i_val = vlc_getaddrinfo( p_this, psz_host, i_port, &hints, &res );
+    if( i_val )
+    {
+        msg_Err( p_this, "cannot resolve %s port %d : %s", psz_host, i_port,
+                 vlc_gai_strerror( i_val ) );
+        return NULL;
+    }
+
+    pi_handles = NULL;
+    i_size = 1;
+
+    for( ptr = res; ptr != NULL; ptr = ptr->ai_next )
+    {
+        int fd, *newpi;
+
+        fd = net_Socket( p_this, ptr->ai_family, ptr->ai_socktype,
+                         ptr->ai_protocol );
+        if( fd == -1 )
+            continue;
+
+        /* 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;
+            pi_handles = newpi;
+        }
+    }
+
+    vlc_freeaddrinfo( res );
+
+    if( pi_handles != NULL )
+        pi_handles[i_size - 1] = -1;
+    return pi_handles;
+}
+
+/*****************************************************************************
+ * __net_Accept:
+ *****************************************************************************
+ * Accept a connection on a set of listening sockets and return it
+ *****************************************************************************/
+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);
+
+    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_ZERO( &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_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;
+        }
+        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 ) );
+#endif
+            return -1;
+        }
+
+        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() );
+#else
+                msg_Err( p_this, "accept failed (%s)", strerror( errno ) );
+#endif
+            }
+            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 -1;
+}
+
+
+/*****************************************************************************
+ * SocksNegociate:
+ *****************************************************************************
+ * Negociate authentication with a SOCKS server.
+ *****************************************************************************/
+static int SocksNegociate( vlc_object_t *p_obj,
+                           int fd, int i_socks_version,
+                           char *psz_socks_user,
+                           char *psz_socks_passwd )
+{
+    uint8_t buffer[128+2*256];
+    int i_len;
+    vlc_bool_t b_auth = VLC_FALSE;
+
+    if( i_socks_version != 5 )
+        return VLC_SUCCESS;
+
+    /* We negociate authentication */
+
+    if( psz_socks_user && psz_socks_passwd &&
+        *psz_socks_user && *psz_socks_passwd )
+        b_auth = VLC_TRUE;
+
+    buffer[0] = i_socks_version;    /* SOCKS version */
+    if( b_auth )
+    {
+        buffer[1] = 2;                  /* Number of methods */
+        buffer[2] = 0x00;               /* - No auth required */
+        buffer[3] = 0x02;               /* - USer/Password */
+        i_len = 4;
+    }
+    else
+    {
+        buffer[1] = 1;                  /* Number of methods */
+        buffer[2] = 0x00;               /* - No auth required */
+        i_len = 3;
+    }
+
+    if( net_Write( p_obj, fd, NULL, buffer, i_len ) != i_len )
+        return VLC_EGENERIC;
+    if( net_Read( p_obj, fd, NULL, buffer, 2, VLC_TRUE ) != 2 )
+        return VLC_EGENERIC;
+
+    msg_Dbg( p_obj, "socks: v=%d method=%x", buffer[0], buffer[1] );
+
+    if( buffer[1] == 0x00 )
+    {
+        msg_Dbg( p_obj, "socks: no authentication required" );
+    }
+    else if( buffer[1] == 0x02 )
+    {
+        int i_len1 = __MIN( strlen(psz_socks_user), 255 );
+        int i_len2 = __MIN( strlen(psz_socks_passwd), 255 );
+        msg_Dbg( p_obj, "socks: username/password authentication" );
+
+        /* XXX: we don't support user/pwd > 255 (truncated)*/
+        buffer[0] = i_socks_version;        /* Version */
+        buffer[1] = i_len1;                 /* User length */
+        memcpy( &buffer[2], psz_socks_user, i_len1 );
+        buffer[2+i_len1] = i_len2;          /* Password length */
+        memcpy( &buffer[2+i_len1+1], psz_socks_passwd, i_len2 );
+
+        i_len = 3 + i_len1 + i_len2;
+
+        if( net_Write( p_obj, fd, NULL, buffer, i_len ) != i_len )
+            return VLC_EGENERIC;
+
+        if( net_Read( p_obj, fd, NULL, buffer, 2, VLC_TRUE ) != 2 )
+            return VLC_EGENERIC;
+
+        msg_Dbg( p_obj, "socks: v=%d status=%x", buffer[0], buffer[1] );
+        if( buffer[1] != 0x00 )
+        {
+            msg_Err( p_obj, "socks: authentication rejected" );
+            return VLC_EGENERIC;
+        }
+    }
+    else
+    {
+        if( b_auth )
+            msg_Err( p_obj, "socks: unsupported authentication method %x",
+                     buffer[0] );
+        else
+            msg_Err( p_obj, "socks: authentification needed" );
+        return VLC_EGENERIC;
+    }
+
+    return VLC_SUCCESS;
+}
+
+/*****************************************************************************
+ * SocksHandshakeTCP:
+ *****************************************************************************
+ * Open a TCP connection using a SOCKS server and return a handle (RFC 1928)
+ *****************************************************************************/
+static int SocksHandshakeTCP( vlc_object_t *p_obj,
+                              int fd,
+                              int i_socks_version,
+                              char *psz_socks_user, char *psz_socks_passwd,
+                              const char *psz_host, int i_port )
+{
+    uint8_t buffer[128+2*256];
+
+    if( i_socks_version != 4 && i_socks_version != 5 )
+    {
+        msg_Warn( p_obj, "invalid socks protocol version %d", i_socks_version );
+        i_socks_version = 5;
+    }
+
+    if( i_socks_version == 5 && 
+        SocksNegociate( p_obj, fd, i_socks_version,
+                        psz_socks_user, psz_socks_passwd ) )
+        return VLC_EGENERIC;
+
+    if( i_socks_version == 4 )
+    {
+        struct addrinfo hints = { 0 }, *p_res;
+
+        /* v4 only support ipv4 */
+        hints.ai_family = AF_INET;
+        if( vlc_getaddrinfo( p_obj, psz_host, 0, &hints, &p_res ) )
+            return VLC_EGENERIC;
+
+        buffer[0] = i_socks_version;
+        buffer[1] = 0x01;               /* CONNECT */
+        SetWBE( &buffer[2], i_port );   /* Port */
+        memcpy( &buffer[4],             /* Address */
+                &((struct sockaddr_in *)(p_res->ai_addr))->sin_addr, 4 );
+        vlc_freeaddrinfo( p_res );
+
+        buffer[8] = 0;                  /* Empty user id */
+
+        if( net_Write( p_obj, fd, NULL, buffer, 9 ) != 9 )
+            return VLC_EGENERIC;
+        if( net_Read( p_obj, fd, NULL, buffer, 8, VLC_TRUE ) != 8 )
+            return VLC_EGENERIC;
+
+        msg_Dbg( p_obj, "socks: v=%d cd=%d",
+                 buffer[0], buffer[1] );
+
+        if( buffer[1] != 90 )
+            return VLC_EGENERIC;
+    }
+    else if( i_socks_version == 5 )
+    {
+        int i_hlen = __MIN(strlen( psz_host ), 255);
+        int i_len;
+
+        buffer[0] = i_socks_version;    /* Version */
+        buffer[1] = 0x01;               /* Cmd: connect */
+        buffer[2] = 0x00;               /* Reserved */
+        buffer[3] = 3;                  /* ATYP: for now domainname */
+
+        buffer[4] = i_hlen;
+        memcpy( &buffer[5], psz_host, i_hlen );
+        SetWBE( &buffer[5+i_hlen], i_port );
+
+        i_len = 5 + i_hlen + 2;
+
+
+        if( net_Write( p_obj, fd, NULL, buffer, i_len ) != i_len )
+            return VLC_EGENERIC;
+
+        /* Read the header */
+        if( net_Read( p_obj, fd, NULL, buffer, 5, VLC_TRUE ) != 5 )
+            return VLC_EGENERIC;
+
+        msg_Dbg( p_obj, "socks: v=%d rep=%d atyp=%d",
+                 buffer[0], buffer[1], buffer[3] );
+
+        if( buffer[1] != 0x00 )
+        {
+            msg_Err( p_obj, "socks: CONNECT request failed\n" );
+            return VLC_EGENERIC;
+        }
+
+        /* Read the remaining bytes */
+        if( buffer[3] == 0x01 )
+            i_len = 4-1 + 2;
+        else if( buffer[3] == 0x03 )
+            i_len = buffer[4] + 2;
+        else if( buffer[3] == 0x04 )
+            i_len = 16-1+2;
+        else 
+            return VLC_EGENERIC;
+
+        if( net_Read( p_obj, fd, NULL, buffer, i_len, VLC_TRUE ) != i_len )
+            return VLC_EGENERIC;
+    }
+
+    return VLC_SUCCESS;
+}
+
+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 );
+    }
+}
diff --git a/src/network/udp.c b/src/network/udp.c
new file mode 100644 (file)
index 0000000..e11d1bc
--- /dev/null
@@ -0,0 +1,241 @@
+/*****************************************************************************
+ * udp.c:
+ *****************************************************************************
+ * Copyright (C) 2004-2005 the VideoLAN team
+ * $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
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
+ *****************************************************************************/
+
+/*****************************************************************************
+ * Preamble
+ *****************************************************************************/
+#include <stdlib.h>
+#include <vlc/vlc.h>
+
+#include <errno.h>
+
+#ifdef HAVE_FCNTL_H
+#   include <fcntl.h>
+#endif
+#ifdef HAVE_SYS_TIME_H
+#    include <sys/time.h>
+#endif
+#ifdef HAVE_UNISTD_H
+#   include <unistd.h>
+#endif
+
+#include "network.h"
+
+#ifndef INADDR_ANY
+#   define INADDR_ANY  0x00000000
+#endif
+#ifndef INADDR_NONE
+#   define INADDR_NONE 0xFFFFFFFF
+#endif
+
+extern int net_Socket( vlc_object_t *p_this, int i_family, int i_socktype,
+                       int i_protocol );
+
+/*****************************************************************************
+ * __net_ConnectUDP:
+ *****************************************************************************
+ * Open a UDP socket to send data to a defined destination, with an optional
+ * hop limit.
+ *****************************************************************************/
+int __net_ConnectUDP( vlc_object_t *p_this, const char *psz_host, int i_port,
+                      int hlim )
+{
+    struct addrinfo hints, *res, *ptr;
+    int             i_val, i_handle = -1;
+    vlc_bool_t      b_unreach = VLC_FALSE;
+
+    if( i_port == 0 )
+        i_port = 1234; /* historical VLC thing */
+
+    memset( &hints, 0, sizeof( hints ) );
+    hints.ai_socktype = SOCK_DGRAM;
+
+    msg_Dbg( p_this, "net: connecting to %s port %d", psz_host, i_port );
+
+    i_val = vlc_getaddrinfo( p_this, psz_host, i_port, &hints, &res );
+    if( i_val )
+    {
+        msg_Err( p_this, "cannot resolve %s port %d : %s", psz_host, i_port,
+                 vlc_gai_strerror( i_val ) );
+        return -1;
+    }
+
+    for( ptr = res; ptr != NULL; ptr = ptr->ai_next )
+    {
+        int fd;
+
+        fd = net_Socket( p_this, ptr->ai_family, ptr->ai_socktype,
+                         ptr->ai_protocol );
+        if( fd == -1 )
+            continue;
+#if !defined( SYS_BEOS )
+        else
+        {
+            int i_val;
+
+            /* Increase the receive buffer size to 1/2MB (8Mb/s during 1/2s) to avoid
+            * packet loss caused by scheduling problems */
+            i_val = 0x80000;
+            setsockopt( i_handle, SOL_SOCKET, SO_RCVBUF, (void *)&i_val,
+                        sizeof( i_val ) );
+            i_val = 0x80000;
+            setsockopt( i_handle, SOL_SOCKET, SO_SNDBUF, (void *)&i_val,
+                        sizeof( i_val ) );
+        }
+#endif
+
+        if( connect( fd, ptr->ai_addr, ptr->ai_addrlen ) == 0 )
+        {
+            /* success */
+            i_handle = fd;
+            break;
+        }
+
+#if defined( WIN32 ) || defined( UNDER_CE )
+        if( WSAGetLastError () == WSAENETUNREACH )
+#else
+        if( errno == ENETUNREACH )
+#endif
+            b_unreach = VLC_TRUE;
+        else
+        {
+            msg_Warn( p_this, "%s port %d : %s", psz_host, i_port,
+                      strerror( errno ) );
+            net_Close( fd );
+            continue;
+        }
+    }
+
+    vlc_freeaddrinfo( res );
+
+    if( i_handle == -1 )
+    {
+        if( b_unreach )
+            msg_Err( p_this, "Host %s port %d is unreachable", psz_host,
+                     i_port );
+        return -1;
+    }
+
+    return i_handle;
+}
+
+/*****************************************************************************
+ * __net_OpenUDP:
+ *****************************************************************************
+ * Open a UDP connection and return a handle
+ *****************************************************************************/
+int __net_OpenUDP( vlc_object_t *p_this, const char *psz_bind, int i_bind,
+                   const char *psz_server, int i_server )
+{
+    vlc_value_t      v4, v6;
+    void            *private;
+    network_socket_t sock;
+    module_t         *p_network = NULL;
+
+    if( ( psz_server != NULL ) && ( psz_server[0] == '\0' ) )
+        msg_Warn( p_this, "calling net_OpenUDP with an explicit destination "
+                  "is obsolete - use net_ConnectUDP instead" );
+    if( i_server != 0 )
+        msg_Warn( p_this, "calling net_OpenUDP with an explicit destination "
+                  "port is obsolete - use __net_ConnectUDP instead" );
+
+    if( psz_server == NULL ) psz_server = "";
+    if( psz_bind == NULL ) psz_bind = "";
+
+    /* Prepare the network_socket_t structure */
+    sock.psz_bind_addr   = psz_bind;
+    sock.i_bind_port     = i_bind;
+    sock.psz_server_addr = psz_server;
+    sock.i_server_port   = i_server;
+    sock.i_ttl           = 0;
+    sock.v6only          = 0;
+    sock.i_handle        = -1;
+
+    msg_Dbg( p_this, "net: connecting to '[%s]:%d@[%s]:%d'",
+             psz_server, i_server, psz_bind, i_bind );
+
+    /* Check if we have force ipv4 or ipv6 */
+    var_Create( p_this, "ipv4", VLC_VAR_BOOL | VLC_VAR_DOINHERIT );
+    var_Get( p_this, "ipv4", &v4 );
+    var_Create( p_this, "ipv6", VLC_VAR_BOOL | VLC_VAR_DOINHERIT );
+    var_Get( p_this, "ipv6", &v6 );
+
+    if( !v4.b_bool )
+    {
+        if( v6.b_bool )
+            sock.v6only = 1;
+
+        /* try IPv6 first (unless IPv4 forced) */
+        private = p_this->p_private;
+        p_this->p_private = (void*)&sock;
+        p_network = module_Need( p_this, "network", "ipv6", VLC_TRUE );
+
+        if( p_network != NULL )
+            module_Unneed( p_this, p_network );
+
+        p_this->p_private = private;
+
+        /*
+         * Check if the IP stack can receive IPv4 packets on IPv6 sockets.
+         * If yes, then it is better to use the IPv6 socket.
+         * Otherwise, if we also get an IPv4, we have to choose, so we use
+         * IPv4 only.
+         */
+        if( ( sock.i_handle != -1 ) && ( ( sock.v6only == 0 ) || v6.b_bool ) )
+            return sock.i_handle;
+    }
+
+    if( !v6.b_bool )
+    {
+        int fd6 = sock.i_handle;
+
+        /* also try IPv4 (unless IPv6 forced) */
+        private = p_this->p_private;
+        p_this->p_private = (void*)&sock;
+        p_network = module_Need( p_this, "network", "ipv4", VLC_TRUE );
+
+        if( p_network != NULL )
+            module_Unneed( p_this, p_network );
+
+        p_this->p_private = private;
+
+        if( fd6 != -1 )
+        {
+            if( sock.i_handle != -1 )
+            {
+                msg_Warn( p_this, "net: lame IPv6/IPv4 dual-stack present. "
+                                  "Using only IPv4." );
+                net_Close( fd6 );
+            }
+            else
+                sock.i_handle = fd6;
+        }
+    }
+
+    if( sock.i_handle == -1 )
+        msg_Dbg( p_this, "net: connection to '[%s]:%d@[%s]:%d' failed",
+                psz_server, i_server, psz_bind, i_bind );
+
+    return sock.i_handle;
+}