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>
48 # define ENETUNREACH WSAENETUNREACH
50 # include <sys/socket.h>
51 # include <netinet/in.h>
52 # ifdef HAVE_ARPA_INET_H
53 # include <arpa/inet.h>
65 # define INADDR_ANY 0x00000000
68 # define INADDR_NONE 0xFFFFFFFF
71 static int SocksNegociate( vlc_object_t *, int fd, int i_socks_version,
72 char *psz_socks_user, char *psz_socks_passwd );
73 static int SocksHandshakeTCP( vlc_object_t *,
74 int fd, int i_socks_version,
75 char *psz_socks_user, char *psz_socks_passwd,
76 const char *psz_host, int i_port );
78 static int net_Socket( vlc_object_t *p_this, int i_family, int i_socktype,
83 fd = socket( i_family, i_socktype, i_protocol );
86 #if defined(WIN32) || defined(UNDER_CE)
87 if( WSAGetLastError ( ) != WSAEAFNOSUPPORT )
88 msg_Warn( p_this, "cannot create socket (%i)",
91 if( errno != EAFNOSUPPORT )
92 msg_Warn( p_this, "cannot create socket (%s)",
98 /* Set to non-blocking */
99 #if defined( WIN32 ) || defined( UNDER_CE )
101 unsigned long i_dummy = 1;
102 if( ioctlsocket( fd, FIONBIO, &i_dummy ) != 0 )
103 msg_Err( p_this, "cannot set socket to non-blocking mode" );
106 if( ( ( i_val = fcntl( fd, F_GETFL, 0 ) ) < 0 ) ||
107 ( fcntl( fd, F_SETFL, i_val | O_NONBLOCK ) < 0 ) )
108 msg_Err( p_this, "cannot set socket to non-blocking mode (%s)",
113 setsockopt( fd, SOL_SOCKET, SO_REUSEADDR, (void *)&i_val,
118 * Accepts only IPv6 connections on IPv6 sockets
119 * (and open an IPv4 socket later as well if needed).
120 * Only Linux and FreeBSD can map IPv4 connections on IPv6 sockets,
121 * so this allows for more uniform handling across platforms. Besides,
122 * it makes sure that IPv4 addresses will be printed as w.x.y.z rather
123 * than ::ffff:w.x.y.z
125 if( i_family == AF_INET6 )
126 setsockopt( fd, IPPROTO_IPV6, IPV6_V6ONLY, (void *)&i_val,
130 #if defined( WIN32 ) || defined( UNDER_CE )
131 # ifndef IPV6_PROTECTION_LEVEL
132 # define IPV6_PROTECTION_LEVEL 23
134 if( i_family == AF_INET6 )
136 i_val = 30 /*PROTECTION_LEVEL_UNRESTRICTED*/;
137 setsockopt( fd, IPPROTO_IPV6, IPV6_PROTECTION_LEVEL,
138 (const char*)&i_val, sizeof( i_val ) );
144 /*****************************************************************************
146 *****************************************************************************
147 * Open a TCP connection and return a handle
148 *****************************************************************************/
149 int __net_OpenTCP( vlc_object_t *p_this, const char *psz_host, int i_port )
151 struct addrinfo hints, *res, *ptr;
152 const char *psz_realhost;
154 int i_realport, i_val, i_handle = -1;
155 vlc_bool_t b_unreach = VLC_FALSE;
158 i_port = 80; /* historical VLC thing */
160 memset( &hints, 0, sizeof( hints ) );
161 hints.ai_socktype = SOCK_STREAM;
163 psz_socks = var_CreateGetString( p_this, "socks" );
164 if( *psz_socks && *psz_socks != ':' )
166 char *psz = strchr( psz_socks, ':' );
171 psz_realhost = psz_socks;
172 i_realport = ( psz != NULL ) ? atoi( psz ) : 1080;
174 msg_Dbg( p_this, "net: connecting to %s port %d for %s port %d",
175 psz_realhost, i_realport, psz_host, i_port );
179 psz_realhost = psz_host;
182 msg_Dbg( p_this, "net: connecting to %s port %d", psz_realhost,
186 i_val = vlc_getaddrinfo( p_this, psz_realhost, i_realport, &hints, &res );
189 msg_Err( p_this, "cannot resolve %s port %d : %s", psz_realhost,
190 i_realport, vlc_gai_strerror( i_val ) );
195 for( ptr = res; (ptr != NULL) && (i_handle == -1); ptr = ptr->ai_next )
199 fd = net_Socket( p_this, ptr->ai_family, ptr->ai_socktype,
204 if( connect( fd, ptr->ai_addr, ptr->ai_addrlen ) )
206 socklen_t i_val_size = sizeof( i_val );
211 #if defined( WIN32 ) || defined( UNDER_CE )
212 if( WSAGetLastError() != WSAEWOULDBLOCK )
214 if( WSAGetLastError () == WSAENETUNREACH )
215 b_unreach = VLC_TRUE;
217 msg_Warn( p_this, "connection to %s port %d failed (%d)",
218 psz_host, i_port, WSAGetLastError( ) );
223 if( errno != EINPROGRESS )
225 if( errno == ENETUNREACH )
226 b_unreach = VLC_FALSE;
228 msg_Warn( p_this, "connection to %s port %d : %s", psz_host,
229 i_port, strerror( errno ) );
235 var_Create( p_this, "ipv4-timeout",
236 VLC_VAR_INTEGER | VLC_VAR_DOINHERIT );
237 var_Get( p_this, "ipv4-timeout", &timeout );
238 if( timeout.i_int < 0 )
240 msg_Err( p_this, "invalid negative value for ipv4-timeout" );
243 d = div( timeout.i_int, 100 );
245 msg_Dbg( p_this, "connection in progress" );
252 msg_Dbg( p_this, "connection aborted" );
254 vlc_freeaddrinfo( res );
259 /* Initialize file descriptor set */
263 /* We'll wait 0.1 second if nothing happens */
265 tv.tv_usec = (d.quot > 0) ? 100000 : (1000 * d.rem);
267 i_val = select( fd + 1, NULL, &fds, NULL, &tv );
271 msg_Dbg( p_this, "connection timed out" );
279 while( ( i_val == 0 ) || ( ( i_val < 0 ) &&
280 #if defined( WIN32 ) || defined( UNDER_CE )
281 ( WSAGetLastError() == WSAEWOULDBLOCK )
288 continue; /* timeout */
292 msg_Warn( p_this, "connection aborted (select failed)" );
297 #if !defined( SYS_BEOS ) && !defined( UNDER_CE )
298 if( getsockopt( fd, SOL_SOCKET, SO_ERROR, (void*)&i_val,
299 &i_val_size ) == -1 || i_val != 0 )
301 if( i_val == ENETUNREACH )
302 b_unreach = VLC_TRUE;
306 msg_Warn( p_this, "connection to %s port %d failed (%d)",
307 psz_host, i_port, WSAGetLastError( ) );
309 msg_Warn( p_this, "connection to %s port %d : %s", psz_host,
310 i_port, strerror( i_val ) );
318 i_handle = fd; /* success! */
321 vlc_freeaddrinfo( res );
326 msg_Err( p_this, "Host %s port %d is unreachable", psz_host,
331 if( *psz_socks && *psz_socks != ':' )
333 char *psz_user = var_CreateGetString( p_this, "socks-user" );
334 char *psz_pwd = var_CreateGetString( p_this, "socks-pwd" );
336 if( SocksHandshakeTCP( p_this, i_handle, 5, psz_user, psz_pwd,
339 msg_Err( p_this, "failed to use the SOCKS server" );
340 net_Close( i_handle );
353 /*****************************************************************************
355 *****************************************************************************
356 * Open TCP passive "listening" socket(s)
357 * This function returns NULL in case of error.
358 *****************************************************************************/
359 int *__net_ListenTCP( vlc_object_t *p_this, const char *psz_host, int i_port )
361 struct addrinfo hints, *res, *ptr;
362 int i_val, *pi_handles, i_size;
364 memset( &hints, 0, sizeof( hints ) );
365 hints.ai_socktype = SOCK_STREAM;
366 hints.ai_flags = AI_PASSIVE;
368 msg_Dbg( p_this, "net: listening to %s port %d", psz_host, i_port );
370 i_val = vlc_getaddrinfo( p_this, psz_host, i_port, &hints, &res );
373 msg_Err( p_this, "cannot resolve %s port %d : %s", psz_host, i_port,
374 vlc_gai_strerror( i_val ) );
381 for( ptr = res; ptr != NULL; ptr = ptr->ai_next )
385 fd = net_Socket( p_this, ptr->ai_family, ptr->ai_socktype,
390 /* Bind the socket */
391 if( bind( fd, ptr->ai_addr, ptr->ai_addrlen ) )
393 #if defined(WIN32) || defined(UNDER_CE)
394 msg_Warn( p_this, "cannot bind socket (%i)", WSAGetLastError( ) );
396 msg_Warn( p_this, "cannot bind socket (%s)", strerror( errno ) );
403 if( listen( fd, 100 ) == -1 )
405 #if defined(WIN32) || defined(UNDER_CE)
406 msg_Err( p_this, "cannot bring socket in listening mode (%i)",
409 msg_Err( p_this, "cannot bring the socket in listening mode (%s)",
416 newpi = (int *)realloc( pi_handles, (++i_size) * sizeof( int ) );
424 newpi[i_size - 2] = fd;
429 vlc_freeaddrinfo( res );
431 if( pi_handles != NULL )
432 pi_handles[i_size - 1] = -1;
436 /*****************************************************************************
438 *****************************************************************************
439 * Accept a connection on a set of listening sockets and return it
440 *****************************************************************************/
441 int __net_Accept( vlc_object_t *p_this, int *pi_fd, mtime_t i_wait )
443 vlc_bool_t b_die = p_this->b_die, b_block = (i_wait < 0);
445 while( p_this->b_die == b_die )
447 int i_val = -1, *pi, *pi_end;
448 struct timeval timeout;
453 /* Initialize file descriptor set */
457 for( pi = pi_fd; *pi != -1; pi++ )
464 FD_SET( i_fd, &fds_r );
465 FD_SET( i_fd, &fds_e );
470 timeout.tv_usec = b_block ? 500000 : i_wait;
472 i_val = select( i_val + 1, &fds_r, NULL, &fds_e, &timeout );
473 if( ( ( i_val < 0 ) && ( errno == EINTR ) ) || i_val == 0 )
482 #if defined(WIN32) || defined(UNDER_CE)
483 msg_Err( p_this, "network select error (%i)", WSAGetLastError() );
485 msg_Err( p_this, "network select error (%s)", strerror( errno ) );
490 for( pi = pi_fd; *pi != -1; pi++ )
494 if( !FD_ISSET( i_fd, &fds_r ) && !FD_ISSET( i_fd, &fds_e ) )
497 i_val = accept( i_fd, NULL, 0 );
500 #if defined(WIN32) || defined(UNDER_CE)
501 msg_Err( p_this, "accept failed (%i)", WSAGetLastError() );
503 msg_Err( p_this, "accept failed (%s)", strerror( errno ) );
509 * This round-robin trick ensures that the first sockets in
510 * pi_fd won't prevent the last ones from getting accept'ed.
513 memmove( pi, pi + 1, pi_end - pi );
523 /*****************************************************************************
525 *****************************************************************************
526 * Open a UDP connection and return a handle
527 *****************************************************************************/
528 int __net_OpenUDP( vlc_object_t *p_this, const char *psz_bind, int i_bind,
529 const char *psz_server, int i_server )
533 network_socket_t sock;
534 module_t *p_network = NULL;
536 if( psz_server == NULL ) psz_server = "";
537 if( psz_bind == NULL ) psz_bind = "";
539 /* Prepare the network_socket_t structure */
540 sock.psz_bind_addr = psz_bind;
541 sock.i_bind_port = i_bind;
542 sock.psz_server_addr = psz_server;
543 sock.i_server_port = i_server;
548 msg_Dbg( p_this, "net: connecting to '[%s]:%d@[%s]:%d'",
549 psz_server, i_server, psz_bind, i_bind );
551 /* Check if we have force ipv4 or ipv6 */
552 var_Create( p_this, "ipv4", VLC_VAR_BOOL | VLC_VAR_DOINHERIT );
553 var_Get( p_this, "ipv4", &v4 );
554 var_Create( p_this, "ipv6", VLC_VAR_BOOL | VLC_VAR_DOINHERIT );
555 var_Get( p_this, "ipv6", &v6 );
562 /* try IPv6 first (unless IPv4 forced) */
563 private = p_this->p_private;
564 p_this->p_private = (void*)&sock;
565 p_network = module_Need( p_this, "network", "ipv6", VLC_TRUE );
567 if( p_network != NULL )
568 module_Unneed( p_this, p_network );
570 p_this->p_private = private;
573 * Check if the IP stack can receive IPv4 packets on IPv6 sockets.
574 * If yes, then it is better to use the IPv6 socket.
575 * Otherwise, if we also get an IPv4, we have to choose, so we use
578 if( ( sock.i_handle != -1 ) && ( ( sock.v6only == 0 ) || v6.b_bool ) )
579 return sock.i_handle;
584 int fd6 = sock.i_handle;
586 /* also try IPv4 (unless IPv6 forced) */
587 private = p_this->p_private;
588 p_this->p_private = (void*)&sock;
589 p_network = module_Need( p_this, "network", "ipv4", VLC_TRUE );
591 if( p_network != NULL )
592 module_Unneed( p_this, p_network );
594 p_this->p_private = private;
598 if( sock.i_handle != -1 )
600 msg_Warn( p_this, "net: lame IPv6/IPv4 dual-stack present. "
601 "Using only IPv4." );
609 if( sock.i_handle == -1 )
610 msg_Dbg( p_this, "net: connection to '[%s]:%d@[%s]:%d' failed",
611 psz_server, i_server, psz_bind, i_bind );
613 return sock.i_handle;
616 /*****************************************************************************
618 *****************************************************************************
619 * Close a network handle
620 *****************************************************************************/
621 void net_Close( int fd )
624 CloseHandle( (HANDLE)fd );
625 #elif defined( WIN32 )
632 void net_ListenClose( int *pi_fd )
638 for( pi = pi_fd; *pi != -1; pi++ )
644 /*****************************************************************************
646 *****************************************************************************
647 * Read from a network socket
648 * If b_retry is true, then we repeat until we have read the right amount of
650 *****************************************************************************/
651 int __net_Read( vlc_object_t *p_this, int fd, v_socket_t *p_vs,
652 uint8_t *p_data, int i_data, vlc_bool_t b_retry )
654 struct timeval timeout;
659 vlc_bool_t b_die = p_this->b_die;
665 if( p_this->b_die != b_die )
670 /* Initialize file descriptor set */
672 FD_SET( fd, &fds_r );
674 FD_SET( fd, &fds_e );
676 /* We'll wait 0.5 second if nothing happens */
678 timeout.tv_usec = 500000;
680 } while( (i_ret = select(fd + 1, &fds_r, NULL, &fds_e, &timeout)) == 0
681 || ( i_ret < 0 && errno == EINTR ) );
685 #if defined(WIN32) || defined(UNDER_CE)
686 msg_Err( p_this, "network select error (%d)", WSAGetLastError() );
688 msg_Err( p_this, "network select error (%s)", strerror(errno) );
690 return i_total > 0 ? i_total : -1;
693 if( ( i_recv = (p_vs != NULL)
694 ? p_vs->pf_recv( p_vs->p_sys, p_data, i_data )
695 : recv( fd, p_data, i_data, 0 ) ) < 0 )
697 #if defined(WIN32) || defined(UNDER_CE)
698 if( WSAGetLastError() == WSAEWOULDBLOCK )
700 /* only happens with p_vs (SSL) - not really an error */
704 /* On win32 recv() will fail if the datagram doesn't fit inside
705 * the passed buffer, even though the buffer will be filled with
706 * the first part of the datagram. */
707 if( WSAGetLastError() == WSAEMSGSIZE )
709 msg_Err( p_this, "recv() failed. "
710 "Increase the mtu size (--mtu option)" );
713 else if( WSAGetLastError() == WSAEINTR ) continue;
714 else msg_Err( p_this, "recv failed (%i)", WSAGetLastError() );
716 /* EAGAIN only happens with p_vs (TLS) and it's not an error */
717 if( errno != EAGAIN )
718 msg_Err( p_this, "recv failed (%s)", strerror(errno) );
720 return i_total > 0 ? i_total : -1;
722 else if( i_recv == 0 )
724 /* Connection closed */
739 /*****************************************************************************
740 * __net_ReadNonBlock:
741 *****************************************************************************
742 * Read from a network socket, non blocking mode (with timeout)
743 *****************************************************************************/
744 int __net_ReadNonBlock( vlc_object_t *p_this, int fd, v_socket_t *p_vs,
745 uint8_t *p_data, int i_data, mtime_t i_wait)
747 struct timeval timeout;
752 /* Initialize file descriptor set */
754 FD_SET( fd, &fds_r );
756 FD_SET( fd, &fds_e );
759 timeout.tv_usec = i_wait;
761 i_ret = select(fd + 1, &fds_r, NULL, &fds_e, &timeout);
763 if( i_ret < 0 && errno == EINTR )
769 #if defined(WIN32) || defined(UNDER_CE)
770 msg_Err( p_this, "network select error (%d)", WSAGetLastError() );
772 msg_Err( p_this, "network select error (%s)", strerror(errno) );
782 #if !defined(UNDER_CE)
783 if( fd == 0/*STDIN_FILENO*/ ) i_recv = read( fd, p_data, i_data ); else
785 if( ( i_recv = (p_vs != NULL)
786 ? p_vs->pf_recv( p_vs->p_sys, p_data, i_data )
787 : recv( fd, p_data, i_data, 0 ) ) < 0 )
789 #if defined(WIN32) || defined(UNDER_CE)
791 /* On win32 recv() will fail if the datagram doesn't fit inside
792 * the passed buffer, even though the buffer will be filled with
793 * the first part of the datagram. */
794 if( WSAGetLastError() == WSAEMSGSIZE )
796 msg_Err( p_this, "recv() failed. "
797 "Increase the mtu size (--mtu option)" );
799 else msg_Err( p_this, "recv failed (%i)", WSAGetLastError() );
801 msg_Err( p_this, "recv failed (%s)", strerror(errno) );
806 return i_recv ? i_recv : -1; /* !i_recv -> connection closed if tcp */
809 /* We will never be here */
813 /*****************************************************************************
815 *****************************************************************************
816 * Read from several sockets (with timeout). Takes data from the first socket
818 *****************************************************************************/
819 int __net_Select( vlc_object_t *p_this, int *pi_fd, v_socket_t **pp_vs,
820 int i_fd, uint8_t *p_data, int i_data, mtime_t i_wait )
822 struct timeval timeout;
829 /* Initialize file descriptor set */
833 for( i = 0 ; i < i_fd ; i++)
835 if( pi_fd[i] > i_max_fd ) i_max_fd = pi_fd[i];
836 FD_SET( pi_fd[i], &fds_r );
837 FD_SET( pi_fd[i], &fds_e );
841 timeout.tv_usec = i_wait;
843 i_ret = select( i_max_fd + 1, &fds_r, NULL, &fds_e, &timeout );
845 if( i_ret < 0 && errno == EINTR )
851 msg_Err( p_this, "network select error (%s)", strerror(errno) );
854 else if( i_ret == 0 )
860 for( i = 0 ; i < i_fd ; i++)
862 if( FD_ISSET( pi_fd[i], &fds_r ) )
864 i_recv = ((pp_vs != NULL) && (pp_vs[i] != NULL))
865 ? pp_vs[i]->pf_recv( pp_vs[i]->p_sys, p_data, i_data )
866 : recv( pi_fd[i], p_data, i_data, 0 );
871 /* On win32 recv() will fail if the datagram doesn't
872 * fit inside the passed buffer, even though the buffer
873 * will be filled with the first part of the datagram. */
874 if( WSAGetLastError() == WSAEMSGSIZE )
876 msg_Err( p_this, "recv() failed. "
877 "Increase the mtu size (--mtu option)" );
879 else msg_Err( p_this, "recv failed (%i)",
882 msg_Err( p_this, "recv failed (%s)", strerror(errno) );
892 /* We will never be here */
897 /* Write exact amount requested */
898 int __net_Write( vlc_object_t *p_this, int fd, v_socket_t *p_vs,
899 const uint8_t *p_data, int i_data )
901 struct timeval timeout;
907 vlc_bool_t b_die = p_this->b_die;
913 if( p_this->b_die != b_die )
918 /* Initialize file descriptor set */
920 FD_SET( fd, &fds_w );
922 FD_SET( fd, &fds_e );
924 /* We'll wait 0.5 second if nothing happens */
926 timeout.tv_usec = 500000;
928 } while( (i_ret = select(fd + 1, NULL, &fds_w, &fds_e, &timeout)) == 0
929 || ( i_ret < 0 && errno == EINTR ) );
933 #if defined(WIN32) || defined(UNDER_CE)
934 msg_Err( p_this, "network select error (%d)", WSAGetLastError() );
936 msg_Err( p_this, "network select error (%s)", strerror(errno) );
938 return i_total > 0 ? i_total : -1;
941 if( ( i_send = (p_vs != NULL)
942 ? p_vs->pf_send( p_vs->p_sys, p_data, i_data )
943 : send( fd, p_data, i_data, 0 ) ) < 0 )
945 /* XXX With udp for example, it will issue a message if the host
947 /* msg_Err( p_this, "send failed (%s)", strerror(errno) ); */
948 return i_total > 0 ? i_total : -1;
958 char *__net_Gets( vlc_object_t *p_this, int fd, v_socket_t *p_vs )
960 char *psz_line = NULL, *ptr = NULL;
961 size_t i_line = 0, i_max = 0;
966 if( i_line == i_max )
969 psz_line = realloc( psz_line, i_max );
970 ptr = psz_line + i_line;
973 if( net_Read( p_this, fd, p_vs, (uint8_t *)ptr, 1, VLC_TRUE ) != 1 )
992 if( ( ptr >= psz_line ) && ( *ptr == '\r' ) )
998 int net_Printf( vlc_object_t *p_this, int fd, v_socket_t *p_vs,
999 const char *psz_fmt, ... )
1003 va_start( args, psz_fmt );
1004 i_ret = net_vaPrintf( p_this, fd, p_vs, psz_fmt, args );
1010 int __net_vaPrintf( vlc_object_t *p_this, int fd, v_socket_t *p_vs,
1011 const char *psz_fmt, va_list args )
1016 i_size = vasprintf( &psz, psz_fmt, args );
1017 i_ret = __net_Write( p_this, fd, p_vs, (uint8_t *)psz, i_size ) < i_size
1026 /*****************************************************************************
1028 *****************************************************************************
1029 * Negociate authentication with a SOCKS server.
1030 *****************************************************************************/
1031 static int SocksNegociate( vlc_object_t *p_obj,
1032 int fd, int i_socks_version,
1033 char *psz_socks_user,
1034 char *psz_socks_passwd )
1036 uint8_t buffer[128+2*256];
1038 vlc_bool_t b_auth = VLC_FALSE;
1040 if( i_socks_version != 5 )
1043 /* We negociate authentication */
1045 if( psz_socks_user && psz_socks_passwd &&
1046 *psz_socks_user && *psz_socks_passwd )
1049 buffer[0] = i_socks_version; /* SOCKS version */
1052 buffer[1] = 2; /* Number of methods */
1053 buffer[2] = 0x00; /* - No auth required */
1054 buffer[3] = 0x02; /* - USer/Password */
1059 buffer[1] = 1; /* Number of methods */
1060 buffer[2] = 0x00; /* - No auth required */
1064 if( net_Write( p_obj, fd, NULL, buffer, i_len ) != i_len )
1065 return VLC_EGENERIC;
1066 if( net_Read( p_obj, fd, NULL, buffer, 2, VLC_TRUE ) != 2 )
1067 return VLC_EGENERIC;
1069 msg_Dbg( p_obj, "socks: v=%d method=%x", buffer[0], buffer[1] );
1071 if( buffer[1] == 0x00 )
1073 msg_Dbg( p_obj, "socks: no authentication required" );
1075 else if( buffer[1] == 0x02 )
1077 int i_len1 = __MIN( strlen(psz_socks_user), 255 );
1078 int i_len2 = __MIN( strlen(psz_socks_passwd), 255 );
1079 msg_Dbg( p_obj, "socks: username/password authentication" );
1081 /* XXX: we don't support user/pwd > 255 (truncated)*/
1082 buffer[0] = i_socks_version; /* Version */
1083 buffer[1] = i_len1; /* User length */
1084 memcpy( &buffer[2], psz_socks_user, i_len1 );
1085 buffer[2+i_len1] = i_len2; /* Password length */
1086 memcpy( &buffer[2+i_len1+1], psz_socks_passwd, i_len2 );
1088 i_len = 3 + i_len1 + i_len2;
1090 if( net_Write( p_obj, fd, NULL, buffer, i_len ) != i_len )
1091 return VLC_EGENERIC;
1093 if( net_Read( p_obj, fd, NULL, buffer, 2, VLC_TRUE ) != 2 )
1094 return VLC_EGENERIC;
1096 msg_Dbg( p_obj, "socks: v=%d status=%x", buffer[0], buffer[1] );
1097 if( buffer[1] != 0x00 )
1099 msg_Err( p_obj, "socks: authentication rejected" );
1100 return VLC_EGENERIC;
1106 msg_Err( p_obj, "socks: unsupported authentication method %x",
1109 msg_Err( p_obj, "socks: authentification needed" );
1110 return VLC_EGENERIC;
1116 /*****************************************************************************
1117 * SocksHandshakeTCP:
1118 *****************************************************************************
1119 * Open a TCP connection using a SOCKS server and return a handle (RFC 1928)
1120 *****************************************************************************/
1121 static int SocksHandshakeTCP( vlc_object_t *p_obj,
1123 int i_socks_version,
1124 char *psz_socks_user, char *psz_socks_passwd,
1125 const char *psz_host, int i_port )
1127 uint8_t buffer[128+2*256];
1129 if( i_socks_version != 4 && i_socks_version != 5 )
1131 msg_Warn( p_obj, "invalid socks protocol version %d", i_socks_version );
1132 i_socks_version = 5;
1135 if( i_socks_version == 5 &&
1136 SocksNegociate( p_obj, fd, i_socks_version,
1137 psz_socks_user, psz_socks_passwd ) )
1138 return VLC_EGENERIC;
1140 if( i_socks_version == 4 )
1142 struct addrinfo hints = { 0 }, *p_res;
1144 /* v4 only support ipv4 */
1145 hints.ai_family = AF_INET;
1146 if( vlc_getaddrinfo( p_obj, psz_host, 0, &hints, &p_res ) )
1147 return VLC_EGENERIC;
1149 buffer[0] = i_socks_version;
1150 buffer[1] = 0x01; /* CONNECT */
1151 SetWBE( &buffer[2], i_port ); /* Port */
1152 memcpy( &buffer[4], /* Address */
1153 &((struct sockaddr_in *)(p_res->ai_addr))->sin_addr, 4 );
1154 vlc_freeaddrinfo( p_res );
1156 buffer[8] = 0; /* Empty user id */
1158 if( net_Write( p_obj, fd, NULL, buffer, 9 ) != 9 )
1159 return VLC_EGENERIC;
1160 if( net_Read( p_obj, fd, NULL, buffer, 8, VLC_TRUE ) != 8 )
1161 return VLC_EGENERIC;
1163 msg_Dbg( p_obj, "socks: v=%d cd=%d",
1164 buffer[0], buffer[1] );
1166 if( buffer[1] != 90 )
1167 return VLC_EGENERIC;
1169 else if( i_socks_version == 5 )
1171 int i_hlen = __MIN(strlen( psz_host ), 255);
1174 buffer[0] = i_socks_version; /* Version */
1175 buffer[1] = 0x01; /* Cmd: connect */
1176 buffer[2] = 0x00; /* Reserved */
1177 buffer[3] = 3; /* ATYP: for now domainname */
1180 memcpy( &buffer[5], psz_host, i_hlen );
1181 SetWBE( &buffer[5+i_hlen], i_port );
1183 i_len = 5 + i_hlen + 2;
1186 if( net_Write( p_obj, fd, NULL, buffer, i_len ) != i_len )
1187 return VLC_EGENERIC;
1189 /* Read the header */
1190 if( net_Read( p_obj, fd, NULL, buffer, 5, VLC_TRUE ) != 5 )
1191 return VLC_EGENERIC;
1193 msg_Dbg( p_obj, "socks: v=%d rep=%d atyp=%d",
1194 buffer[0], buffer[1], buffer[3] );
1196 if( buffer[1] != 0x00 )
1198 msg_Err( p_obj, "socks: CONNECT request failed\n" );
1199 return VLC_EGENERIC;
1202 /* Read the remaining bytes */
1203 if( buffer[3] == 0x01 )
1205 else if( buffer[3] == 0x03 )
1206 i_len = buffer[4] + 2;
1207 else if( buffer[3] == 0x04 )
1210 return VLC_EGENERIC;
1212 if( net_Read( p_obj, fd, NULL, buffer, i_len, VLC_TRUE ) != i_len )
1213 return VLC_EGENERIC;
1219 /*****************************************************************************
1220 * inet_pton replacement for obsolete and/or crap operating systems
1221 *****************************************************************************/
1222 #ifndef HAVE_INET_PTON
1223 int inet_pton(int af, const char *src, void *dst)
1226 /* As we already know, Microsoft always go its own way, so even if they do
1227 * provide IPv6, they don't provide the API. */
1228 struct sockaddr_storage addr;
1229 int len = sizeof( addr );
1231 /* Damn it, they didn't even put LPCSTR for the firs parameter!!! */
1232 char *workaround_for_ill_designed_api = strdup( src );
1234 if( !WSAStringToAddress( workaround_for_ill_designed_api, af, NULL,
1235 (LPSOCKADDR)&addr, &len ) )
1237 free( workaround_for_ill_designed_api );
1240 free( workaround_for_ill_designed_api );
1245 memcpy( dst, &((struct sockaddr_in6 *)&addr)->sin6_addr, 16 );
1249 memcpy( dst, &((struct sockaddr_in *)&addr)->sin_addr, 4 );
1253 WSASetLastError( WSAEAFNOSUPPORT );
1257 /* Assume IPv6 is not supported. */
1258 /* Would be safer and more simpler to use inet_aton() but it is most
1259 * likely not provided either. */
1264 errno = EAFNOSUPPORT;
1268 ipv4 = inet_addr( src );
1269 if( ipv4 == INADDR_NONE )
1272 memcpy( dst, &ipv4, 4 );
1276 #endif /* HAVE_INET_PTON */