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>
54 #elif defined( WIN32 ) && !defined( UNDER_CE )
61 # define INADDR_ANY 0x00000000
64 # define INADDR_NONE 0xFFFFFFFF
67 static int SocksNegociate( vlc_object_t *, int fd, int i_socks_version,
68 char *psz_socks_user, char *psz_socks_passwd );
69 static int SocksHandshakeTCP( vlc_object_t *,
70 int fd, int i_socks_version,
71 char *psz_socks_user, char *psz_socks_passwd,
72 const char *psz_host, int i_port );
74 /*****************************************************************************
76 *****************************************************************************
77 * Open a TCP connection and return a handle
78 *****************************************************************************/
79 int net_ConvertIPv4( uint32_t *p_addr, const char * psz_address )
88 struct hostent *p_hostent;
90 /* Try to convert address directly from in_addr - this will work if
91 * psz_address is dotted decimal. */
92 #ifdef HAVE_ARPA_INET_H
93 if( !inet_aton( psz_address, &p_addr ) )
95 *p_addr = inet_addr( psz_address );
96 if( *p_addr == INADDR_NONE )
99 /* We have a fqdn, try to find its address */
100 if ( (p_hostent = gethostbyname( psz_address )) == NULL )
105 /* Copy the first address of the host in the socket address */
106 memcpy( p_addr, p_hostent->h_addr_list[0],
107 p_hostent->h_length );
113 /*****************************************************************************
115 *****************************************************************************
116 * Open a TCP connection and return a handle
117 *****************************************************************************/
118 int __net_OpenTCP( vlc_object_t *p_this, const char *psz_host, int i_port )
123 char *psz_network = "";
124 network_socket_t sock;
127 /* Check if we have force ipv4 or ipv6 */
128 var_Create( p_this, "ipv4", VLC_VAR_BOOL | VLC_VAR_DOINHERIT );
129 var_Get( p_this, "ipv4", &val );
132 psz_network = "ipv4";
135 var_Create( p_this, "ipv6", VLC_VAR_BOOL | VLC_VAR_DOINHERIT );
136 var_Get( p_this, "ipv6", &val );
139 psz_network = "ipv6";
142 /* Prepare the network_socket_t structure */
143 sock.i_type = NETWORK_TCP;
144 sock.psz_bind_addr = "";
145 sock.i_bind_port = 0;
148 var_Create( p_this, "socks", VLC_VAR_STRING | VLC_VAR_DOINHERIT );
149 var_Get( p_this, "socks", &val );
150 if( *val.psz_string && *val.psz_string != ':' )
152 char *psz = strchr( val.psz_string, ':' );
157 sock.psz_server_addr = (char*)val.psz_string;
158 sock.i_server_port = psz ? atoi( psz ) : 1080;
160 msg_Dbg( p_this, "net: connecting to '%s:%d' for '%s:%d'",
161 sock.psz_server_addr, sock.i_server_port,
166 sock.psz_server_addr = (char*)psz_host;
167 sock.i_server_port = i_port;
168 msg_Dbg( p_this, "net: connecting to '%s:%d'", psz_host, i_port );
172 private = p_this->p_private;
173 p_this->p_private = (void*)&sock;
174 if( !( p_network = module_Need( p_this, "network", psz_network, 0 ) ) )
176 msg_Dbg( p_this, "net: connection to '%s:%d' failed",
180 module_Unneed( p_this, p_network );
181 p_this->p_private = private;
183 if( *val.psz_string && *val.psz_string != ':' )
185 char *psz_user = var_CreateGetString( p_this, "socks-user" );
186 char *psz_pwd = var_CreateGetString( p_this, "socks-pwd" );
188 if( SocksHandshakeTCP( p_this, sock.i_handle, 5,
192 msg_Err( p_this, "failed to use the SOCKS server" );
193 net_Close( sock.i_handle );
200 free( val.psz_string );
202 return sock.i_handle;
205 /*****************************************************************************
207 *****************************************************************************
208 * Open a TCP listening socket and return it
209 *****************************************************************************/
210 int __net_ListenTCP( vlc_object_t *p_this, char *psz_host, int i_port )
215 char *psz_network = "";
216 network_socket_t sock;
219 /* Check if we have force ipv4 or ipv6 */
220 var_Create( p_this, "ipv4", VLC_VAR_BOOL | VLC_VAR_DOINHERIT );
221 var_Get( p_this, "ipv4", &val );
224 psz_network = "ipv4";
227 var_Create( p_this, "ipv6", VLC_VAR_BOOL | VLC_VAR_DOINHERIT );
228 var_Get( p_this, "ipv6", &val );
231 psz_network = "ipv6";
234 /* Prepare the network_socket_t structure */
235 sock.i_type = NETWORK_TCP_PASSIVE;
236 sock.psz_bind_addr = "";
237 sock.i_bind_port = 0;
238 sock.psz_server_addr = psz_host;
239 sock.i_server_port = i_port;
242 msg_Dbg( p_this, "net: listening to '%s:%d'", psz_host, i_port );
243 private = p_this->p_private;
244 p_this->p_private = (void*)&sock;
245 if( !( p_network = module_Need( p_this, "network", psz_network, 0 ) ) )
247 msg_Dbg( p_this, "net: listening to '%s:%d' failed",
251 module_Unneed( p_this, p_network );
252 p_this->p_private = private;
254 return sock.i_handle;
257 /*****************************************************************************
259 *****************************************************************************
260 * Accept a connection on a listening socket and return it
261 *****************************************************************************/
262 int __net_Accept( vlc_object_t *p_this, int fd, mtime_t i_wait )
264 vlc_bool_t b_die = p_this->b_die, b_block = (i_wait < 0);
265 struct timeval timeout;
269 while( p_this->b_die == b_die )
271 /* Initialize file descriptor set */
273 FD_SET( fd, &fds_r );
275 FD_SET( fd, &fds_e );
278 timeout.tv_usec = b_block ? 500000 : i_wait;
280 i_ret = select(fd + 1, &fds_r, NULL, &fds_e, &timeout);
281 if( (i_ret < 0 && errno == EINTR) || i_ret == 0 )
283 if( b_block ) continue;
288 #if defined(WIN32) || defined(UNDER_CE)
289 msg_Err( p_this, "network select error (%i)", WSAGetLastError() );
291 msg_Err( p_this, "network select error (%s)", strerror(errno) );
296 if( ( i_ret = accept( fd, 0, 0 ) ) <= 0 )
298 #if defined(WIN32) || defined(UNDER_CE)
299 msg_Err( p_this, "accept failed (%i)", WSAGetLastError() );
301 msg_Err( p_this, "accept failed (%s)", strerror(errno) );
312 /*****************************************************************************
314 *****************************************************************************
315 * Open a UDP connection and return a handle
316 *****************************************************************************/
317 int __net_OpenUDP( vlc_object_t *p_this, char *psz_bind, int i_bind,
318 char *psz_server, int i_server )
323 char *psz_network = "";
324 network_socket_t sock;
328 /* Check if we have force ipv4 or ipv6 */
329 var_Create( p_this, "ipv4", VLC_VAR_BOOL | VLC_VAR_DOINHERIT );
330 var_Get( p_this, "ipv4", &val );
333 psz_network = "ipv4";
336 var_Create( p_this, "ipv6", VLC_VAR_BOOL | VLC_VAR_DOINHERIT );
337 var_Get( p_this, "ipv6", &val );
340 psz_network = "ipv6";
342 if( psz_server == NULL ) psz_server = "";
343 if( psz_bind == NULL ) psz_bind = "";
345 /* Prepare the network_socket_t structure */
346 sock.i_type = NETWORK_UDP;
347 sock.psz_bind_addr = psz_bind;
348 sock.i_bind_port = i_bind;
349 sock.psz_server_addr = psz_server;
350 sock.i_server_port = i_server;
353 msg_Dbg( p_this, "net: connecting to '%s:%d@%s:%d'",
354 psz_server, i_server, psz_bind, i_bind );
355 private = p_this->p_private;
356 p_this->p_private = (void*)&sock;
357 if( !( p_network = module_Need( p_this, "network", psz_network, 0 ) ) )
359 msg_Dbg( p_this, "net: connection to '%s:%d@%s:%d' failed",
360 psz_server, i_server, psz_bind, i_bind );
363 module_Unneed( p_this, p_network );
364 p_this->p_private = private;
366 return sock.i_handle;
369 /*****************************************************************************
371 *****************************************************************************
372 * Close a network handle
373 *****************************************************************************/
374 void net_Close( int fd )
377 CloseHandle( (HANDLE)fd );
378 #elif defined( WIN32 )
385 /*****************************************************************************
387 *****************************************************************************
388 * Read from a network socket
389 * If b_rety is true, then we repeat until we have read the right amount of
391 *****************************************************************************/
392 int __net_Read( vlc_object_t *p_this, int fd, v_socket_t *p_vs,
393 uint8_t *p_data, int i_data, vlc_bool_t b_retry )
395 struct timeval timeout;
400 vlc_bool_t b_die = p_this->b_die;
406 if( p_this->b_die != b_die )
411 /* Initialize file descriptor set */
413 FD_SET( fd, &fds_r );
415 FD_SET( fd, &fds_e );
417 /* We'll wait 0.5 second if nothing happens */
419 timeout.tv_usec = 500000;
421 } while( (i_ret = select(fd + 1, &fds_r, NULL, &fds_e, &timeout)) == 0
422 || ( i_ret < 0 && errno == EINTR ) );
426 #if defined(WIN32) || defined(UNDER_CE)
427 msg_Err( p_this, "network select error" );
429 msg_Err( p_this, "network select error (%s)", strerror(errno) );
431 return i_total > 0 ? i_total : -1;
434 if( ( i_recv = (p_vs != NULL)
435 ? p_vs->pf_recv( p_vs->p_sys, p_data, i_data )
436 : recv( fd, p_data, i_data, 0 ) ) < 0 )
438 #if defined(WIN32) || defined(UNDER_CE)
440 /* On win32 recv() will fail if the datagram doesn't fit inside
441 * the passed buffer, even though the buffer will be filled with
442 * the first part of the datagram. */
443 if( WSAGetLastError() == WSAEMSGSIZE )
445 msg_Err( p_this, "recv() failed. "
446 "Increase the mtu size (--mtu option)" );
450 msg_Err( p_this, "recv failed (%i)", WSAGetLastError() );
452 msg_Err( p_this, "recv failed (%s)", strerror(errno) );
454 return i_total > 0 ? i_total : -1;
456 else if( i_recv == 0 )
458 /* Connection closed */
473 /*****************************************************************************
474 * __net_ReadNonBlock:
475 *****************************************************************************
476 * Read from a network socket, non blocking mode (with timeout)
477 *****************************************************************************/
478 int __net_ReadNonBlock( vlc_object_t *p_this, int fd, v_socket_t *p_vs,
479 uint8_t *p_data, int i_data, mtime_t i_wait)
481 struct timeval timeout;
486 /* Initialize file descriptor set */
488 FD_SET( fd, &fds_r );
490 FD_SET( fd, &fds_e );
493 timeout.tv_usec = i_wait;
495 i_ret = select(fd + 1, &fds_r, NULL, &fds_e, &timeout);
497 if( i_ret < 0 && errno == EINTR )
503 #if defined(WIN32) || defined(UNDER_CE)
504 msg_Err( p_this, "network select error" );
506 msg_Err( p_this, "network select error (%s)", strerror(errno) );
516 #if !defined(UNDER_CE)
517 if( fd == 0/*STDIN_FILENO*/ ) i_recv = read( fd, p_data, i_data ); else
519 if( ( i_recv = (p_vs != NULL)
520 ? p_vs->pf_recv( p_vs->p_sys, p_data, i_data )
521 : recv( fd, p_data, i_data, 0 ) ) <= 0 )
523 #if defined(WIN32) || defined(UNDER_CE)
525 /* On win32 recv() will fail if the datagram doesn't fit inside
526 * the passed buffer, even though the buffer will be filled with
527 * the first part of the datagram. */
528 if( WSAGetLastError() == WSAEMSGSIZE )
530 msg_Err( p_this, "recv() failed. "
531 "Increase the mtu size (--mtu option)" );
534 msg_Err( p_this, "recv failed (%i)", WSAGetLastError() );
536 msg_Err( p_this, "recv failed (%s)", strerror(errno) );
541 return i_recv ? i_recv : -1; /* !i_recv -> connection closed if tcp */
544 /* We will never be here */
548 /*****************************************************************************
550 *****************************************************************************
551 * Read from several sockets (with timeout). Takes data from the first socket
553 *****************************************************************************/
554 int __net_Select( vlc_object_t *p_this, int *pi_fd, v_socket_t **pp_vs,
555 int i_fd, uint8_t *p_data, int i_data, mtime_t i_wait )
557 struct timeval timeout;
564 /* Initialize file descriptor set */
568 for( i = 0 ; i < i_fd ; i++)
570 if( pi_fd[i] > i_max_fd ) i_max_fd = pi_fd[i];
571 FD_SET( pi_fd[i], &fds_r );
572 FD_SET( pi_fd[i], &fds_e );
576 timeout.tv_usec = i_wait;
578 i_ret = select( i_max_fd + 1, &fds_r, NULL, &fds_e, &timeout );
580 if( i_ret < 0 && errno == EINTR )
586 msg_Err( p_this, "network select error (%s)", strerror(errno) );
589 else if( i_ret == 0 )
595 for( i = 0 ; i < i_fd ; i++)
597 if( FD_ISSET( pi_fd[i], &fds_r ) )
599 i_recv = ((pp_vs != NULL) && (pp_vs[i] != NULL))
600 ? pp_vs[i]->pf_recv( pp_vs[i]->p_sys, p_data, i_data )
601 : recv( pi_fd[i], p_data, i_data, 0 );
606 /* On win32 recv() will fail if the datagram doesn't
607 * fit inside the passed buffer, even though the buffer
608 * will be filled with the first part of the datagram. */
609 if( WSAGetLastError() == WSAEMSGSIZE )
611 msg_Err( p_this, "recv() failed. "
612 "Increase the mtu size (--mtu option)" );
615 msg_Err( p_this, "recv failed (%i)",
618 msg_Err( p_this, "recv failed (%s)", strerror(errno) );
628 /* We will never be here */
633 /* Write exact amount requested */
634 int __net_Write( vlc_object_t *p_this, int fd, v_socket_t *p_vs,
635 uint8_t *p_data, int i_data )
637 struct timeval timeout;
643 vlc_bool_t b_die = p_this->b_die;
649 if( p_this->b_die != b_die )
654 /* Initialize file descriptor set */
656 FD_SET( fd, &fds_w );
658 FD_SET( fd, &fds_e );
660 /* We'll wait 0.5 second if nothing happens */
662 timeout.tv_usec = 500000;
664 } while( (i_ret = select(fd + 1, NULL, &fds_w, &fds_e, &timeout)) == 0
665 || ( i_ret < 0 && errno == EINTR ) );
669 #if defined(WIN32) || defined(UNDER_CE)
670 msg_Err( p_this, "network select error" );
672 msg_Err( p_this, "network select error (%s)", strerror(errno) );
674 return i_total > 0 ? i_total : -1;
677 if( ( i_send = (p_vs != NULL)
678 ? p_vs->pf_send( p_vs->p_sys, p_data, i_data )
679 : send( fd, p_data, i_data, 0 ) ) < 0 )
681 /* XXX With udp for example, it will issue a message if the host
683 /* msg_Err( p_this, "send failed (%s)", strerror(errno) ); */
684 return i_total > 0 ? i_total : -1;
694 char *__net_Gets( vlc_object_t *p_this, int fd, v_socket_t *p_vs )
696 char *psz_line = malloc( 1024 );
703 if( net_Read( p_this, fd, p_vs, &psz_line[i_line], 1, VLC_TRUE ) != 1 )
705 psz_line[i_line] = '\0';
710 if( psz_line[i_line-1] == '\n' )
712 psz_line[i_line] = '\0';
716 if( i_line >= i_max - 1 )
719 psz_line = realloc( psz_line, i_max );
729 while( i_line >= 1 &&
730 ( psz_line[i_line-1] == '\n' || psz_line[i_line-1] == '\r' ) )
733 psz_line[i_line] = '\0';
738 int net_Printf( vlc_object_t *p_this, int fd, v_socket_t *p_vs,
739 const char *psz_fmt, ... )
743 va_start( args, psz_fmt );
744 i_ret = net_vaPrintf( p_this, fd, p_vs, psz_fmt, args );
750 int __net_vaPrintf( vlc_object_t *p_this, int fd, v_socket_t *p_vs,
751 const char *psz_fmt, va_list args )
756 vasprintf( &psz, psz_fmt, args );
757 i_size = strlen( psz );
758 i_ret = __net_Write( p_this, fd, p_vs, psz, i_size ) < i_size ? -1 : i_size;
766 /*****************************************************************************
768 *****************************************************************************
769 * Negociate authentication with a SOCKS server.
770 *****************************************************************************/
771 static int SocksNegociate( vlc_object_t *p_obj,
772 int fd, int i_socks_version,
773 char *psz_socks_user,
774 char *psz_socks_passwd )
776 uint8_t buffer[128+2*256];
778 vlc_bool_t b_auth = VLC_FALSE;
780 if( i_socks_version != 5 )
783 /* We negociate authentication */
785 if( psz_socks_user && psz_socks_passwd &&
786 *psz_socks_user && *psz_socks_passwd )
789 buffer[0] = i_socks_version; /* SOCKS version */
792 buffer[1] = 2; /* Number of methods */
793 buffer[2] = 0x00; /* - No auth required */
794 buffer[3] = 0x02; /* - USer/Password */
799 buffer[1] = 1; /* Number of methods */
800 buffer[2] = 0x00; /* - No auth required */
804 if( net_Write( p_obj, fd, NULL, buffer, i_len ) != i_len )
806 if( net_Read( p_obj, fd, NULL, buffer, 2, VLC_TRUE ) != 2 )
809 msg_Dbg( p_obj, "socks: v=%d method=%x", buffer[0], buffer[1] );
811 if( buffer[1] == 0x00 )
813 msg_Dbg( p_obj, "socks: no authentication required" );
815 else if( buffer[1] == 0x02 )
817 int i_len1 = __MIN( strlen(psz_socks_user), 255 );
818 int i_len2 = __MIN( strlen(psz_socks_passwd), 255 );
819 msg_Dbg( p_obj, "socks: username/password authentication" );
821 /* XXX: we don't support user/pwd > 255 (truncated)*/
822 buffer[0] = i_socks_version; /* Version */
823 buffer[1] = i_len1; /* User length */
824 memcpy( &buffer[2], psz_socks_user, i_len1 );
825 buffer[2+i_len1] = i_len2; /* Password length */
826 memcpy( &buffer[2+i_len1+1], psz_socks_passwd, i_len2 );
828 i_len = 3 + i_len1 + i_len2;
830 if( net_Write( p_obj, fd, NULL, buffer, i_len ) != i_len )
833 if( net_Read( p_obj, fd, NULL, buffer, 2, VLC_TRUE ) != 2 )
836 msg_Dbg( p_obj, "socks: v=%d status=%x", buffer[0], buffer[1] );
837 if( buffer[1] != 0x00 )
839 msg_Err( p_obj, "socks: authentication rejected" );
846 msg_Err( p_obj, "socks: unsupported authentication method %x",
849 msg_Err( p_obj, "socks: authentification needed" );
856 /*****************************************************************************
858 *****************************************************************************
859 * Open a TCP connection using a SOCKS server and return a handle (RFC 1928)
860 *****************************************************************************/
861 static int SocksHandshakeTCP( vlc_object_t *p_obj,
864 char *psz_socks_user, char *psz_socks_passwd,
865 const char *psz_host, int i_port )
867 uint8_t buffer[128+2*256];
869 if( i_socks_version != 4 && i_socks_version != 5 )
871 msg_Warn( p_obj, "invalid socks protocol version %d", i_socks_version );
875 if( i_socks_version == 5 &&
876 SocksNegociate( p_obj, fd, i_socks_version,
877 psz_socks_user, psz_socks_passwd ) )
880 if( i_socks_version == 4 )
884 /* v4 only support ipv4 */
885 if( net_ConvertIPv4( &addr, psz_host ) )
888 buffer[0] = i_socks_version;
889 buffer[1] = 0x01; /* CONNECT */
890 SetWBE( &buffer[2], i_port ); /* Port */
891 memcpy( &buffer[4], &addr, 4 ); /* Addresse */
892 buffer[8] = 0; /* Empty user id */
894 if( net_Write( p_obj, fd, NULL, buffer, 9 ) != 9 )
896 if( net_Read( p_obj, fd, NULL, buffer, 8, VLC_TRUE ) != 8 )
899 msg_Dbg( p_obj, "socks: v=%d cd=%d",
900 buffer[0], buffer[1] );
902 if( buffer[1] != 90 )
905 else if( i_socks_version == 5 )
907 int i_hlen = __MIN(strlen( psz_host ), 255);
910 buffer[0] = i_socks_version; /* Version */
911 buffer[1] = 0x01; /* Cmd: connect */
912 buffer[2] = 0x00; /* Reserved */
913 buffer[3] = 3; /* ATYP: for now domainname */
916 memcpy( &buffer[5], psz_host, i_hlen );
917 SetWBE( &buffer[5+i_hlen], i_port );
919 i_len = 5 + i_hlen + 2;
922 if( net_Write( p_obj, fd, NULL, buffer, i_len ) != i_len )
925 /* Read the header */
926 if( net_Read( p_obj, fd, NULL, buffer, 5, VLC_TRUE ) != 5 )
929 msg_Dbg( p_obj, "socks: v=%d rep=%d atyp=%d",
930 buffer[0], buffer[1], buffer[3] );
932 if( buffer[1] != 0x00 )
934 msg_Err( p_obj, "socks: CONNECT request failed\n" );
938 /* Read the remaining bytes */
939 if( buffer[3] == 0x01 )
941 else if( buffer[3] == 0x03 )
942 i_len = buffer[4] + 2;
943 else if( buffer[3] == 0x04 )
948 if( net_Read( p_obj, fd, NULL, buffer, i_len, VLC_TRUE ) != i_len )