]> git.sesse.net Git - vlc/commitdiff
- When both IPv4 and IPv6 plugins return a socket, use the IPv6 one if
authorRémi Denis-Courmont <rem@videolan.org>
Tue, 2 Aug 2005 15:31:47 +0000 (15:31 +0000)
committerRémi Denis-Courmont <rem@videolan.org>
Tue, 2 Aug 2005 15:31:47 +0000 (15:31 +0000)
  IPV6_ONLY can be turned off. It is supposed to be off by default, and
  it actually is. Unfortunately, OpenBSD and NetBSD people think
  network software programmer like us are too stupid to use this
  feature properly, so they just removed it. Lets say the most stupid
  are not always the ones one think. Also, Windows doesn't support this
  yet. On all these OSes, keep the old behavior; that is prefer IPv4.
  Closes #166.

- Windows protection level compile fix

include/network.h
modules/misc/network/ipv4.c
modules/misc/network/ipv6.c
src/misc/net.c

index 52a707fbbf207c75ec12935afcbea0dc7a596e2c..dfe8accd4547980849625c5989bc6cfa8e8bbcdd 100644 (file)
@@ -62,6 +62,8 @@ struct network_socket_t
 
     int i_ttl;
 
+    int v6only;
+
     /* Return values */
     int i_handle;
     size_t i_mtu;
index 5e0ac543737dd37f72c33fc79b5942ab78e140a1..6a54f913dd0a394b5ef4682404df54d447d46afa 100644 (file)
@@ -198,12 +198,14 @@ static int OpenUDP( vlc_object_t * p_this )
      };
 #endif
 
+    p_socket->i_handle = -1;
+
     /* Open a SOCK_DGRAM (UDP) socket, in the AF_INET domain, automatic (0)
      * protocol */
     if( (i_handle = socket( AF_INET, SOCK_DGRAM, 0 )) == -1 )
     {
         msg_Warn( p_this, "cannot create socket (%s)", strerror(errno) );
-        return( -1 );
+        return 0;
     }
 
     /* We may want to reuse an already used socket */
@@ -214,7 +216,7 @@ static int OpenUDP( vlc_object_t * p_this )
         msg_Warn( p_this, "cannot configure socket (SO_REUSEADDR: %s)",
                           strerror(errno));
         close( i_handle );
-        return( -1 );
+        return 0;
     }
 
 #ifdef SO_REUSEPORT
@@ -249,7 +251,7 @@ static int OpenUDP( vlc_object_t * p_this )
     {
         msg_Dbg( p_this, "could not build local address" );
         close( i_handle );
-        return( -1 );
+        return 0;
     }
 
     /* Bind it */
@@ -257,7 +259,7 @@ static int OpenUDP( vlc_object_t * p_this )
     {
         msg_Warn( p_this, "cannot bind socket (%s)", strerror(errno) );
         close( i_handle );
-        return( -1 );
+        return 0;
     }
 
 #if defined( WIN32 ) || defined( UNDER_CE )
@@ -268,7 +270,7 @@ static int OpenUDP( vlc_object_t * p_this )
         {
             msg_Dbg( p_this, "could not build local address" );
             close( i_handle );
-            return( -1 );
+            return 0;
         }
     }
 #endif
@@ -323,7 +325,7 @@ static int OpenUDP( vlc_object_t * p_this )
                                   strerror(errno) );
                 msg_Err( p_this, "are you sure your OS supports IGMPv3?" );
                 close( i_handle );
-                return( -1 );
+                return 0;
             }
          }
          /* If there is no source address, we use IP_ADD_MEMBERSHIP */
@@ -351,7 +353,7 @@ static int OpenUDP( vlc_object_t * p_this )
                 msg_Err( p_this, "failed to join IP multicast group (%s)",
                                   strerror(errno) );
                 close( i_handle );
-                return( -1 );
+                return 0;
             }
          }
     }
@@ -364,7 +366,7 @@ static int OpenUDP( vlc_object_t * p_this )
         {
             msg_Warn( p_this, "cannot build remote address" );
             close( i_handle );
-            return( -1 );
+            return 0;
         }
 
         /* Connect the socket */
@@ -373,7 +375,7 @@ static int OpenUDP( vlc_object_t * p_this )
         {
             msg_Warn( p_this, "cannot connect socket (%s)", strerror(errno) );
             close( i_handle );
-            return( -1 );
+            return 0;
         }
 
 #if !defined( SYS_BEOS )
@@ -396,7 +398,7 @@ static int OpenUDP( vlc_object_t * p_this )
                 {
                     msg_Dbg( p_this, "failed to set multicast interface (%s).", strerror(errno) );
                     close( i_handle );
-                    return ( -1 );
+                    return 0;
                 }
             }
 
@@ -428,7 +430,7 @@ static int OpenUDP( vlc_object_t * p_this )
                     msg_Err( p_this, "failed to set ttl (%s)",
                              strerror(errno) );
                     close( i_handle );
