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 *****************************************************************************/
36 #ifdef HAVE_SYS_TIME_H
37 # include <sys/time.h>
46 # define INADDR_ANY 0x00000000
49 # define INADDR_NONE 0xFFFFFFFF
52 static int SocksNegociate( vlc_object_t *, int fd, int i_socks_version,
53 char *psz_socks_user, char *psz_socks_passwd );
54 static int SocksHandshakeTCP( vlc_object_t *,
55 int fd, int i_socks_version,
56 char *psz_socks_user, char *psz_socks_passwd,
57 const char *psz_host, int i_port );
59 static int net_Socket( vlc_object_t *p_this, int i_family, int i_socktype,
64 fd = socket( i_family, i_socktype, i_protocol );
67 #if defined(WIN32) || defined(UNDER_CE)
68 if( WSAGetLastError ( ) != WSAEAFNOSUPPORT )
69 msg_Warn( p_this, "cannot create socket (%i)",
72 if( errno != EAFNOSUPPORT )
73 msg_Warn( p_this, "cannot create socket (%s)",
79 /* Set to non-blocking */
80 #if defined( WIN32 ) || defined( UNDER_CE )
82 unsigned long i_dummy = 1;
83 if( ioctlsocket( fd, FIONBIO, &i_dummy ) != 0 )
84 msg_Err( p_this, "cannot set socket to non-blocking mode" );
87 if( ( ( i_val = fcntl( fd, F_GETFL, 0 ) ) < 0 ) ||
88 ( fcntl( fd, F_SETFL, i_val | O_NONBLOCK ) < 0 ) )
89 msg_Err( p_this, "cannot set socket to non-blocking mode (%s)",
94 setsockopt( fd, SOL_SOCKET, SO_REUSEADDR, (void *)&i_val,
99 * Accepts only IPv6 connections on IPv6 sockets
100 * (and open an IPv4 socket later as well if needed).
101 * Only Linux and FreeBSD can map IPv4 connections on IPv6 sockets,
102 * so this allows for more uniform handling across platforms. Besides,
103 * it makes sure that IPv4 addresses will be printed as w.x.y.z rather
104 * than ::ffff:w.x.y.z
106 if( i_family == AF_INET6 )
107 setsockopt( fd, IPPROTO_IPV6, IPV6_V6ONLY, (void *)&i_val,
111 #if defined( WIN32 ) || defined( UNDER_CE )
112 # ifndef IPV6_PROTECTION_LEVEL
113 # define IPV6_PROTECTION_LEVEL 23
115 if( i_family == AF_INET6 )
117 i_val = 30 /*PROTECTION_LEVEL_UNRESTRICTED*/;
118 setsockopt( fd, IPPROTO_IPV6, IPV6_PROTECTION_LEVEL,
119 (const char*)&i_val, sizeof( i_val ) );
125 /*****************************************************************************
127 *****************************************************************************
128 * Open a TCP connection and return a handle
129 *****************************************************************************/
130 int __net_ConnectTCP( vlc_object_t *p_this, const char *psz_host, int i_port )
132 struct addrinfo hints, *res, *ptr;
133 const char *psz_realhost;
135 int i_realport, i_val, i_handle = -1;
136 vlc_bool_t b_unreach = VLC_FALSE;
139 i_port = 80; /* historical VLC thing */
141 memset( &hints, 0, sizeof( hints ) );
142 hints.ai_socktype = SOCK_STREAM;
144 psz_socks = var_CreateGetString( p_this, "socks" );
145 if( *psz_socks && *psz_socks != ':' )
147 char *psz = strchr( psz_socks, ':' );
152 psz_realhost = psz_socks;
153 i_realport = ( psz != NULL ) ? atoi( psz ) : 1080;
155 msg_Dbg( p_this, "net: connecting to %s port %d for %s port %d",
156 psz_realhost, i_realport, psz_host, i_port );
160 psz_realhost = psz_host;
163 msg_Dbg( p_this, "net: connecting to %s port %d", psz_realhost,
167 i_val = vlc_getaddrinfo( p_this, psz_realhost, i_realport, &hints, &res );
170 msg_Err( p_this, "cannot resolve %s port %d : %s", psz_realhost,
171 i_realport, vlc_gai_strerror( i_val ) );
176 for( ptr = res; (ptr != NULL) && (i_handle == -1); ptr = ptr->ai_next )
180 fd = net_Socket( p_this, ptr->ai_family, ptr->ai_socktype,
185 if( connect( fd, ptr->ai_addr, ptr->ai_addrlen ) )
187 socklen_t i_val_size = sizeof( i_val );
192 #if defined( WIN32 ) || defined( UNDER_CE )
193 if( WSAGetLastError() != WSAEWOULDBLOCK )
195 if( WSAGetLastError () == WSAENETUNREACH )
196 b_unreach = VLC_TRUE;
198 msg_Warn( p_this, "connection to %s port %d failed (%d)",
199 psz_host, i_port, WSAGetLastError( ) );
204 if( errno != EINPROGRESS )
206 if( errno == ENETUNREACH )
207 b_unreach = VLC_TRUE;
209 msg_Warn( p_this, "connection to %s port %d : %s", psz_host,
210 i_port, strerror( errno ) );
216 var_Create( p_this, "ipv4-timeout",
217 VLC_VAR_INTEGER | VLC_VAR_DOINHERIT );
218 var_Get( p_this, "ipv4-timeout", &timeout );
219 if( timeout.i_int < 0 )
221 msg_Err( p_this, "invalid negative value for ipv4-timeout" );
224 d = div( timeout.i_int, 100 );
226 msg_Dbg( p_this, "connection in progress" );
233 msg_Dbg( p_this, "connection aborted" );
235 vlc_freeaddrinfo( res );
240 /* Initialize file descriptor set */
244 /* We'll wait 0.1 second if nothing happens */
246 tv.tv_usec = (d.quot > 0) ? 100000 : (1000 * d.rem);
248 i_val = select( fd + 1, NULL, &fds, NULL, &tv );
252 msg_Dbg( p_this, "connection timed out" );
260 while( ( i_val == 0 ) || ( ( i_val < 0 ) &&
261 #if defined( WIN32 ) || defined( UNDER_CE )
262 ( WSAGetLastError() == WSAEWOULDBLOCK )
269 continue; /* timeout */
273 msg_Warn( p_this, "connection aborted (select failed)" );
278 #if !defined( SYS_BEOS ) && !defined( UNDER_CE )
279 if( getsockopt( fd, SOL_SOCKET, SO_ERROR, (void*)&i_val,
280 &i_val_size ) == -1 || i_val != 0 )
282 if( i_val == ENETUNREACH )
283 b_unreach = VLC_TRUE;
287 msg_Warn( p_this, "connection to %s port %d failed (%d)",
288 psz_host, i_port, WSAGetLastError( ) );
290 msg_Warn( p_this, "connection to %s port %d : %s", psz_host,
291 i_port, strerror( i_val ) );
299 i_handle = fd; /* success! */
302 vlc_freeaddrinfo( res );
307 msg_Err( p_this, "Host %s port %d is unreachable", psz_host,
312 if( *psz_socks && *psz_socks != ':' )
314 char *psz_user = var_CreateGetString( p_this, "socks-user" );
315 char *psz_pwd = var_CreateGetString( p_this, "socks-pwd" );
317 if( SocksHandshakeTCP( p_this, i_handle, 5, psz_user, psz_pwd,
320 msg_Err( p_this, "failed to use the SOCKS server" );
321 net_Close( i_handle );
334 /*****************************************************************************
336 *****************************************************************************
337 * Open TCP passive "listening" socket(s)
338 * This function returns NULL in case of error.
339 *****************************************************************************/
340 int *__net_ListenTCP( vlc_object_t *p_this, const char *psz_host, int i_port )
342 struct addrinfo hints, *res, *ptr;
343 int i_val, *pi_handles, i_size;
345 memset( &hints, 0, sizeof( hints ) );
346 hints.ai_socktype = SOCK_STREAM;
347 hints.ai_flags = AI_PASSIVE;
349 msg_Dbg( p_this, "net: listening to %s port %d", psz_host, i_port );
351 i_val = vlc_getaddrinfo( p_this, psz_host, i_port, &hints, &res );
354 msg_Err( p_this, "cannot resolve %s port %d : %s", psz_host, i_port,
355 vlc_gai_strerror( i_val ) );
362 for( ptr = res; ptr != NULL; ptr = ptr->ai_next )
366 fd = net_Socket( p_this, ptr->ai_family, ptr->ai_socktype,
371 /* Bind the socket */
372 if( bind( fd, ptr->ai_addr, ptr->ai_addrlen ) )
374 #if defined(WIN32) || defined(UNDER_CE)
375 msg_Warn( p_this, "cannot bind socket (%i)", WSAGetLastError( ) );
377 msg_Warn( p_this, "cannot bind socket (%s)", strerror( errno ) );
384 if( listen( fd, 100 ) == -1 )
386 #if defined(WIN32) || defined(UNDER_CE)
387 msg_Err( p_this, "cannot bring socket in listening mode (%i)",
390 msg_Err( p_this, "cannot bring the socket in listening mode (%s)",
397 newpi = (int *)realloc( pi_handles, (++i_size) * sizeof( int ) );
405 newpi[i_size - 2] = fd;
410 vlc_freeaddrinfo( res );
412 if( pi_handles != NULL )
413 pi_handles[i_size - 1] = -1;
417 /*****************************************************************************
419 *****************************************************************************
420 * Accept a connection on a set of listening sockets and return it
421 *****************************************************************************/
422 int __net_Accept( vlc_object_t *p_this, int *pi_fd, mtime_t i_wait )
424 vlc_bool_t b_die = p_this->b_die, b_block = (i_wait < 0);
426 while( p_this->b_die == b_die )
428 int i_val = -1, *pi, *pi_end;
429 struct timeval timeout;
434 /* Initialize file descriptor set */
438 for( pi = pi_fd; *pi != -1; pi++ )
445 FD_SET( i_fd, &fds_r );
446 FD_SET( i_fd, &fds_e );
451 timeout.tv_usec = b_block ? 500000 : i_wait;
453 i_val = select( i_val + 1, &fds_r, NULL, &fds_e, &timeout );
454 if( ( ( i_val < 0 ) && ( errno == EINTR ) ) || i_val == 0 )
463 #if defined(WIN32) || defined(UNDER_CE)
464 msg_Err( p_this, "network select error (%i)", WSAGetLastError() );
466 msg_Err( p_this, "network select error (%s)", strerror( errno ) );
471 for( pi = pi_fd; *pi != -1; pi++ )
475 if( !FD_ISSET( i_fd, &fds_r ) && !FD_ISSET( i_fd, &fds_e ) )
478 i_val = accept( i_fd, NULL, 0 );
481 #if defined(WIN32) || defined(UNDER_CE)
482 msg_Err( p_this, "accept failed (%i)", WSAGetLastError() );
484 msg_Err( p_this, "accept failed (%s)", strerror( errno ) );
490 * This round-robin trick ensures that the first sockets in
491 * pi_fd won't prevent the last ones from getting accept'ed.
494 memmove( pi, pi + 1, pi_end - pi );
505 /*****************************************************************************
507 *****************************************************************************
508 * Open a UDP socket to send data to a defined destination, with an optional
510 *****************************************************************************/
511 int __net_ConnectUDP( vlc_object_t *p_this, const char *psz_host, int i_port,
514 struct addrinfo hints, *res, *ptr;
515 int i_val, i_handle = -1;
516 vlc_bool_t b_unreach = VLC_FALSE;
519 i_port = 1234; /* historical VLC thing */
521 memset( &hints, 0, sizeof( hints ) );
522 hints.ai_socktype = SOCK_DGRAM;
524 msg_Dbg( p_this, "net: connecting to %s port %d", psz_host, i_port );
526 i_val = vlc_getaddrinfo( p_this, psz_host, i_port, &hints, &res );
529 msg_Err( p_this, "cannot resolve %s port %d : %s", psz_host, i_port,
530 vlc_gai_strerror( i_val ) );
534 for( ptr = res; ptr != NULL; ptr = ptr->ai_next )
538 fd = net_Socket( p_this, ptr->ai_family, ptr->ai_socktype,
542 #if !defined( SYS_BEOS )
547 /* Increase the receive buffer size to 1/2MB (8Mb/s during 1/2s) to avoid
548 * packet loss caused by scheduling problems */
550 setsockopt( i_handle, SOL_SOCKET, SO_RCVBUF, (void *)&i_val,
553 setsockopt( i_handle, SOL_SOCKET, SO_SNDBUF, (void *)&i_val,
558 if( connect( fd, ptr->ai_addr, ptr->ai_addrlen ) == 0 )
565 #if defined( WIN32 ) || defined( UNDER_CE )
566 if( WSAGetLastError () == WSAENETUNREACH )
568 if( errno == ENETUNREACH )
570 b_unreach = VLC_TRUE;
573 msg_Warn( p_this, "%s port %d : %s", psz_host, i_port,
580 vlc_freeaddrinfo( res );
585 msg_Err( p_this, "Host %s port %d is unreachable", psz_host,
593 /*****************************************************************************
595 *****************************************************************************
596 * Open a UDP connection and return a handle
597 *****************************************************************************/
598 int __net_OpenUDP( vlc_object_t *p_this, const char *psz_bind, int i_bind,
599 const char *psz_server, int i_server )
603 network_socket_t sock;
604 module_t *p_network = NULL;
606 if( ( psz_server != NULL ) && ( psz_server[0] == '\0' ) )
607 msg_Warn( p_this, "calling net_OpenUDP with an explicit destination "
608 "is obsolete - use net_ConnectUDP instead" );
610 msg_Warn( p_this, "calling net_OpenUDP with an explicit destination "
611 "port is obsolete - use __net_ConnectUDP instead" );
613 if( psz_server == NULL ) psz_server = "";
614 if( psz_bind == NULL ) psz_bind = "";
616 /* Prepare the network_socket_t structure */
617 sock.psz_bind_addr = psz_bind;
618 sock.i_bind_port = i_bind;
619 sock.psz_server_addr = psz_server;
620 sock.i_server_port = i_server;
625 msg_Dbg( p_this, "net: connecting to '[%s]:%d@[%s]:%d'",
626 psz_server, i_server, psz_bind, i_bind );
628 /* Check if we have force ipv4 or ipv6 */
629 var_Create( p_this, "ipv4", VLC_VAR_BOOL | VLC_VAR_DOINHERIT );
630 var_Get( p_this, "ipv4", &v4 );
631 var_Create( p_this, "ipv6", VLC_VAR_BOOL | VLC_VAR_DOINHERIT );
632 var_Get( p_this, "ipv6", &v6 );
639 /* try IPv6 first (unless IPv4 forced) */
640 private = p_this->p_private;
641 p_this->p_private = (void*)&sock;
642 p_network = module_Need( p_this, "network", "ipv6", VLC_TRUE );
644 if( p_network != NULL )
645 module_Unneed( p_this, p_network );
647 p_this->p_private = private;
650 * Check if the IP stack can receive IPv4 packets on IPv6 sockets.
651 * If yes, then it is better to use the IPv6 socket.
652 * Otherwise, if we also get an IPv4, we have to choose, so we use
655 if( ( sock.i_handle != -1 ) && ( ( sock.v6only == 0 ) || v6.b_bool ) )
656 return sock.i_handle;
661 int fd6 = sock.i_handle;
663 /* also try IPv4 (unless IPv6 forced) */
664 private = p_this->p_private;
665 p_this->p_private = (void*)&sock;
666 p_network = module_Need( p_this, "network", "ipv4", VLC_TRUE );
668 if( p_network != NULL )
669 module_Unneed( p_this, p_network );
671 p_this->p_private = private;
675 if( sock.i_handle != -1 )
677 msg_Warn( p_this, "net: lame IPv6/IPv4 dual-stack present. "
678 "Using only IPv4." );
686 if( sock.i_handle == -1 )
687 msg_Dbg( p_this, "net: connection to '[%s]:%d@[%s]:%d' failed",
688 psz_server, i_server, psz_bind, i_bind );
690 return sock.i_handle;
693 /*****************************************************************************
695 *****************************************************************************
696 * Close a network handle
697 *****************************************************************************/
698 void net_Close( int fd )
701 CloseHandle( (HANDLE)fd );
702 #elif defined( WIN32 )
709 void net_ListenClose( int *pi_fd )
715 for( pi = pi_fd; *pi != -1; pi++ )
721 /*****************************************************************************
723 *****************************************************************************
724 * Read from a network socket
725 * If b_retry is true, then we repeat until we have read the right amount of
727 *****************************************************************************/
728 int __net_Read( vlc_object_t *p_this, int fd, v_socket_t *p_vs,
729 uint8_t *p_data, int i_data, vlc_bool_t b_retry )
731 struct timeval timeout;
736 vlc_bool_t b_die = p_this->b_die;
742 if( p_this->b_die != b_die )
747 /* Initialize file descriptor set */
749 FD_SET( fd, &fds_r );
751 FD_SET( fd, &fds_e );
753 /* We'll wait 0.5 second if nothing happens */
755 timeout.tv_usec = 500000;
757 } while( (i_ret = select(fd + 1, &fds_r, NULL, &fds_e, &timeout)) == 0
758 || ( i_ret < 0 && errno == EINTR ) );
762 #if defined(WIN32) || defined(UNDER_CE)
763 msg_Err( p_this, "network select error (%d)", WSAGetLastError() );
765 msg_Err( p_this, "network select error (%s)", strerror(errno) );
767 return i_total > 0 ? i_total : -1;
770 if( ( i_recv = (p_vs != NULL)
771 ? p_vs->pf_recv( p_vs->p_sys, p_data, i_data )
772 : recv( fd, p_data, i_data, 0 ) ) < 0 )
774 #if defined(WIN32) || defined(UNDER_CE)
775 if( WSAGetLastError() == WSAEWOULDBLOCK )
777 /* only happens with p_vs (SSL) - not really an error */
781 /* On win32 recv() will fail if the datagram doesn't fit inside
782 * the passed buffer, even though the buffer will be filled with
783 * the first part of the datagram. */
784 if( WSAGetLastError() == WSAEMSGSIZE )
786 msg_Err( p_this, "recv() failed. "
787 "Increase the mtu size (--mtu option)" );
790 else if( WSAGetLastError() == WSAEINTR ) continue;
791 else msg_Err( p_this, "recv failed (%i)", WSAGetLastError() );
793 /* EAGAIN only happens with p_vs (TLS) and it's not an error */
794 if( errno != EAGAIN )
795 msg_Err( p_this, "recv failed (%s)", strerror(errno) );
797 return i_total > 0 ? i_total : -1;
799 else if( i_recv == 0 )
801 /* Connection closed */
816 /*****************************************************************************
817 * __net_ReadNonBlock:
818 *****************************************************************************
819 * Read from a network socket, non blocking mode (with timeout)
820 *****************************************************************************/
821 int __net_ReadNonBlock( vlc_object_t *p_this, int fd, v_socket_t *p_vs,
822 uint8_t *p_data, int i_data, mtime_t i_wait)
824 struct timeval timeout;
829 /* Initialize file descriptor set */
831 FD_SET( fd, &fds_r );
833 FD_SET( fd, &fds_e );
836 timeout.tv_usec = i_wait;
838 i_ret = select(fd + 1, &fds_r, NULL, &fds_e, &timeout);
840 if( i_ret < 0 && errno == EINTR )
846 #if defined(WIN32) || defined(UNDER_CE)
847 msg_Err( p_this, "network select error (%d)", WSAGetLastError() );
849 msg_Err( p_this, "network select error (%s)", strerror(errno) );
859 #if !defined(UNDER_CE)
860 if( fd == 0/*STDIN_FILENO*/ ) i_recv = read( fd, p_data, i_data ); else
862 if( ( i_recv = (p_vs != NULL)
863 ? p_vs->pf_recv( p_vs->p_sys, p_data, i_data )
864 : recv( fd, p_data, i_data, 0 ) ) < 0 )
866 #if defined(WIN32) || defined(UNDER_CE)
868 /* On win32 recv() will fail if the datagram doesn't fit inside
869 * the passed buffer, even though the buffer will be filled with
870 * the first part of the datagram. */
871 if( WSAGetLastError() == WSAEMSGSIZE )
873 msg_Err( p_this, "recv() failed. "
874 "Increase the mtu size (--mtu option)" );
876 else msg_Err( p_this, "recv failed (%i)", WSAGetLastError() );
878 msg_Err( p_this, "recv failed (%s)", strerror(errno) );
883 return i_recv ? i_recv : -1; /* !i_recv -> connection closed if tcp */
886 /* We will never be here */
890 /*****************************************************************************
892 *****************************************************************************
893 * Read from several sockets (with timeout). Takes data from the first socket
895 *****************************************************************************/
896 int __net_Select( vlc_object_t *p_this, int *pi_fd, v_socket_t **pp_vs,
897 int i_fd, uint8_t *p_data, int i_data, mtime_t i_wait )
899 struct timeval timeout;
906 /* Initialize file descriptor set */
910 for( i = 0 ; i < i_fd ; i++)
912 if( pi_fd[i] > i_max_fd ) i_max_fd = pi_fd[i];
913 FD_SET( pi_fd[i], &fds_r );
914 FD_SET( pi_fd[i], &fds_e );
918 timeout.tv_usec = i_wait;
920 i_ret = select( i_max_fd + 1, &fds_r, NULL, &fds_e, &timeout );
922 if( i_ret < 0 && errno == EINTR )
928 msg_Err( p_this, "network select error (%s)", strerror(errno) );
931 else if( i_ret == 0 )
937 for( i = 0 ; i < i_fd ; i++)
939 if( FD_ISSET( pi_fd[i], &fds_r ) )
941 i_recv = ((pp_vs != NULL) && (pp_vs[i] != NULL))
942 ? pp_vs[i]->pf_recv( pp_vs[i]->p_sys, p_data, i_data )
943 : recv( pi_fd[i], p_data, i_data, 0 );
948 /* On win32 recv() will fail if the datagram doesn't
949 * fit inside the passed buffer, even though the buffer
950 * will be filled with the first part of the datagram. */
951 if( WSAGetLastError() == WSAEMSGSIZE )
953 msg_Err( p_this, "recv() failed. "
954 "Increase the mtu size (--mtu option)" );
956 else msg_Err( p_this, "recv failed (%i)",
959 msg_Err( p_this, "recv failed (%s)", strerror(errno) );
969 /* We will never be here */
974 /* Write exact amount requested */
975 int __net_Write( vlc_object_t *p_this, int fd, v_socket_t *p_vs,
976 const uint8_t *p_data, int i_data )
978 struct timeval timeout;
984 vlc_bool_t b_die = p_this->b_die;
990 if( p_this->b_die != b_die )
995 /* Initialize file descriptor set */
997 FD_SET( fd, &fds_w );
999 FD_SET( fd, &fds_e );
1001 /* We'll wait 0.5 second if nothing happens */
1003 timeout.tv_usec = 500000;
1005 } while( (i_ret = select(fd + 1, NULL, &fds_w, &fds_e, &timeout)) == 0
1006 || ( i_ret < 0 && errno == EINTR ) );
1010 #if defined(WIN32) || defined(UNDER_CE)
1011 msg_Err( p_this, "network select error (%d)", WSAGetLastError() );
1013 msg_Err( p_this, "network select error (%s)", strerror(errno) );
1015 return i_total > 0 ? i_total : -1;
1018 if( ( i_send = (p_vs != NULL)
1019 ? p_vs->pf_send( p_vs->p_sys, p_data, i_data )
1020 : send( fd, p_data, i_data, 0 ) ) < 0 )
1022 /* XXX With udp for example, it will issue a message if the host
1023 * isn't listening */
1024 /* msg_Err( p_this, "send failed (%s)", strerror(errno) ); */
1025 return i_total > 0 ? i_total : -1;
1035 char *__net_Gets( vlc_object_t *p_this, int fd, v_socket_t *p_vs )
1037 char *psz_line = NULL, *ptr = NULL;
1038 size_t i_line = 0, i_max = 0;
1043 if( i_line == i_max )
1046 psz_line = realloc( psz_line, i_max );
1047 ptr = psz_line + i_line;
1050 if( net_Read( p_this, fd, p_vs, (uint8_t *)ptr, 1, VLC_TRUE ) != 1 )
1069 if( ( ptr >= psz_line ) && ( *ptr == '\r' ) )
1075 int net_Printf( vlc_object_t *p_this, int fd, v_socket_t *p_vs,
1076 const char *psz_fmt, ... )
1080 va_start( args, psz_fmt );
1081 i_ret = net_vaPrintf( p_this, fd, p_vs, psz_fmt, args );
1087 int __net_vaPrintf( vlc_object_t *p_this, int fd, v_socket_t *p_vs,
1088 const char *psz_fmt, va_list args )
1093 i_size = vasprintf( &psz, psz_fmt, args );
1094 i_ret = __net_Write( p_this, fd, p_vs, (uint8_t *)psz, i_size ) < i_size
1103 /*****************************************************************************
1105 *****************************************************************************
1106 * Negociate authentication with a SOCKS server.
1107 *****************************************************************************/
1108 static int SocksNegociate( vlc_object_t *p_obj,
1109 int fd, int i_socks_version,
1110 char *psz_socks_user,
1111 char *psz_socks_passwd )
1113 uint8_t buffer[128+2*256];
1115 vlc_bool_t b_auth = VLC_FALSE;
1117 if( i_socks_version != 5 )
1120 /* We negociate authentication */
1122 if( psz_socks_user && psz_socks_passwd &&
1123 *psz_socks_user && *psz_socks_passwd )
1126 buffer[0] = i_socks_version; /* SOCKS version */
1129 buffer[1] = 2; /* Number of methods */
1130 buffer[2] = 0x00; /* - No auth required */
1131 buffer[3] = 0x02; /* - USer/Password */
1136 buffer[1] = 1; /* Number of methods */
1137 buffer[2] = 0x00; /* - No auth required */
1141 if( net_Write( p_obj, fd, NULL, buffer, i_len ) != i_len )
1142 return VLC_EGENERIC;
1143 if( net_Read( p_obj, fd, NULL, buffer, 2, VLC_TRUE ) != 2 )
1144 return VLC_EGENERIC;
1146 msg_Dbg( p_obj, "socks: v=%d method=%x", buffer[0], buffer[1] );
1148 if( buffer[1] == 0x00 )
1150 msg_Dbg( p_obj, "socks: no authentication required" );
1152 else if( buffer[1] == 0x02 )
1154 int i_len1 = __MIN( strlen(psz_socks_user), 255 );
1155 int i_len2 = __MIN( strlen(psz_socks_passwd), 255 );
1156 msg_Dbg( p_obj, "socks: username/password authentication" );
1158 /* XXX: we don't support user/pwd > 255 (truncated)*/
1159 buffer[0] = i_socks_version; /* Version */
1160 buffer[1] = i_len1; /* User length */
1161 memcpy( &buffer[2], psz_socks_user, i_len1 );
1162 buffer[2+i_len1] = i_len2; /* Password length */
1163 memcpy( &buffer[2+i_len1+1], psz_socks_passwd, i_len2 );
1165 i_len = 3 + i_len1 + i_len2;
1167 if( net_Write( p_obj, fd, NULL, buffer, i_len ) != i_len )
1168 return VLC_EGENERIC;
1170 if( net_Read( p_obj, fd, NULL, buffer, 2, VLC_TRUE ) != 2 )
1171 return VLC_EGENERIC;
1173 msg_Dbg( p_obj, "socks: v=%d status=%x", buffer[0], buffer[1] );
1174 if( buffer[1] != 0x00 )
1176 msg_Err( p_obj, "socks: authentication rejected" );
1177 return VLC_EGENERIC;
1183 msg_Err( p_obj, "socks: unsupported authentication method %x",
1186 msg_Err( p_obj, "socks: authentification needed" );
1187 return VLC_EGENERIC;
1193 /*****************************************************************************
1194 * SocksHandshakeTCP:
1195 *****************************************************************************
1196 * Open a TCP connection using a SOCKS server and return a handle (RFC 1928)
1197 *****************************************************************************/
1198 static int SocksHandshakeTCP( vlc_object_t *p_obj,
1200 int i_socks_version,
1201 char *psz_socks_user, char *psz_socks_passwd,
1202 const char *psz_host, int i_port )
1204 uint8_t buffer[128+2*256];
1206 if( i_socks_version != 4 && i_socks_version != 5 )
1208 msg_Warn( p_obj, "invalid socks protocol version %d", i_socks_version );
1209 i_socks_version = 5;
1212 if( i_socks_version == 5 &&
1213 SocksNegociate( p_obj, fd, i_socks_version,
1214 psz_socks_user, psz_socks_passwd ) )
1215 return VLC_EGENERIC;
1217 if( i_socks_version == 4 )
1219 struct addrinfo hints = { 0 }, *p_res;
1221 /* v4 only support ipv4 */
1222 hints.ai_family = AF_INET;
1223 if( vlc_getaddrinfo( p_obj, psz_host, 0, &hints, &p_res ) )
1224 return VLC_EGENERIC;
1226 buffer[0] = i_socks_version;
1227 buffer[1] = 0x01; /* CONNECT */
1228 SetWBE( &buffer[2], i_port ); /* Port */
1229 memcpy( &buffer[4], /* Address */
1230 &((struct sockaddr_in *)(p_res->ai_addr))->sin_addr, 4 );
1231 vlc_freeaddrinfo( p_res );
1233 buffer[8] = 0; /* Empty user id */
1235 if( net_Write( p_obj, fd, NULL, buffer, 9 ) != 9 )
1236 return VLC_EGENERIC;
1237 if( net_Read( p_obj, fd, NULL, buffer, 8, VLC_TRUE ) != 8 )
1238 return VLC_EGENERIC;
1240 msg_Dbg( p_obj, "socks: v=%d cd=%d",
1241 buffer[0], buffer[1] );
1243 if( buffer[1] != 90 )
1244 return VLC_EGENERIC;
1246 else if( i_socks_version == 5 )
1248 int i_hlen = __MIN(strlen( psz_host ), 255);
1251 buffer[0] = i_socks_version; /* Version */
1252 buffer[1] = 0x01; /* Cmd: connect */
1253 buffer[2] = 0x00; /* Reserved */
1254 buffer[3] = 3; /* ATYP: for now domainname */
1257 memcpy( &buffer[5], psz_host, i_hlen );
1258 SetWBE( &buffer[5+i_hlen], i_port );
1260 i_len = 5 + i_hlen + 2;
1263 if( net_Write( p_obj, fd, NULL, buffer, i_len ) != i_len )
1264 return VLC_EGENERIC;
1266 /* Read the header */
1267 if( net_Read( p_obj, fd, NULL, buffer, 5, VLC_TRUE ) != 5 )
1268 return VLC_EGENERIC;
1270 msg_Dbg( p_obj, "socks: v=%d rep=%d atyp=%d",
1271 buffer[0], buffer[1], buffer[3] );
1273 if( buffer[1] != 0x00 )
1275 msg_Err( p_obj, "socks: CONNECT request failed\n" );
1276 return VLC_EGENERIC;
1279 /* Read the remaining bytes */
1280 if( buffer[3] == 0x01 )
1282 else if( buffer[3] == 0x03 )
1283 i_len = buffer[4] + 2;
1284 else if( buffer[3] == 0x04 )
1287 return VLC_EGENERIC;
1289 if( net_Read( p_obj, fd, NULL, buffer, i_len, VLC_TRUE ) != i_len )
1290 return VLC_EGENERIC;
1296 /*****************************************************************************
1297 * inet_pton replacement for obsolete and/or crap operating systems
1298 *****************************************************************************/
1299 #ifndef HAVE_INET_PTON
1300 int inet_pton(int af, const char *src, void *dst)
1303 /* As we already know, Microsoft always go its own way, so even if they do
1304 * provide IPv6, they don't provide the API. */
1305 struct sockaddr_storage addr;
1306 int len = sizeof( addr );
1308 /* Damn it, they didn't even put LPCSTR for the firs parameter!!! */
1310 wchar_t *workaround_for_ill_designed_api =
1311 malloc( MAX_PATH * sizeof(wchar_t) );
1312 mbstowcs( workaround_for_ill_designed_api, src, MAX_PATH );
1313 workaround_for_ill_designed_api[MAX_PATH-1] = 0;
1315 char *workaround_for_ill_designed_api = strdup( src );
1318 if( !WSAStringToAddress( workaround_for_ill_designed_api, af, NULL,
1319 (LPSOCKADDR)&addr, &len ) )
1321 free( workaround_for_ill_designed_api );
1324 free( workaround_for_ill_designed_api );
1329 memcpy( dst, &((struct sockaddr_in6 *)&addr)->sin6_addr, 16 );
1333 memcpy( dst, &((struct sockaddr_in *)&addr)->sin_addr, 4 );
1337 WSASetLastError( WSAEAFNOSUPPORT );
1341 /* Assume IPv6 is not supported. */
1342 /* Would be safer and more simpler to use inet_aton() but it is most
1343 * likely not provided either. */
1348 errno = EAFNOSUPPORT;
1352 ipv4 = inet_addr( src );
1353 if( ipv4 == INADDR_NONE )
1356 memcpy( dst, &ipv4, 4 );
1360 #endif /* HAVE_INET_PTON */