]> git.sesse.net Git - vlc/blob - src/misc/net.c
Wrappers for shutdown() API
[vlc] / src / misc / net.c
1 /*****************************************************************************
2  * net.c:
3  *****************************************************************************
4  * Copyright (C) 2004-2005 VideoLAN
5  * $Id$
6  *
7  * Authors: Laurent Aimar <fenrir@videolan.org>
8  *          RĂ©mi Denis-Courmont <rem # videolan.org>
9  *
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.
14  *
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.
19  *
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  *****************************************************************************/
24
25 /*****************************************************************************
26  * Preamble
27  *****************************************************************************/
28 #include <stdlib.h>
29 #include <vlc/vlc.h>
30
31 #include <errno.h>
32
33 #ifdef HAVE_FCNTL_H
34 #   include <fcntl.h>
35 #endif
36
37 #ifdef HAVE_SYS_TIME_H
38 #    include <sys/time.h>
39 #endif
40
41 #if defined( WIN32 ) || defined( UNDER_CE )
42 #   if defined(UNDER_CE) && defined(sockaddr_storage)
43 #       undef sockaddr_storage
44 #   endif
45 #   include <winsock2.h>
46 #   include <ws2tcpip.h>
47 #else
48 #   include <sys/socket.h>
49 #   include <netinet/in.h>
50 #   ifdef HAVE_ARPA_INET_H
51 #       include <arpa/inet.h>
52 #   endif
53 #   include <netdb.h>
54 #endif
55
56 #ifdef HAVE_UNISTD_H
57 #   include <unistd.h>
58 #endif
59
60 #include "network.h"
61
62 #ifndef INADDR_ANY
63 #   define INADDR_ANY  0x00000000
64 #endif
65 #ifndef INADDR_NONE
66 #   define INADDR_NONE 0xFFFFFFFF
67 #endif
68 #ifndef PF_INET
69 #   define PF_INET AF_INET
70 #endif
71
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 );
78
79 /*****************************************************************************
80  * __net_OpenTCP:
81  *****************************************************************************
82  * Open a TCP connection and return a handle
83  *****************************************************************************/
84 int __net_OpenTCP( vlc_object_t *p_this, const char *psz_host, int i_port )
85 {
86     struct addrinfo hints, *res, *ptr;
87     const char      *psz_realhost;
88     char            *psz_socks;
89     int             i_realport, i_val, i_handle = -1;
90
91     if( i_port == 0 )
92         i_port = 80; /* historical VLC thing */
93
94     memset( &hints, 0, sizeof( hints ) );
95     hints.ai_socktype = SOCK_STREAM;
96
97     psz_socks = var_CreateGetString( p_this, "socks" );
98     if( *psz_socks && *psz_socks != ':' )
99     {
100         char *psz = strchr( psz_socks, ':' );
101
102         if( psz )
103             *psz++ = '\0';
104
105         psz_realhost = psz_socks;
106         i_realport = ( psz != NULL ) ? atoi( psz ) : 1080;
107
108         msg_Dbg( p_this, "net: connecting to '%s:%d' for '%s:%d'",
109                  psz_realhost, i_realport, psz_host, i_port );
110     }
111     else
112     {
113         psz_realhost = psz_host;
114         i_realport = i_port;
115
116         msg_Dbg( p_this, "net: connecting to '%s:%d'", psz_realhost,
117                  i_realport );
118     }
119
120     i_val = vlc_getaddrinfo( p_this, psz_realhost, i_realport, &hints, &res );
121     if( i_val )
122     {
123         msg_Err( p_this, "cannot resolve '%s:%d' : %s", psz_realhost,
124                  i_realport, vlc_gai_strerror( i_val ) );
125         free( psz_socks );
126         return -1;
127     }
128
129     for( ptr = res; (ptr != NULL) && (i_handle == -1); ptr = ptr->ai_next )
130     {
131         int fd;
132
133         fd = socket( ptr->ai_family, ptr->ai_socktype, ptr->ai_protocol );
134         if( fd == -1 )
135         {
136 #if defined(WIN32) || defined(UNDER_CE)
137             msg_Warn( p_this, "cannot create socket (%i)",
138                       WSAGetLastError() );
139 #else
140             msg_Warn( p_this, "cannot create socket (%s)",
141                       strerror( errno ) );
142 #endif
143             continue;
144         }
145
146
147         /* Set to non-blocking */
148 #if defined( WIN32 ) || defined( UNDER_CE )
149         {
150             unsigned long i_dummy = 1;
151             if( ioctlsocket( fd, FIONBIO, &i_dummy ) != 0 )
152                 msg_Err( p_this, "cannot set socket to non-blocking mode" );
153         }
154 #else
155         if( ( ( i_val = fcntl( fd, F_GETFL, 0 ) ) < 0 ) ||
156             ( fcntl( fd, F_SETFL, i_val | O_NONBLOCK ) < 0 ) )
157             msg_Err( p_this, "cannot set socket to non-blocking mode (%s)",
158                      strerror( errno ) );
159 #endif
160
161         i_val = 1;
162         setsockopt( fd, SOL_SOCKET, SO_REUSEADDR, (void *)&i_val,
163                     sizeof( i_val ) );
164
165         if( connect( fd, ptr->ai_addr, ptr->ai_addrlen ) )
166         {
167             int i_val_size = sizeof( i_val );
168             div_t d;
169             struct timeval tv;
170             vlc_value_t timeout;
171 #if defined( WIN32 ) || defined( UNDER_CE )
172             if( WSAGetLastError() != WSAEWOULDBLOCK )
173             {
174                 msg_Warn( p_this, "connection to %s:%d failed (%d)", psz_host,
175                           i_port, WSAGetLastError( ) );
176                 net_Close( fd );
177                 continue;
178             }
179 #else
180             if( errno != EINPROGRESS )
181             {
182                 msg_Warn( p_this, "connection to %s:%d : %s", psz_host,
183                           i_port, strerror( errno ) );
184                 net_Close( fd );
185                 continue;
186             }
187 #endif
188
189             var_Create( p_this, "ipv4-timeout",
190                         VLC_VAR_INTEGER | VLC_VAR_DOINHERIT );
191             var_Get( p_this, "ipv4-timeout", &timeout );
192             if( timeout.i_int < 0 )
193             {
194                 msg_Err( p_this, "invalid negative value for ipv4-timeout" );
195                 timeout.i_int = 0;
196             }
197             d = div( timeout.i_int, 100 );
198
199             msg_Dbg( p_this, "connection in progress" );
200             do
201             {
202                 fd_set fds;
203
204                 if( p_this->b_die )
205                 {
206                     msg_Dbg( p_this, "connection aborted" );
207                     net_Close( fd );
208                     vlc_freeaddrinfo( res );
209                     free( psz_socks );
210                     return -1;
211                 }
212
213                 /* Initialize file descriptor set */
214                 FD_ZERO( &fds );
215                 FD_SET( fd, &fds );
216
217                 /* We'll wait 0.1 second if nothing happens */
218                 tv.tv_sec = 0;
219                 tv.tv_usec = (d.quot > 0) ? 100000 : (1000 * d.rem);
220
221                 i_val = select( fd + 1, NULL, &fds, NULL, &tv );
222
223                 if( d.quot <= 0 )
224                 {
225                     msg_Dbg( p_this, "connection timed out" );
226                     net_Close( fd );
227                     fd = -1;
228                     break;
229                 }
230
231                 d.quot--;
232             }
233             while( ( i_val == 0 ) || ( ( i_val < 0 ) &&
234 #if defined( WIN32 ) || defined( UNDER_CE )
235                             ( WSAGetLastError() == WSAEWOULDBLOCK )
236 #else
237                             ( errno == EINTR )
238 #endif
239                      ) );
240
241             if( fd == -1 )
242                 continue; /* timeout */
243
244             if( i_val < 0 )
245             {
246                 msg_Warn( p_this, "connection aborted (select failed)" );
247                 net_Close( fd );
248                 continue;
249             }
250
251 #if !defined( SYS_BEOS ) && !defined( UNDER_CE )
252             if( getsockopt( fd, SOL_SOCKET, SO_ERROR, (void*)&i_val,
253                             &i_val_size ) == -1 || i_val != 0 )
254             {
255 #ifdef WIN32
256                 msg_Warn( p_this, "connection to %s:%d failed (%d)", psz_host,
257                           i_port, WSAGetLastError( ) );
258 #else
259                 msg_Warn( p_this, "connection to %s:%d : %s", psz_host,
260                           i_port, strerror( i_val ) );
261 #endif
262                 net_Close( fd );
263                 continue;
264             }
265 #endif
266         }
267         i_handle = fd; /* success! */
268     }
269     
270     vlc_freeaddrinfo( res );
271
272     if( *psz_socks && *psz_socks != ':' )
273     {
274         char *psz_user = var_CreateGetString( p_this, "socks-user" );
275         char *psz_pwd  = var_CreateGetString( p_this, "socks-pwd" );
276
277         if( SocksHandshakeTCP( p_this, i_handle, 5, psz_user, psz_pwd,
278                                psz_host, i_port ) )
279         {
280             msg_Err( p_this, "failed to use the SOCKS server" );
281             net_Close( i_handle );
282             i_handle = -1;
283         }
284
285         free( psz_user );
286         free( psz_pwd );
287     }
288     free( psz_socks );
289
290     return i_handle;
291 }
292
293
294 /*****************************************************************************
295  * __net_ListenTCP:
296  *****************************************************************************
297  * Open TCP passive "listening" socket(s)
298  * This function returns NULL in case of error.
299  *****************************************************************************/
300 int *__net_ListenTCP( vlc_object_t *p_this, const char *psz_host, int i_port )
301 {
302     struct addrinfo hints, *res, *ptr;
303     int             i_val, *pi_handles, i_size;
304
305     memset( &hints, 0, sizeof( hints ) );
306     hints.ai_socktype = SOCK_STREAM;
307     hints.ai_flags = AI_PASSIVE;
308
309     msg_Dbg( p_this, "net: listening to '%s:%d'", psz_host, i_port );
310
311     i_val = vlc_getaddrinfo( p_this, psz_host, i_port, &hints, &res );
312     if( i_val )
313     {
314         msg_Err( p_this, "cannot resolve '%s:%d' : %s", psz_host, i_port,
315                  vlc_gai_strerror( i_val ) );
316         return NULL;
317     }
318
319     pi_handles = NULL;
320     i_size = 1;
321
322     for( ptr = res; ptr != NULL; ptr = ptr->ai_next )
323     {
324         int fd, *newpi;
325
326         fd = socket( ptr->ai_family, ptr->ai_socktype, ptr->ai_protocol );
327         if( fd == -1 )
328         {
329 #if defined(WIN32) || defined(UNDER_CE)
330             msg_Warn( p_this, "cannot create socket (%i)",
331                       WSAGetLastError() );
332 #else
333             msg_Warn( p_this, "cannot create socket (%s)",
334                       strerror( errno ) );
335 #endif
336             continue;
337         }
338
339         /* Set to non-blocking */
340 #if defined( WIN32 ) || defined( UNDER_CE )
341         {
342             unsigned long i_dummy = 1;
343             if( ioctlsocket( fd, FIONBIO, &i_dummy ) != 0 )
344                 msg_Err( p_this, "cannot set socket to non-blocking mode" );
345         }
346 #else
347         if( ( ( i_val = fcntl( fd, F_GETFL, 0 ) ) < 0 ) ||
348             ( fcntl( fd, F_SETFL, i_val | O_NONBLOCK ) < 0 ) )
349             msg_Err( p_this, "cannot set socket to non-blocking mode (%s)",
350                      strerror( errno ) );
351 #endif
352
353         i_val = 1;
354         setsockopt( fd, SOL_SOCKET, SO_REUSEADDR, (void *)&i_val,
355                     sizeof( i_val ) );
356
357 #ifdef IPV6_V6ONLY
358         /*
359          * Accepts only IPv6 connections on IPv6 sockets
360          * (and open an IPv4 socket later as well if needed).
361          * Only Linux and FreeBSD can map IPv4 connections on IPv6 sockets,
362          * so this allows for more uniform handling across platforms. Besides,
363          * it makes sure that IPv4 addresses will be printed as w.x.y.z rather
364          * than ::ffff:w.x.y.z
365          */
366         if( ptr->ai_family == PF_INET6 )
367             setsockopt( fd, IPPROTO_IPV6, IPV6_V6ONLY, (void *)&i_val,
368                         sizeof( i_val ) );
369 #endif
370
371 #if defined( WIN32 ) || defined( UNDER_CE )
372 # ifdef IPV6_PROTECTION_LEVEL
373         if( ptr->ai_family == PF_INET6 )
374         {
375             i_val = PROTECTION_LEVEL_UNRESTRICTED;
376             setsockopt( fd, IPPROTO_IPV6, IPV6_PROTECTION_LEVEL, &i_val,
377                         sizeof( i_val ) );
378         }
379 # else
380 # warning You are using outdated headers for Winsock !
381 # endif
382 #endif
383
384         /* Bind the socket */
385         if( bind( fd, ptr->ai_addr, ptr->ai_addrlen ) )
386         {
387 #if defined(WIN32) || defined(UNDER_CE)
388             msg_Warn( p_this, "cannot bind socket (%i)", WSAGetLastError( ) );
389 #else
390             msg_Warn( p_this, "cannot bind socket (%s)", strerror( errno ) );
391 #endif
392             net_Close( fd );
393             continue;
394         }
395  
396         /* Listen */
397         if( listen( fd, 100 ) == -1 )
398         {
399 #if defined(WIN32) || defined(UNDER_CE)
400             msg_Err( p_this, "cannot bring socket in listening mode (%i)",
401                      WSAGetLastError());
402 #else
403             msg_Err( p_this, "cannot bring the socket in listening mode (%s)",
404                      strerror( errno ) );
405 #endif
406             net_Close( fd );
407             continue;
408         }
409
410         newpi = (int *)realloc( pi_handles, (++i_size) * sizeof( int ) );
411         if( newpi == NULL )
412         {
413             net_Close( fd );
414             break;
415         }
416         else
417         {
418             newpi[i_size - 2] = fd;
419             pi_handles = newpi;
420         }
421     }
422     
423     vlc_freeaddrinfo( res );
424
425     if( pi_handles != NULL )
426         pi_handles[i_size - 1] = -1;
427     return pi_handles;
428 }
429
430 /*****************************************************************************
431  * __net_Accept:
432  *****************************************************************************
433  * Accept a connection on a set of listening sockets and return it
434  *****************************************************************************/
435 int __net_Accept( vlc_object_t *p_this, int *pi_fd, mtime_t i_wait )
436 {
437     vlc_bool_t b_die = p_this->b_die, b_block = (i_wait < 0);
438
439     while( p_this->b_die == b_die )
440     {
441         int i_val = -1, *pi, *pi_end;
442         struct timeval timeout;
443         fd_set fds_r, fds_e;
444
445         pi = pi_fd;
446
447         /* Initialize file descriptor set */
448         FD_ZERO( &fds_r );
449         FD_ZERO( &fds_e );
450
451         for( pi = pi_fd; *pi != -1; pi++ )
452         {
453             int i_fd = *pi;
454
455             if( i_fd > i_val )
456                 i_val = i_fd;
457
458             FD_SET( i_fd, &fds_r );
459             FD_SET( i_fd, &fds_e );
460         }
461         pi_end = pi;
462
463         timeout.tv_sec = 0;
464         timeout.tv_usec = b_block ? 500000 : i_wait;
465
466         i_val = select( i_val + 1, &fds_r, NULL, &fds_e, &timeout );
467         if( ( ( i_val < 0 ) && ( errno == EINTR ) ) || i_val == 0 )
468         {
469             if( b_block )
470                 continue;
471             else
472                 return -1;
473         }
474         else if( i_val < 0 )
475         {
476 #if defined(WIN32) || defined(UNDER_CE)
477             msg_Err( p_this, "network select error (%i)", WSAGetLastError() );
478 #else
479             msg_Err( p_this, "network select error (%s)", strerror( errno ) );
480 #endif
481             return -1;
482         }
483
484         for( pi = pi_fd; *pi != -1; pi++ )
485         {
486             int i_fd = *pi;
487
488             if( !FD_ISSET( i_fd, &fds_r ) && !FD_ISSET( i_fd, &fds_e ) )
489                 continue;
490
491             i_val = accept( i_fd, NULL, 0 );
492             if( i_val < 0 )
493             {
494 #if defined(WIN32) || defined(UNDER_CE)
495                 msg_Err( p_this, "accept failed (%i)", WSAGetLastError() );
496 #else
497                 msg_Err( p_this, "accept failed (%s)", strerror( errno ) );
498 #endif
499             }
500             else
501             {
502                 /*
503                  * This round-robin trick ensures that the first sockets in
504                  * pi_fd won't prevent the last ones from getting accept'ed.
505                  */
506                 --pi_end;
507                 memmove( pi, pi + 1, pi_end - pi );
508                 *pi_end = i_fd;
509                 return i_val;
510             }
511         }
512     }
513
514     return -1;
515 }
516
517 /*****************************************************************************
518  * __net_OpenUDP:
519  *****************************************************************************
520  * Open a UDP connection and return a handle
521  *****************************************************************************/
522 int __net_OpenUDP( vlc_object_t *p_this, char *psz_bind, int i_bind,
523                    char *psz_server, int i_server )
524 {
525     vlc_value_t      val;
526     void            *private;
527
528     char            *psz_network = "";
529     network_socket_t sock;
530     module_t         *p_network;
531
532
533     /* Check if we have force ipv4 or ipv6 */
534     var_Create( p_this, "ipv4", VLC_VAR_BOOL | VLC_VAR_DOINHERIT );
535     var_Get( p_this, "ipv4", &val );
536     if( val.b_bool )
537     {
538         psz_network = "ipv4";
539     }
540
541     var_Create( p_this, "ipv6", VLC_VAR_BOOL | VLC_VAR_DOINHERIT );
542     var_Get( p_this, "ipv6", &val );
543     if( val.b_bool )
544     {
545         psz_network = "ipv6";
546     }
547     if( psz_server == NULL ) psz_server = "";
548     if( psz_bind   == NULL ) psz_bind   = "";
549
550     /* Prepare the network_socket_t structure */
551     sock.psz_bind_addr   = psz_bind;
552     sock.i_bind_port     = i_bind;
553     sock.psz_server_addr = psz_server;
554     sock.i_server_port   = i_server;
555     sock.i_ttl           = 0;
556
557     msg_Dbg( p_this, "net: connecting to '%s:%d@%s:%d'",
558              psz_server, i_server, psz_bind, i_bind );
559     private = p_this->p_private;
560     p_this->p_private = (void*)&sock;
561     if( !( p_network = module_Need( p_this, "network", psz_network, 0 ) ) )
562     {
563         msg_Dbg( p_this, "net: connection to '%s:%d@%s:%d' failed",
564                  psz_server, i_server, psz_bind, i_bind );
565         return -1;
566     }
567     module_Unneed( p_this, p_network );
568     p_this->p_private = private;
569
570     return sock.i_handle;
571 }
572
573 /*****************************************************************************
574  * __net_Close:
575  *****************************************************************************
576  * Close a network handle
577  *****************************************************************************/
578 void net_Close( int fd )
579 {
580 #ifdef UNDER_CE
581     CloseHandle( (HANDLE)fd );
582 #elif defined( WIN32 )
583     closesocket( fd );
584 #else
585     close( fd );
586 #endif
587 }
588
589 void net_ListenClose( int *pi_fd )
590 {
591     if( pi_fd != NULL )
592     {
593         int *pi;
594
595         for( pi = pi_fd; *pi != -1; pi++ )
596             net_Close( *pi );
597         free( pi_fd );
598     }
599 }
600
601 /*****************************************************************************
602  * __net_Read:
603  *****************************************************************************
604  * Read from a network socket
605  * If b_rety is true, then we repeat until we have read the right amount of
606  * data
607  *****************************************************************************/
608 int __net_Read( vlc_object_t *p_this, int fd, v_socket_t *p_vs,
609                 uint8_t *p_data, int i_data, vlc_bool_t b_retry )
610 {
611     struct timeval  timeout;
612     fd_set          fds_r, fds_e;
613     int             i_recv;
614     int             i_total = 0;
615     int             i_ret;
616     vlc_bool_t      b_die = p_this->b_die;
617
618     while( i_data > 0 )
619     {
620         do
621         {
622             if( p_this->b_die != b_die )
623             {
624                 return 0;
625             }
626
627             /* Initialize file descriptor set */
628             FD_ZERO( &fds_r );
629             FD_SET( fd, &fds_r );
630             FD_ZERO( &fds_e );
631             FD_SET( fd, &fds_e );
632
633             /* We'll wait 0.5 second if nothing happens */
634             timeout.tv_sec = 0;
635             timeout.tv_usec = 500000;
636
637         } while( (i_ret = select(fd + 1, &fds_r, NULL, &fds_e, &timeout)) == 0
638                  || ( i_ret < 0 && errno == EINTR ) );
639
640         if( i_ret < 0 )
641         {
642 #if defined(WIN32) || defined(UNDER_CE)
643             msg_Err( p_this, "network select error" );
644 #else
645             msg_Err( p_this, "network select error (%s)", strerror(errno) );
646 #endif
647             return i_total > 0 ? i_total : -1;
648         }
649
650         if( ( i_recv = (p_vs != NULL)
651               ? p_vs->pf_recv( p_vs->p_sys, p_data, i_data )
652               : recv( fd, p_data, i_data, 0 ) ) < 0 )
653         {
654 #if defined(WIN32) || defined(UNDER_CE)
655             if( WSAGetLastError() == WSAEWOULDBLOCK )
656             {
657                 /* only happens with p_vs (SSL) - not really an error */
658             }
659             else
660             /* For udp only */
661             /* On win32 recv() will fail if the datagram doesn't fit inside
662              * the passed buffer, even though the buffer will be filled with
663              * the first part of the datagram. */
664             if( WSAGetLastError() == WSAEMSGSIZE )
665             {
666                 msg_Err( p_this, "recv() failed. "
667                          "Increase the mtu size (--mtu option)" );
668                 i_total += i_data;
669             }
670             else if( WSAGetLastError() == WSAEINTR ) continue;
671             else msg_Err( p_this, "recv failed (%i)", WSAGetLastError() );
672 #else
673             /* EAGAIN only happens with p_vs (SSL) and it's not an error */
674             if( errno != EAGAIN )
675                 msg_Err( p_this, "recv failed (%s)", strerror(errno) );
676 #endif
677             return i_total > 0 ? i_total : -1;
678         }
679         else if( i_recv == 0 )
680         {
681             /* Connection closed */
682             b_retry = VLC_FALSE;
683         }
684
685         p_data += i_recv;
686         i_data -= i_recv;
687         i_total+= i_recv;
688         if( !b_retry )
689         {
690             break;
691         }
692     }
693     return i_total;
694 }
695
696 /*****************************************************************************
697  * __net_ReadNonBlock:
698  *****************************************************************************
699  * Read from a network socket, non blocking mode (with timeout)
700  *****************************************************************************/
701 int __net_ReadNonBlock( vlc_object_t *p_this, int fd, v_socket_t *p_vs,
702                         uint8_t *p_data, int i_data, mtime_t i_wait)
703 {
704     struct timeval  timeout;
705     fd_set          fds_r, fds_e;
706     int             i_recv;
707     int             i_ret;
708
709     /* Initialize file descriptor set */
710     FD_ZERO( &fds_r );
711     FD_SET( fd, &fds_r );
712     FD_ZERO( &fds_e );
713     FD_SET( fd, &fds_e );
714
715     timeout.tv_sec = 0;
716     timeout.tv_usec = i_wait;
717
718     i_ret = select(fd + 1, &fds_r, NULL, &fds_e, &timeout);
719
720     if( i_ret < 0 && errno == EINTR )
721     {
722         return 0;
723     }
724     else if( i_ret < 0 )
725     {
726 #if defined(WIN32) || defined(UNDER_CE)
727         msg_Err( p_this, "network select error" );
728 #else
729         msg_Err( p_this, "network select error (%s)", strerror(errno) );
730 #endif
731         return -1;
732     }
733     else if( i_ret == 0)
734     {
735         return 0;
736     }
737     else
738     {
739 #if !defined(UNDER_CE)
740         if( fd == 0/*STDIN_FILENO*/ ) i_recv = read( fd, p_data, i_data ); else
741 #endif
742         if( ( i_recv = (p_vs != NULL)
743               ? p_vs->pf_recv( p_vs->p_sys, p_data, i_data )
744               : recv( fd, p_data, i_data, 0 ) ) <= 0 )
745         {
746 #if defined(WIN32) || defined(UNDER_CE)
747             /* For udp only */
748             /* On win32 recv() will fail if the datagram doesn't fit inside
749              * the passed buffer, even though the buffer will be filled with
750              * the first part of the datagram. */
751             if( WSAGetLastError() == WSAEMSGSIZE )
752             {
753                 msg_Err( p_this, "recv() failed. "
754                          "Increase the mtu size (--mtu option)" );
755             }
756             else msg_Err( p_this, "recv failed (%i)", WSAGetLastError() );
757 #else
758             msg_Err( p_this, "recv failed (%s)", strerror(errno) );
759 #endif
760             return -1;
761         }
762
763         return i_recv ? i_recv : -1;  /* !i_recv -> connection closed if tcp */
764     }
765
766     /* We will never be here */
767     return -1;
768 }
769
770 /*****************************************************************************
771  * __net_Select:
772  *****************************************************************************
773  * Read from several sockets (with timeout). Takes data from the first socket
774  * that has some.
775  *****************************************************************************/
776 int __net_Select( vlc_object_t *p_this, int *pi_fd, v_socket_t **pp_vs,
777                   int i_fd, uint8_t *p_data, int i_data, mtime_t i_wait )
778 {
779     struct timeval  timeout;
780     fd_set          fds_r, fds_e;
781     int             i_recv;
782     int             i_ret;
783     int             i;
784     int             i_max_fd = 0;
785
786     /* Initialize file descriptor set */
787     FD_ZERO( &fds_r );
788     FD_ZERO( &fds_e );
789
790     for( i = 0 ; i < i_fd ; i++)
791     {
792         if( pi_fd[i] > i_max_fd ) i_max_fd = pi_fd[i];
793         FD_SET( pi_fd[i], &fds_r );
794         FD_SET( pi_fd[i], &fds_e );
795     }
796
797     timeout.tv_sec = 0;
798     timeout.tv_usec = i_wait;
799
800     i_ret = select( i_max_fd + 1, &fds_r, NULL, &fds_e, &timeout );
801
802     if( i_ret < 0 && errno == EINTR )
803     {
804         return 0;
805     }
806     else if( i_ret < 0 )
807     {
808         msg_Err( p_this, "network select error (%s)", strerror(errno) );
809         return -1;
810     }
811     else if( i_ret == 0 )
812     {
813         return 0;
814     }
815     else
816     {
817         for( i = 0 ; i < i_fd ; i++)
818         {
819             if( FD_ISSET( pi_fd[i], &fds_r ) )
820             {
821                 i_recv = ((pp_vs != NULL) && (pp_vs[i] != NULL))
822                          ? pp_vs[i]->pf_recv( pp_vs[i]->p_sys, p_data, i_data )
823                          : recv( pi_fd[i], p_data, i_data, 0 );
824                 if( i_recv <= 0 )
825                 {
826 #ifdef WIN32
827                     /* For udp only */
828                     /* On win32 recv() will fail if the datagram doesn't
829                      * fit inside the passed buffer, even though the buffer
830                      *  will be filled with the first part of the datagram. */
831                     if( WSAGetLastError() == WSAEMSGSIZE )
832                     {
833                         msg_Err( p_this, "recv() failed. "
834                              "Increase the mtu size (--mtu option)" );
835                     }
836                     else msg_Err( p_this, "recv failed (%i)",
837                                   WSAGetLastError() );
838 #else
839                      msg_Err( p_this, "recv failed (%s)", strerror(errno) );
840 #endif
841                     return VLC_EGENERIC;
842                 }
843
844                 return i_recv;
845             }
846         }
847     }
848
849     /* We will never be here */
850     return -1;
851 }
852
853
854 /* Write exact amount requested */
855 int __net_Write( vlc_object_t *p_this, int fd, v_socket_t *p_vs,
856                  uint8_t *p_data, int i_data )
857 {
858     struct timeval  timeout;
859     fd_set          fds_w, fds_e;
860     int             i_send;
861     int             i_total = 0;
862     int             i_ret;
863
864     vlc_bool_t      b_die = p_this->b_die;
865
866     while( i_data > 0 )
867     {
868         do
869         {
870             if( p_this->b_die != b_die )
871             {
872                 return 0;
873             }
874
875             /* Initialize file descriptor set */
876             FD_ZERO( &fds_w );
877             FD_SET( fd, &fds_w );
878             FD_ZERO( &fds_e );
879             FD_SET( fd, &fds_e );
880
881             /* We'll wait 0.5 second if nothing happens */
882             timeout.tv_sec = 0;
883             timeout.tv_usec = 500000;
884
885         } while( (i_ret = select(fd + 1, NULL, &fds_w, &fds_e, &timeout)) == 0
886                  || ( i_ret < 0 && errno == EINTR ) );
887
888         if( i_ret < 0 )
889         {
890 #if defined(WIN32) || defined(UNDER_CE)
891             msg_Err( p_this, "network select error" );
892 #else
893             msg_Err( p_this, "network select error (%s)", strerror(errno) );
894 #endif
895             return i_total > 0 ? i_total : -1;
896         }
897
898         if( ( i_send = (p_vs != NULL)
899                        ? p_vs->pf_send( p_vs->p_sys, p_data, i_data )
900                        : send( fd, p_data, i_data, 0 ) ) < 0 )
901         {
902             /* XXX With udp for example, it will issue a message if the host
903              * isn't listening */
904             /* msg_Err( p_this, "send failed (%s)", strerror(errno) ); */
905             return i_total > 0 ? i_total : -1;
906         }
907
908         p_data += i_send;
909         i_data -= i_send;
910         i_total+= i_send;
911     }
912     return i_total;
913 }
914
915 char *__net_Gets( vlc_object_t *p_this, int fd, v_socket_t *p_vs )
916 {
917     char *psz_line = malloc( 1024 );
918     int  i_line = 0;
919     int  i_max = 1024;
920
921
922     for( ;; )
923     {
924         if( net_Read( p_this, fd, p_vs, &psz_line[i_line], 1, VLC_TRUE ) != 1 )
925         {
926             psz_line[i_line] = '\0';
927             break;
928         }
929         i_line++;
930
931         if( psz_line[i_line-1] == '\n' )
932         {
933             psz_line[i_line] = '\0';
934             break;
935         }
936
937         if( i_line >= i_max - 1 )
938         {
939             i_max += 1024;
940             psz_line = realloc( psz_line, i_max );
941         }
942     }
943
944     if( i_line <= 0 )
945     {
946         free( psz_line );
947         return NULL;
948     }
949
950     while( i_line >= 1 &&
951            ( psz_line[i_line-1] == '\n' || psz_line[i_line-1] == '\r' ) )
952     {
953         i_line--;
954         psz_line[i_line] = '\0';
955     }
956     return psz_line;
957 }
958
959 int net_Printf( vlc_object_t *p_this, int fd, v_socket_t *p_vs,
960                 const char *psz_fmt, ... )
961 {
962     int i_ret;
963     va_list args;
964     va_start( args, psz_fmt );
965     i_ret = net_vaPrintf( p_this, fd, p_vs, psz_fmt, args );
966     va_end( args );
967
968     return i_ret;
969 }
970
971 int __net_vaPrintf( vlc_object_t *p_this, int fd, v_socket_t *p_vs,
972                     const char *psz_fmt, va_list args )
973 {
974     char    *psz;
975     int     i_size, i_ret;
976
977     vasprintf( &psz, psz_fmt, args );
978     i_size = strlen( psz );
979     i_ret = __net_Write( p_this, fd, p_vs, psz, i_size ) < i_size ? -1 : i_size;
980     free( psz );
981
982     return i_ret;
983 }
984
985
986
987 /*****************************************************************************
988  * SocksNegociate:
989  *****************************************************************************
990  * Negociate authentication with a SOCKS server.
991  *****************************************************************************/
992 static int SocksNegociate( vlc_object_t *p_obj,
993                            int fd, int i_socks_version,
994                            char *psz_socks_user,
995                            char *psz_socks_passwd )
996 {
997     uint8_t buffer[128+2*256];
998     int i_len;
999     vlc_bool_t b_auth = VLC_FALSE;
1000
1001     if( i_socks_version != 5 )
1002         return VLC_SUCCESS;
1003
1004     /* We negociate authentication */
1005
1006     if( psz_socks_user && psz_socks_passwd &&
1007         *psz_socks_user && *psz_socks_passwd )
1008         b_auth = VLC_TRUE;
1009
1010     buffer[0] = i_socks_version;    /* SOCKS version */
1011     if( b_auth )
1012     {
1013         buffer[1] = 2;                  /* Number of methods */
1014         buffer[2] = 0x00;               /* - No auth required */
1015         buffer[3] = 0x02;               /* - USer/Password */
1016         i_len = 4;
1017     }
1018     else
1019     {
1020         buffer[1] = 1;                  /* Number of methods */
1021         buffer[2] = 0x00;               /* - No auth required */
1022         i_len = 3;
1023     }
1024     
1025     if( net_Write( p_obj, fd, NULL, buffer, i_len ) != i_len )
1026         return VLC_EGENERIC;
1027     if( net_Read( p_obj, fd, NULL, buffer, 2, VLC_TRUE ) != 2 )
1028         return VLC_EGENERIC;
1029
1030     msg_Dbg( p_obj, "socks: v=%d method=%x", buffer[0], buffer[1] );
1031
1032     if( buffer[1] == 0x00 )
1033     {
1034         msg_Dbg( p_obj, "socks: no authentication required" );
1035     }
1036     else if( buffer[1] == 0x02 )
1037     {
1038         int i_len1 = __MIN( strlen(psz_socks_user), 255 );
1039         int i_len2 = __MIN( strlen(psz_socks_passwd), 255 );
1040         msg_Dbg( p_obj, "socks: username/password authentication" );
1041
1042         /* XXX: we don't support user/pwd > 255 (truncated)*/
1043         buffer[0] = i_socks_version;        /* Version */
1044         buffer[1] = i_len1;                 /* User length */
1045         memcpy( &buffer[2], psz_socks_user, i_len1 );
1046         buffer[2+i_len1] = i_len2;          /* Password length */
1047         memcpy( &buffer[2+i_len1+1], psz_socks_passwd, i_len2 );
1048
1049         i_len = 3 + i_len1 + i_len2;
1050
1051         if( net_Write( p_obj, fd, NULL, buffer, i_len ) != i_len )
1052             return VLC_EGENERIC;
1053
1054         if( net_Read( p_obj, fd, NULL, buffer, 2, VLC_TRUE ) != 2 )
1055             return VLC_EGENERIC;
1056
1057         msg_Dbg( p_obj, "socks: v=%d status=%x", buffer[0], buffer[1] );
1058         if( buffer[1] != 0x00 )
1059         {
1060             msg_Err( p_obj, "socks: authentication rejected" );
1061             return VLC_EGENERIC;
1062         }
1063     }
1064     else
1065     {
1066         if( b_auth )
1067             msg_Err( p_obj, "socks: unsupported authentication method %x",
1068                      buffer[0] );
1069         else
1070             msg_Err( p_obj, "socks: authentification needed" );
1071         return VLC_EGENERIC;
1072     }
1073
1074     return VLC_SUCCESS;
1075 }
1076
1077 /*****************************************************************************
1078  * SocksHandshakeTCP:
1079  *****************************************************************************
1080  * Open a TCP connection using a SOCKS server and return a handle (RFC 1928)
1081  *****************************************************************************/
1082 static int SocksHandshakeTCP( vlc_object_t *p_obj,
1083                               int fd,
1084                               int i_socks_version,
1085                               char *psz_socks_user, char *psz_socks_passwd,
1086                               const char *psz_host, int i_port )
1087 {
1088     uint8_t buffer[128+2*256];
1089
1090     if( i_socks_version != 4 && i_socks_version != 5 )
1091     {
1092         msg_Warn( p_obj, "invalid socks protocol version %d", i_socks_version );
1093         i_socks_version = 5;
1094     }
1095
1096     if( i_socks_version == 5 && 
1097         SocksNegociate( p_obj, fd, i_socks_version,
1098                         psz_socks_user, psz_socks_passwd ) )
1099         return VLC_EGENERIC;
1100
1101     if( i_socks_version == 4 )
1102     {
1103         struct addrinfo hints = { 0 }, *p_res;
1104
1105         /* v4 only support ipv4 */
1106         hints.ai_family = PF_INET;
1107         if( vlc_getaddrinfo( p_obj, psz_host, 0, &hints, &p_res ) )
1108             return VLC_EGENERIC;
1109
1110         buffer[0] = i_socks_version;
1111         buffer[1] = 0x01;               /* CONNECT */
1112         SetWBE( &buffer[2], i_port );   /* Port */
1113         memcpy( &buffer[4],             /* Address */
1114                 &((struct sockaddr_in *)(p_res->ai_addr))->sin_addr, 4 );
1115         vlc_freeaddrinfo( p_res );
1116
1117         buffer[8] = 0;                  /* Empty user id */
1118
1119         if( net_Write( p_obj, fd, NULL, buffer, 9 ) != 9 )
1120             return VLC_EGENERIC;
1121         if( net_Read( p_obj, fd, NULL, buffer, 8, VLC_TRUE ) != 8 )
1122             return VLC_EGENERIC;
1123
1124         msg_Dbg( p_obj, "socks: v=%d cd=%d",
1125                  buffer[0], buffer[1] );
1126
1127         if( buffer[1] != 90 )
1128             return VLC_EGENERIC;
1129     }
1130     else if( i_socks_version == 5 )
1131     {
1132         int i_hlen = __MIN(strlen( psz_host ), 255);
1133         int i_len;
1134
1135         buffer[0] = i_socks_version;    /* Version */
1136         buffer[1] = 0x01;               /* Cmd: connect */
1137         buffer[2] = 0x00;               /* Reserved */
1138         buffer[3] = 3;                  /* ATYP: for now domainname */
1139
1140         buffer[4] = i_hlen;
1141         memcpy( &buffer[5], psz_host, i_hlen );
1142         SetWBE( &buffer[5+i_hlen], i_port );
1143
1144         i_len = 5 + i_hlen + 2;
1145
1146
1147         if( net_Write( p_obj, fd, NULL, buffer, i_len ) != i_len )
1148             return VLC_EGENERIC;
1149
1150         /* Read the header */
1151         if( net_Read( p_obj, fd, NULL, buffer, 5, VLC_TRUE ) != 5 )
1152             return VLC_EGENERIC;
1153
1154         msg_Dbg( p_obj, "socks: v=%d rep=%d atyp=%d",
1155                  buffer[0], buffer[1], buffer[3] );
1156
1157         if( buffer[1] != 0x00 )
1158         {
1159             msg_Err( p_obj, "socks: CONNECT request failed\n" );
1160             return VLC_EGENERIC;
1161         }
1162
1163         /* Read the remaining bytes */
1164         if( buffer[3] == 0x01 )
1165             i_len = 4-1 + 2;
1166         else if( buffer[3] == 0x03 )
1167             i_len = buffer[4] + 2;
1168         else if( buffer[3] == 0x04 )
1169             i_len = 16-1+2;
1170         else 
1171             return VLC_EGENERIC;
1172
1173         if( net_Read( p_obj, fd, NULL, buffer, i_len, VLC_TRUE ) != i_len )
1174             return VLC_EGENERIC;
1175     }
1176
1177     return VLC_SUCCESS;
1178 }
1179
1180 /*****************************************************************************
1181  * net_StopRecv/Send
1182  *****************************************************************************
1183  * Wrappers for shutdown()
1184  *****************************************************************************/
1185 int net_StopRecv( int fd )
1186 {
1187 #if defined (SHUT_RD)
1188     /* the standard way */
1189     return shutdown( fd, SHUT_RD );
1190 #elif defined (SD_RECEIVE)
1191     /* the Microsoft seemingly-purposedly-different-for-the-sake-of-it way */
1192     return shutdown( fd, SD_RECEIVE );
1193 #else
1194 # warning FIXME: implement shutdown on your platform!
1195     return -1;
1196 #endif
1197 }
1198
1199 int net_StopSend( int fd )
1200 {
1201 #if defined (SHUT_WR)
1202     /* the standard way */
1203     return shutdown( fd, SHUT_WR );
1204 #elif defined (SD_SEND)
1205     /* the Microsoft seemingly-purposedly-different-for-the-sake-of-it way */
1206     return shutdown( fd, SD_SEND );
1207 #else
1208 # warning FIXME: implement shutdown on your platform!
1209     return -1;
1210 #endif
1211 }
1212
1213 /*****************************************************************************
1214  * __net_CheckIP
1215  *****************************************************************************
1216  * Check that a given IP is within a set of IP/netmask.
1217  *****************************************************************************/
1218 int __net_CheckIP( vlc_object_t *p_this, char *psz_ip, char **ppsz_hosts,
1219                    int i_hosts )
1220 {
1221     struct in_addr ip;
1222     int i;
1223
1224     if( (ip.s_addr = inet_addr( psz_ip )) == INADDR_NONE )
1225     {
1226         return VLC_EGENERIC;
1227     }
1228
1229     for( i = 0; i < i_hosts; i++ )
1230     {
1231         struct in_addr base, mask;
1232         char *psz_host = strdup( ppsz_hosts[i] );
1233         char *p = strchr( psz_host, '/' );
1234
1235         if( p != NULL )
1236         {
1237             int i_mask;
1238             *p++ = '\0';
1239             i_mask = atoi(p);
1240             if( i_mask < 0 || i_mask > 32 )
1241             {
1242                 msg_Err( p_this, "invalid netmask %s", p );
1243                 mask.s_addr = INADDR_NONE;
1244             }
1245             else if( i_mask == 0 )
1246                 mask.s_addr = INADDR_ANY;
1247             else
1248                 mask.s_addr = htonl( ntohl(INADDR_NONE) << (32 - i_mask) );
1249         }
1250         else
1251             mask.s_addr = INADDR_NONE;
1252
1253         if( (base.s_addr = inet_addr( psz_host )) == INADDR_NONE )
1254         {
1255             msg_Err( p_this, "invalid base address %s", psz_host );
1256             free( psz_host );
1257             continue;
1258         }
1259         free( psz_host );
1260
1261         if( !((ip.s_addr ^ base.s_addr) & mask.s_addr) )
1262             return VLC_TRUE;
1263     }
1264
1265     return VLC_FALSE;
1266 }
1267