/*****************************************************************************
* net.c:
*****************************************************************************
- * Copyright (C) 2004-2005 VideoLAN
+ * Copyright (C) 2004-2005 the VideoLAN team
* $Id$
*
* Authors: Laurent Aimar <fenrir@videolan.org>
# if defined(UNDER_CE) && defined(sockaddr_storage)
# undef sockaddr_storage
# endif
+# include <io.h>
# include <winsock2.h>
# include <ws2tcpip.h>
#else
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 !
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;
*****************************************************************************
* 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;
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;
}
* __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,
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 )
{
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;
}
/*****************************************************************************
- * __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 */