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 #include <errno.h>
00035
00036 #ifdef HAVE_SYS_TYPES_H
00037 # include <sys/types.h>
00038 #endif
00039 #ifdef HAVE_SYS_STAT_H
00040 # include <sys/stat.h>
00041 #endif
00042 #ifdef HAVE_FCNTL_H
00043 # include <fcntl.h>
00044 #endif
00045
00046 #ifdef HAVE_UNISTD_H
00047 # include <unistd.h>
00048 #endif
00049
00050 #if defined(WIN32) || defined(UNDER_CE)
00051 # if defined(UNDER_CE) && defined(sockaddr_storage)
00052 # undef sockaddr_storage
00053 # endif
00054 # include <winsock2.h>
00055 # include <ws2tcpip.h>
00056 # include <iphlpapi.h>
00057 # define close closesocket
00058 # if defined(UNDER_CE)
00059 # undef IP_MULTICAST_TTL
00060 # define IP_MULTICAST_TTL 3
00061 # undef IP_ADD_MEMBERSHIP
00062 # define IP_ADD_MEMBERSHIP 5
00063 # endif
00064 #else
00065 # include <netdb.h>
00066 # include <sys/socket.h>
00067 # include <netinet/in.h>
00068 # ifdef HAVE_ARPA_INET_H
00069 # include <arpa/inet.h>
00070 # endif
00071 #endif
00072
00073 #include "network.h"
00074
00075 #ifndef INADDR_ANY
00076 # define INADDR_ANY 0x00000000
00077 #endif
00078 #ifndef INADDR_NONE
00079 # define INADDR_NONE 0xFFFFFFFF
00080 #endif
00081 #ifndef IN_MULTICAST
00082 # define IN_MULTICAST(a) IN_CLASSD(a)
00083 #endif
00084
00085
00086
00087
00088
00089 static int OpenUDP( vlc_object_t * );
00090
00091
00092
00093
00094 #define MIFACE_TEXT N_("Multicast output interface")
00095 #define MIFACE_LONGTEXT N_( \
00096 "Indicate here the multicast output interface. " \
00097 "This overrides the routing table.")
00098
00099 vlc_module_begin();
00100 set_shortname( "IPv4" );
00101 set_description( _("UDP/IPv4 network abstraction layer") );
00102 set_capability( "network", 50 );
00103 set_category( CAT_INPUT );
00104 set_subcategory( SUBCAT_INPUT_GENERAL );
00105 set_callbacks( OpenUDP, NULL );
00106 add_string( "miface-addr", NULL, NULL, MIFACE_TEXT, MIFACE_LONGTEXT, VLC_TRUE );
00107 vlc_module_end();
00108
00109
00110
00111
00112 static int BuildAddr( struct sockaddr_in * p_socket,
00113 const char * psz_address, int i_port )
00114 {
00115
00116 memset( p_socket, 0, sizeof( struct sockaddr_in ) );
00117 p_socket->sin_family = AF_INET;
00118 p_socket->sin_port = htons( (uint16_t)i_port );
00119 if( !*psz_address )
00120 {
00121 p_socket->sin_addr.s_addr = INADDR_ANY;
00122 }
00123 else
00124 {
00125 struct hostent * p_hostent;
00126
00127
00128
00129 #ifdef HAVE_ARPA_INET_H
00130 if( !inet_aton( psz_address, &p_socket->sin_addr ) )
00131 #else
00132 p_socket->sin_addr.s_addr = inet_addr( psz_address );
00133 if( p_socket->sin_addr.s_addr == INADDR_NONE )
00134 #endif
00135 {
00136
00137 if ( (p_hostent = gethostbyname( psz_address )) == NULL )
00138 {
00139 return( -1 );
00140 }
00141
00142
00143 memcpy( &p_socket->sin_addr, p_hostent->h_addr_list[0],
00144 p_hostent->h_length );
00145 }
00146 }
00147 return( 0 );
00148 }
00149
00150 #if defined(WIN32) || defined(UNDER_CE)
00151 # define WINSOCK_STRERROR_SIZE 20
00152 static const char *winsock_strerror( char *buf )
00153 {
00154 snprintf( buf, WINSOCK_STRERROR_SIZE, "Winsock error %d",
00155 WSAGetLastError( ) );
00156 buf[WINSOCK_STRERROR_SIZE - 1] = '\0';
00157 return buf;
00158 }
00159 #endif
00160
00161
00162
00163
00164
00165
00166
00167
00168
00169
00170
00171
00172
00173
00174 static int OpenUDP( vlc_object_t * p_this )
00175 {
00176 network_socket_t * p_socket = p_this->p_private;
00177 const char * psz_bind_addr = p_socket->psz_bind_addr;
00178 int i_bind_port = p_socket->i_bind_port;
00179 const char * psz_server_addr = p_socket->psz_server_addr;
00180 int i_server_port = p_socket->i_server_port;
00181
00182 int i_handle, i_opt;
00183 struct sockaddr_in sock;
00184 vlc_value_t val;
00185 #if defined(WIN32) || defined(UNDER_CE)
00186 char strerror_buf[WINSOCK_STRERROR_SIZE];
00187 # define strerror( x ) winsock_strerror( strerror_buf )
00188 #endif
00189
00190
00191
00192
00193 #ifndef IP_ADD_SOURCE_MEMBERSHIP
00194 #define IP_ADD_SOURCE_MEMBERSHIP 39
00195 struct ip_mreq_source {
00196 struct in_addr imr_multiaddr;
00197 struct in_addr imr_interface;
00198 struct in_addr imr_sourceaddr;
00199 };
00200 #endif
00201
00202 p_socket->i_handle = -1;
00203
00204
00205
00206 if( (i_handle = socket( AF_INET, SOCK_DGRAM, 0 )) == -1 )
00207 {
00208 msg_Warn( p_this, "cannot create socket (%s)", strerror(errno) );
00209 return 0;
00210 }
00211
00212
00213 i_opt = 1;
00214 if( setsockopt( i_handle, SOL_SOCKET, SO_REUSEADDR,
00215 (void *) &i_opt, sizeof( i_opt ) ) == -1 )
00216 {
00217 msg_Warn( p_this, "cannot configure socket (SO_REUSEADDR: %s)",
00218 strerror(errno));
00219 close( i_handle );
00220 return 0;
00221 }
00222
00223 #ifdef SO_REUSEPORT
00224 i_opt = 1;
00225 if( setsockopt( i_handle, SOL_SOCKET, SO_REUSEPORT,
00226 (void *) &i_opt, sizeof( i_opt ) ) == -1 )
00227 {
00228 msg_Warn( p_this, "cannot configure socket (SO_REUSEPORT)" );
00229 }
00230 #endif
00231
00232
00233
00234 #if !defined( SYS_BEOS )
00235 i_opt = 0x80000;
00236 if( setsockopt( i_handle, SOL_SOCKET, SO_RCVBUF, (void *) &i_opt,
00237 sizeof( i_opt ) ) == -1 )
00238 msg_Dbg( p_this, "cannot configure socket (SO_RCVBUF: %s)",
00239 strerror(errno));
00240 i_opt = 0x80000;
00241 if( setsockopt( i_handle, SOL_SOCKET, SO_SNDBUF, (void *) &i_opt,
00242 sizeof( i_opt ) ) == -1 )
00243 msg_Dbg( p_this, "cannot configure socket (SO_SNDBUF: %s)",
00244 strerror(errno));
00245 #endif
00246
00247
00248
00249 #if defined( WIN32 ) || defined( UNDER_CE )
00250
00251
00252 if( BuildAddr( &sock, IN_MULTICAST( ntohl( inet_addr(psz_bind_addr) ) ) ?
00253 "" : psz_bind_addr, i_bind_port ) == -1 )
00254 #else
00255 if( BuildAddr( &sock, psz_bind_addr, i_bind_port ) == -1 )
00256 #endif
00257 {
00258 msg_Dbg( p_this, "could not build local address" );
00259 close( i_handle );
00260 return 0;
00261 }
00262
00263
00264 if( bind( i_handle, (struct sockaddr *)&sock, sizeof( sock ) ) < 0 )
00265 {
00266 msg_Warn( p_this, "cannot bind socket (%s)", strerror(errno) );
00267 close( i_handle );
00268 return 0;
00269 }
00270
00271 #if defined( WIN32 ) || defined( UNDER_CE )
00272
00273 if( IN_MULTICAST( ntohl( inet_addr(psz_bind_addr) ) ) )
00274 {
00275 if ( BuildAddr( &sock, psz_bind_addr, i_bind_port ) == -1 )
00276 {
00277 msg_Dbg( p_this, "could not build local address" );
00278 close( i_handle );
00279 return 0;
00280 }
00281 }
00282 #endif
00283
00284 #if !defined( SYS_BEOS )
00285
00286 if( !*psz_bind_addr )
00287 {
00288 i_opt = 1;
00289 if( setsockopt( i_handle, SOL_SOCKET, SO_BROADCAST, (void*) &i_opt,
00290 sizeof( i_opt ) ) == -1 )
00291 msg_Warn( p_this, "cannot configure socket (SO_BROADCAST: %s)",
00292 strerror(errno) );
00293 }
00294 #endif
00295
00296 #if !defined( SYS_BEOS )
00297
00298 if( IN_MULTICAST( ntohl(sock.sin_addr.s_addr) ) )
00299 {
00300
00301 char * psz_if_addr = config_GetPsz( p_this, "miface-addr" );
00302
00303
00304
00305
00306 if( *psz_server_addr )
00307 {
00308 struct ip_mreq_source imr;
00309
00310 imr.imr_multiaddr.s_addr = sock.sin_addr.s_addr;
00311 imr.imr_sourceaddr.s_addr = inet_addr(psz_server_addr);
00312
00313 if( psz_if_addr != NULL && *psz_if_addr
00314 && inet_addr(psz_if_addr) != INADDR_NONE )
00315 {
00316 imr.imr_interface.s_addr = inet_addr(psz_if_addr);
00317 }
00318 else
00319 {
00320 imr.imr_interface.s_addr = INADDR_ANY;
00321 }
00322 if( psz_if_addr != NULL ) free( psz_if_addr );
00323
00324 msg_Dbg( p_this, "IP_ADD_SOURCE_MEMBERSHIP multicast request" );
00325
00326 if( setsockopt( i_handle, IPPROTO_IP, IP_ADD_SOURCE_MEMBERSHIP,
00327 (char*)&imr,
00328 sizeof(struct ip_mreq_source) ) == -1 )
00329 {
00330 msg_Err( p_this, "failed to join IP multicast group (%s)",
00331 strerror(errno) );
00332 msg_Err( p_this, "are you sure your OS supports IGMPv3?" );
00333 close( i_handle );
00334 return 0;
00335 }
00336 }
00337
00338 else
00339 {
00340 struct ip_mreq imr;
00341
00342 imr.imr_interface.s_addr = INADDR_ANY;
00343 imr.imr_multiaddr.s_addr = sock.sin_addr.s_addr;
00344 if( psz_if_addr != NULL && *psz_if_addr
00345 && inet_addr(psz_if_addr) != INADDR_NONE )
00346 {
00347 imr.imr_interface.s_addr = inet_addr(psz_if_addr);
00348 }
00349 #if defined (WIN32) || defined (UNDER_CE)
00350 else
00351 {
00352 typedef DWORD (CALLBACK * GETBESTINTERFACE) ( IPAddr, PDWORD );
00353 typedef DWORD (CALLBACK * GETIPADDRTABLE) ( PMIB_IPADDRTABLE, PULONG, BOOL );
00354
00355 GETBESTINTERFACE OurGetBestInterface;
00356 GETIPADDRTABLE OurGetIpAddrTable;
00357 HINSTANCE hiphlpapi = LoadLibrary(_T("Iphlpapi.dll"));
00358 DWORD i_index;
00359
00360 if( hiphlpapi )
00361 {
00362 OurGetBestInterface =
00363 (void *)GetProcAddress( hiphlpapi,
00364 _T("GetBestInterface") );
00365 OurGetIpAddrTable =
00366 (void *)GetProcAddress( hiphlpapi,
00367 _T("GetIpAddrTable") );
00368 }
00369
00370 if( hiphlpapi && OurGetBestInterface && OurGetIpAddrTable &&
00371 OurGetBestInterface( sock.sin_addr.s_addr,
00372 &i_index ) == NO_ERROR )
00373 {
00374 PMIB_IPADDRTABLE p_table;
00375 DWORD i = 0;
00376
00377 msg_Dbg( p_this, "Winsock best interface is %lu",
00378 (unsigned long)i_index );
00379 OurGetIpAddrTable( NULL, &i, 0 );
00380
00381 p_table = (PMIB_IPADDRTABLE)malloc( i );
00382 if( p_table != NULL )
00383 {
00384 if( OurGetIpAddrTable( p_table, &i, 0 ) == NO_ERROR )
00385 {
00386 for( i = 0; i < p_table->dwNumEntries; i-- )
00387 {
00388 if( p_table->table[i].dwIndex == i_index )
00389 {
00390 imr.imr_interface.s_addr =
00391 p_table->table[i].dwAddr;
00392 msg_Dbg( p_this, "using interface 0x%08x",
00393 p_table->table[i].dwAddr );
00394 }
00395 }
00396 }
00397 else msg_Warn( p_this, "GetIpAddrTable failed" );
00398 free( p_table );
00399 }
00400 }
00401 else msg_Dbg( p_this, "GetBestInterface failed" );
00402
00403 if( hiphlpapi ) FreeLibrary( hiphlpapi );
00404 }
00405 #endif
00406 if( psz_if_addr != NULL ) free( psz_if_addr );
00407
00408 msg_Dbg( p_this, "IP_ADD_MEMBERSHIP multicast request" );
00409
00410 if( setsockopt( i_handle, IPPROTO_IP, IP_ADD_MEMBERSHIP,
00411 (char*)&imr, sizeof(struct ip_mreq) ) == -1 )
00412 {
00413 msg_Err( p_this, "failed to join IP multicast group (%s)",
00414 strerror(errno) );
00415 close( i_handle );
00416 return 0;
00417 }
00418 }
00419 }
00420 #endif
00421
00422 if( *psz_server_addr )
00423 {
00424
00425 if ( BuildAddr( &sock, psz_server_addr, i_server_port ) == -1 )
00426 {
00427 msg_Warn( p_this, "cannot build remote address" );
00428 close( i_handle );
00429 return 0;
00430 }
00431
00432
00433 if( connect( i_handle, (struct sockaddr *) &sock,
00434 sizeof( sock ) ) == (-1) )
00435 {
00436 msg_Warn( p_this, "cannot connect socket (%s)", strerror(errno) );
00437 close( i_handle );
00438 return 0;
00439 }
00440
00441 #if !defined( SYS_BEOS )
00442 if( IN_MULTICAST( ntohl(inet_addr(psz_server_addr) ) ) )
00443 {
00444
00445 int i_ttl = p_socket->i_ttl;
00446 unsigned char ttl;
00447
00448
00449 char * psz_mif_addr = config_GetPsz( p_this, "miface-addr" );
00450 if( psz_mif_addr )
00451 {
00452 struct in_addr intf;
00453 intf.s_addr = inet_addr(psz_mif_addr);
00454 free( psz_mif_addr );
00455
00456 if( setsockopt( i_handle, IPPROTO_IP, IP_MULTICAST_IF,
00457 &intf, sizeof( intf ) ) < 0 )
00458 {
00459 msg_Dbg( p_this, "failed to set multicast interface (%s).", strerror(errno) );
00460 close( i_handle );
00461 return 0;
00462 }
00463 }
00464
00465 if( i_ttl < 1 )
00466 {
00467 if( var_Get( p_this, "ttl", &val ) != VLC_SUCCESS )
00468 {
00469 var_Create( p_this, "ttl",
00470 VLC_VAR_INTEGER | VLC_VAR_DOINHERIT );
00471 var_Get( p_this, "ttl", &val );
00472 }
00473 i_ttl = val.i_int;
00474 }
00475 if( i_ttl < 1 ) i_ttl = 1;
00476 ttl = (unsigned char) i_ttl;
00477
00478
00479
00480
00481
00482 if( setsockopt( i_handle, IPPROTO_IP, IP_MULTICAST_TTL,
00483 &ttl, sizeof( ttl ) ) < 0 )
00484 {
00485 msg_Dbg( p_this, "failed to set ttl (%s). Let's try it "
00486 "the integer way.", strerror(errno) );
00487 if( setsockopt( i_handle, IPPROTO_IP, IP_MULTICAST_TTL,
00488 &i_ttl, sizeof( i_ttl ) ) <0 )
00489 {
00490 msg_Err( p_this, "failed to set ttl (%s)",
00491 strerror(errno) );
00492 close( i_handle );
00493 return 0;
00494 }
00495 }
00496 }
00497 #endif
00498 }
00499
00500 p_socket->i_handle = i_handle;
00501
00502 if( var_Get( p_this, "mtu", &val ) != VLC_SUCCESS )
00503 {
00504 var_Create( p_this, "mtu", VLC_VAR_INTEGER | VLC_VAR_DOINHERIT );
00505 var_Get( p_this, "mtu", &val );
00506 }
00507 p_socket->i_mtu = val.i_int;
00508
00509 return 0;
00510 }