-                    return( -1 );
+                    return 0;
                 }
             }
         }
index e18878e190cce221490d3f6054e42bed96d826ec..4cd5514c6be29ce570e7932bd2358692bfb6a3ef 100644 (file)
@@ -167,22 +167,37 @@ static int OpenUDP( vlc_object_t * p_this )
 # define strerror( x ) winsock_strerror( strerror_buf )
 #endif
 
+    p_socket->i_handle = -1;
+
     /* Open a SOCK_DGRAM (UDP) socket, in the AF_INET6 domain, automatic (0)
      * protocol */
     if( (i_handle = socket( AF_INET6, SOCK_DGRAM, 0 )) == -1 )
     {
         msg_Warn( p_this, "cannot create socket (%s)", strerror(errno) );
-        return( -1 );
+        return 0;
+    }
+
+#ifdef IPV6_V6ONLY
+    val.i_int = p_socket->v6only;
+
+    if( setsockopt( i_handle, IPPROTO_IPV6, IPV6_V6ONLY, (void *)&val.i_int,
+                    sizeof( val.i_int ) ) )
+    {
+        msg_Warn( p_this, "IPV6_V6ONLY: %s", strerror( errno ) );
+        p_socket->v6only = 1;
     }
+#else
+    p_socket->v6only = 1;
+#endif
 
 #ifdef WIN32
 # ifdef IPV6_PROTECTION_LEVEL
-        if( ptr->ai_family == AF_INET6 )
-        {
-            i_val = PROTECTION_LEVEL_UNRESTRICTED;
-            setsockopt( fd, IPPROTO_IPV6, IPV6_PROTECTION_LEVEL, &i_val,
-                        sizeof( i_val ) );
-        }
+    if( ptr->ai_family == AF_INET6 )
+    {
+        int 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
@@ -196,7 +211,7 @@ static int OpenUDP( vlc_object_t * p_this )
         msg_Warn( p_this, "cannot configure socket (SO_REUSEADDR: %s)",
                          strerror(errno) );
         close( i_handle );
-        return( -1 );
+        return 0;
     }
 
     /* Increase the receive buffer size to 1/2MB (8Mb/s during 1/2s) to avoid
@@ -213,7 +228,7 @@ static int OpenUDP( vlc_object_t * p_this )
     if ( BuildAddr( p_this, &sock, psz_bind_addr, i_bind_port ) == -1 )        
     {
         close( i_handle );
-        return( -1 );
+        return 0;
     }
 
 #if defined(WIN32)
@@ -229,7 +244,7 @@ static int OpenUDP( vlc_object_t * p_this )
         {
             msg_Warn( p_this, "cannot bind socket (%s)", strerror(errno) );
             close( i_handle );
-            return( -1 );
+            return 0;
         }
     }
     else
@@ -239,7 +254,7 @@ static int OpenUDP( vlc_object_t * p_this )
     {
         msg_Warn( p_this, "cannot bind socket (%s)", strerror(errno) );
         close( i_handle );
-        return( -1 );
+        return 0;
     }
 
     /* Allow broadcast reception if we bound on in6addr_any */
@@ -276,7 +291,7 @@ static int OpenUDP( vlc_object_t * p_this )
             {
                 msg_Warn( p_this, "cannot build remote address" );
                 close( i_handle );
-                return( -1 );
+                return 0;
             }
             p_sin6 = (struct sockaddr_in6 *)&imr.gsr_source;
             p_sin6->sin6_addr = sock.sin6_addr;
@@ -330,7 +345,7 @@ static int OpenUDP( vlc_object_t * p_this )
         {
             msg_Warn( p_this, "cannot build remote address" );
             close( i_handle );
-            return( -1 );
+            return 0;
         }
 
         /* Connect the socket */
@@ -339,7 +354,7 @@ static int OpenUDP( vlc_object_t * p_this )
         {
             msg_Warn( p_this, "cannot connect socket (%s)", strerror(errno) );
             close( i_handle );
-            return( -1 );
+            return 0;
         }
 
         /* Set the time-to-live */
@@ -374,5 +389,5 @@ static int OpenUDP( vlc_object_t * p_this )
     var_Get( p_this, "mtu", &val );
     p_socket->i_mtu = val.i_int;
 
-    return( 0 );
+    return 0;
 }
index 36e783fa759ba075a09e5548f42306660e113593..4c60b17b17b7c3c8b6d7301c493521abad3caebd 100644 (file)
@@ -505,30 +505,10 @@ int __net_Accept( vlc_object_t *p_this, int *pi_fd, mtime_t i_wait )
 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;
@@ -536,19 +516,78 @@ int __net_OpenUDP( vlc_object_t *p_this, const 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;
+
+    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;
+    }
+
+    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;
+        }
     }
-    module_Unneed( p_this, p_network );
-    p_this->p_private = private;
+
+    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;
 }