Commit 331d097f authored by Rémi Denis-Courmont's avatar Rémi Denis-Courmont

- When both IPv4 and IPv6 plugins return a socket, use the IPv6 one if

  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
parent 8e916c37
......@@ -62,6 +62,8 @@ struct network_socket_t
int i_ttl;
int v6only;
/* Return values */
int i_handle;
size_t i_mtu;
......
......@@ -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;
}
}
}
......
......@@ -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;
}
......@@ -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;
}
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment