1 /*****************************************************************************
3 *****************************************************************************
4 * Copyright (C) 2004 VideoLAN
7 * Authors: Laurent Aimar <fenrir@videolan.org>
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA.
22 *****************************************************************************/
24 /*****************************************************************************
26 *****************************************************************************/
36 #ifdef HAVE_SYS_TIME_H
37 # include <sys/time.h>
40 #if defined( UNDER_CE )
42 #elif defined( WIN32 )
43 # include <winsock2.h>
44 # include <ws2tcpip.h>
46 # define IN_MULTICAST(a) IN_CLASSD(a)
49 # include <sys/socket.h>
50 # include <netinet/in.h>
51 # ifdef HAVE_ARPA_INET_H
52 # include <arpa/inet.h>
59 #elif defined( WIN32 ) && !defined( UNDER_CE )
66 # define INADDR_ANY 0x00000000
69 # define INADDR_NONE 0xFFFFFFFF
72 static int SocksNegociate( vlc_object_t *, int fd, int i_socks_version,
73 char *psz_socks_user, char *psz_socks_passwd );
74 static int SocksHandshakeTCP( vlc_object_t *,
75 int fd, int i_socks_version,
76 char *psz_socks_user, char *psz_socks_passwd,
77 const char *psz_host, int i_port );
79 /*****************************************************************************
81 *****************************************************************************
82 * Open a TCP connection and return a handle
83 *****************************************************************************/
84 int net_ConvertIPv4( uint32_t *p_addr, const char * psz_address )
93 struct hostent *p_hostent;
95 /* Try to convert address directly from in_addr - this will work if
96 * psz_address is dotted decimal. */
97 #ifdef HAVE_ARPA_INET_H
98 if( !inet_aton( psz_address, (struct in_addr *)p_addr ) )
100 *p_addr = inet_addr( psz_address );
101 if( *p_addr == INADDR_NONE )
104 /* We have a fqdn, try to find its address */
105 if ( (p_hostent = gethostbyname( psz_address )) == NULL )
110 /* Copy the first address of the host in the socket address */
111 memcpy( p_addr, p_hostent->h_addr_list[0],
112 p_hostent->h_length );
118 /*****************************************************************************
120 *****************************************************************************
121 * Open a TCP connection and return a handle
122 *****************************************************************************/
123 int __net_OpenTCP( vlc_object_t *p_this, const char *psz_host, int i_port )
128 char *psz_network = "";
129 network_socket_t sock;
132 /* Check if we have force ipv4 or ipv6 */
133 var_Create( p_this, "ipv4", VLC_VAR_BOOL | VLC_VAR_DOINHERIT );
134 var_Get( p_this, "ipv4", &val );
137 psz_network = "ipv4";
140 var_Create( p_this, "ipv6", VLC_VAR_BOOL | VLC_VAR_DOINHERIT );
141 var_Get( p_this, "ipv6", &val );
144 psz_network = "ipv6";
147 /* Prepare the network_socket_t structure */
148 sock.i_type = NETWORK_TCP;
149 sock.psz_bind_addr = "";
150 sock.i_bind_port = 0;
153 var_Create( p_this, "socks", VLC_VAR_STRING | VLC_VAR_DOINHERIT );
154 var_Get( p_this, "socks", &val );
155 if( *val.psz_string && *val.psz_string != ':' )
157 char *psz = strchr( val.psz_string, ':' );
162 sock.psz_server_addr = (char*)val.psz_string;
163 sock.i_server_port = psz ? atoi( psz ) : 1080;
165 msg_Dbg( p_this, "net: connecting to '%s:%d' for '%s:%d'",
166 sock.psz_server_addr, sock.i_server_port,
171 sock.psz_server_addr = (char*)psz_host;
172 sock.i_server_port = i_port;
173 msg_Dbg( p_this, "net: connecting to '%s:%d'", psz_host, i_port );
177 private = p_this->p_private;
178 p_this->p_private = (void*)&sock;
179 if( !( p_network = module_Need( p_this, "network", psz_network, 0 ) ) )
181 msg_Dbg( p_this, "net: connection to '%s:%d' failed",
185 module_Unneed( p_this, p_network );
186 p_this->p_private = private;
188 if( *val.psz_string && *val.psz_string != ':' )
190 char *psz_user = var_CreateGetString( p_this, "socks-user" );
191 char *psz_pwd = var_CreateGetString( p_this, "socks-pwd" );
193 if( SocksHandshakeTCP( p_this, sock.i_handle, 5,
197 msg_Err( p_this, "failed to use the SOCKS server" );
198 net_Close( sock.i_handle );
205 free( val.psz_string );
207 return sock.i_handle;
210 /*****************************************************************************
212 *****************************************************************************
213 * Open a TCP listening socket and return it
214 *****************************************************************************/
215 int __net_ListenTCP( vlc_object_t *p_this, char *psz_host, int i_port )
220 char *psz_network = "";
221 network_socket_t sock;
224 /* Check if we have force ipv4 or ipv6 */
225 var_Create( p_this, "ipv4", VLC_VAR_BOOL | VLC_VAR_DOINHERIT );
226 var_Get( p_this, "ipv4", &val );
229 psz_network = "ipv4";
232 var_Create( p_this, "ipv6", VLC_VAR_BOOL | VLC_VAR_DOINHERIT );
233 var_Get( p_this, "ipv6", &val );
236 psz_network = "ipv6";
239 /* Prepare the network_socket_t structure */
240 sock.i_type = NETWORK_TCP_PASSIVE;
241 sock.psz_bind_addr = "";
242 sock.i_bind_port = 0;
243 sock.psz_server_addr = psz_host;
244 sock.i_server_port = i_port;
247 msg_Dbg( p_this, "net: listening to '%s:%d'", psz_host, i_port );
248 private = p_this->p_private;
249 p_this->p_private = (void*)&sock;
250 if( !( p_network = module_Need( p_this, "network", psz_network, 0 ) ) )
252 msg_Dbg( p_this, "net: listening to '%s:%d' failed",
256 module_Unneed( p_this, p_network );
257 p_this->p_private = private;
259 return sock.i_handle;
262 /*****************************************************************************
264 *****************************************************************************
265 * Accept a connection on a listening socket and return it
266 *****************************************************************************/
267 int __net_Accept( vlc_object_t *p_this, int fd, mtime_t i_wait )
269 vlc_bool_t b_die = p_this->b_die, b_block = (i_wait < 0);
270 struct timeval timeout;
274 while( p_this->b_die == b_die )
276 /* Initialize file descriptor set */
278 FD_SET( fd, &fds_r );
280 FD_SET( fd, &fds_e );
283 timeout.tv_usec = b_block ? 500000 : i_wait;
285 i_ret = select(fd + 1, &fds_r, NULL, &fds_e, &timeout);
286 if( (i_ret < 0 && errno == EINTR) || i_ret == 0 )
288 if( b_block ) continue;
293 #if defined(WIN32) || defined(UNDER_CE)
294 msg_Err( p_this, "network select error (%i)", WSAGetLastError() );
296 msg_Err( p_this, "network select error (%s)", strerror(errno) );
301 if( ( i_ret = accept( fd, 0, 0 ) ) <= 0 )
303 #if defined(WIN32) || defined(UNDER_CE)
304 msg_Err( p_this, "accept failed (%i)", WSAGetLastError() );
306 msg_Err( p_this, "accept failed (%s)", strerror(errno) );
317 /*****************************************************************************
319 *****************************************************************************
320 * Open a UDP connection and return a handle
321 *****************************************************************************/
322 int __net_OpenUDP( vlc_object_t *p_this, char *psz_bind, int i_bind,
323 char *psz_server, int i_server )
328 char *psz_network = "";
329 network_socket_t sock;
333 /* Check if we have force ipv4 or ipv6 */
334 var_Create( p_this, "ipv4", VLC_VAR_BOOL | VLC_VAR_DOINHERIT );
335 var_Get( p_this, "ipv4", &val );
338 psz_network = "ipv4";
341 var_Create( p_this, "ipv6", VLC_VAR_BOOL | VLC_VAR_DOINHERIT );
342 var_Get( p_this, "ipv6", &val );
345 psz_network = "ipv6";
347 if( psz_server == NULL ) psz_server = "";
348 if( psz_bind == NULL ) psz_bind = "";
350 /* Prepare the network_socket_t structure */
351 sock.i_type = NETWORK_UDP;
352 sock.psz_bind_addr = psz_bind;
353 sock.i_bind_port = i_bind;
354 sock.psz_server_addr = psz_server;
355 sock.i_server_port = i_server;
358 msg_Dbg( p_this, "net: connecting to '%s:%d@%s:%d'",
359 psz_server, i_server, psz_bind, i_bind );
360 private = p_this->p_private;
361 p_this->p_private = (void*)&sock;
362 if( !( p_network = module_Need( p_this, "network", psz_network, 0 ) ) )
364 msg_Dbg( p_this, "net: connection to '%s:%d@%s:%d' failed",
365 psz_server, i_server, psz_bind, i_bind );
368 module_Unneed( p_this, p_network );
369 p_this->p_private = private;
371 return sock.i_handle;
374 /*****************************************************************************
376 *****************************************************************************
377 * Close a network handle
378 *****************************************************************************/
379 void net_Close( int fd )
382 CloseHandle( (HANDLE)fd );
383 #elif defined( WIN32 )
390 /*****************************************************************************
392 *****************************************************************************
393 * Read from a network socket
394 * If b_rety is true, then we repeat until we have read the right amount of
396 *****************************************************************************/
397 int __net_Read( vlc_object_t *p_this, int fd, v_socket_t *p_vs,
398 uint8_t *p_data, int i_data, vlc_bool_t b_retry )
400 struct timeval timeout;
405 vlc_bool_t b_die = p_this->b_die;
411 if( p_this->b_die != b_die )
416 /* Initialize file descriptor set */
418 FD_SET( fd, &fds_r );
420 FD_SET( fd, &fds_e );
422 /* We'll wait 0.5 second if nothing happens */
424 timeout.tv_usec = 500000;
426 } while( (i_ret = select(fd + 1, &fds_r, NULL, &fds_e, &timeout)) == 0
427 || ( i_ret < 0 && errno == EINTR ) );
431 #if defined(WIN32) || defined(UNDER_CE)
432 msg_Err( p_this, "network select error" );
434 msg_Err( p_this, "network select error (%s)", strerror(errno) );
436 return i_total > 0 ? i_total : -1;
439 if( ( i_recv = (p_vs != NULL)
440 ? p_vs->pf_recv( p_vs->p_sys, p_data, i_data )
441 : recv( fd, p_data, i_data, 0 ) ) < 0 )
443 #if defined(WIN32) || defined(UNDER_CE)
445 /* On win32 recv() will fail if the datagram doesn't fit inside
446 * the passed buffer, even though the buffer will be filled with
447 * the first part of the datagram. */
448 if( WSAGetLastError() == WSAEMSGSIZE )
450 msg_Err( p_this, "recv() failed. "
451 "Increase the mtu size (--mtu option)" );
455 msg_Err( p_this, "recv failed (%i)", WSAGetLastError() );
457 msg_Err( p_this, "recv failed (%s)", strerror(errno) );
459 return i_total > 0 ? i_total : -1;
461 else if( i_recv == 0 )
463 /* Connection closed */
478 /*****************************************************************************
479 * __net_ReadNonBlock:
480 *****************************************************************************
481 * Read from a network socket, non blocking mode (with timeout)
482 *****************************************************************************/
483 int __net_ReadNonBlock( vlc_object_t *p_this, int fd, v_socket_t *p_vs,
484 uint8_t *p_data, int i_data, mtime_t i_wait)
486 struct timeval timeout;
491 /* Initialize file descriptor set */
493 FD_SET( fd, &fds_r );
495 FD_SET( fd, &fds_e );
498 timeout.tv_usec = i_wait;
500 i_ret = select(fd + 1, &fds_r, NULL, &fds_e, &timeout);
502 if( i_ret < 0 && errno == EINTR )
508 #if defined(WIN32) || defined(UNDER_CE)
509 msg_Err( p_this, "network select error" );
511 msg_Err( p_this, "network select error (%s)", strerror(errno) );
521 #if !defined(UNDER_CE)
522 if( fd == 0/*STDIN_FILENO*/ ) i_recv = read( fd, p_data, i_data ); else
524 if( ( i_recv = (p_vs != NULL)
525 ? p_vs->pf_recv( p_vs->p_sys, p_data, i_data )
526 : recv( fd, p_data, i_data, 0 ) ) <= 0 )
528 #if defined(WIN32) || defined(UNDER_CE)
530 /* On win32 recv() will fail if the datagram doesn't fit inside
531 * the passed buffer, even though the buffer will be filled with
532 * the first part of the datagram. */
533 if( WSAGetLastError() == WSAEMSGSIZE )
535 msg_Err( p_this, "recv() failed. "
536 "Increase the mtu size (--mtu option)" );
539 msg_Err( p_this, "recv failed (%i)", WSAGetLastError() );
541 msg_Err( p_this, "recv failed (%s)", strerror(errno) );
546 return i_recv ? i_recv : -1; /* !i_recv -> connection closed if tcp */
549 /* We will never be here */
553 /*****************************************************************************
555 *****************************************************************************
556 * Read from several sockets (with timeout). Takes data from the first socket
558 *****************************************************************************/
559 int __net_Select( vlc_object_t *p_this, int *pi_fd, v_socket_t **pp_vs,
560 int i_fd, uint8_t *p_data, int i_data, mtime_t i_wait )
562 struct timeval timeout;
569 /* Initialize file descriptor set */
573 for( i = 0 ; i < i_fd ; i++)
575 if( pi_fd[i] > i_max_fd ) i_max_fd = pi_fd[i];
576 FD_SET( pi_fd[i], &fds_r );
577 FD_SET( pi_fd[i], &fds_e );
581 timeout.tv_usec = i_wait;
583 i_ret = select( i_max_fd + 1, &fds_r, NULL, &fds_e, &timeout );
585 if( i_ret < 0 && errno == EINTR )
591 msg_Err( p_this, "network select error (%s)", strerror(errno) );
594 else if( i_ret == 0 )
600 for( i = 0 ; i < i_fd ; i++)
602 if( FD_ISSET( pi_fd[i], &fds_r ) )
604 i_recv = ((pp_vs != NULL) && (pp_vs[i] != NULL))
605 ? pp_vs[i]->pf_recv( pp_vs[i]->p_sys, p_data, i_data )
606 : recv( pi_fd[i], p_data, i_data, 0 );
611 /* On win32 recv() will fail if the datagram doesn't
612 * fit inside the passed buffer, even though the buffer
613 * will be filled with the first part of the datagram. */
614 if( WSAGetLastError() == WSAEMSGSIZE )
616 msg_Err( p_this, "recv() failed. "
617 "Increase the mtu size (--mtu option)" );
620 msg_Err( p_this, "recv failed (%i)",
623 msg_Err( p_this, "recv failed (%s)", strerror(errno) );
633 /* We will never be here */
638 /* Write exact amount requested */
639 int __net_Write( vlc_object_t *p_this, int fd, v_socket_t *p_vs,
640 uint8_t *p_data, int i_data )
642 struct timeval timeout;
648 vlc_bool_t b_die = p_this->b_die;
654 if( p_this->b_die != b_die )
659 /* Initialize file descriptor set */
661 FD_SET( fd, &fds_w );
663 FD_SET( fd, &fds_e );
665 /* We'll wait 0.5 second if nothing happens */
667 timeout.tv_usec = 500000;
669 } while( (i_ret = select(fd + 1, NULL, &fds_w, &fds_e, &timeout)) == 0
670 || ( i_ret < 0 && errno == EINTR ) );
674 #if defined(WIN32) || defined(UNDER_CE)
675 msg_Err( p_this, "network select error" );
677 msg_Err( p_this, "network select error (%s)", strerror(errno) );
679 return i_total > 0 ? i_total : -1;
682 if( ( i_send = (p_vs != NULL)
683 ? p_vs->pf_send( p_vs->p_sys, p_data, i_data )
684 : send( fd, p_data, i_data, 0 ) ) < 0 )
686 /* XXX With udp for example, it will issue a message if the host
688 /* msg_Err( p_this, "send failed (%s)", strerror(errno) ); */
689 return i_total > 0 ? i_total : -1;
699 char *__net_Gets( vlc_object_t *p_this, int fd, v_socket_t *p_vs )
701 char *psz_line = malloc( 1024 );
708 if( net_Read( p_this, fd, p_vs, &psz_line[i_line], 1, VLC_TRUE ) != 1 )
710 psz_line[i_line] = '\0';
715 if( psz_line[i_line-1] == '\n' )
717 psz_line[i_line] = '\0';
721 if( i_line >= i_max - 1 )
724 psz_line = realloc( psz_line, i_max );
734 while( i_line >= 1 &&
735 ( psz_line[i_line-1] == '\n' || psz_line[i_line-1] == '\r' ) )
738 psz_line[i_line] = '\0';
743 int net_Printf( vlc_object_t *p_this, int fd, v_socket_t *p_vs,
744 const char *psz_fmt, ... )
748 va_start( args, psz_fmt );
749 i_ret = net_vaPrintf( p_this, fd, p_vs, psz_fmt, args );
755 int __net_vaPrintf( vlc_object_t *p_this, int fd, v_socket_t *p_vs,
756 const char *psz_fmt, va_list args )
761 vasprintf( &psz, psz_fmt, args );
762 i_size = strlen( psz );
763 i_ret = __net_Write( p_this, fd, p_vs, psz, i_size ) < i_size ? -1 : i_size;
771 /*****************************************************************************
773 *****************************************************************************
774 * Negociate authentication with a SOCKS server.
775 *****************************************************************************/
776 static int SocksNegociate( vlc_object_t *p_obj,
777 int fd, int i_socks_version,
778 char *psz_socks_user,
779 char *psz_socks_passwd )
781 uint8_t buffer[128+2*256];
783 vlc_bool_t b_auth = VLC_FALSE;
785 if( i_socks_version != 5 )
788 /* We negociate authentication */
790 if( psz_socks_user && psz_socks_passwd &&
791 *psz_socks_user && *psz_socks_passwd )
794 buffer[0] = i_socks_version; /* SOCKS version */
797 buffer[1] = 2; /* Number of methods */
798 buffer[2] = 0x00; /* - No auth required */
799 buffer[3] = 0x02; /* - USer/Password */
804 buffer[1] = 1; /* Number of methods */
805 buffer[2] = 0x00; /* - No auth required */
809 if( net_Write( p_obj, fd, NULL, buffer, i_len ) != i_len )
811 if( net_Read( p_obj, fd, NULL, buffer, 2, VLC_TRUE ) != 2 )
814 msg_Dbg( p_obj, "socks: v=%d method=%x", buffer[0], buffer[1] );
816 if( buffer[1] == 0x00 )
818 msg_Dbg( p_obj, "socks: no authentication required" );
820 else if( buffer[1] == 0x02 )
822 int i_len1 = __MIN( strlen(psz_socks_user), 255 );
823 int i_len2 = __MIN( strlen(psz_socks_passwd), 255 );
824 msg_Dbg( p_obj, "socks: username/password authentication" );
826 /* XXX: we don't support user/pwd > 255 (truncated)*/
827 buffer[0] = i_socks_version; /* Version */
828 buffer[1] = i_len1; /* User length */
829 memcpy( &buffer[2], psz_socks_user, i_len1 );
830 buffer[2+i_len1] = i_len2; /* Password length */
831 memcpy( &buffer[2+i_len1+1], psz_socks_passwd, i_len2 );
833 i_len = 3 + i_len1 + i_len2;
835 if( net_Write( p_obj, fd, NULL, buffer, i_len ) != i_len )
838 if( net_Read( p_obj, fd, NULL, buffer, 2, VLC_TRUE ) != 2 )
841 msg_Dbg( p_obj, "socks: v=%d status=%x", buffer[0], buffer[1] );
842 if( buffer[1] != 0x00 )
844 msg_Err( p_obj, "socks: authentication rejected" );
851 msg_Err( p_obj, "socks: unsupported authentication method %x",
854 msg_Err( p_obj, "socks: authentification needed" );
861 /*****************************************************************************
863 *****************************************************************************
864 * Open a TCP connection using a SOCKS server and return a handle (RFC 1928)
865 *****************************************************************************/
866 static int SocksHandshakeTCP( vlc_object_t *p_obj,
869 char *psz_socks_user, char *psz_socks_passwd,
870 const char *psz_host, int i_port )
872 uint8_t buffer[128+2*256];
874 if( i_socks_version != 4 && i_socks_version != 5 )
876 msg_Warn( p_obj, "invalid socks protocol version %d", i_socks_version );
880 if( i_socks_version == 5 &&
881 SocksNegociate( p_obj, fd, i_socks_version,
882 psz_socks_user, psz_socks_passwd ) )
885 if( i_socks_version == 4 )
889 /* v4 only support ipv4 */
890 if( net_ConvertIPv4( &addr, psz_host ) )
893 buffer[0] = i_socks_version;
894 buffer[1] = 0x01; /* CONNECT */
895 SetWBE( &buffer[2], i_port ); /* Port */
896 memcpy( &buffer[4], &addr, 4 ); /* Addresse */
897 buffer[8] = 0; /* Empty user id */
899 if( net_Write( p_obj, fd, NULL, buffer, 9 ) != 9 )
901 if( net_Read( p_obj, fd, NULL, buffer, 8, VLC_TRUE ) != 8 )
904 msg_Dbg( p_obj, "socks: v=%d cd=%d",
905 buffer[0], buffer[1] );
907 if( buffer[1] != 90 )
910 else if( i_socks_version == 5 )
912 int i_hlen = __MIN(strlen( psz_host ), 255);
915 buffer[0] = i_socks_version; /* Version */
916 buffer[1] = 0x01; /* Cmd: connect */
917 buffer[2] = 0x00; /* Reserved */
918 buffer[3] = 3; /* ATYP: for now domainname */
921 memcpy( &buffer[5], psz_host, i_hlen );
922 SetWBE( &buffer[5+i_hlen], i_port );
924 i_len = 5 + i_hlen + 2;
927 if( net_Write( p_obj, fd, NULL, buffer, i_len ) != i_len )
930 /* Read the header */
931 if( net_Read( p_obj, fd, NULL, buffer, 5, VLC_TRUE ) != 5 )
934 msg_Dbg( p_obj, "socks: v=%d rep=%d atyp=%d",
935 buffer[0], buffer[1], buffer[3] );
937 if( buffer[1] != 0x00 )
939 msg_Err( p_obj, "socks: CONNECT request failed\n" );
943 /* Read the remaining bytes */
944 if( buffer[3] == 0x01 )
946 else if( buffer[3] == 0x03 )
947 i_len = buffer[4] + 2;
948 else if( buffer[3] == 0x04 )
953 if( net_Read( p_obj, fd, NULL, buffer, i_len, VLC_TRUE ) != i_len )