]> git.sesse.net Git - vlc/blobdiff - src/misc/net.c
Speed up LocaleFree()
[vlc] / src / misc / net.c
index d5910be145ae5e0dec1026d372570273904e7bcd..4c60b17b17b7c3c8b6d7301c493521abad3caebd 100644 (file)
@@ -1,7 +1,7 @@
 /*****************************************************************************
  * net.c:
  *****************************************************************************
- * Copyright (C) 2004-2005 VideoLAN
+ * Copyright (C) 2004-2005 the VideoLAN team
  * $Id$
  *
  * Authors: Laurent Aimar <fenrir@videolan.org>
 #    include <sys/time.h>
 #endif
 
-#if defined( UNDER_CE )
-#   include <winsock.h>
-#elif defined( WIN32 )
+#if defined( WIN32 ) || defined( UNDER_CE )
+#   if defined(UNDER_CE) && defined(sockaddr_storage)
+#       undef sockaddr_storage
+#   endif
+#   include <io.h>
 #   include <winsock2.h>
 #   include <ws2tcpip.h>
-#   ifndef IN_MULTICAST
-#       define IN_MULTICAST(a) IN_CLASSD(a)
-#   endif
 #else
 #   include <sys/socket.h>
 #   include <netinet/in.h>
@@ -57,8 +56,6 @@
 
 #ifdef HAVE_UNISTD_H
 #   include <unistd.h>
-#elif defined( WIN32 ) && !defined( UNDER_CE )
-#   include <io.h>
 #endif
 
 #include "network.h"
@@ -77,44 +74,69 @@ static int SocksHandshakeTCP( vlc_object_t *,
                               char *psz_socks_user, char *psz_socks_passwd,
                               const char *psz_host, int i_port );
 
-/*****************************************************************************
- * net_ConvertIPv4:
- *****************************************************************************
- * Open a TCP connection and return a handle
- * FIXME: not thread-safe, should use vlc_getaddrinfo instead
- *****************************************************************************/
-static int net_ConvertIPv4( uint32_t *p_addr, const char * psz_address )
+static int net_Socket( vlc_object_t *p_this, int i_family, int i_socktype,
+                       int i_protocol )
 {
-    /* Reset struct */
-    if( !*psz_address )
+    int fd, i_val;
+
+    fd = socket( i_family, i_socktype, i_protocol );
+    if( fd == -1 )
     {
-        *p_addr = INADDR_ANY;
+#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;
     }
-    else
-    {
-        struct hostent *p_hostent;
 
-        /* Try to convert address directly from in_addr - this will work if
-         * psz_address is dotted decimal. */
-#ifdef HAVE_ARPA_INET_H
-        if( !inet_aton( psz_address, (struct in_addr *)p_addr ) )
+        /* 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
-        *p_addr = inet_addr( psz_address );
-        if( *p_addr == INADDR_NONE )
+    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
-        {
-            /* We have a fqdn, try to find its address */
-            if ( (p_hostent = gethostbyname( psz_address )) == NULL )
-            {
-                return VLC_EGENERIC;
-            }
 
-            /* Copy the first address of the host in the socket address */
-            memcpy( p_addr, p_hostent->h_addr_list[0],
-                    p_hostent->h_length );
-        }
+    i_val = 1;
+    setsockopt( fd, SOL_SOCKET, SO_REUSEADDR, (void *)&i_val,
+                sizeof( i_val ) );
+
+#ifdef IPV6_V6ONLY
+    /*
+     * Accepts only IPv6 connections on IPv6 sockets
+     * (and open an IPv4 socket later as well if needed).
+     * Only Linux and FreeBSD can map IPv4 connections on IPv6 sockets,
+     * so this allows for more uniform handling across platforms. Besides,
+     * it makes sure that IPv4 addresses will be printed as w.x.y.z rather
+     * than ::ffff:w.x.y.z
+     */
+    if( i_family == AF_INET6 )
+        setsockopt( fd, IPPROTO_IPV6, IPV6_V6ONLY, (void *)&i_val,
+                    sizeof( i_val ) );
+#endif
+
+#if defined( WIN32 ) || defined( UNDER_CE )
+# ifdef IPV6_PROTECTION_LEVEL
+    if( i_family == AF_INET6 )
+    {
+        i_val = PROTECTION_LEVEL_UNRESTRICTED;
+        setsockopt( fd, IPPROTO_IPV6, IPV6_PROTECTION_LEVEL,
+                   (const char*)&i_val, sizeof( i_val ) );
     }
-    return VLC_SUCCESS;
+# else
+# warning You are using outdated headers for Winsock !
+# endif
+#endif
+    return fd;
 }
 
 /*****************************************************************************
@@ -126,11 +148,9 @@ int __net_OpenTCP( vlc_object_t *p_this, const char *psz_host, int i_port )
 {
     struct addrinfo hints, *res, *ptr;
     const char      *psz_realhost;
-    char            *psz_realport, *psz_socks;
-    int             i_val, i_handle = -1;
+    char            *psz_socks;
+    int             i_realport, i_val, i_handle = -1;
 
-    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 */
 
