Main Page | Modules | Class Hierarchy | Class List | Directories | File List | Class Members | File Members | Related Pages

net.c

00001 /*****************************************************************************
00002  * net.c:
00003  *****************************************************************************
00004  * Copyright (C) 2004-2005 the VideoLAN team
00005  * $Id: net.c 12946 2005-10-23 16:24:30Z gbazin $
00006  *
00007  * Authors: Laurent Aimar <[email protected]>
00008  *          RĂ©mi Denis-Courmont <rem # videolan.org>
00009  *
00010  * This program is free software; you can redistribute it and/or modify
00011  * it under the terms of the GNU General Public License as published by
00012  * the Free Software Foundation; either version 2 of the License, or
00013  * (at your option) any later version.
00014  *
00015  * This program is distributed in the hope that it will be useful,
00016  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00017  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00018  * GNU General Public License for more details.
00019  *
00020  * You should have received a copy of the GNU General Public License
00021  * along with this program; if not, write to the Free Software
00022  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
00023  *****************************************************************************/
00024 
00025 /*****************************************************************************
00026  * Preamble
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         /* Set to non-blocking */
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      * Accepts only IPv6 connections on IPv6 sockets
00100      * (and open an IPv4 socket later as well if needed).
00101      * Only Linux and FreeBSD can map IPv4 connections on IPv6 sockets,
00102      * so this allows for more uniform handling across platforms. Besides,
00103      * it makes sure that IPv4 addresses will be printed as w.x.y.z rather
00104      * than ::ffff:w.x.y.z
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 /*PROTECTION_LEVEL_UNRESTRICTED*/;
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  * __net_OpenTCP:
00127  *****************************************************************************
00128  * Open a TCP connection and return a handle
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; /* historical VLC thing */
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                 /* Initialize file descriptor set */
00241                 FD_ZERO( &fds );
00242                 FD_SET( fd, &fds );
00243 
00244                 /* We'll wait 0.1 second if nothing happens */
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; /* timeout */
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; /* success! */
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  * __net_ListenTCP:
00336  *****************************************************************************
00337  * Open TCP passive "listening" socket(s)
00338  * This function returns NULL in case of error.
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         /* Bind the socket */
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         /* Listen */
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  * __net_Accept:
00419  *****************************************************************************
00420  * Accept a connection on a set of listening sockets and return it
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         /* Initialize file descriptor set */
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                  * This round-robin trick ensures that the first sockets in
00491                  * pi_fd won't prevent the last ones from getting accept'ed.
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  * __net_OpenUDP:
00506  *****************************************************************************
00507  * Open a UDP connection and return a handle
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     /* Prepare the network_socket_t structure */
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     /* Check if we have force ipv4 or ipv6 */
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         /* try IPv6 first (unless IPv4 forced) */
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          * Check if the IP stack can receive IPv4 packets on IPv6 sockets.
00555          * If yes, then it is better to use the IPv6 socket.
00556          * Otherwise, if we also get an IPv4, we have to choose, so we use
00557          * IPv4 only.
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         /* also try IPv4 (unless IPv6 forced) */
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  * __net_Close:
00599  *****************************************************************************
00600  * Close a network handle
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  * __net_Read:
00627  *****************************************************************************
00628  * Read from a network socket
00629  * If b_retry is true, then we repeat until we have read the right amount of
00630  * data
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             /* Initialize file descriptor set */
00652             FD_ZERO( &fds_r );
00653             FD_SET( fd, &fds_r );
00654             FD_ZERO( &fds_e );
00655             FD_SET( fd, &fds_e );
00656 
00657             /* We'll wait 0.5 second if nothing happens */
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                 /* only happens with p_vs (SSL) - not really an error */
00682             }
00683             else
00684             /* For udp only */
00685             /* On win32 recv() will fail if the datagram doesn't fit inside
00686              * the passed buffer, even though the buffer will be filled with
00687              * the first part of the datagram. */
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             /* EAGAIN only happens with p_vs (TLS) and it's not an error */
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             /* Connection closed */
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  * __net_ReadNonBlock:
00722  *****************************************************************************
00723  * Read from a network socket, non blocking mode (with timeout)
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     /* Initialize file descriptor set */
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/*STDIN_FILENO*/ ) 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             /* For udp only */
00772             /* On win32 recv() will fail if the datagram doesn't fit inside
00773              * the passed buffer, even though the buffer will be filled with
00774              * the first part of the datagram. */
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;  /* !i_recv -> connection closed if tcp */
00788     }
00789 
00790     /* We will never be here */
00791     return -1;
00792 }
00793 
00794 /*****************************************************************************
00795  * __net_Select:
00796  *****************************************************************************
00797  * Read from several sockets (with timeout). Takes data from the first socket
00798  * that has some.
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     /* Initialize file descriptor set */
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                     /* For udp only */
00852                     /* On win32 recv() will fail if the datagram doesn't
00853                      * fit inside the passed buffer, even though the buffer
00854                      *  will be filled with the first part of the datagram. */
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     /* We will never be here */
00874     return -1;
00875 }
00876 
00877 
00878 /* Write exact amount requested */
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             /* Initialize file descriptor set */
00900             FD_ZERO( &fds_w );
00901             FD_SET( fd, &fds_w );
00902             FD_ZERO( &fds_e );
00903             FD_SET( fd, &fds_e );
00904 
00905             /* We'll wait 0.5 second if nothing happens */
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             /* XXX With udp for example, it will issue a message if the host
00927              * isn't listening */
00928             /* msg_Err( p_this, "send failed (%s)", strerror(errno) ); */
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  * SocksNegociate:
01009  *****************************************************************************
01010  * Negociate authentication with a SOCKS server.
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     /* We negociate authentication */
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;    /* SOCKS version */
01031     if( b_auth )
01032     {
01033         buffer[1] = 2;                  /* Number of methods */
01034         buffer[2] = 0x00;               /* - No auth required */
01035         buffer[3] = 0x02;               /* - USer/Password */
01036         i_len = 4;
01037     }
01038     else
01039     {
01040         buffer[1] = 1;                  /* Number of methods */
01041         buffer[2] = 0x00;               /* - No auth required */
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         /* XXX: we don't support user/pwd > 255 (truncated)*/
01063         buffer[0] = i_socks_version;        /* Version */
01064         buffer[1] = i_len1;                 /* User length */
01065         memcpy( &buffer[2], psz_socks_user, i_len1 );
01066         buffer[2+i_len1] = i_len2;          /* Password length */
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  * SocksHandshakeTCP:
01099  *****************************************************************************
01100  * Open a TCP connection using a SOCKS server and return a handle (RFC 1928)
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         /* v4 only support ipv4 */
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;               /* CONNECT */
01132         SetWBE( &buffer[2], i_port );   /* Port */
01133         memcpy( &buffer[4],             /* Address */
01134                 &((struct sockaddr_in *)(p_res->ai_addr))->sin_addr, 4 );
01135         vlc_freeaddrinfo( p_res );
01136 
01137         buffer[8] = 0;                  /* Empty user id */
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;    /* Version */
01156         buffer[1] = 0x01;               /* Cmd: connect */
01157         buffer[2] = 0x00;               /* Reserved */
01158         buffer[3] = 3;                  /* ATYP: for now domainname */
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         /* Read the header */
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         /* Read the remaining bytes */
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  * inet_pton replacement for obsolete and/or crap operating systems
01202  *****************************************************************************/
01203 #ifndef HAVE_INET_PTON
01204 int inet_pton(int af, const char *src, void *dst)
01205 {
01206 # ifdef WIN32
01207     /* As we already know, Microsoft always go its own way, so even if they do
01208      * provide IPv6, they don't provide the API. */
01209     struct sockaddr_storage addr;
01210     int len = sizeof( addr );
01211 
01212     /* Damn it, they didn't even put LPCSTR for the firs parameter!!! */
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     /* Assume IPv6 is not supported. */
01246     /* Would be safer and more simpler to use inet_aton() but it is most
01247      * likely not provided either. */
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 /* WIN32 */
01262     return 0;
01263 }
01264 #endif /* HAVE_INET_PTON */

Generated on Tue Dec 20 10:15:00 2005 for vlc-0.8.4a by  doxygen 1.4.2