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