};
#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 */
msg_Warn( p_this, "cannot configure socket (SO_REUSEADDR: %s)",
strerror(errno));
close( i_handle );
- return( -1 );
+ return 0;
}
#ifdef SO_REUSEPORT
{
msg_Dbg( p_this, "could not build local address" );
close( i_handle );
- return( -1 );
+ return 0;
}
/* Bind it */
{
msg_Warn( p_this, "cannot bind socket (%s)", strerror(errno) );
close( i_handle );
- return( -1 );
+ return 0;
}
#if defined( WIN32 ) || defined( UNDER_CE )
{
msg_Dbg( p_this, "could not build local address" );
close( i_handle );
- return( -1 );
+ return 0;
}
}
#endif
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 */
msg_Err( p_this, "failed to join IP multicast group (%s)",
strerror(errno) );
close( i_handle );
- return( -1 );
+ return 0;
}
}
}
{
msg_Warn( p_this, "cannot build remote address" );
close( i_handle );
- return( -1 );
+ return 0;
}
/* Connect the socket */
{
msg_Warn( p_this, "cannot connect socket (%s)", strerror(errno) );
close( i_handle );
- return( -1 );
+ return 0;
}
#if !defined( SYS_BEOS )
{
msg_Dbg( p_this, "failed to set multicast interface (%s).", strerror(errno) );
close( i_handle );
- return ( -1 );
+ return 0;
}
}
msg_Err( p_this, "failed to set ttl (%s)",
strerror(errno) );
close( i_handle );
- return( -1 );
+ return 0;
}
}
}
# 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
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
if ( BuildAddr( p_this, &sock, psz_bind_addr, i_bind_port ) == -1 )
{
close( i_handle );
- return( -1 );
+ return 0;
}
#if defined(WIN32)
{
msg_Warn( p_this, "cannot bind socket (%s)", strerror(errno) );
close( i_handle );
- return( -1 );
+ return 0;
}
}
else
{
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 */
{
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;
{
msg_Warn( p_this, "cannot build remote address" );
close( i_handle );
- return( -1 );
+ return 0;
}
/* Connect the socket */
{
msg_Warn( p_this, "cannot connect socket (%s)", strerror(errno) );
close( i_handle );
- return( -1 );
+ return 0;
}
/* Set the time-to-live */
var_Get( p_this, "mtu", &val );
p_socket->i_mtu = val.i_int;
- return( 0 );
+ return 0;
}
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;
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;
}