@@ -146,33 +166,25 @@ int __net_OpenTCP( vlc_object_t *p_this, const char *psz_host, int i_port )
             *psz++ = '\0';
 
         psz_realhost = psz_socks;
-        psz_realport = strdup( ( psz != NULL ) ? psz : "1080" );
+        i_realport = ( psz != NULL ) ? atoi( psz ) : 1080;
 
-        msg_Dbg( p_this, "net: connecting to '%s:%s' for '%s:%d'",
-                 psz_realhost, psz_realport, psz_host, i_port );
+        msg_Dbg( p_this, "net: connecting to '%s:%d' for '%s:%d'",
+                 psz_realhost, i_realport, psz_host, i_port );
     }
     else
     {
         psz_realhost = psz_host;
-        psz_realport = malloc( 6 );
-        if( psz_realport == NULL )
-        {
-            free( psz_socks );
-            return -1;
-        }
+        i_realport = i_port;
 
-        sprintf( psz_realport, "%d", i_port );
-        msg_Dbg( p_this, "net: connecting to '%s:%s'", psz_realhost,
-                 psz_realport );
+        msg_Dbg( p_this, "net: connecting to '%s:%d'", psz_realhost,
+                 i_realport );
     }
 
-    i_val = vlc_getaddrinfo( p_this, psz_realhost, psz_realport, &hints,
-                             &res );
-    free( psz_realport );
+    i_val = vlc_getaddrinfo( p_this, psz_realhost, i_realport, &hints, &res );
     if( i_val )
     {
-        msg_Err( p_this, "cannot resolve '%s' : %s", psz_realhost,
-                 vlc_gai_strerror( i_val ) );
+        msg_Err( p_this, "cannot resolve '%s:%d' : %s", psz_realhost,
+                 i_realport, vlc_gai_strerror( i_val ) );
         free( psz_socks );
         return -1;
     }
@@ -181,56 +193,17 @@ int __net_OpenTCP( vlc_object_t *p_this, const char *psz_host, int i_port )
     {
         int fd;
 
-        fd = socket( ptr->ai_family, ptr->ai_socktype, ptr->ai_protocol );
+        fd = net_Socket( p_this, 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;
+            socklen_t i_val_size = sizeof( i_val );
+            div_t d;
             struct timeval tv;
             vlc_value_t timeout;
-            fd_set fds;
-
 #if defined( WIN32 ) || defined( UNDER_CE )
             if( WSAGetLastError() != WSAEWOULDBLOCK )
             {
@@ -252,11 +225,18 @@ int __net_OpenTCP( vlc_object_t *p_this, const char *psz_host, int i_port )
             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;
+            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" );
@@ -265,14 +245,6 @@ int __net_OpenTCP( vlc_object_t *p_this, const char *psz_host, int i_port )
                     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 );
@@ -280,9 +252,19 @@ int __net_OpenTCP( vlc_object_t *p_this, const char *psz_host, int i_port )
 
                 /* We'll wait 0.1 second if nothing happens */
                 tv.tv_sec = 0;
-                tv.tv_usec = 100000;
+                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 )
@@ -292,6 +274,9 @@ int __net_OpenTCP( vlc_object_t *p_this, const char *psz_host, int i_port )
 #endif
                      ) );
 
