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