]> git.sesse.net Git - vlc/blob - src/network/io.c
More cleanup
[vlc] / src / network / io.c
1 /*****************************************************************************
2  * io.c: network I/O functions
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., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, 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 int net_Socket( vlc_object_t *p_this, int i_family, int i_socktype,
53                 int i_protocol )
54 {
55     int fd, i_val;
56
57     fd = socket( i_family, i_socktype, i_protocol );
58     if( fd == -1 )
59     {
60 #if defined(WIN32) || defined(UNDER_CE)
61         if( WSAGetLastError ( ) != WSAEAFNOSUPPORT )
62 #else
63         if( errno != EAFNOSUPPORT )
64 #endif
65             msg_Warn( p_this, "cannot create socket: %s",
66                       net_strerror(net_errno) );
67         return -1;
68     }
69
70 #if defined( WIN32 ) || defined( UNDER_CE )
71     {
72         unsigned long i_dummy = 1;
73         if( ioctlsocket( fd, FIONBIO, &i_dummy ) != 0 )
74             msg_Err( p_this, "cannot set socket to non-blocking mode" );
75     }
76 #else
77     if( fd >= FD_SETSIZE )
78     {
79         /* We don't want to overflow select() fd_set */
80         msg_Err( p_this, "cannot create socket (too many already in use)" );
81         net_Close( fd );
82         return -1;
83     }
84
85     fcntl( fd, F_SETFD, FD_CLOEXEC );
86     i_val = fcntl( fd, F_GETFL, 0 );
87     fcntl( fd, F_SETFL, ((i_val != -1) ? i_val : 0) | O_NONBLOCK );
88 #endif
89
90     i_val = 1;
91     setsockopt( fd, SOL_SOCKET, SO_REUSEADDR, (void *)&i_val,
92                 sizeof( i_val ) );
93
94 #ifdef IPV6_V6ONLY
95     /*
96      * Accepts only IPv6 connections on IPv6 sockets
97      * (and open an IPv4 socket later as well if needed).
98      * Only Linux and FreeBSD can map IPv4 connections on IPv6 sockets,
99      * so this allows for more uniform handling across platforms. Besides,
100      * it makes sure that IPv4 addresses will be printed as w.x.y.z rather
101      * than ::ffff:w.x.y.z
102      */
103     if( i_family == AF_INET6 )
104         setsockopt( fd, IPPROTO_IPV6, IPV6_V6ONLY, (void *)&i_val,
105                     sizeof( i_val ) );
106 #endif
107
108 #if defined( WIN32 ) || defined( UNDER_CE )
109 # ifndef IPV6_PROTECTION_LEVEL
110 #  define IPV6_PROTECTION_LEVEL 23
111 # endif
112     if( i_family == AF_INET6 )
113     {
114         i_val = 30 /*PROTECTION_LEVEL_UNRESTRICTED*/;
115         setsockopt( fd, IPPROTO_IPV6, IPV6_PROTECTION_LEVEL,
116                    (const char*)&i_val, sizeof( i_val ) );
117     }
118 #endif
119     return fd;
120 }
121
122
123 /*****************************************************************************
124  * __net_Close:
125  *****************************************************************************
126  * Close a network handle
127  *****************************************************************************/
128 void net_Close( int fd )
129 {
130 #ifdef UNDER_CE
131     CloseHandle( (HANDLE)fd );
132 #elif defined( WIN32 )
133     closesocket( fd );
134 #else
135     close( fd );
136 #endif
137 }
138
139 /*****************************************************************************
140  * __net_Read:
141  *****************************************************************************
142  * Read from a network socket
143  * If b_retry is true, then we repeat until we have read the right amount of
144  * data
145  *****************************************************************************/
146 int __net_Read( vlc_object_t *p_this, int fd, v_socket_t *p_vs,
147                 uint8_t *p_data, int i_data, vlc_bool_t b_retry )
148 {
149     struct timeval  timeout;
150     fd_set          fds_r, fds_e;
151     int             i_recv;
152     int             i_total = 0;
153     int             i_ret;
154     vlc_bool_t      b_die = p_this->b_die;
155
156     while( i_data > 0 )
157     {
158         do
159         {
160             if( p_this->b_die != b_die )
161             {
162                 return 0;
163             }
164
165             /* Initialize file descriptor set */
166             FD_ZERO( &fds_r );
167             FD_SET( fd, &fds_r );
168             FD_ZERO( &fds_e );
169             FD_SET( fd, &fds_e );
170
171             /* We'll wait 0.5 second if nothing happens */
172             timeout.tv_sec = 0;
173             timeout.tv_usec = 500000;
174
175         } while( (i_ret = select(fd + 1, &fds_r, NULL, &fds_e, &timeout)) == 0
176                  || ( i_ret < 0 && errno == EINTR ) );
177
178         if( i_ret < 0 )
179         {
180             msg_Err( p_this, "network select error (%s)",
181                      net_strerror(net_errno) );
182             return i_total > 0 ? i_total : -1;
183         }
184
185         if( ( i_recv = (p_vs != NULL)
186               ? p_vs->pf_recv( p_vs->p_sys, p_data, i_data )
187               : recv( fd, p_data, i_data, 0 ) ) < 0 )
188         {
189 #if defined(WIN32) || defined(UNDER_CE)
190             if( WSAGetLastError() == WSAEWOULDBLOCK )
191             {
192                 /* only happens with p_vs (SSL) - not really an error */
193             }
194             else
195             /* For udp only */
196             /* On win32 recv() will fail if the datagram doesn't fit inside
197              * the passed buffer, even though the buffer will be filled with
198              * the first part of the datagram. */
199             if( WSAGetLastError() == WSAEMSGSIZE )
200             {
201                 msg_Err( p_this, "recv() failed. "
202                          "Increase the mtu size (--mtu option)" );
203                 i_total += i_data;
204             }
205             else if( WSAGetLastError() == WSAEINTR ) continue;
206 #else
207             /* EAGAIN only happens with p_vs (TLS) and it's not an error */
208             if( errno != EAGAIN )
209 #endif
210                 msg_Err( p_this, "recv failed: %s", net_strerror(net_errno) );
211             return i_total > 0 ? i_total : -1;
212         }
213         else if( i_recv == 0 )
214         {
215             /* Connection closed */
216             b_retry = VLC_FALSE;
217         }
218
219         p_data += i_recv;
220         i_data -= i_recv;
221         i_total+= i_recv;
222         if( !b_retry )
223         {
224             break;
225         }
226     }
227     return i_total;
228 }
229
230 /*****************************************************************************
231  * __net_ReadNonBlock:
232  *****************************************************************************
233  * Read from a network socket, non blocking mode (with timeout)
234  *****************************************************************************/
235 int __net_ReadNonBlock( vlc_object_t *p_this, int fd, v_socket_t *p_vs,
236                         uint8_t *p_data, int i_data, mtime_t i_wait)
237 {
238     struct timeval  timeout;
239     fd_set          fds_r, fds_e;
240     int             i_recv;
241     int             i_ret;
242
243     /* Initialize file descriptor set */
244     FD_ZERO( &fds_r );
245     FD_SET( fd, &fds_r );
246     FD_ZERO( &fds_e );
247     FD_SET( fd, &fds_e );
248
249     timeout.tv_sec = 0;
250     timeout.tv_usec = i_wait;
251
252     i_ret = select(fd + 1, &fds_r, NULL, &fds_e, &timeout);
253
254     if( i_ret < 0 && errno == EINTR )
255     {
256         return 0;
257     }
258     else if( i_ret < 0 )
259     {
260         msg_Err( p_this, "network error: %s", net_strerror(net_errno) );
261         return -1;
262     }
263     else if( i_ret == 0)
264     {
265         return 0;
266     }
267     else
268     {
269 #if !defined(UNDER_CE)
270         if( fd == 0/*STDIN_FILENO*/ ) i_recv = read( fd, p_data, i_data ); else
271 #endif
272         if( ( i_recv = (p_vs != NULL)
273               ? p_vs->pf_recv( p_vs->p_sys, p_data, i_data )
274               : recv( fd, p_data, i_data, 0 ) ) < 0 )
275         {
276 #if defined(WIN32) || defined(UNDER_CE)
277             /* For udp only */
278             /* On win32 recv() will fail if the datagram doesn't fit inside
279              * the passed buffer, even though the buffer will be filled with
280              * the first part of the datagram. */
281             if( WSAGetLastError() == WSAEMSGSIZE )
282             {
283                 msg_Err( p_this, "recv() failed. "
284                          "Increase the mtu size (--mtu option)" );
285             }
286             else
287 #endif
288             msg_Err( p_this, "recv failed: %s", net_strerror(net_errno) );
289             return -1;
290         }
291
292         return i_recv ? i_recv : -1;  /* !i_recv -> connection closed if tcp */
293     }
294
295     /* We will never be here */
296     return -1;
297 }
298
299 /*****************************************************************************
300  * __net_Select:
301  *****************************************************************************
302  * Read from several sockets (with timeout). Takes data from the first socket
303  * that has some.
304  *****************************************************************************/
305 int __net_Select( vlc_object_t *p_this, int *pi_fd, v_socket_t **pp_vs,
306                   int i_fd, uint8_t *p_data, int i_data, mtime_t i_wait )
307 {
308     struct timeval  timeout;
309     fd_set          fds_r, fds_e;
310     int             i_recv;
311     int             i_ret;
312     int             i;
313     int             i_max_fd = 0;
314
315     /* Initialize file descriptor set */
316     FD_ZERO( &fds_r );
317     FD_ZERO( &fds_e );
318
319     for( i = 0 ; i < i_fd ; i++)
320     {
321         if( pi_fd[i] > i_max_fd ) i_max_fd = pi_fd[i];
322         FD_SET( pi_fd[i], &fds_r );
323         FD_SET( pi_fd[i], &fds_e );
324     }
325
326     timeout.tv_sec = 0;
327     timeout.tv_usec = i_wait;
328
329     i_ret = select( i_max_fd + 1, &fds_r, NULL, &fds_e, &timeout );
330
331     if( i_ret < 0 && errno == EINTR )
332     {
333         return 0;
334     }
335     else if( i_ret < 0 )
336     {
337         msg_Err( p_this, "network selection error: %s", net_strerror(net_errno) );
338         return -1;
339     }
340     else if( i_ret == 0 )
341     {
342         return 0;
343     }
344     else
345     {
346         for( i = 0 ; i < i_fd ; i++)
347         {
348             if( FD_ISSET( pi_fd[i], &fds_r ) )
349             {
350                 i_recv = ((pp_vs != NULL) && (pp_vs[i] != NULL))
351                          ? pp_vs[i]->pf_recv( pp_vs[i]->p_sys, p_data, i_data )
352                          : recv( pi_fd[i], p_data, i_data, 0 );
353                 if( i_recv < 0 )
354                 {
355 #ifdef WIN32
356                     /* For udp only */
357                     /* On win32 recv() will fail if the datagram doesn't
358                      * fit inside the passed buffer, even though the buffer
359                      *  will be filled with the first part of the datagram. */
360                     if( WSAGetLastError() == WSAEMSGSIZE )
361                     {
362                         msg_Err( p_this, "recv() failed. "
363                              "Increase the mtu size (--mtu option)" );
364                     }
365                     else msg_Err( p_this, "recv failed (%i)",
366                                   WSAGetLastError() );
367 #else
368                     msg_Err( p_this, "recv failed (%s)", strerror(errno) );
369 #endif
370                     return VLC_EGENERIC;
371                 }
372
373                 return i_recv;
374             }
375         }
376     }
377
378     /* We will never be here */
379     return -1;
380 }
381
382
383 /* Write exact amount requested */
384 int __net_Write( vlc_object_t *p_this, int fd, v_socket_t *p_vs,
385                  const uint8_t *p_data, int i_data )
386 {
387     struct timeval  timeout;
388     fd_set          fds_w, fds_e;
389     int             i_send;
390     int             i_total = 0;
391     int             i_ret;
392
393     vlc_bool_t      b_die = p_this->b_die;
394
395     while( i_data > 0 )
396     {
397         do
398         {
399             if( p_this->b_die != b_die )
400             {
401                 return 0;
402             }
403
404             /* Initialize file descriptor set */
405             FD_ZERO( &fds_w );
406             FD_SET( fd, &fds_w );
407             FD_ZERO( &fds_e );
408             FD_SET( fd, &fds_e );
409
410             /* We'll wait 0.5 second if nothing happens */
411             timeout.tv_sec = 0;
412             timeout.tv_usec = 500000;
413
414         } while( (i_ret = select(fd + 1, NULL, &fds_w, &fds_e, &timeout)) == 0
415                  || ( i_ret < 0 && errno == EINTR ) );
416
417         if( i_ret < 0 )
418         {
419 #if defined(WIN32) || defined(UNDER_CE)
420             msg_Err( p_this, "network selection error (%d)", WSAGetLastError() );
421 #else
422             msg_Err( p_this, "network selection error (%s)", strerror(errno) );
423 #endif
424             return i_total > 0 ? i_total : -1;
425         }
426
427         if( ( i_send = (p_vs != NULL)
428                        ? p_vs->pf_send( p_vs->p_sys, p_data, i_data )
429                        : send( fd, p_data, i_data, 0 ) ) < 0 )
430         {
431             /* XXX With udp for example, it will issue a message if the host
432              * isn't listening */
433             /* msg_Err( p_this, "send failed (%s)", strerror(errno) ); */
434             return i_total > 0 ? i_total : -1;
435         }
436
437         p_data += i_send;
438         i_data -= i_send;
439         i_total+= i_send;
440     }
441     return i_total;
442 }
443
444 char *__net_Gets( vlc_object_t *p_this, int fd, v_socket_t *p_vs )
445 {
446     char *psz_line = NULL, *ptr = NULL;
447     size_t  i_line = 0, i_max = 0;
448
449
450     for( ;; )
451     {
452         if( i_line == i_max )
453         {
454             i_max += 1024;
455             psz_line = realloc( psz_line, i_max );
456             ptr = psz_line + i_line;
457         }
458
459         if( net_Read( p_this, fd, p_vs, (uint8_t *)ptr, 1, VLC_TRUE ) != 1 )
460         {
461             if( i_line == 0 )
462             {
463                 free( psz_line );
464                 return NULL;
465             }
466             break;
467         }
468
469         if ( *ptr == '\n' )
470             break;
471
472         i_line++;
473         ptr++;
474     }
475
476     *ptr-- = '\0';
477
478     if( ( ptr >= psz_line ) && ( *ptr == '\r' ) )
479         *ptr = '\0';
480
481     return psz_line;
482 }
483
484 int net_Printf( vlc_object_t *p_this, int fd, v_socket_t *p_vs,
485                 const char *psz_fmt, ... )
486 {
487     int i_ret;
488     va_list args;
489     va_start( args, psz_fmt );
490     i_ret = net_vaPrintf( p_this, fd, p_vs, psz_fmt, args );
491     va_end( args );
492
493     return i_ret;
494 }
495
496 int __net_vaPrintf( vlc_object_t *p_this, int fd, v_socket_t *p_vs,
497                     const char *psz_fmt, va_list args )
498 {
499     char    *psz;
500     int     i_size, i_ret;
501
502     i_size = vasprintf( &psz, psz_fmt, args );
503     i_ret = __net_Write( p_this, fd, p_vs, (uint8_t *)psz, i_size ) < i_size
504         ? -1 : i_size;
505     free( psz );
506
507     return i_ret;
508 }
509
510
511 /*****************************************************************************
512  * inet_pton replacement for obsolete and/or crap operating systems
513  *****************************************************************************/
514 #ifndef HAVE_INET_PTON
515 int inet_pton(int af, const char *src, void *dst)
516 {
517 # ifdef WIN32
518     /* As we already know, Microsoft always go its own way, so even if they do
519      * provide IPv6, they don't provide the API. */
520     struct sockaddr_storage addr;
521     int len = sizeof( addr );
522
523     /* Damn it, they didn't even put LPCSTR for the firs parameter!!! */
524 #ifdef UNICODE
525     wchar_t *workaround_for_ill_designed_api =
526         malloc( MAX_PATH * sizeof(wchar_t) );
527     mbstowcs( workaround_for_ill_designed_api, src, MAX_PATH );
528     workaround_for_ill_designed_api[MAX_PATH-1] = 0;
529 #else
530     char *workaround_for_ill_designed_api = strdup( src );
531 #endif
532
533     if( !WSAStringToAddress( workaround_for_ill_designed_api, af, NULL,
534                              (LPSOCKADDR)&addr, &len ) )
535     {
536         free( workaround_for_ill_designed_api );
537         return -1;
538     }
539     free( workaround_for_ill_designed_api );
540
541     switch( af )
542     {
543         case AF_INET6:
544             memcpy( dst, &((struct sockaddr_in6 *)&addr)->sin6_addr, 16 );
545             break;
546
547         case AF_INET:
548             memcpy( dst, &((struct sockaddr_in *)&addr)->sin_addr, 4 );
549             break;
550
551         default:
552             WSASetLastError( WSAEAFNOSUPPORT );
553             return -1;
554     }
555 # else
556     /* Assume IPv6 is not supported. */
557     /* Would be safer and more simpler to use inet_aton() but it is most
558      * likely not provided either. */
559     uint32_t ipv4;
560
561     if( af != AF_INET )
562     {
563         errno = EAFNOSUPPORT;
564         return -1;
565     }
566
567     ipv4 = inet_addr( src );
568     if( ipv4 == INADDR_NONE )
569         return -1;
570
571     memcpy( dst, &ipv4, 4 );
572 # endif /* WIN32 */
573     return 0;
574 }
575 #endif /* HAVE_INET_PTON */