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