00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030 #include <stdlib.h>
00031 #include <string.h>
00032
00033 #include <vlc/vlc.h>
00034
00035 #include <errno.h>
00036
00037 #ifdef HAVE_FCNTL_H
00038 # include <fcntl.h>
00039 #endif
00040 #ifdef HAVE_SYS_TYPES_H
00041 # include <sys/types.h>
00042 #endif
00043 #ifdef HAVE_UNISTD_H
00044 # include <unistd.h>
00045 #endif
00046
00047 #ifdef WIN32
00048 # include <winsock2.h>
00049 # include <ws2tcpip.h>
00050 #elif !defined( SYS_BEOS ) && !defined( SYS_NTO )
00051 # include <netdb.h>
00052 # include <sys/socket.h>
00053 # include <netinet/in.h>
00054 #endif
00055
00056 #include "network.h"
00057
00058 #if defined(WIN32)
00059 static const struct in6_addr in6addr_any = {{IN6ADDR_ANY_INIT}};
00060
00061 # ifndef IPPROTO_IPV6
00062 # define IPPROTO_IPV6 41
00063 # endif
00064 # ifndef IPV6_JOIN_GROUP
00065 # define IPV6_JOIN_GROUP 12
00066 # endif
00067 # ifndef IPV6_MULTICAST_HOPS
00068 # define IPV6_MULTICAST_HOPS 10
00069 # endif
00070 # ifndef IPV6_UNICAST_HOPS
00071 # define IPV6_UNICAST_HOPS 4
00072 # endif
00073 # define close closesocket
00074 #endif
00075
00076 #ifndef MCAST_JOIN_SOURCE_GROUP
00077 # define MCAST_JOIN_SOURCE_GROUP 46
00078 struct group_source_req
00079 {
00080 uint32_t gsr_interface;
00081 struct sockaddr_storage gsr_group;
00082 struct sockaddr_storage gsr_source;
00083 };
00084 #endif
00085
00086
00087
00088
00089 static int OpenUDP( vlc_object_t * );
00090
00091
00092
00093
00094 vlc_module_begin();
00095 set_description( _("UDP/IPv6 network abstraction layer") );
00096 set_capability( "network", 40 );
00097 set_callbacks( OpenUDP, NULL );
00098 vlc_module_end();
00099
00100
00101
00102
00103 static int BuildAddr( vlc_object_t *p_this, struct sockaddr_in6 *p_socket,
00104 const char *psz_address, int i_port )
00105 {
00106 struct addrinfo hints, *res;
00107 int i;
00108
00109 memset( &hints, 0, sizeof( hints ) );
00110 hints.ai_family = AF_INET6;
00111 hints.ai_socktype = SOCK_DGRAM;
00112 hints.ai_flags = AI_PASSIVE;
00113
00114 i = vlc_getaddrinfo( p_this, psz_address, 0, &hints, &res );
00115 if( i )
00116 {
00117 msg_Dbg( p_this, "%s: %s", psz_address, vlc_gai_strerror( i ) );
00118 return -1;
00119 }
00120 if ( res->ai_addrlen > sizeof (struct sockaddr_in6) )
00121 {
00122 vlc_freeaddrinfo( res );
00123 return -1;
00124 }
00125
00126 memcpy( p_socket, res->ai_addr, res->ai_addrlen );
00127 vlc_freeaddrinfo( res );
00128 p_socket->sin6_port = htons( i_port );
00129
00130 return 0;
00131 }
00132
00133 #if defined(WIN32) || defined(UNDER_CE)
00134 # define WINSOCK_STRERROR_SIZE 20
00135 static const char *winsock_strerror( char *buf )
00136 {
00137 snprintf( buf, WINSOCK_STRERROR_SIZE, "Winsock error %d",
00138 WSAGetLastError( ) );
00139 buf[WINSOCK_STRERROR_SIZE - 1] = '\0';
00140 return buf;
00141 }
00142 #endif
00143
00144
00145
00146
00147
00148
00149
00150
00151
00152
00153
00154
00155
00156
00157 static int OpenUDP( vlc_object_t * p_this )
00158 {
00159 network_socket_t *p_socket = p_this->p_private;
00160 const char *psz_bind_addr = p_socket->psz_bind_addr;
00161 int i_bind_port = p_socket->i_bind_port;
00162 const char *psz_server_addr = p_socket->psz_server_addr;
00163 int i_server_port = p_socket->i_server_port;
00164 int i_handle, i_opt;
00165 struct sockaddr_in6 sock;
00166 vlc_value_t val;
00167 #if defined(WIN32) || defined(UNDER_CE)
00168 char strerror_buf[WINSOCK_STRERROR_SIZE];
00169 # define strerror( x ) winsock_strerror( strerror_buf )
00170 #endif
00171
00172 p_socket->i_handle = -1;
00173
00174
00175 if ( BuildAddr( p_this, &sock, psz_bind_addr, i_bind_port ) == -1 )
00176 return 0;
00177
00178
00179
00180 if( (i_handle = socket( AF_INET6, SOCK_DGRAM, 0 )) == -1 )
00181 {
00182 msg_Warn( p_this, "cannot create socket (%s)", strerror(errno) );
00183 return 0;
00184 }
00185
00186 #ifdef IPV6_V6ONLY
00187 val.i_int = p_socket->v6only;
00188
00189 if( setsockopt( i_handle, IPPROTO_IPV6, IPV6_V6ONLY, (void *)&val.i_int,
00190 sizeof( val.i_int ) ) )
00191 {
00192 msg_Warn( p_this, "IPV6_V6ONLY: %s", strerror( errno ) );
00193 p_socket->v6only = 1;
00194 }
00195 #else
00196 p_socket->v6only = 1;
00197 #endif
00198
00199 #ifdef WIN32
00200 # ifndef IPV6_PROTECTION_LEVEL
00201 # define IPV6_PROTECTION_LEVEL 23
00202 # endif
00203 {
00204 int i_val = 30 ;
00205 setsockopt( i_handle, IPPROTO_IPV6, IPV6_PROTECTION_LEVEL, &i_val,
00206 sizeof( i_val ) );
00207 }
00208 #endif
00209
00210
00211 i_opt = 1;
00212 if( setsockopt( i_handle, SOL_SOCKET, SO_REUSEADDR,
00213 (void *) &i_opt, sizeof( i_opt ) ) == -1 )
00214 {
00215 msg_Warn( p_this, "cannot configure socket (SO_REUSEADDR: %s)",
00216 strerror(errno) );
00217 close( i_handle );
00218 return 0;
00219 }
00220
00221
00222
00223 i_opt = 0x80000;
00224 if( setsockopt( i_handle, SOL_SOCKET, SO_RCVBUF,
00225 (void *) &i_opt, sizeof( i_opt ) ) == -1 )
00226 {
00227 msg_Warn( p_this, "cannot configure socket (SO_RCVBUF: %s)",
00228 strerror(errno) );
00229 }
00230
00231 #if defined(WIN32)
00232
00233 if( IN6_IS_ADDR_MULTICAST(&sock.sin6_addr) )
00234 {
00235 struct sockaddr_in6 sockany = sock;
00236 sockany.sin6_addr = in6addr_any;
00237 sockany.sin6_scope_id = 0;
00238
00239
00240 if( bind( i_handle, (struct sockaddr *)&sockany, sizeof( sock ) ) < 0 )
00241 {
00242 msg_Warn( p_this, "cannot bind socket (%s)", strerror(errno) );
00243 close( i_handle );
00244 return 0;
00245 }
00246 }
00247 else
00248 #endif
00249
00250 if( bind( i_handle, (struct sockaddr *)&sock, sizeof( sock ) ) < 0 )
00251 {
00252 msg_Warn( p_this, "cannot bind socket (%s)", strerror(errno) );
00253 close( i_handle );
00254 return 0;
00255 }
00256
00257
00258 if( !*psz_bind_addr )
00259 {
00260 i_opt = 1;
00261 if( setsockopt( i_handle, SOL_SOCKET, SO_BROADCAST,
00262 (void*) &i_opt, sizeof( i_opt ) ) == -1 )
00263 {
00264 msg_Warn( p_this, "IPv6 warning: cannot configure socket "
00265 "(SO_BROADCAST: %s)", strerror(errno) );
00266 }
00267 }
00268
00269
00270 #if defined( WIN32 ) || defined( HAVE_IF_NAMETOINDEX )
00271 if( IN6_IS_ADDR_MULTICAST(&sock.sin6_addr) )
00272 {
00273 if(*psz_server_addr)
00274 {
00275 struct group_source_req imr;
00276 struct sockaddr_in6 *p_sin6;
00277
00278 imr.gsr_interface = 0;
00279 imr.gsr_group.ss_family = AF_INET6;
00280 imr.gsr_source.ss_family = AF_INET6;
00281 p_sin6 = (struct sockaddr_in6 *)&imr.gsr_group;
00282 p_sin6->sin6_addr = sock.sin6_addr;
00283
00284
00285 msg_Dbg( p_this, "psz_server_addr : %s", psz_server_addr);
00286
00287 if ( BuildAddr( p_this, &sock, psz_server_addr, i_server_port ) )
00288 {
00289 msg_Warn( p_this, "cannot build remote address" );
00290 close( i_handle );
00291 return 0;
00292 }
00293 p_sin6 = (struct sockaddr_in6 *)&imr.gsr_source;
00294 p_sin6->sin6_addr = sock.sin6_addr;
00295
00296 msg_Dbg( p_this, "IPV6_ADD_SOURCE_MEMBERSHIP multicast request" );
00297 if( setsockopt( i_handle, IPPROTO_IPV6, MCAST_JOIN_SOURCE_GROUP,
00298 (char *)&imr, sizeof(struct group_source_req) ) == -1 )
00299 {
00300
00301 msg_Err( p_this, "failed to join IP multicast group (%s)",
00302 strerror(errno) );
00303 }
00304 }
00305 else
00306 {
00307
00308 struct ipv6_mreq imr;
00309 int res;
00310
00311 imr.ipv6mr_interface = sock.sin6_scope_id;
00312 imr.ipv6mr_multiaddr = sock.sin6_addr;
00313 res = setsockopt(i_handle, IPPROTO_IPV6, IPV6_JOIN_GROUP, (void*) &imr,
00314 #if defined(WIN32)
00315 sizeof(imr) + 4);
00316 #else
00317 sizeof(imr));
00318 #endif
00319
00320 if( res == -1 )
00321 {
00322 msg_Err( p_this, "cannot join multicast group" );
00323 }
00324 }
00325 }
00326 #else
00327 msg_Warn( p_this, "Multicast IPv6 is not supported on your OS" );
00328 #endif
00329
00330
00331 if( *psz_server_addr )
00332 {
00333 int ttl = p_socket->i_ttl;
00334 if( ttl < 1 )
00335 {
00336 ttl = config_GetInt( p_this, "ttl" );
00337 }
00338 if( ttl < 1 ) ttl = 1;
00339
00340
00341 if ( BuildAddr( p_this, &sock, psz_server_addr, i_server_port ) == -1 )
00342 {
00343 msg_Warn( p_this, "cannot build remote address" );
00344 close( i_handle );
00345 return 0;
00346 }
00347
00348
00349 if( connect( i_handle, (struct sockaddr *) &sock,
00350 sizeof( sock ) ) == (-1) )
00351 {
00352 msg_Warn( p_this, "cannot connect socket (%s)", strerror(errno) );
00353 close( i_handle );
00354 return 0;
00355 }
00356
00357
00358 if( ttl > 1 )
00359 {
00360 #if defined( WIN32 ) || defined( HAVE_IF_NAMETOINDEX )
00361 if( IN6_IS_ADDR_MULTICAST(&sock.sin6_addr) )
00362 {
00363 if( setsockopt( i_handle, IPPROTO_IPV6, IPV6_MULTICAST_HOPS,
00364 (void *)&ttl, sizeof( ttl ) ) < 0 )
00365 {
00366 msg_Err( p_this, "failed to set multicast ttl (%s)",
00367 strerror(errno) );
00368 }
00369 }
00370 else
00371 #endif
00372 {
00373 if( setsockopt( i_handle, IPPROTO_IPV6, IPV6_UNICAST_HOPS,
00374 (void *)&ttl, sizeof( ttl ) ) < 0 )
00375 {
00376 msg_Err( p_this, "failed to set unicast ttl (%s)",
00377 strerror(errno) );
00378 }
00379 }
00380 }
00381 }
00382
00383 p_socket->i_handle = i_handle;
00384
00385 var_Create( p_this, "mtu", VLC_VAR_INTEGER | VLC_VAR_DOINHERIT );
00386 var_Get( p_this, "mtu", &val );
00387 p_socket->i_mtu = val.i_int;
00388
00389 return 0;
00390 }