+            if( fd == -1 )
+                continue; /* timeout */
+
             if( i_val < 0 )
             {
                 msg_Warn( p_this, "connection aborted (select failed)" );
@@ -352,29 +337,17 @@ 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;
-    char            *psz_port;
-
-    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 */
 
     memset( &hints, 0, sizeof( hints ) );
     hints.ai_socktype = SOCK_STREAM;
     hints.ai_flags = AI_PASSIVE;
 
-    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 );
+    msg_Dbg( p_this, "net: listening to '%s:%d'", psz_host, i_port );
 
-    i_val = vlc_getaddrinfo( p_this, psz_host, psz_port, &hints, &res );
-    free( psz_port );
+    i_val = vlc_getaddrinfo( p_this, psz_host, i_port, &hints, &res );
     if( i_val )
     {
-        msg_Err( p_this, "cannot resolve '%s' : %s", psz_host,
+        msg_Err( p_this, "cannot resolve '%s:%d' : %s", psz_host, i_port,
                  vlc_gai_strerror( i_val ) );
         return NULL;
     }
@@ -386,36 +359,10 @@ int *__net_ListenTCP( vlc_object_t *p_this, const char *psz_host, int i_port )
     {
         int fd, *newpi;
 
-        fd = socket( ptr->ai_family, ptr->ai_socktype, ptr->ai_protocol );
+        fd = net_Socket( p_this, 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 ) )
@@ -452,14 +399,14 @@ int *__net_ListenTCP( vlc_object_t *p_this, const char *psz_host, int i_port )
         else
         {
             newpi[i_size - 2] = fd;
-            if( pi_handles == NULL )
-                newpi[i_size - 1] = -1;
             pi_handles = newpi;
         }
     }
     
     vlc_freeaddrinfo( res );
 
+    if( pi_handles != NULL )
+        pi_handles[i_size - 1] = -1;
     return pi_handles;
 }
 
@@ -555,33 +502,13 @@ int __net_Accept( vlc_object_t *p_this, int *pi_fd, mtime_t i_wait )
  *****************************************************************************
  * Open a UDP connection and return a handle
  *****************************************************************************/
-int __net_OpenUDP( vlc_object_t *p_this, char *psz_bind, int i_bind,
-                   char *psz_server, int i_server )
+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      val;
+    vlc_value_t      v4, v6;
     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";
-    }
-
-    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( psz_server == NULL ) psz_server = "";
-    if( psz_bind   == NULL ) psz_bind   = "";
+    module_t         *p_network = NULL;
 
     /* Prepare the network_socket_t structure */
     sock.psz_bind_addr   = psz_bind;
