]> git.sesse.net Git - vlc/blobdiff - src/misc/net.c
Speed up LocaleFree()
[vlc] / src / misc / net.c
index ce140e95a4623350da4b769010415c76022d72bf..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>
@@ -42,6 +42,7 @@
 #   if defined(UNDER_CE) && defined(sockaddr_storage)
 #       undef sockaddr_storage
 #   endif
+#   include <io.h>
 #   include <winsock2.h>
 #   include <ws2tcpip.h>
 #else
@@ -128,8 +129,8 @@ static int net_Socket( vlc_object_t *p_this, int i_family, int i_socktype,
     if( i_family == AF_INET6 )
     {
         i_val = PROTECTION_LEVEL_UNRESTRICTED;
-        setsockopt( fd, IPPROTO_IPV6, IPV6_PROTECTION_LEVEL, &i_val,
-                    sizeof( i_val ) );
+        setsockopt( fd, IPPROTO_IPV6, IPV6_PROTECTION_LEVEL,
+                   (const char*)&i_val, sizeof( i_val ) );
     }
 # else
 # warning You are using outdated headers for Winsock !
@@ -199,7 +200,7 @@ int __net_OpenTCP( vlc_object_t *p_this, const char *psz_host, int i_port )
 
         if( connect( fd, ptr->ai_addr, ptr->ai_addrlen ) )
         {
-            int i_val_size = sizeof( i_val );
+            socklen_t i_val_size = sizeof( i_val );
             div_t d;
             struct timeval tv;
             vlc_value_t timeout;
@@ -501,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;
@@ -535,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;
 }
@@ -584,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,
@@ -622,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
@@ -706,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
@@ -870,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
@@ -909,7 +949,7 @@ char *__net_Gets( vlc_object_t *p_this, int fd, v_socket_t *p_vs )
             ptr = psz_line + i_line;
         }
 
-        if( net_Read( p_this, fd, p_vs, ptr, 1, VLC_TRUE ) != 1 )
+        if( net_Read( p_this, fd, p_vs, (uint8_t *)ptr, 1, VLC_TRUE ) != 1 )
         {
             if( i_line == 0 )
             {
@@ -928,7 +968,7 @@ char *__net_Gets( vlc_object_t *p_this, int fd, v_socket_t *p_vs )
 
     *ptr-- = '\0';
 
-    if( ( ptr > psz_line ) && ( *ptr == '\r' ) )
+    if( ( ptr >= psz_line ) && ( *ptr == '\r' ) )
         *ptr = '\0';
 
     return psz_line;
@@ -952,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;
@@ -1156,57 +1196,60 @@ static int SocksHandshakeTCP( vlc_object_t *p_obj,
 }
 
 /*****************************************************************************
- * __net_CheckIP
- *****************************************************************************
- * Check that a given IP is within a set of IP/netmask.
+ * inet_pton replacement for obsolete and/or crap operating systems
  *****************************************************************************/
-int __net_CheckIP( vlc_object_t *p_this, char *psz_ip, char **ppsz_hosts,
-                   int i_hosts )
+#ifndef HAVE_INET_PTON
+int inet_pton(int af, const char *src, void *dst)
 {
-    struct in_addr ip;
-    int i;
-
-    if( (ip.s_addr = inet_addr( psz_ip )) == INADDR_NONE )
+# 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 ) )
     {
-        return VLC_EGENERIC;
+        free( workaround_for_ill_designed_api );
+        return -1;
     }
+    free( workaround_for_ill_designed_api );
 
-    for( i = 0; i < i_hosts; i++ )
+    switch( af )
     {
-        struct in_addr base, mask;
-        char *psz_host = strdup( ppsz_hosts[i] );
-        char *p = strchr( psz_host, '/' );
-
-        if( p != NULL )
-        {
-            int i_mask;
-            *p++ = '\0';
-            i_mask = atoi(p);
-            if( i_mask < 0 || i_mask > 32 )
-            {
-                msg_Err( p_this, "invalid netmask %s", p );
-                mask.s_addr = INADDR_NONE;
-            }
-            else if( i_mask == 0 )
-                mask.s_addr = INADDR_ANY;
-            else
-                mask.s_addr = htonl( ntohl(INADDR_NONE) << (32 - i_mask) );
-        }
-        else
-            mask.s_addr = INADDR_NONE;
+        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;
 
-        if( (base.s_addr = inet_addr( psz_host )) == INADDR_NONE )
-        {
-            msg_Err( p_this, "invalid base address %s", psz_host );
-            free( psz_host );
-            continue;
-        }
-        free( psz_host );
+        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( !((ip.s_addr ^ base.s_addr) & mask.s_addr) )
-            return VLC_TRUE;
+    if( af != AF_INET )
+    {
+        errno = EAFNOSUPPORT;
+        return -1;
     }
 
-    return VLC_FALSE;
-}
+    ipv4 = inet_addr( src );
+    if( ipv4 == INADDR_NONE )
+        return -1;
 
+    memcpy( dst; &ipv4, 4 );
+# endif /* WIN32 */
+    return 0;
+}
+#endif /* HAVE_INET_PTON */