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