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