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 #include <stdlib.h>
00029 #include <vlc/vlc.h>
00030
00031 #include <errno.h>
00032
00033 #ifdef HAVE_FCNTL_H
00034 # include <fcntl.h>
00035 #endif
00036 #ifdef HAVE_SYS_TIME_H
00037 # include <sys/time.h>
00038 #endif
00039 #ifdef HAVE_UNISTD_H
00040 # include <unistd.h>
00041 #endif
00042
00043 #include "network.h"
00044
00045 #ifndef INADDR_ANY
00046 # define INADDR_ANY 0x00000000
00047 #endif
00048 #ifndef INADDR_NONE
00049 # define INADDR_NONE 0xFFFFFFFF
00050 #endif
00051
00052 static int SocksNegociate( vlc_object_t *, int fd, int i_socks_version,
00053 char *psz_socks_user, char *psz_socks_passwd );
00054 static int SocksHandshakeTCP( vlc_object_t *,
00055 int fd, int i_socks_version,
00056 char *psz_socks_user, char *psz_socks_passwd,
00057 const char *psz_host, int i_port );
00058
00059 static int net_Socket( vlc_object_t *p_this, int i_family, int i_socktype,
00060 int i_protocol )
00061 {
00062 int fd, i_val;
00063
00064 fd = socket( i_family, i_socktype, i_protocol );
00065 if( fd == -1 )
00066 {
00067 #if defined(WIN32) || defined(UNDER_CE)
00068 if( WSAGetLastError ( ) != WSAEAFNOSUPPORT )
00069 msg_Warn( p_this, "cannot create socket (%i)",
00070 WSAGetLastError() );
00071 #else
00072 if( errno != EAFNOSUPPORT )
00073 msg_Warn( p_this, "cannot create socket (%s)",
00074 strerror( errno ) );
00075 #endif
00076 return -1;
00077 }
00078
00079
00080 #if defined( WIN32 ) || defined( UNDER_CE )
00081 {
00082 unsigned long i_dummy = 1;
00083 if( ioctlsocket( fd, FIONBIO, &i_dummy ) != 0 )
00084 msg_Err( p_this, "cannot set socket to non-blocking mode" );
00085 }
00086 #else
00087 if( ( ( i_val = fcntl( fd, F_GETFL, 0 ) ) < 0 ) ||
00088 ( fcntl( fd, F_SETFL, i_val | O_NONBLOCK ) < 0 ) )
00089 msg_Err( p_this, "cannot set socket to non-blocking mode (%s)",
00090 strerror( errno ) );
00091 #endif
00092
00093 i_val = 1;
00094 setsockopt( fd, SOL_SOCKET, SO_REUSEADDR, (void *)&i_val,
00095 sizeof( i_val ) );
00096
00097 #ifdef IPV6_V6ONLY
00098
00099
00100
00101
00102
00103
00104
00105
00106 if( i_family == AF_INET6 )
00107 setsockopt( fd, IPPROTO_IPV6, IPV6_V6ONLY, (void *)&i_val,
00108 sizeof( i_val ) );
00109 #endif
00110
00111 #if defined( WIN32 ) || defined( UNDER_CE )
00112 # ifndef IPV6_PROTECTION_LEVEL
00113 # define IPV6_PROTECTION_LEVEL 23
00114 # endif
00115 if( i_family == AF_INET6 )
00116 {
00117 i_val = 30 ;
00118 setsockopt( fd, IPPROTO_IPV6, IPV6_PROTECTION_LEVEL,
00119 (const char*)&i_val, sizeof( i_val ) );
00120 }
00121 #endif
00122 return fd;
00123 }
00124
00125
00126
00127
00128
00129
00130 int __net_OpenTCP( vlc_object_t *p_this, const char *psz_host, int i_port )
00131 {
00132 struct addrinfo hints, *res, *ptr;
00133 const char *psz_realhost;
00134 char *psz_socks;
00135 int i_realport, i_val, i_handle = -1;
00136 vlc_bool_t b_unreach = VLC_FALSE;
00137
00138 if( i_port == 0 )
00139 i_port = 80;
00140
00141 memset( &hints, 0, sizeof( hints ) );
00142 hints.ai_socktype = SOCK_STREAM;
00143
00144 psz_socks = var_CreateGetString( p_this, "socks" );
00145 if( *psz_socks && *psz_socks != ':' )
00146 {
00147 char *psz = strchr( psz_socks, ':' );
00148
00149 if( psz )
00150 *psz++ = '\0';
00151
00152 psz_realhost = psz_socks;
00153 i_realport = ( psz != NULL ) ? atoi( psz ) : 1080;
00154
00155 msg_Dbg( p_this, "net: connecting to %s port %d for %s port %d",
00156 psz_realhost, i_realport, psz_host, i_port );
00157 }
00158 else
00159 {
00160 psz_realhost = psz_host;
00161 i_realport = i_port;
00162
00163 msg_Dbg( p_this, "net: connecting to %s port %d", psz_realhost,
00164 i_realport );
00165 }
00166
00167 i_val = vlc_getaddrinfo( p_this, psz_realhost, i_realport, &hints, &res );
00168 if( i_val )
00169 {
00170 msg_Err( p_this, "cannot resolve %s port %d : %s", psz_realhost,
00171 i_realport, vlc_gai_strerror( i_val ) );
00172 free( psz_socks );
00173 return -1;
00174 }
00175
00176 for( ptr = res; (ptr != NULL) && (i_handle == -1); ptr = ptr->ai_next )
00177 {
00178 int fd;
00179
00180 fd = net_Socket( p_this, ptr->ai_family, ptr->ai_socktype,
00181 ptr->ai_protocol );
00182 if( fd == -1 )
00183 continue;
00184
00185 if( connect( fd, ptr->ai_addr, ptr->ai_addrlen ) )
00186 {
00187 socklen_t i_val_size = sizeof( i_val );
00188 div_t d;
00189 struct timeval tv;
00190 vlc_value_t timeout;
00191
00192 #if defined( WIN32 ) || defined( UNDER_CE )
00193 if( WSAGetLastError() != WSAEWOULDBLOCK )
00194 {
00195 if( WSAGetLastError () == WSAENETUNREACH )
00196 b_unreach = VLC_TRUE;
00197 else
00198 msg_Warn( p_this, "connection to %s port %d failed (%d)",
00199 psz_host, i_port, WSAGetLastError( ) );
00200 net_Close( fd );
00201 continue;
00202 }
00203 #else
00204 if( errno != EINPROGRESS )
00205 {
00206 if( errno == ENETUNREACH )
00207 b_unreach = VLC_FALSE;
00208 else
00209 msg_Warn( p_this, "connection to %s port %d : %s", psz_host,
00210 i_port, strerror( errno ) );
00211 net_Close( fd );
00212 continue;
00213 }
00214 #endif
00215
00216 var_Create( p_this, "ipv4-timeout",
00217 VLC_VAR_INTEGER | VLC_VAR_DOINHERIT );
00218 var_Get( p_this, "ipv4-timeout", &timeout );
00219 if( timeout.i_int < 0 )
00220 {
00221 msg_Err( p_this, "invalid negative value for ipv4-timeout" );
00222 timeout.i_int = 0;
00223 }
00224 d = div( timeout.i_int, 100 );
00225
00226 msg_Dbg( p_this, "connection in progress" );
00227 do
00228 {
00229 fd_set fds;
00230
00231 if( p_this->b_die )
00232 {
00233 msg_Dbg( p_this, "connection aborted" );
00234 net_Close( fd );
00235 vlc_freeaddrinfo( res );
00236 free( psz_socks );
00237 return -1;
00238 }
00239
00240
00241 FD_ZERO( &fds );
00242 FD_SET( fd, &fds );
00243
00244
00245 tv.tv_sec = 0;
00246 tv.tv_usec = (d.quot > 0) ? 100000 : (1000 * d.rem);
00247
00248 i_val = select( fd + 1, NULL, &fds, NULL, &tv );
00249
00250 if( d.quot <= 0 )
00251 {
00252 msg_Dbg( p_this, "connection timed out" );
00253 net_Close( fd );
00254 fd = -1;
00255 break;
00256 }
00257
00258 d.quot--;
00259 }
00260 while( ( i_val == 0 ) || ( ( i_val < 0 ) &&
00261 #if defined( WIN32 ) || defined( UNDER_CE )
00262 ( WSAGetLastError() == WSAEWOULDBLOCK )
00263 #else
00264 ( errno == EINTR )
00265 #endif
00266 ) );
00267
00268 if( fd == -1 )
00269 continue;
00270
00271 if( i_val < 0 )
00272 {
00273 msg_Warn( p_this, "connection aborted (select failed)" );
00274 net_Close( fd );
00275 continue;
00276 }
00277
00278 #if !defined( SYS_BEOS ) && !defined( UNDER_CE )
00279 if( getsockopt( fd, SOL_SOCKET, SO_ERROR, (void*)&i_val,
00280 &i_val_size ) == -1 || i_val != 0 )
00281 {
00282 if( i_val == ENETUNREACH )
00283 b_unreach = VLC_TRUE;
00284 else
00285 {
00286 #ifdef WIN32
00287 msg_Warn( p_this, "connection to %s port %d failed (%d)",
00288 psz_host, i_port, WSAGetLastError( ) );
00289 #else
00290 msg_Warn( p_this, "connection to %s port %d : %s", psz_host,
00291 i_port, strerror( i_val ) );
00292 #endif
00293 }
00294 net_Close( fd );
00295 continue;
00296 }
00297 #endif
00298 }
00299 i_handle = fd;
00300 }
00301
00302 vlc_freeaddrinfo( res );
00303
00304 if( i_handle == -1 )
00305 {
00306 if( b_unreach )
00307 msg_Err( p_this, "Host %s port %d is unreachable", psz_host,
00308 i_port );
00309 return -1;
00310 }
00311
00312 if( *psz_socks && *psz_socks != ':' )
00313 {
00314 char *psz_user = var_CreateGetString( p_this, "socks-user" );
00315 char *psz_pwd = var_CreateGetString( p_this, "socks-pwd" );
00316
00317 if( SocksHandshakeTCP( p_this, i_handle, 5, psz_user, psz_pwd,
00318 psz_host, i_port ) )
00319 {
00320 msg_Err( p_this, "failed to use the SOCKS server" );
00321 net_Close( i_handle );
00322 i_handle = -1;
00323 }
00324
00325 free( psz_user );
00326 free( psz_pwd );
00327 }
00328 free( psz_socks );
00329
00330 return i_handle;
00331 }
00332
00333
00334
00335
00336
00337
00338
00339
00340 int *__net_ListenTCP( vlc_object_t *p_this, const char *psz_host, int i_port )
00341 {
00342 struct addrinfo hints, *res, *ptr;
00343 int i_val, *pi_handles, i_size;
00344
00345 memset( &hints, 0, sizeof( hints ) );
00346 hints.ai_socktype = SOCK_STREAM;
00347 hints.ai_flags = AI_PASSIVE;
00348
00349 msg_Dbg( p_this, "net: listening to %s port %d", psz_host, i_port );
00350
00351 i_val = vlc_getaddrinfo( p_this, psz_host, i_port, &hints, &res );
00352 if( i_val )
00353 {
00354 msg_Err( p_this, "cannot resolve %s port %d : %s", psz_host, i_port,
00355 vlc_gai_strerror( i_val ) );
00356 return NULL;
00357 }
00358
00359 pi_handles = NULL;
00360 i_size = 1;
00361
00362 for( ptr = res; ptr != NULL; ptr = ptr->ai_next )
00363 {
00364 int fd, *newpi;
00365
00366 fd = net_Socket( p_this, ptr->ai_family, ptr->ai_socktype,
00367 ptr->ai_protocol );
00368 if( fd == -1 )
00369 continue;
00370
00371
00372 if( bind( fd, ptr->ai_addr, ptr->ai_addrlen ) )
00373 {
00374 #if defined(WIN32) || defined(UNDER_CE)
00375 msg_Warn( p_this, "cannot bind socket (%i)", WSAGetLastError( ) );
00376 #else
00377 msg_Warn( p_this, "cannot bind socket (%s)", strerror( errno ) );
00378 #endif
00379 net_Close( fd );
00380 continue;
00381 }
00382
00383
00384 if( listen( fd, 100 ) == -1 )
00385 {
00386 #if defined(WIN32) || defined(UNDER_CE)
00387 msg_Err( p_this, "cannot bring socket in listening mode (%i)",
00388 WSAGetLastError());
00389 #else
00390 msg_Err( p_this, "cannot bring the socket in listening mode (%s)",
00391 strerror( errno ) );
00392 #endif
00393 net_Close( fd );
00394 continue;
00395 }
00396
00397 newpi = (int *)realloc( pi_handles, (++i_size) * sizeof( int ) );
00398 if( newpi == NULL )
00399 {
00400 net_Close( fd );
00401 break;
00402 }
00403 else
00404 {
00405 newpi[i_size - 2] = fd;
00406 pi_handles = newpi;
00407 }
00408 }
00409
00410 vlc_freeaddrinfo( res );
00411
00412 if( pi_handles != NULL )
00413 pi_handles[i_size - 1] = -1;
00414 return pi_handles;
00415 }
00416
00417
00418
00419
00420
00421
00422 int __net_Accept( vlc_object_t *p_this, int *pi_fd, mtime_t i_wait )
00423 {
00424 vlc_bool_t b_die = p_this->b_die, b_block = (i_wait < 0);
00425
00426 while( p_this->b_die == b_die )
00427 {
00428 int i_val = -1, *pi, *pi_end;
00429 struct timeval timeout;
00430 fd_set fds_r, fds_e;
00431
00432 pi = pi_fd;
00433
00434
00435 FD_ZERO( &fds_r );
00436 FD_ZERO( &fds_e );
00437
00438 for( pi = pi_fd; *pi != -1; pi++ )
00439 {
00440 int i_fd = *pi;
00441
00442 if( i_fd > i_val )
00443 i_val = i_fd;
00444
00445 FD_SET( i_fd, &fds_r );
00446 FD_SET( i_fd, &fds_e );
00447 }
00448 pi_end = pi;
00449
00450 timeout.tv_sec = 0;
00451 timeout.tv_usec = b_block ? 500000 : i_wait;
00452
00453 i_val = select( i_val + 1, &fds_r, NULL, &fds_e, &timeout );
00454 if( ( ( i_val < 0 ) && ( errno == EINTR ) ) || i_val == 0 )
00455 {
00456 if( b_block )
00457 continue;
00458 else
00459 return -1;
00460 }
00461 else if( i_val < 0 )
00462 {
00463 #if defined(WIN32) || defined(UNDER_CE)
00464 msg_Err( p_this, "network select error (%i)", WSAGetLastError() );
00465 #else
00466 msg_Err( p_this, "network select error (%s)", strerror( errno ) );
00467 #endif
00468 return -1;
00469 }
00470
00471 for( pi = pi_fd; *pi != -1; pi++ )
00472 {
00473 int i_fd = *pi;
00474
00475 if( !FD_ISSET( i_fd, &fds_r ) && !FD_ISSET( i_fd, &fds_e ) )
00476 continue;
00477
00478 i_val = accept( i_fd, NULL, 0 );
00479 if( i_val < 0 )
00480 {
00481 #if defined(WIN32) || defined(UNDER_CE)
00482 msg_Err( p_this, "accept failed (%i)", WSAGetLastError() );
00483 #else
00484 msg_Err( p_this, "accept failed (%s)", strerror( errno ) );
00485 #endif
00486 }
00487 else
00488 {
00489
00490
00491
00492
00493 --pi_end;
00494 memmove( pi, pi + 1, pi_end - pi );
00495 *pi_end = i_fd;
00496 return i_val;
00497 }
00498 }
00499 }
00500
00501 return -1;
00502 }
00503
00504
00505
00506
00507
00508
00509 int __net_OpenUDP( vlc_object_t *p_this, const char *psz_bind, int i_bind,
00510 const char *psz_server, int i_server )
00511 {
00512 vlc_value_t v4, v6;
00513 void *private;
00514 network_socket_t sock;
00515 module_t *p_network = NULL;
00516
00517 if( psz_server == NULL ) psz_server = "";
00518 if( psz_bind == NULL ) psz_bind = "";
00519
00520
00521 sock.psz_bind_addr = psz_bind;
00522 sock.i_bind_port = i_bind;
00523 sock.psz_server_addr = psz_server;
00524 sock.i_server_port = i_server;
00525 sock.i_ttl = 0;
00526 sock.v6only = 0;
00527 sock.i_handle = -1;
00528
00529 msg_Dbg( p_this, "net: connecting to '[%s]:%d@[%s]:%d'",
00530 psz_server, i_server, psz_bind, i_bind );
00531
00532
00533 var_Create( p_this, "ipv4", VLC_VAR_BOOL | VLC_VAR_DOINHERIT );
00534 var_Get( p_this, "ipv4", &v4 );
00535 var_Create( p_this, "ipv6", VLC_VAR_BOOL | VLC_VAR_DOINHERIT );
00536 var_Get( p_this, "ipv6", &v6 );
00537
00538 if( !v4.b_bool )
00539 {
00540 if( v6.b_bool )
00541 sock.v6only = 1;
00542
00543
00544 private = p_this->p_private;
00545 p_this->p_private = (void*)&sock;
00546 p_network = module_Need( p_this, "network", "ipv6", VLC_TRUE );
00547
00548 if( p_network != NULL )
00549 module_Unneed( p_this, p_network );
00550
00551 p_this->p_private = private;
00552
00553
00554
00555
00556
00557
00558
00559 if( ( sock.i_handle != -1 ) && ( ( sock.v6only == 0 ) || v6.b_bool ) )
00560 return sock.i_handle;
00561 }
00562
00563 if( !v6.b_bool )
00564 {
00565 int fd6 = sock.i_handle;
00566
00567
00568 private = p_this->p_private;
00569 p_this->p_private = (void*)&sock;
00570 p_network = module_Need( p_this, "network", "ipv4", VLC_TRUE );
00571
00572 if( p_network != NULL )
00573 module_Unneed( p_this, p_network );
00574
00575 p_this->p_private = private;
00576
00577 if( fd6 != -1 )
00578 {
00579 if( sock.i_handle != -1 )
00580 {
00581 msg_Warn( p_this, "net: lame IPv6/IPv4 dual-stack present. "
00582 "Using only IPv4." );
00583 net_Close( fd6 );
00584 }
00585 else
00586 sock.i_handle = fd6;
00587 }
00588 }
00589
00590 if( sock.i_handle == -1 )
00591 msg_Dbg( p_this, "net: connection to '[%s]:%d@[%s]:%d' failed",
00592 psz_server, i_server, psz_bind, i_bind );
00593
00594 return sock.i_handle;
00595 }
00596
00597
00598
00599
00600
00601
00602 void net_Close( int fd )
00603 {
00604 #ifdef UNDER_CE
00605 CloseHandle( (HANDLE)fd );
00606 #elif defined( WIN32 )
00607 closesocket( fd );
00608 #else
00609 close( fd );
00610 #endif
00611 }
00612
00613 void net_ListenClose( int *pi_fd )
00614 {
00615 if( pi_fd != NULL )
00616 {
00617 int *pi;
00618
00619 for( pi = pi_fd; *pi != -1; pi++ )
00620 net_Close( *pi );
00621 free( pi_fd );
00622 }
00623 }
00624
00625
00626
00627
00628
00629
00630
00631
00632 int __net_Read( vlc_object_t *p_this, int fd, v_socket_t *p_vs,
00633 uint8_t *p_data, int i_data, vlc_bool_t b_retry )
00634 {
00635 struct timeval timeout;
00636 fd_set fds_r, fds_e;
00637 int i_recv;
00638 int i_total = 0;
00639 int i_ret;
00640 vlc_bool_t b_die = p_this->b_die;
00641
00642 while( i_data > 0 )
00643 {
00644 do
00645 {
00646 if( p_this->b_die != b_die )
00647 {
00648 return 0;
00649 }
00650
00651
00652 FD_ZERO( &fds_r );
00653 FD_SET( fd, &fds_r );
00654 FD_ZERO( &fds_e );
00655 FD_SET( fd, &fds_e );
00656
00657
00658 timeout.tv_sec = 0;
00659 timeout.tv_usec = 500000;
00660
00661 } while( (i_ret = select(fd + 1, &fds_r, NULL, &fds_e, &timeout)) == 0
00662 || ( i_ret < 0 && errno == EINTR ) );
00663
00664 if( i_ret < 0 )
00665 {
00666 #if defined(WIN32) || defined(UNDER_CE)
00667 msg_Err( p_this, "network select error (%d)", WSAGetLastError() );
00668 #else
00669 msg_Err( p_this, "network select error (%s)", strerror(errno) );
00670 #endif
00671 return i_total > 0 ? i_total : -1;
00672 }
00673
00674 if( ( i_recv = (p_vs != NULL)
00675 ? p_vs->pf_recv( p_vs->p_sys, p_data, i_data )
00676 : recv( fd, p_data, i_data, 0 ) ) < 0 )
00677 {
00678 #if defined(WIN32) || defined(UNDER_CE)
00679 if( WSAGetLastError() == WSAEWOULDBLOCK )
00680 {
00681
00682 }
00683 else
00684
00685
00686
00687
00688 if( WSAGetLastError() == WSAEMSGSIZE )
00689 {
00690 msg_Err( p_this, "recv() failed. "
00691 "Increase the mtu size (--mtu option)" );
00692 i_total += i_data;
00693 }
00694 else if( WSAGetLastError() == WSAEINTR ) continue;
00695 else msg_Err( p_this, "recv failed (%i)", WSAGetLastError() );
00696 #else
00697
00698 if( errno != EAGAIN )
00699 msg_Err( p_this, "recv failed (%s)", strerror(errno) );
00700 #endif
00701 return i_total > 0 ? i_total : -1;
00702 }
00703 else if( i_recv == 0 )
00704 {
00705
00706 b_retry = VLC_FALSE;
00707 }
00708
00709 p_data += i_recv;
00710 i_data -= i_recv;
00711 i_total+= i_recv;
00712 if( !b_retry )
00713 {
00714 break;
00715 }
00716 }
00717 return i_total;
00718 }
00719
00720
00721
00722
00723
00724
00725 int __net_ReadNonBlock( vlc_object_t *p_this, int fd, v_socket_t *p_vs,
00726 uint8_t *p_data, int i_data, mtime_t i_wait)
00727 {
00728 struct timeval timeout;
00729 fd_set fds_r, fds_e;
00730 int i_recv;
00731 int i_ret;
00732
00733
00734 FD_ZERO( &fds_r );
00735 FD_SET( fd, &fds_r );
00736 FD_ZERO( &fds_e );
00737 FD_SET( fd, &fds_e );
00738
00739 timeout.tv_sec = 0;
00740 timeout.tv_usec = i_wait;
00741
00742 i_ret = select(fd + 1, &fds_r, NULL, &fds_e, &timeout);
00743
00744 if( i_ret < 0 && errno == EINTR )
00745 {
00746 return 0;
00747 }
00748 else if( i_ret < 0 )
00749 {
00750 #if defined(WIN32) || defined(UNDER_CE)
00751 msg_Err( p_this, "network select error (%d)", WSAGetLastError() );
00752 #else
00753 msg_Err( p_this, "network select error (%s)", strerror(errno) );
00754 #endif
00755 return -1;
00756 }
00757 else if( i_ret == 0)
00758 {
00759 return 0;
00760 }
00761 else
00762 {
00763 #if !defined(UNDER_CE)
00764 if( fd == 0 ) i_recv = read( fd, p_data, i_data ); else
00765 #endif
00766 if( ( i_recv = (p_vs != NULL)
00767 ? p_vs->pf_recv( p_vs->p_sys, p_data, i_data )
00768 : recv( fd, p_data, i_data, 0 ) ) < 0 )
00769 {
00770 #if defined(WIN32) || defined(UNDER_CE)
00771
00772
00773
00774
00775 if( WSAGetLastError() == WSAEMSGSIZE )
00776 {
00777 msg_Err( p_this, "recv() failed. "
00778 "Increase the mtu size (--mtu option)" );
00779 }
00780 else msg_Err( p_this, "recv failed (%i)", WSAGetLastError() );
00781 #else
00782 msg_Err( p_this, "recv failed (%s)", strerror(errno) );
00783 #endif
00784 return -1;
00785 }
00786
00787 return i_recv ? i_recv : -1;
00788 }
00789
00790
00791 return -1;
00792 }
00793
00794
00795
00796
00797
00798
00799
00800 int __net_Select( vlc_object_t *p_this, int *pi_fd, v_socket_t **pp_vs,
00801 int i_fd, uint8_t *p_data, int i_data, mtime_t i_wait )
00802 {
00803 struct timeval timeout;
00804 fd_set fds_r, fds_e;
00805 int i_recv;
00806 int i_ret;
00807 int i;
00808 int i_max_fd = 0;
00809
00810
00811 FD_ZERO( &fds_r );
00812 FD_ZERO( &fds_e );
00813
00814 for( i = 0 ; i < i_fd ; i++)
00815 {
00816 if( pi_fd[i] > i_max_fd ) i_max_fd = pi_fd[i];
00817 FD_SET( pi_fd[i], &fds_r );
00818 FD_SET( pi_fd[i], &fds_e );
00819 }
00820
00821 timeout.tv_sec = 0;
00822 timeout.tv_usec = i_wait;
00823
00824 i_ret = select( i_max_fd + 1, &fds_r, NULL, &fds_e, &timeout );
00825
00826 if( i_ret < 0 && errno == EINTR )
00827 {
00828 return 0;
00829 }
00830 else if( i_ret < 0 )
00831 {
00832 msg_Err( p_this, "network select error (%s)", strerror(errno) );
00833 return -1;
00834 }
00835 else if( i_ret == 0 )
00836 {
00837 return 0;
00838 }
00839 else
00840 {
00841 for( i = 0 ; i < i_fd ; i++)
00842 {
00843 if( FD_ISSET( pi_fd[i], &fds_r ) )
00844 {
00845 i_recv = ((pp_vs != NULL) && (pp_vs[i] != NULL))
00846 ? pp_vs[i]->pf_recv( pp_vs[i]->p_sys, p_data, i_data )
00847 : recv( pi_fd[i], p_data, i_data, 0 );
00848 if( i_recv < 0 )
00849 {
00850 #ifdef WIN32
00851
00852
00853
00854
00855 if( WSAGetLastError() == WSAEMSGSIZE )
00856 {
00857 msg_Err( p_this, "recv() failed. "
00858 "Increase the mtu size (--mtu option)" );
00859 }
00860 else msg_Err( p_this, "recv failed (%i)",
00861 WSAGetLastError() );
00862 #else
00863 msg_Err( p_this, "recv failed (%s)", strerror(errno) );
00864 #endif
00865 return VLC_EGENERIC;
00866 }
00867
00868 return i_recv;
00869 }
00870 }
00871 }
00872
00873
00874 return -1;
00875 }
00876
00877
00878
00879 int __net_Write( vlc_object_t *p_this, int fd, v_socket_t *p_vs,
00880 const uint8_t *p_data, int i_data )
00881 {
00882 struct timeval timeout;
00883 fd_set fds_w, fds_e;
00884 int i_send;
00885 int i_total = 0;
00886 int i_ret;
00887
00888 vlc_bool_t b_die = p_this->b_die;
00889
00890 while( i_data > 0 )
00891 {
00892 do
00893 {
00894 if( p_this->b_die != b_die )
00895 {
00896 return 0;
00897 }
00898
00899
00900 FD_ZERO( &fds_w );
00901 FD_SET( fd, &fds_w );
00902 FD_ZERO( &fds_e );
00903 FD_SET( fd, &fds_e );
00904
00905
00906 timeout.tv_sec = 0;
00907 timeout.tv_usec = 500000;
00908
00909 } while( (i_ret = select(fd + 1, NULL, &fds_w, &fds_e, &timeout)) == 0
00910 || ( i_ret < 0 && errno == EINTR ) );
00911
00912 if( i_ret < 0 )
00913 {
00914 #if defined(WIN32) || defined(UNDER_CE)
00915 msg_Err( p_this, "network select error (%d)", WSAGetLastError() );
00916 #else
00917 msg_Err( p_this, "network select error (%s)", strerror(errno) );
00918 #endif
00919 return i_total > 0 ? i_total : -1;
00920 }
00921
00922 if( ( i_send = (p_vs != NULL)
00923 ? p_vs->pf_send( p_vs->p_sys, p_data, i_data )
00924 : send( fd, p_data, i_data, 0 ) ) < 0 )
00925 {
00926
00927
00928
00929 return i_total > 0 ? i_total : -1;
00930 }
00931
00932 p_data += i_send;
00933 i_data -= i_send;
00934 i_total+= i_send;
00935 }
00936 return i_total;
00937 }
00938
00939 char *__net_Gets( vlc_object_t *p_this, int fd, v_socket_t *p_vs )
00940 {
00941 char *psz_line = NULL, *ptr = NULL;
00942 size_t i_line = 0, i_max = 0;
00943
00944
00945 for( ;; )
00946 {
00947 if( i_line == i_max )
00948 {
00949 i_max += 1024;
00950 psz_line = realloc( psz_line, i_max );
00951 ptr = psz_line + i_line;
00952 }
00953
00954 if( net_Read( p_this, fd, p_vs, (uint8_t *)ptr, 1, VLC_TRUE ) != 1 )
00955 {
00956 if( i_line == 0 )
00957 {
00958 free( psz_line );
00959 return NULL;
00960 }
00961 break;
00962 }
00963
00964 if ( *ptr == '\n' )
00965 break;
00966
00967 i_line++;
00968 ptr++;
00969 }
00970
00971 *ptr-- = '\0';
00972
00973 if( ( ptr >= psz_line ) && ( *ptr == '\r' ) )
00974 *ptr = '\0';
00975
00976 return psz_line;
00977 }
00978
00979 int net_Printf( vlc_object_t *p_this, int fd, v_socket_t *p_vs,
00980 const char *psz_fmt, ... )
00981 {
00982 int i_ret;
00983 va_list args;
00984 va_start( args, psz_fmt );
00985 i_ret = net_vaPrintf( p_this, fd, p_vs, psz_fmt, args );
00986 va_end( args );
00987
00988 return i_ret;
00989 }
00990
00991 int __net_vaPrintf( vlc_object_t *p_this, int fd, v_socket_t *p_vs,
00992 const char *psz_fmt, va_list args )
00993 {
00994 char *psz;
00995 int i_size, i_ret;
00996
00997 i_size = vasprintf( &psz, psz_fmt, args );
00998 i_ret = __net_Write( p_this, fd, p_vs, (uint8_t *)psz, i_size ) < i_size
00999 ? -1 : i_size;
01000 free( psz );
01001
01002 return i_ret;
01003 }
01004
01005
01006
01007
01008
01009
01010
01011
01012 static int SocksNegociate( vlc_object_t *p_obj,
01013 int fd, int i_socks_version,
01014 char *psz_socks_user,
01015 char *psz_socks_passwd )
01016 {
01017 uint8_t buffer[128+2*256];
01018 int i_len;
01019 vlc_bool_t b_auth = VLC_FALSE;
01020
01021 if( i_socks_version != 5 )
01022 return VLC_SUCCESS;
01023
01024
01025
01026 if( psz_socks_user && psz_socks_passwd &&
01027 *psz_socks_user && *psz_socks_passwd )
01028 b_auth = VLC_TRUE;
01029
01030 buffer[0] = i_socks_version;
01031 if( b_auth )
01032 {
01033 buffer[1] = 2;
01034 buffer[2] = 0x00;
01035 buffer[3] = 0x02;
01036 i_len = 4;
01037 }
01038 else
01039 {
01040 buffer[1] = 1;
01041 buffer[2] = 0x00;
01042 i_len = 3;
01043 }
01044
01045 if( net_Write( p_obj, fd, NULL, buffer, i_len ) != i_len )
01046 return VLC_EGENERIC;
01047 if( net_Read( p_obj, fd, NULL, buffer, 2, VLC_TRUE ) != 2 )
01048 return VLC_EGENERIC;
01049
01050 msg_Dbg( p_obj, "socks: v=%d method=%x", buffer[0], buffer[1] );
01051
01052 if( buffer[1] == 0x00 )
01053 {
01054 msg_Dbg( p_obj, "socks: no authentication required" );
01055 }
01056 else if( buffer[1] == 0x02 )
01057 {
01058 int i_len1 = __MIN( strlen(psz_socks_user), 255 );
01059 int i_len2 = __MIN( strlen(psz_socks_passwd), 255 );
01060 msg_Dbg( p_obj, "socks: username/password authentication" );
01061
01062
01063 buffer[0] = i_socks_version;
01064 buffer[1] = i_len1;
01065 memcpy( &buffer[2], psz_socks_user, i_len1 );
01066 buffer[2+i_len1] = i_len2;
01067 memcpy( &buffer[2+i_len1+1], psz_socks_passwd, i_len2 );
01068
01069 i_len = 3 + i_len1 + i_len2;
01070
01071 if( net_Write( p_obj, fd, NULL, buffer, i_len ) != i_len )
01072 return VLC_EGENERIC;
01073
01074 if( net_Read( p_obj, fd, NULL, buffer, 2, VLC_TRUE ) != 2 )
01075 return VLC_EGENERIC;
01076
01077 msg_Dbg( p_obj, "socks: v=%d status=%x", buffer[0], buffer[1] );
01078 if( buffer[1] != 0x00 )
01079 {
01080 msg_Err( p_obj, "socks: authentication rejected" );
01081 return VLC_EGENERIC;
01082 }
01083 }
01084 else
01085 {
01086 if( b_auth )
01087 msg_Err( p_obj, "socks: unsupported authentication method %x",
01088 buffer[0] );
01089 else
01090 msg_Err( p_obj, "socks: authentification needed" );
01091 return VLC_EGENERIC;
01092 }
01093
01094 return VLC_SUCCESS;
01095 }
01096
01097
01098
01099
01100
01101
01102 static int SocksHandshakeTCP( vlc_object_t *p_obj,
01103 int fd,
01104 int i_socks_version,
01105 char *psz_socks_user, char *psz_socks_passwd,
01106 const char *psz_host, int i_port )
01107 {
01108 uint8_t buffer[128+2*256];
01109
01110 if( i_socks_version != 4 && i_socks_version != 5 )
01111 {
01112 msg_Warn( p_obj, "invalid socks protocol version %d", i_socks_version );
01113 i_socks_version = 5;
01114 }
01115
01116 if( i_socks_version == 5 &&
01117 SocksNegociate( p_obj, fd, i_socks_version,
01118 psz_socks_user, psz_socks_passwd ) )
01119 return VLC_EGENERIC;
01120
01121 if( i_socks_version == 4 )
01122 {
01123 struct addrinfo hints = { 0 }, *p_res;
01124
01125
01126 hints.ai_family = AF_INET;
01127 if( vlc_getaddrinfo( p_obj, psz_host, 0, &hints, &p_res ) )
01128 return VLC_EGENERIC;
01129
01130 buffer[0] = i_socks_version;
01131 buffer[1] = 0x01;
01132 SetWBE( &buffer[2], i_port );
01133 memcpy( &buffer[4],
01134 &((struct sockaddr_in *)(p_res->ai_addr))->sin_addr, 4 );
01135 vlc_freeaddrinfo( p_res );
01136
01137 buffer[8] = 0;
01138
01139 if( net_Write( p_obj, fd, NULL, buffer, 9 ) != 9 )
01140 return VLC_EGENERIC;
01141 if( net_Read( p_obj, fd, NULL, buffer, 8, VLC_TRUE ) != 8 )
01142 return VLC_EGENERIC;
01143
01144 msg_Dbg( p_obj, "socks: v=%d cd=%d",
01145 buffer[0], buffer[1] );
01146
01147 if( buffer[1] != 90 )
01148 return VLC_EGENERIC;
01149 }
01150 else if( i_socks_version == 5 )
01151 {
01152 int i_hlen = __MIN(strlen( psz_host ), 255);
01153 int i_len;
01154
01155 buffer[0] = i_socks_version;
01156 buffer[1] = 0x01;
01157 buffer[2] = 0x00;
01158 buffer[3] = 3;
01159
01160 buffer[4] = i_hlen;
01161 memcpy( &buffer[5], psz_host, i_hlen );
01162 SetWBE( &buffer[5+i_hlen], i_port );
01163
01164 i_len = 5 + i_hlen + 2;
01165
01166
01167 if( net_Write( p_obj, fd, NULL, buffer, i_len ) != i_len )
01168 return VLC_EGENERIC;
01169
01170
01171 if( net_Read( p_obj, fd, NULL, buffer, 5, VLC_TRUE ) != 5 )
01172 return VLC_EGENERIC;
01173
01174 msg_Dbg( p_obj, "socks: v=%d rep=%d atyp=%d",
01175 buffer[0], buffer[1], buffer[3] );
01176
01177 if( buffer[1] != 0x00 )
01178 {
01179 msg_Err( p_obj, "socks: CONNECT request failed\n" );
01180 return VLC_EGENERIC;
01181 }
01182
01183
01184 if( buffer[3] == 0x01 )
01185 i_len = 4-1 + 2;
01186 else if( buffer[3] == 0x03 )
01187 i_len = buffer[4] + 2;
01188 else if( buffer[3] == 0x04 )
01189 i_len = 16-1+2;
01190 else
01191 return VLC_EGENERIC;
01192
01193 if( net_Read( p_obj, fd, NULL, buffer, i_len, VLC_TRUE ) != i_len )
01194 return VLC_EGENERIC;
01195 }
01196
01197 return VLC_SUCCESS;
01198 }
01199
01200
01201
01202
01203 #ifndef HAVE_INET_PTON
01204 int inet_pton(int af, const char *src, void *dst)
01205 {
01206 # ifdef WIN32
01207
01208
01209 struct sockaddr_storage addr;
01210 int len = sizeof( addr );
01211
01212
01213 #ifdef UNICODE
01214 wchar_t *workaround_for_ill_designed_api =
01215 malloc( MAX_PATH * sizeof(wchar_t) );
01216 mbstowcs( workaround_for_ill_designed_api, src, MAX_PATH );
01217 workaround_for_ill_designed_api[MAX_PATH-1] = 0;
01218 #else
01219 char *workaround_for_ill_designed_api = strdup( src );
01220 #endif
01221
01222 if( !WSAStringToAddress( workaround_for_ill_designed_api, af, NULL,
01223 (LPSOCKADDR)&addr, &len ) )
01224 {
01225 free( workaround_for_ill_designed_api );
01226 return -1;
01227 }
01228 free( workaround_for_ill_designed_api );
01229
01230 switch( af )
01231 {
01232 case AF_INET6:
01233 memcpy( dst, &((struct sockaddr_in6 *)&addr)->sin6_addr, 16 );
01234 break;
01235
01236 case AF_INET:
01237 memcpy( dst, &((struct sockaddr_in *)&addr)->sin_addr, 4 );
01238 break;
01239
01240 default:
01241 WSASetLastError( WSAEAFNOSUPPORT );
01242 return -1;
01243 }
01244 # else
01245
01246
01247
01248 uint32_t ipv4;
01249
01250 if( af != AF_INET )
01251 {
01252 errno = EAFNOSUPPORT;
01253 return -1;
01254 }
01255
01256 ipv4 = inet_addr( src );
01257 if( ipv4 == INADDR_NONE )
01258 return -1;
01259
01260 memcpy( dst, &ipv4, 4 );
01261 # endif
01262 return 0;
01263 }
01264 #endif