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