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