@@ -589,19 +516,78 @@ int __net_OpenUDP( vlc_object_t *p_this, char *psz_bind, int 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'",
+    if( psz_server == NULL )
+        psz_server = "";
+    if( psz_bind == NULL )
+        psz_bind = "";
+
+    msg_Dbg( p_this, "net: connecting to '[%s]:%d@[%s]:%d'",
              psz_server, i_server, psz_bind, i_bind );
-    private = p_this->p_private;
-    p_this->p_private = (void*)&sock;
-    if( !( p_network = module_Need( p_this, "network", psz_network, 0 ) ) )
+
+    /* 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 )
     {
-        msg_Dbg( p_this, "net: connection to '%s:%d@%s:%d' failed",
-                 psz_server, i_server, psz_bind, i_bind );
-        return -1;
+        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;
     }
-    module_Unneed( p_this, p_network );
-    p_this->p_private = private;
+
+    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;
 }
@@ -638,7 +624,7 @@ void net_ListenClose( int *pi_fd )
  * __net_Read:
  *****************************************************************************
  * Read from a network socket
- * If b_rety is true, then we repeat until we have read the right amount of
+ * If b_retry is true, then we repeat until we have read the right amount of
  * data
  *****************************************************************************/
 int __net_Read( vlc_object_t *p_this, int fd, v_socket_t *p_vs,
@@ -676,7 +662,7 @@ int __net_Read( vlc_object_t *p_this, int fd, v_socket_t *p_vs,
         if( i_ret < 0 )
         {
 #if defined(WIN32) || defined(UNDER_CE)
-            msg_Err( p_this, "network select error" );
+            msg_Err( p_this, "network select error (%d)", WSAGetLastError() );
 #else
             msg_Err( p_this, "network select error (%s)", strerror(errno) );
 #endif
@@ -703,8 +689,8 @@ int __net_Read( vlc_object_t *p_this, int fd, v_socket_t *p_vs,
                          "Increase the mtu size (--mtu option)" );
                 i_total += i_data;
             }
-            else
-                msg_Err( p_this, "recv failed (%i)", WSAGetLastError() );
+            else if( WSAGetLastError() == WSAEINTR ) continue;
+            else msg_Err( p_this, "recv failed (%i)", WSAGetLastError() );
 #else
             /* EAGAIN only happens with p_vs (SSL) and it's not an error */
             if( errno != EAGAIN )
@@ -760,7 +746,7 @@ int __net_ReadNonBlock( vlc_object_t *p_this, int fd, v_socket_t *p_vs,
     else if( i_ret < 0 )
     {
 #if defined(WIN32) || defined(UNDER_CE)
-        msg_Err( p_this, "network select error" );
+        msg_Err( p_this, "network select error (%d)", WSAGetLastError() );
 #else
         msg_Err( p_this, "network select error (%s)", strerror(errno) );
 #endif
@@ -789,8 +775,7 @@ int __net_ReadNonBlock( vlc_object_t *p_this, int fd, v_socket_t *p_vs,
                 msg_Err( p_this, "recv() failed. "
                          "Increase the mtu size (--mtu option)" );
             }
-            else
-                msg_Err( p_this, "recv failed (%i)", WSAGetLastError() );
+            else msg_Err( p_this, "recv failed (%i)", WSAGetLastError() );
 #else
             msg_Err( p_this, "recv failed (%s)", strerror(errno) );
 #endif
@@ -870,9 +855,8 @@ int __net_Select( vlc_object_t *p_this, int *pi_fd, v_socket_t **pp_vs,
                         msg_Err( p_this, "recv() failed. "
                              "Increase the mtu size (--mtu option)" );
                     }
-                    else
-                        msg_Err( p_this, "recv failed (%i)",
-                                        WSAGetLastError() );
+                    else msg_Err( p_this, "recv failed (%i)",
+                                  WSAGetLastError() );
 #else
                      msg_Err( p_this, "recv failed (%s)", strerror(errno) );
 #endif
@@ -926,7 +910,7 @@ int __net_Write( vlc_object_t *p_this, int fd, v_socket_t *p_vs,
         if( i_ret < 0 )
         {
 #if defined(WIN32) || defined(UNDER_CE)
-            msg_Err( p_this, "network select error" );
+            msg_Err( p_this, "network select error (%d)", WSAGetLastError() );
 #else
             msg_Err( p_this, "network select error (%s)", strerror(errno) );
 #endif
@@ -952,45 +936,41 @@ int __net_Write( vlc_object_t *p_this, int fd, v_socket_t *p_vs,
 
 char *__net_Gets( vlc_object_t *p_this, int fd, v_socket_t *p_vs )
 {
-    char *psz_line = malloc( 1024 );
-    int  i_line = 0;
-    int  i_max = 1024;
+    char *psz_line = NULL, *ptr = NULL;
+    size_t  i_line = 0, i_max = 0;
 
 
     for( ;; )
     {
-        if( net_Read( p_this, fd, p_vs, &psz_line[i_line], 1, VLC_TRUE ) != 1 )
+        if( i_line == i_max )
         {
-            psz_line[i_line] = '\0';
-            break;
+            i_max += 1024;
+            psz_line = realloc( psz_line, i_max );
+            ptr = psz_line + i_line;
         }
-        i_line++;
 
-        if( psz_line[i_line-1] == '\n' )
+        if( net_Read( p_this, fd, p_vs, (uint8_t *)ptr, 1, VLC_TRUE ) != 1 )
         {
-            psz_line[i_line] = '\0';
+            if( i_line == 0 )
+            {
+                free( psz_line );
+                return NULL;
+            }
             break;
         }
 
-        if( i_line >= i_max - 1 )
-        {
-            i_max += 1024;
-            psz_line = realloc( psz_line, i_max );
-        }
-    }
+        if ( *ptr == '\n' )
+            break;
 
-    if( i_line <= 0 )
-    {
-        free( psz_line );
-        return NULL;
+        i_line++;
+        ptr++;
     }
 
-    while( i_line >= 1 &&
-           ( psz_line[i_line-1] == '\n' || psz_line[i_line-1] == '\r' ) )
-    {
-        i_line--;
-        psz_line[i_line] = '\0';
-    }
+    *ptr-- = '\0';
+
+    if( ( ptr >= psz_line ) && ( *ptr == '\r' ) )
+        *ptr = '\0';
+
     return psz_line;
 }
 
@@ -1012,9 +992,9 @@ int __net_vaPrintf( vlc_object_t *p_this, int fd, v_socket_t *p_vs,
     char    *psz;
     int     i_size, i_ret;
 
-    vasprintf( &psz, psz_fmt, args );
-    i_size = strlen( psz );
-    i_ret = __net_Write( p_this, fd, p_vs, psz, i_size ) < i_size ? -1 : i_size;
+    i_size = vasprintf( &psz, psz_fmt, args );
+    i_ret = __net_Write( p_this, fd, p_vs, (uint8_t *)psz, i_size ) < i_size
+        ? -1 : i_size;
     free( psz );
 
     return i_ret;
@@ -1138,16 +1118,20 @@ static int SocksHandshakeTCP( vlc_object_t *p_obj,
 
     if( i_socks_version == 4 )
     {
-        uint32_t addr;
+        struct addrinfo hints = { 0 }, *p_res;
 
         /* v4 only support ipv4 */
-        if( net_ConvertIPv4( &addr, psz_host ) )
+        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], &addr, 4 ); /* Addresse */
+        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 )
@@ -1211,4 +1195,61 @@ static int SocksHandshakeTCP( vlc_object_t *p_obj,
     return VLC_SUCCESS;
 }
 
+/*****************************************************************************
+ * inet_pton replacement for obsolete and/or crap operating systems
+ *****************************************************************************/
+#ifndef HAVE_INET_PTON
+int inet_pton(int af, const char *src, void *dst)
+{
+# ifdef WIN32
+    /* As we already know, Microsoft always go its own way, so even if they do
+     * provide IPv6, they don't provide the API. */
+    struct sockaddr_storage addr;
+    int len = sizeof( addr );
+
+    /* Damn it, they didn't even put LPCSTR for the firs parameter!!! */
+    char *workaround_for_ill_designed_api = strdup( src );
+    
+    if( !WSAStringToAddress( workaround_for_ill_designed_api, af, NULL,
+                             (LPSOCKADDR)&addr, &len ) )
+    {
+        free( workaround_for_ill_designed_api );
+        return -1;
+    }
+    free( workaround_for_ill_designed_api );
 
+    switch( af )
+    {
+        case AF_INET6:
+            memcpy( dst, &((struct sockaddr_in6 *)&addr)->sin6_addr, 16 );
+            break;
+            
+        case AF_INET:
+            memcpy( dst, &((struct sockaddr_in *)&addr)->sin_addr, 4 );
+            break;
+
+        default:
+            WSASetLastError( WSAEAFNOSUPPORT );
+            return -1;
+    }
+# else
+    /* Assume IPv6 is not supported. */
+    /* Would be safer and more simpler to use inet_aton() but it is most
+     * likely not provided either. */
+    uint32_t ipv4;
+
+    if( af != AF_INET )
+    {
+        errno = EAFNOSUPPORT;
+        return -1;
+    }
+
+    ipv4 = inet_addr( src );
+    if( ipv4 == INADDR_NONE )
+        return -1;
+
+    memcpy( dst; &ipv4, 4 );
+# endif /* WIN32 */
+    return 0;
+}
+#endif /* HAVE_INET_PTON */