]> git.sesse.net Git - vlc/blob - src/network/io.c
Ahem: (v)asprintf requires stdio.h; strndup requires string.h
[vlc] / src / network / io.c
1 /*****************************************************************************
2  * io.c: network I/O functions
3  *****************************************************************************
4  * Copyright (C) 2004-2005 the VideoLAN team
5  * Copyright © 2005-2006 Rémi Denis-Courmont
6  * $Id$
7  *
8  * Authors: Laurent Aimar <fenrir@videolan.org>
9  *          Rémi Denis-Courmont <rem # videolan.org>
10  *
11  * This program is free software; you can redistribute it and/or modify
12  * it under the terms of the GNU General Public License as published by
13  * the Free Software Foundation; either version 2 of the License, or
14  * (at your option) any later version.
15  *
16  * This program is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19  * GNU General Public License for more details.
20  *
21  * You should have received a copy of the GNU General Public License
22  * along with this program; if not, write to the Free Software
23  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
24  *****************************************************************************/
25
26 /*****************************************************************************
27  * Preamble
28  *****************************************************************************/
29
30 #include <vlc/vlc.h>
31
32 #include <stdlib.h>
33 #include <stdio.h>
34
35 #include <errno.h>
36 #include <assert.h>
37
38 #ifdef HAVE_FCNTL_H
39 #   include <fcntl.h>
40 #endif
41 #ifdef HAVE_SYS_TIME_H
42 #    include <sys/time.h>
43 #endif
44 #ifdef HAVE_UNISTD_H
45 #   include <unistd.h>
46 #endif
47 #ifdef HAVE_POLL
48 #   include <poll.h>
49 #endif
50
51 #include "network.h"
52
53 #ifndef INADDR_ANY
54 #   define INADDR_ANY  0x00000000
55 #endif
56 #ifndef INADDR_NONE
57 #   define INADDR_NONE 0xFFFFFFFF
58 #endif
59
60 int net_Socket( vlc_object_t *p_this, int i_family, int i_socktype,
61                 int i_protocol )
62 {
63     int fd, i_val;
64
65     fd = socket( i_family, i_socktype, i_protocol );
66     if( fd == -1 )
67     {
68 #if defined(WIN32) || defined(UNDER_CE)
69         if( WSAGetLastError ( ) != WSAEAFNOSUPPORT )
70 #else
71         if( errno != EAFNOSUPPORT )
72 #endif
73             msg_Warn( p_this, "cannot create socket: %s",
74                       net_strerror(net_errno) );
75         return -1;
76     }
77
78 #if defined( WIN32 ) || defined( UNDER_CE )
79     {
80         unsigned long i_dummy = 1;
81         if( ioctlsocket( fd, FIONBIO, &i_dummy ) != 0 )
82             msg_Err( p_this, "cannot set socket to non-blocking mode" );
83     }
84 #else
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 static int
141 net_ReadInner( vlc_object_t *restrict p_this, unsigned fdc, const int *fdv,
142                const v_socket_t *const *restrict vsv,
143                uint8_t *restrict p_buf, size_t i_buflen,
144                int wait_ms, vlc_bool_t waitall )
145 {
146     size_t i_total = 0;
147
148     do
149     {
150         unsigned int i;
151         int n, delay_ms;
152 #ifdef HAVE_POLL
153         struct pollfd ufd[fdc];
154 #else
155         int maxfd = -1;
156         fd_set set;
157 #endif
158
159         if( i_buflen == 0 )
160             return i_total; // output buffer full
161
162         delay_ms = 500;
163         if( (wait_ms != -1) && (wait_ms < 500) )
164             delay_ms = wait_ms;
165
166 #ifdef HAVE_POLL
167         memset(ufd, 0, sizeof (ufd) );
168
169         for( i = 0; i < fdc; i++ )
170         {
171             ufd[i].fd = fdv[i];
172             ufd[i].events = POLLIN;
173         }
174
175         if( p_this->b_die )
176             return i_total;
177
178         n = poll( ufd, fdc, (wait_ms == -1) ? -1 : delay_ms );
179         if( n == -1 )
180             goto error;
181
182         assert( (unsigned int)n <= fdc );
183
184         for( i = 0; n > 0; i++ )
185         {
186             if( (i_total > 0) && (ufd[i].revents & POLLERR) )
187                 return i_total; // error will be dequeued on next run
188
189             if( ufd[i].revents )
190             {
191                 fdc = 1;
192                 fdv += i;
193                 vsv += i;
194                 n--;
195                 goto receive;
196             }
197         }
198 #else
199         FD_ZERO (&set);
200
201         for( i = 0; i < fdc; i++ )
202         {
203 #if !defined(WIN32) && !defined(UNDER_CE)
204             if( fdv[i] >= FD_SETSIZE )
205             {
206                 /* We don't want to overflow select() fd_set */
207                 msg_Err( p_this, "select set overflow" );
208                 return -1;
209             }
210 #endif
211             FD_SET( fdv[i], &set );
212             if( fdv[i] > maxfd )
213                 maxfd = fdv[i];
214         }
215
216         n = select( maxfd + 1, &set, NULL, NULL,
217                     (wait_ms == -1) ? NULL
218                                   : &(struct timeval){ 0, delay_ms * 1000 } );
219         if( n == -1 )
220             goto error;
221
222         for( i = 0; n > 0; i++ )
223             if( FD_ISSET (fdv[i], &set) )
224             {
225                 fdc = 1;
226                 fdv += i;
227                 vsv += i;
228                 n--;
229                 goto receive;
230             }
231 #endif
232
233         continue;
234
235 receive:
236         if( (*vsv) != NULL )
237         {
238             n = (*vsv)->pf_recv( (*vsv)->p_sys, p_buf, i_buflen );
239         }
240         else
241         {
242 #if defined(WIN32) || defined(UNDER_CE)
243             n = recv( *fdv, p_buf, i_buflen, 0 );
244 #else
245             n = read( *fdv, p_buf, i_buflen );
246 #endif
247         }
248
249         if( n == -1 )
250         {
251 #if defined(WIN32) || defined(UNDER_CE)
252             switch( WSAGetLastError() )
253             {
254                 case WSAEWOULDBLOCK:
255                 /* only happens with vs != NULL (SSL) - not really an error */
256                     continue;
257
258                 case WSAEMSGSIZE:
259                 /* For UDP only */
260                 /* On Win32, recv() fails if the datagram doesn't fit inside
261                  * the passed buffer, even though the buffer will be filled
262                  * with the first part of the datagram. */
263                     msg_Err( p_this, "Receive error: "
264                                      "Increase the mtu size (--mtu option)" );
265                     i_total += i_buflen;
266                     return i_total;
267             }
268 #else
269             if( errno == EAGAIN ) /* spurious wake-up (sucks if fdc > 1) */
270                 continue;
271 #endif
272             goto error;
273         }
274
275         i_total += n;
276         p_buf += n;
277         i_buflen -= n;
278
279         if( wait_ms == -1 )
280         {
281             if( !waitall )
282                 return i_total;
283         }
284         else
285         {
286             wait_ms -= delay_ms;
287         }
288     }
289     while( wait_ms );
290
291     return i_total; // timeout
292
293 error:
294     msg_Err( p_this, "Read error: %s", net_strerror (net_errno) );
295     return i_total ? (int)i_total : -1;
296 }
297
298
299 /*****************************************************************************
300  * __net_Read:
301  *****************************************************************************
302  * Read from a network socket
303  * If b_retry is true, then we repeat until we have read the right amount of
304  * data
305  *****************************************************************************/
306 int __net_Read( vlc_object_t *restrict p_this, int fd,
307                 const v_socket_t *restrict p_vs,
308                 uint8_t *restrict p_data, int i_data, vlc_bool_t b_retry )
309 {
310     return net_ReadInner( p_this, 1, &(int){ fd },
311                           &(const v_socket_t *){ p_vs },
312                           p_data, i_data, -1, b_retry );
313 }
314
315
316 /*****************************************************************************
317  * __net_ReadNonBlock:
318  *****************************************************************************
319  * Read from a network socket, non blocking mode (with timeout)
320  *****************************************************************************/
321 int __net_ReadNonBlock( vlc_object_t *restrict p_this, int fd,
322                         const v_socket_t *restrict p_vs,
323                         uint8_t *restrict p_data, int i_data, mtime_t i_wait)
324 {
325     return net_ReadInner (p_this, 1, &(int){ fd },
326                           &(const v_socket_t *){ p_vs },
327                           p_data, i_data, i_wait / 1000, VLC_FALSE);
328 }
329
330
331 /*****************************************************************************
332  * __net_Select:
333  *****************************************************************************
334  * Read from several sockets (with timeout). Takes data from the first socket
335  * that has some.
336  *****************************************************************************/
337 int __net_Select( vlc_object_t *restrict p_this, const int *restrict pi_fd,
338                   const v_socket_t *const *restrict pp_vs,
339                   int i_fd, uint8_t *restrict p_data, int i_data,
340                   mtime_t i_wait )
341 {
342     if( pp_vs == NULL )
343     {
344         const v_socket_t *vsv[i_fd];
345         memset( vsv, 0, sizeof (vsv) );
346
347         return net_ReadInner( p_this, i_fd, pi_fd, vsv, p_data, i_data,
348                               i_wait / 1000, VLC_FALSE );
349     }
350
351     return net_ReadInner( p_this, i_fd, pi_fd, pp_vs, p_data, i_data,
352                           i_wait / 1000, VLC_FALSE );
353 }
354
355
356 /* Write exact amount requested */
357 int __net_Write( vlc_object_t *p_this, int fd, const v_socket_t *p_vs,
358                  const uint8_t *p_data, int i_data )
359 {
360     size_t i_total = 0;
361
362     while( i_data > 0 )
363     {
364         if( p_this->b_die )
365             return i_total;
366
367 #ifdef HAVE_POLL
368         struct pollfd ufd[1];
369         memset (ufd, 0, sizeof (ufd));
370         ufd[0].fd = fd;
371         ufd[0].events = POLLOUT;
372
373         int val = poll (ufd, 1, 500);
374         if ((val > 0) && (ufd[0].revents & POLLERR) && (i_total > 0))
375             return i_total; // error will be dequeued separately on next call
376 #else
377         fd_set set;
378         FD_ZERO (&set);
379
380 #if !defined(WIN32) && !defined(UNDER_CE)
381         if (fd >= FD_SETSIZE)
382         {
383             /* We don't want to overflow select() fd_set */
384             msg_Err (p_this, "select set overflow");
385             return -1;
386         }
387 #endif
388         FD_SET (fd, &set);
389
390         int val = select (fd + 1, NULL, &set, NULL,
391                           &(struct timeval){ 0, 500000 });
392 #endif
393         switch (val)
394         {
395             case -1:
396                 if (errno != EINTR)
397                 {
398                     msg_Err (p_this, "Write error: %s",
399                              net_strerror (net_errno));
400                     return i_total ? (int)i_total : -1;
401                 }
402
403             case 0:
404                 continue;
405         }
406
407         if (p_vs != NULL)
408             val = p_vs->pf_send (p_vs->p_sys, p_data, i_data);
409         else
410 #if defined(WIN32) || defined(UNDER_CE)
411             val = recv (fd, p_data, i_data, 0);
412 #else
413             val = write (fd, p_data, i_data);
414 #endif
415
416         if (val == -1)
417             return i_total ? (int)i_total : -1;
418         if (val == 0)
419             return i_total;
420
421         p_data += val;
422         i_data -= val;
423         i_total += val;
424     }
425
426     return i_total;
427 }
428
429 char *__net_Gets( vlc_object_t *p_this, int fd, const v_socket_t *p_vs )
430 {
431     char *psz_line = NULL, *ptr = NULL;
432     size_t  i_line = 0, i_max = 0;
433
434
435     for( ;; )
436     {
437         if( i_line == i_max )
438         {
439             i_max += 1024;
440             psz_line = realloc( psz_line, i_max );
441             ptr = psz_line + i_line;
442         }
443
444         if( net_Read( p_this, fd, p_vs, (uint8_t *)ptr, 1, VLC_TRUE ) != 1 )
445         {
446             if( i_line == 0 )
447             {
448                 free( psz_line );
449                 return NULL;
450             }
451             break;
452         }
453
454         if ( *ptr == '\n' )
455             break;
456
457         i_line++;
458         ptr++;
459     }
460
461     *ptr-- = '\0';
462
463     if( ( ptr >= psz_line ) && ( *ptr == '\r' ) )
464         *ptr = '\0';
465
466     return psz_line;
467 }
468
469 int net_Printf( vlc_object_t *p_this, int fd, const v_socket_t *p_vs,
470                 const char *psz_fmt, ... )
471 {
472     int i_ret;
473     va_list args;
474     va_start( args, psz_fmt );
475     i_ret = net_vaPrintf( p_this, fd, p_vs, psz_fmt, args );
476     va_end( args );
477
478     return i_ret;
479 }
480
481 int __net_vaPrintf( vlc_object_t *p_this, int fd, const v_socket_t *p_vs,
482                     const char *psz_fmt, va_list args )
483 {
484     char    *psz;
485     int     i_size, i_ret;
486
487     i_size = vasprintf( &psz, psz_fmt, args );
488     i_ret = __net_Write( p_this, fd, p_vs, (uint8_t *)psz, i_size ) < i_size
489         ? -1 : i_size;
490     free( psz );
491
492     return i_ret;
493 }
494
495
496 /*****************************************************************************
497  * inet_pton replacement for obsolete and/or crap operating systems
498  *****************************************************************************/
499 #ifndef HAVE_INET_PTON
500 int inet_pton(int af, const char *src, void *dst)
501 {
502 # ifdef WIN32
503     /* As we already know, Microsoft always go its own way, so even if they do
504      * provide IPv6, they don't provide the API. */
505     struct sockaddr_storage addr;
506     int len = sizeof( addr );
507
508     /* Damn it, they didn't even put LPCSTR for the firs parameter!!! */
509 #ifdef UNICODE
510     wchar_t *workaround_for_ill_designed_api =
511         malloc( MAX_PATH * sizeof(wchar_t) );
512     mbstowcs( workaround_for_ill_designed_api, src, MAX_PATH );
513     workaround_for_ill_designed_api[MAX_PATH-1] = 0;
514 #else
515     char *workaround_for_ill_designed_api = strdup( src );
516 #endif
517
518     if( !WSAStringToAddress( workaround_for_ill_designed_api, af, NULL,
519                              (LPSOCKADDR)&addr, &len ) )
520     {
521         free( workaround_for_ill_designed_api );
522         return -1;
523     }
524     free( workaround_for_ill_designed_api );
525
526     switch( af )
527     {
528         case AF_INET6:
529             memcpy( dst, &((struct sockaddr_in6 *)&addr)->sin6_addr, 16 );
530             break;
531
532         case AF_INET:
533             memcpy( dst, &((struct sockaddr_in *)&addr)->sin_addr, 4 );
534             break;
535
536         default:
537             WSASetLastError( WSAEAFNOSUPPORT );
538             return -1;
539     }
540 # else
541     /* Assume IPv6 is not supported. */
542     /* Would be safer and more simpler to use inet_aton() but it is most
543      * likely not provided either. */
544     uint32_t ipv4;
545
546     if( af != AF_INET )
547     {
548         errno = EAFNOSUPPORT;
549         return -1;
550     }
551
552     ipv4 = inet_addr( src );
553     if( ipv4 == INADDR_NONE )
554         return -1;
555
556     memcpy( dst, &ipv4, 4 );
557 # endif /* WIN32 */
558     return 0;
559 }
560 #endif /* HAVE_INET_PTON */