1 /*****************************************************************************
3 *****************************************************************************
4 * Copyright (C) 2004-2005 the VideoLAN team
7 * Authors: Laurent Aimar <fenrir@videolan.org>
8 * RĂ©mi Denis-Courmont <rem # videolan.org>
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, write to the Free Software
22 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA.
23 *****************************************************************************/
25 /*****************************************************************************
27 *****************************************************************************/
37 #ifdef HAVE_SYS_TIME_H
38 # include <sys/time.h>
41 #if defined( WIN32 ) || defined( UNDER_CE )
42 # if defined(UNDER_CE) && defined(sockaddr_storage)
43 # undef sockaddr_storage
46 # include <winsock2.h>
47 # include <ws2tcpip.h>
49 # include <sys/socket.h>
50 # include <netinet/in.h>
51 # ifdef HAVE_ARPA_INET_H
52 # include <arpa/inet.h>
64 # define INADDR_ANY 0x00000000
67 # define INADDR_NONE 0xFFFFFFFF
70 static int SocksNegociate( vlc_object_t *, int fd, int i_socks_version,
71 char *psz_socks_user, char *psz_socks_passwd );
72 static int SocksHandshakeTCP( vlc_object_t *,
73 int fd, int i_socks_version,
74 char *psz_socks_user, char *psz_socks_passwd,
75 const char *psz_host, int i_port );
77 static int net_Socket( vlc_object_t *p_this, int i_family, int i_socktype,
82 fd = socket( i_family, i_socktype, i_protocol );
85 #if defined(WIN32) || defined(UNDER_CE)
86 msg_Warn( p_this, "cannot create socket (%i)",
89 msg_Warn( p_this, "cannot create socket (%s)",
95 /* Set to non-blocking */
96 #if defined( WIN32 ) || defined( UNDER_CE )
98 unsigned long i_dummy = 1;
99 if( ioctlsocket( fd, FIONBIO, &i_dummy ) != 0 )
100 msg_Err( p_this, "cannot set socket to non-blocking mode" );
103 if( ( ( i_val = fcntl( fd, F_GETFL, 0 ) ) < 0 ) ||
104 ( fcntl( fd, F_SETFL, i_val | O_NONBLOCK ) < 0 ) )
105 msg_Err( p_this, "cannot set socket to non-blocking mode (%s)",
110 setsockopt( fd, SOL_SOCKET, SO_REUSEADDR, (void *)&i_val,
115 * Accepts only IPv6 connections on IPv6 sockets
116 * (and open an IPv4 socket later as well if needed).
117 * Only Linux and FreeBSD can map IPv4 connections on IPv6 sockets,
118 * so this allows for more uniform handling across platforms. Besides,
119 * it makes sure that IPv4 addresses will be printed as w.x.y.z rather
120 * than ::ffff:w.x.y.z
122 if( i_family == AF_INET6 )
123 setsockopt( fd, IPPROTO_IPV6, IPV6_V6ONLY, (void *)&i_val,
127 #if defined( WIN32 ) || defined( UNDER_CE )
128 # ifdef IPV6_PROTECTION_LEVEL
129 if( i_family == AF_INET6 )
131 i_val = 30 /*PROTECTION_LEVEL_UNRESTRICTED*/;
132 setsockopt( fd, IPPROTO_IPV6, IPV6_PROTECTION_LEVEL,
133 (const char*)&i_val, sizeof( i_val ) );
136 # warning You are using outdated headers for Winsock !
142 /*****************************************************************************
144 *****************************************************************************
145 * Open a TCP connection and return a handle
146 *****************************************************************************/
147 int __net_OpenTCP( vlc_object_t *p_this, const char *psz_host, int i_port )
149 struct addrinfo hints, *res, *ptr;
150 const char *psz_realhost;
152 int i_realport, i_val, i_handle = -1;
155 i_port = 80; /* historical VLC thing */
157 memset( &hints, 0, sizeof( hints ) );
158 hints.ai_socktype = SOCK_STREAM;
160 psz_socks = var_CreateGetString( p_this, "socks" );
161 if( *psz_socks && *psz_socks != ':' )
163 char *psz = strchr( psz_socks, ':' );
168 psz_realhost = psz_socks;
169 i_realport = ( psz != NULL ) ? atoi( psz ) : 1080;
171 msg_Dbg( p_this, "net: connecting to '%s:%d' for '%s:%d'",
172 psz_realhost, i_realport, psz_host, i_port );
176 psz_realhost = psz_host;
179 msg_Dbg( p_this, "net: connecting to '%s:%d'", psz_realhost,
183 i_val = vlc_getaddrinfo( p_this, psz_realhost, i_realport, &hints, &res );
186 msg_Err( p_this, "cannot resolve '%s:%d' : %s", psz_realhost,
187 i_realport, vlc_gai_strerror( i_val ) );
192 for( ptr = res; (ptr != NULL) && (i_handle == -1); ptr = ptr->ai_next )
196 fd = net_Socket( p_this, ptr->ai_family, ptr->ai_socktype,
201 if( connect( fd, ptr->ai_addr, ptr->ai_addrlen ) )
203 socklen_t i_val_size = sizeof( i_val );
207 #if defined( WIN32 ) || defined( UNDER_CE )
208 if( WSAGetLastError() != WSAEWOULDBLOCK )
210 msg_Warn( p_this, "connection to %s:%d failed (%d)", psz_host,
211 i_port, WSAGetLastError( ) );
216 if( errno != EINPROGRESS )
218 msg_Warn( p_this, "connection to %s:%d : %s", psz_host,
219 i_port, strerror( errno ) );
225 var_Create( p_this, "ipv4-timeout",
226 VLC_VAR_INTEGER | VLC_VAR_DOINHERIT );
227 var_Get( p_this, "ipv4-timeout", &timeout );
228 if( timeout.i_int < 0 )
230 msg_Err( p_this, "invalid negative value for ipv4-timeout" );
233 d = div( timeout.i_int, 100 );
235 msg_Dbg( p_this, "connection in progress" );
242 msg_Dbg( p_this, "connection aborted" );
244 vlc_freeaddrinfo( res );
249 /* Initialize file descriptor set */
253 /* We'll wait 0.1 second if nothing happens */
255 tv.tv_usec = (d.quot > 0) ? 100000 : (1000 * d.rem);
257 i_val = select( fd + 1, NULL, &fds, NULL, &tv );
261 msg_Dbg( p_this, "connection timed out" );
269 while( ( i_val == 0 ) || ( ( i_val < 0 ) &&
270 #if defined( WIN32 ) || defined( UNDER_CE )
271 ( WSAGetLastError() == WSAEWOULDBLOCK )
278 continue; /* timeout */
282 msg_Warn( p_this, "connection aborted (select failed)" );
287 #if !defined( SYS_BEOS ) && !defined( UNDER_CE )
288 if( getsockopt( fd, SOL_SOCKET, SO_ERROR, (void*)&i_val,
289 &i_val_size ) == -1 || i_val != 0 )
292 msg_Warn( p_this, "connection to %s:%d failed (%d)", psz_host,
293 i_port, WSAGetLastError( ) );
295 msg_Warn( p_this, "connection to %s:%d : %s", psz_host,
296 i_port, strerror( i_val ) );
303 i_handle = fd; /* success! */
306 vlc_freeaddrinfo( res );
308 if( *psz_socks && *psz_socks != ':' )
310 char *psz_user = var_CreateGetString( p_this, "socks-user" );
311 char *psz_pwd = var_CreateGetString( p_this, "socks-pwd" );
313 if( SocksHandshakeTCP( p_this, i_handle, 5, psz_user, psz_pwd,
316 msg_Err( p_this, "failed to use the SOCKS server" );
317 net_Close( i_handle );
330 /*****************************************************************************
332 *****************************************************************************
333 * Open TCP passive "listening" socket(s)
334 * This function returns NULL in case of error.
335 *****************************************************************************/
336 int *__net_ListenTCP( vlc_object_t *p_this, const char *psz_host, int i_port )
338 struct addrinfo hints, *res, *ptr;
339 int i_val, *pi_handles, i_size;
341 memset( &hints, 0, sizeof( hints ) );
342 hints.ai_socktype = SOCK_STREAM;
343 hints.ai_flags = AI_PASSIVE;
345 msg_Dbg( p_this, "net: listening to '%s:%d'", psz_host, i_port );
347 i_val = vlc_getaddrinfo( p_this, psz_host, i_port, &hints, &res );
350 msg_Err( p_this, "cannot resolve '%s:%d' : %s", psz_host, i_port,
351 vlc_gai_strerror( i_val ) );
358 for( ptr = res; ptr != NULL; ptr = ptr->ai_next )
362 fd = net_Socket( p_this, ptr->ai_family, ptr->ai_socktype,
367 /* Bind the socket */
368 if( bind( fd, ptr->ai_addr, ptr->ai_addrlen ) )
370 #if defined(WIN32) || defined(UNDER_CE)
371 msg_Warn( p_this, "cannot bind socket (%i)", WSAGetLastError( ) );
373 msg_Warn( p_this, "cannot bind socket (%s)", strerror( errno ) );
380 if( listen( fd, 100 ) == -1 )
382 #if defined(WIN32) || defined(UNDER_CE)
383 msg_Err( p_this, "cannot bring socket in listening mode (%i)",
386 msg_Err( p_this, "cannot bring the socket in listening mode (%s)",
393 newpi = (int *)realloc( pi_handles, (++i_size) * sizeof( int ) );
401 newpi[i_size - 2] = fd;
406 vlc_freeaddrinfo( res );
408 if( pi_handles != NULL )
409 pi_handles[i_size - 1] = -1;
413 /*****************************************************************************
415 *****************************************************************************
416 * Accept a connection on a set of listening sockets and return it
417 *****************************************************************************/
418 int __net_Accept( vlc_object_t *p_this, int *pi_fd, mtime_t i_wait )
420 vlc_bool_t b_die = p_this->b_die, b_block = (i_wait < 0);
422 while( p_this->b_die == b_die )
424 int i_val = -1, *pi, *pi_end;
425 struct timeval timeout;
430 /* Initialize file descriptor set */
434 for( pi = pi_fd; *pi != -1; pi++ )
441 FD_SET( i_fd, &fds_r );
442 FD_SET( i_fd, &fds_e );
447 timeout.tv_usec = b_block ? 500000 : i_wait;
449 i_val = select( i_val + 1, &fds_r, NULL, &fds_e, &timeout );
450 if( ( ( i_val < 0 ) && ( errno == EINTR ) ) || i_val == 0 )
459 #if defined(WIN32) || defined(UNDER_CE)
460 msg_Err( p_this, "network select error (%i)", WSAGetLastError() );
462 msg_Err( p_this, "network select error (%s)", strerror( errno ) );
467 for( pi = pi_fd; *pi != -1; pi++ )
471 if( !FD_ISSET( i_fd, &fds_r ) && !FD_ISSET( i_fd, &fds_e ) )
474 i_val = accept( i_fd, NULL, 0 );
477 #if defined(WIN32) || defined(UNDER_CE)
478 msg_Err( p_this, "accept failed (%i)", WSAGetLastError() );
480 msg_Err( p_this, "accept failed (%s)", strerror( errno ) );
486 * This round-robin trick ensures that the first sockets in
487 * pi_fd won't prevent the last ones from getting accept'ed.
490 memmove( pi, pi + 1, pi_end - pi );
500 /*****************************************************************************
502 *****************************************************************************
503 * Open a UDP connection and return a handle
504 *****************************************************************************/
505 int __net_OpenUDP( vlc_object_t *p_this, const char *psz_bind, int i_bind,
506 const char *psz_server, int i_server )
510 network_socket_t sock;
511 module_t *p_network = NULL;
513 /* Prepare the network_socket_t structure */
514 sock.psz_bind_addr = psz_bind;
515 sock.i_bind_port = i_bind;
516 sock.psz_server_addr = psz_server;
517 sock.i_server_port = i_server;
522 if( psz_server == NULL )
524 if( psz_bind == NULL )
527 msg_Dbg( p_this, "net: connecting to '[%s]:%d@[%s]:%d'",
528 psz_server, i_server, psz_bind, i_bind );
530 /* Check if we have force ipv4 or ipv6 */
531 var_Create( p_this, "ipv4", VLC_VAR_BOOL | VLC_VAR_DOINHERIT );
532 var_Get( p_this, "ipv4", &v4 );
533 var_Create( p_this, "ipv6", VLC_VAR_BOOL | VLC_VAR_DOINHERIT );
534 var_Get( p_this, "ipv6", &v6 );
541 /* try IPv6 first (unless IPv4 forced) */
542 private = p_this->p_private;
543 p_this->p_private = (void*)&sock;
544 p_network = module_Need( p_this, "network", "ipv6", VLC_TRUE );
546 if( p_network != NULL )
547 module_Unneed( p_this, p_network );
549 p_this->p_private = private;
552 * Check if the IP stack can receive IPv4 packets on IPv6 sockets.
553 * If yes, then it is better to use the IPv6 socket.
554 * Otherwise, if we also get an IPv4, we have to choose, so we use
557 if( ( sock.i_handle != -1 ) && ( ( sock.v6only == 0 ) || v6.b_bool ) )
558 return sock.i_handle;
563 int fd6 = sock.i_handle;
565 /* also try IPv4 (unless IPv6 forced) */
566 private = p_this->p_private;
567 p_this->p_private = (void*)&sock;
568 p_network = module_Need( p_this, "network", "ipv4", VLC_TRUE );
570 if( p_network != NULL )
571 module_Unneed( p_this, p_network );
573 p_this->p_private = private;
577 if( sock.i_handle != -1 )
579 msg_Warn( p_this, "net: lame IPv6/IPv4 dual-stack present. "
580 "Using only IPv4." );
588 if( sock.i_handle == -1 )
589 msg_Dbg( p_this, "net: connection to '[%s]:%d@[%s]:%d' failed",
590 psz_server, i_server, psz_bind, i_bind );
592 return sock.i_handle;
595 /*****************************************************************************
597 *****************************************************************************
598 * Close a network handle
599 *****************************************************************************/
600 void net_Close( int fd )
603 CloseHandle( (HANDLE)fd );
604 #elif defined( WIN32 )
611 void net_ListenClose( int *pi_fd )
617 for( pi = pi_fd; *pi != -1; pi++ )
623 /*****************************************************************************
625 *****************************************************************************
626 * Read from a network socket
627 * If b_retry is true, then we repeat until we have read the right amount of
629 *****************************************************************************/
630 int __net_Read( vlc_object_t *p_this, int fd, v_socket_t *p_vs,
631 uint8_t *p_data, int i_data, vlc_bool_t b_retry )
633 struct timeval timeout;
638 vlc_bool_t b_die = p_this->b_die;
644 if( p_this->b_die != b_die )
649 /* Initialize file descriptor set */
651 FD_SET( fd, &fds_r );
653 FD_SET( fd, &fds_e );
655 /* We'll wait 0.5 second if nothing happens */
657 timeout.tv_usec = 500000;
659 } while( (i_ret = select(fd + 1, &fds_r, NULL, &fds_e, &timeout)) == 0
660 || ( i_ret < 0 && errno == EINTR ) );
664 #if defined(WIN32) || defined(UNDER_CE)
665 msg_Err( p_this, "network select error (%d)", WSAGetLastError() );
667 msg_Err( p_this, "network select error (%s)", strerror(errno) );
669 return i_total > 0 ? i_total : -1;
672 if( ( i_recv = (p_vs != NULL)
673 ? p_vs->pf_recv( p_vs->p_sys, p_data, i_data )
674 : recv( fd, p_data, i_data, 0 ) ) < 0 )
676 #if defined(WIN32) || defined(UNDER_CE)
677 if( WSAGetLastError() == WSAEWOULDBLOCK )
679 /* only happens with p_vs (SSL) - not really an error */
683 /* On win32 recv() will fail if the datagram doesn't fit inside
684 * the passed buffer, even though the buffer will be filled with
685 * the first part of the datagram. */
686 if( WSAGetLastError() == WSAEMSGSIZE )
688 msg_Err( p_this, "recv() failed. "
689 "Increase the mtu size (--mtu option)" );
692 else if( WSAGetLastError() == WSAEINTR ) continue;
693 else msg_Err( p_this, "recv failed (%i)", WSAGetLastError() );
695 /* EAGAIN only happens with p_vs (SSL) and it's not an error */
696 if( errno != EAGAIN )
697 msg_Err( p_this, "recv failed (%s)", strerror(errno) );
699 return i_total > 0 ? i_total : -1;
701 else if( i_recv == 0 )
703 /* Connection closed */
718 /*****************************************************************************
719 * __net_ReadNonBlock:
720 *****************************************************************************
721 * Read from a network socket, non blocking mode (with timeout)
722 *****************************************************************************/
723 int __net_ReadNonBlock( vlc_object_t *p_this, int fd, v_socket_t *p_vs,
724 uint8_t *p_data, int i_data, mtime_t i_wait)
726 struct timeval timeout;
731 /* Initialize file descriptor set */
733 FD_SET( fd, &fds_r );
735 FD_SET( fd, &fds_e );
738 timeout.tv_usec = i_wait;
740 i_ret = select(fd + 1, &fds_r, NULL, &fds_e, &timeout);
742 if( i_ret < 0 && errno == EINTR )
748 #if defined(WIN32) || defined(UNDER_CE)
749 msg_Err( p_this, "network select error (%d)", WSAGetLastError() );
751 msg_Err( p_this, "network select error (%s)", strerror(errno) );
761 #if !defined(UNDER_CE)
762 if( fd == 0/*STDIN_FILENO*/ ) i_recv = read( fd, p_data, i_data ); else
764 if( ( i_recv = (p_vs != NULL)
765 ? p_vs->pf_recv( p_vs->p_sys, p_data, i_data )
766 : recv( fd, p_data, i_data, 0 ) ) < 0 )
768 #if defined(WIN32) || defined(UNDER_CE)
770 /* On win32 recv() will fail if the datagram doesn't fit inside
771 * the passed buffer, even though the buffer will be filled with
772 * the first part of the datagram. */
773 if( WSAGetLastError() == WSAEMSGSIZE )
775 msg_Err( p_this, "recv() failed. "
776 "Increase the mtu size (--mtu option)" );
778 else msg_Err( p_this, "recv failed (%i)", WSAGetLastError() );
780 msg_Err( p_this, "recv failed (%s)", strerror(errno) );
785 return i_recv ? i_recv : -1; /* !i_recv -> connection closed if tcp */
788 /* We will never be here */
792 /*****************************************************************************
794 *****************************************************************************
795 * Read from several sockets (with timeout). Takes data from the first socket
797 *****************************************************************************/
798 int __net_Select( vlc_object_t *p_this, int *pi_fd, v_socket_t **pp_vs,
799 int i_fd, uint8_t *p_data, int i_data, mtime_t i_wait )
801 struct timeval timeout;
808 /* Initialize file descriptor set */
812 for( i = 0 ; i < i_fd ; i++)
814 if( pi_fd[i] > i_max_fd ) i_max_fd = pi_fd[i];
815 FD_SET( pi_fd[i], &fds_r );
816 FD_SET( pi_fd[i], &fds_e );
820 timeout.tv_usec = i_wait;
822 i_ret = select( i_max_fd + 1, &fds_r, NULL, &fds_e, &timeout );
824 if( i_ret < 0 && errno == EINTR )
830 msg_Err( p_this, "network select error (%s)", strerror(errno) );
833 else if( i_ret == 0 )
839 for( i = 0 ; i < i_fd ; i++)
841 if( FD_ISSET( pi_fd[i], &fds_r ) )
843 i_recv = ((pp_vs != NULL) && (pp_vs[i] != NULL))
844 ? pp_vs[i]->pf_recv( pp_vs[i]->p_sys, p_data, i_data )
845 : recv( pi_fd[i], p_data, i_data, 0 );
850 /* On win32 recv() will fail if the datagram doesn't
851 * fit inside the passed buffer, even though the buffer
852 * will be filled with the first part of the datagram. */
853 if( WSAGetLastError() == WSAEMSGSIZE )
855 msg_Err( p_this, "recv() failed. "
856 "Increase the mtu size (--mtu option)" );
858 else msg_Err( p_this, "recv failed (%i)",
861 msg_Err( p_this, "recv failed (%s)", strerror(errno) );
871 /* We will never be here */
876 /* Write exact amount requested */
877 int __net_Write( vlc_object_t *p_this, int fd, v_socket_t *p_vs,
878 uint8_t *p_data, int i_data )
880 struct timeval timeout;
886 vlc_bool_t b_die = p_this->b_die;
892 if( p_this->b_die != b_die )
897 /* Initialize file descriptor set */
899 FD_SET( fd, &fds_w );
901 FD_SET( fd, &fds_e );
903 /* We'll wait 0.5 second if nothing happens */
905 timeout.tv_usec = 500000;
907 } while( (i_ret = select(fd + 1, NULL, &fds_w, &fds_e, &timeout)) == 0
908 || ( i_ret < 0 && errno == EINTR ) );
912 #if defined(WIN32) || defined(UNDER_CE)
913 msg_Err( p_this, "network select error (%d)", WSAGetLastError() );
915 msg_Err( p_this, "network select error (%s)", strerror(errno) );
917 return i_total > 0 ? i_total : -1;
920 if( ( i_send = (p_vs != NULL)
921 ? p_vs->pf_send( p_vs->p_sys, p_data, i_data )
922 : send( fd, p_data, i_data, 0 ) ) < 0 )
924 /* XXX With udp for example, it will issue a message if the host
926 /* msg_Err( p_this, "send failed (%s)", strerror(errno) ); */
927 return i_total > 0 ? i_total : -1;
937 char *__net_Gets( vlc_object_t *p_this, int fd, v_socket_t *p_vs )
939 char *psz_line = NULL, *ptr = NULL;
940 size_t i_line = 0, i_max = 0;
945 if( i_line == i_max )
948 psz_line = realloc( psz_line, i_max );
949 ptr = psz_line + i_line;
952 if( net_Read( p_this, fd, p_vs, (uint8_t *)ptr, 1, VLC_TRUE ) != 1 )
971 if( ( ptr >= psz_line ) && ( *ptr == '\r' ) )
977 int net_Printf( vlc_object_t *p_this, int fd, v_socket_t *p_vs,
978 const char *psz_fmt, ... )
982 va_start( args, psz_fmt );
983 i_ret = net_vaPrintf( p_this, fd, p_vs, psz_fmt, args );
989 int __net_vaPrintf( vlc_object_t *p_this, int fd, v_socket_t *p_vs,
990 const char *psz_fmt, va_list args )
995 i_size = vasprintf( &psz, psz_fmt, args );
996 i_ret = __net_Write( p_this, fd, p_vs, (uint8_t *)psz, i_size ) < i_size
1005 /*****************************************************************************
1007 *****************************************************************************
1008 * Negociate authentication with a SOCKS server.
1009 *****************************************************************************/
1010 static int SocksNegociate( vlc_object_t *p_obj,
1011 int fd, int i_socks_version,
1012 char *psz_socks_user,
1013 char *psz_socks_passwd )
1015 uint8_t buffer[128+2*256];
1017 vlc_bool_t b_auth = VLC_FALSE;
1019 if( i_socks_version != 5 )
1022 /* We negociate authentication */
1024 if( psz_socks_user && psz_socks_passwd &&
1025 *psz_socks_user && *psz_socks_passwd )
1028 buffer[0] = i_socks_version; /* SOCKS version */
1031 buffer[1] = 2; /* Number of methods */
1032 buffer[2] = 0x00; /* - No auth required */
1033 buffer[3] = 0x02; /* - USer/Password */
1038 buffer[1] = 1; /* Number of methods */
1039 buffer[2] = 0x00; /* - No auth required */
1043 if( net_Write( p_obj, fd, NULL, buffer, i_len ) != i_len )
1044 return VLC_EGENERIC;
1045 if( net_Read( p_obj, fd, NULL, buffer, 2, VLC_TRUE ) != 2 )
1046 return VLC_EGENERIC;
1048 msg_Dbg( p_obj, "socks: v=%d method=%x", buffer[0], buffer[1] );
1050 if( buffer[1] == 0x00 )
1052 msg_Dbg( p_obj, "socks: no authentication required" );
1054 else if( buffer[1] == 0x02 )
1056 int i_len1 = __MIN( strlen(psz_socks_user), 255 );
1057 int i_len2 = __MIN( strlen(psz_socks_passwd), 255 );
1058 msg_Dbg( p_obj, "socks: username/password authentication" );
1060 /* XXX: we don't support user/pwd > 255 (truncated)*/
1061 buffer[0] = i_socks_version; /* Version */
1062 buffer[1] = i_len1; /* User length */
1063 memcpy( &buffer[2], psz_socks_user, i_len1 );
1064 buffer[2+i_len1] = i_len2; /* Password length */
1065 memcpy( &buffer[2+i_len1+1], psz_socks_passwd, i_len2 );
1067 i_len = 3 + i_len1 + i_len2;
1069 if( net_Write( p_obj, fd, NULL, buffer, i_len ) != i_len )
1070 return VLC_EGENERIC;
1072 if( net_Read( p_obj, fd, NULL, buffer, 2, VLC_TRUE ) != 2 )
1073 return VLC_EGENERIC;
1075 msg_Dbg( p_obj, "socks: v=%d status=%x", buffer[0], buffer[1] );
1076 if( buffer[1] != 0x00 )
1078 msg_Err( p_obj, "socks: authentication rejected" );
1079 return VLC_EGENERIC;
1085 msg_Err( p_obj, "socks: unsupported authentication method %x",
1088 msg_Err( p_obj, "socks: authentification needed" );
1089 return VLC_EGENERIC;
1095 /*****************************************************************************
1096 * SocksHandshakeTCP:
1097 *****************************************************************************
1098 * Open a TCP connection using a SOCKS server and return a handle (RFC 1928)
1099 *****************************************************************************/
1100 static int SocksHandshakeTCP( vlc_object_t *p_obj,
1102 int i_socks_version,
1103 char *psz_socks_user, char *psz_socks_passwd,
1104 const char *psz_host, int i_port )
1106 uint8_t buffer[128+2*256];
1108 if( i_socks_version != 4 && i_socks_version != 5 )
1110 msg_Warn( p_obj, "invalid socks protocol version %d", i_socks_version );
1111 i_socks_version = 5;
1114 if( i_socks_version == 5 &&
1115 SocksNegociate( p_obj, fd, i_socks_version,
1116 psz_socks_user, psz_socks_passwd ) )
1117 return VLC_EGENERIC;
1119 if( i_socks_version == 4 )
1121 struct addrinfo hints = { 0 }, *p_res;
1123 /* v4 only support ipv4 */
1124 hints.ai_family = AF_INET;
1125 if( vlc_getaddrinfo( p_obj, psz_host, 0, &hints, &p_res ) )
1126 return VLC_EGENERIC;
1128 buffer[0] = i_socks_version;
1129 buffer[1] = 0x01; /* CONNECT */
1130 SetWBE( &buffer[2], i_port ); /* Port */
1131 memcpy( &buffer[4], /* Address */
1132 &((struct sockaddr_in *)(p_res->ai_addr))->sin_addr, 4 );
1133 vlc_freeaddrinfo( p_res );
1135 buffer[8] = 0; /* Empty user id */
1137 if( net_Write( p_obj, fd, NULL, buffer, 9 ) != 9 )
1138 return VLC_EGENERIC;
1139 if( net_Read( p_obj, fd, NULL, buffer, 8, VLC_TRUE ) != 8 )
1140 return VLC_EGENERIC;
1142 msg_Dbg( p_obj, "socks: v=%d cd=%d",
1143 buffer[0], buffer[1] );
1145 if( buffer[1] != 90 )
1146 return VLC_EGENERIC;
1148 else if( i_socks_version == 5 )
1150 int i_hlen = __MIN(strlen( psz_host ), 255);
1153 buffer[0] = i_socks_version; /* Version */
1154 buffer[1] = 0x01; /* Cmd: connect */
1155 buffer[2] = 0x00; /* Reserved */
1156 buffer[3] = 3; /* ATYP: for now domainname */
1159 memcpy( &buffer[5], psz_host, i_hlen );
1160 SetWBE( &buffer[5+i_hlen], i_port );
1162 i_len = 5 + i_hlen + 2;
1165 if( net_Write( p_obj, fd, NULL, buffer, i_len ) != i_len )
1166 return VLC_EGENERIC;
1168 /* Read the header */
1169 if( net_Read( p_obj, fd, NULL, buffer, 5, VLC_TRUE ) != 5 )
1170 return VLC_EGENERIC;
1172 msg_Dbg( p_obj, "socks: v=%d rep=%d atyp=%d",
1173 buffer[0], buffer[1], buffer[3] );
1175 if( buffer[1] != 0x00 )
1177 msg_Err( p_obj, "socks: CONNECT request failed\n" );
1178 return VLC_EGENERIC;
1181 /* Read the remaining bytes */
1182 if( buffer[3] == 0x01 )
1184 else if( buffer[3] == 0x03 )
1185 i_len = buffer[4] + 2;
1186 else if( buffer[3] == 0x04 )
1189 return VLC_EGENERIC;
1191 if( net_Read( p_obj, fd, NULL, buffer, i_len, VLC_TRUE ) != i_len )
1192 return VLC_EGENERIC;
1198 /*****************************************************************************
1199 * inet_pton replacement for obsolete and/or crap operating systems
1200 *****************************************************************************/
1201 #ifndef HAVE_INET_PTON
1202 int inet_pton(int af, const char *src, void *dst)
1205 /* As we already know, Microsoft always go its own way, so even if they do
1206 * provide IPv6, they don't provide the API. */
1207 struct sockaddr_storage addr;
1208 int len = sizeof( addr );
1210 /* Damn it, they didn't even put LPCSTR for the firs parameter!!! */
1211 char *workaround_for_ill_designed_api = strdup( src );
1213 if( !WSAStringToAddress( workaround_for_ill_designed_api, af, NULL,
1214 (LPSOCKADDR)&addr, &len ) )
1216 free( workaround_for_ill_designed_api );
1219 free( workaround_for_ill_designed_api );
1224 memcpy( dst, &((struct sockaddr_in6 *)&addr)->sin6_addr, 16 );
1228 memcpy( dst, &((struct sockaddr_in *)&addr)->sin_addr, 4 );
1232 WSASetLastError( WSAEAFNOSUPPORT );
1236 /* Assume IPv6 is not supported. */
1237 /* Would be safer and more simpler to use inet_aton() but it is most
1238 * likely not provided either. */
1243 errno = EAFNOSUPPORT;
1247 ipv4 = inet_addr( src );
1248 if( ipv4 == INADDR_NONE )
1251 memcpy( dst, &ipv4, 4 );
1255 #endif /* HAVE_INET_PTON */