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