]> git.sesse.net Git - vlc/blob - src/network/io.c
I suggest you stop being sarcastic because your fixes are broken
[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     return i_total;
273
274 error:
275     msg_Err( p_this, "Read error: %s", net_strerror (net_errno) );
276     return i_total ? (ssize_t)i_total : -1;
277 }
278
279
280 /*****************************************************************************
281  * __net_Read:
282  *****************************************************************************
283  * Read from a network socket
284  * If b_retry is true, then we repeat until we have read the right amount of
285  * data
286  *****************************************************************************/
287 int __net_Read( vlc_object_t *restrict p_this, int fd,
288                 const v_socket_t *restrict p_vs,
289                 uint8_t *restrict p_data, int i_data, vlc_bool_t b_retry )
290 {
291     return net_ReadInner( p_this, 1, &(int){ fd },
292                           &(const v_socket_t *){ p_vs },
293                           p_data, i_data, -1, b_retry );
294 }
295
296
297 /*****************************************************************************
298  * __net_ReadNonBlock:
299  *****************************************************************************
300  * Read from a network socket, non blocking mode (with timeout)
301  *****************************************************************************/
302 int __net_ReadNonBlock( 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, mtime_t i_wait)
305 {
306     return net_ReadInner (p_this, 1, &(int){ fd },
307                           &(const v_socket_t *){ p_vs },
308                           p_data, i_data, i_wait / 1000, VLC_FALSE);
309 }
310
311
312 /*****************************************************************************
313  * __net_Select:
314  *****************************************************************************
315  * Read from several sockets (with timeout). Takes data from the first socket
316  * that has some.
317  *****************************************************************************/
318 int __net_Select( vlc_object_t *restrict p_this, const int *restrict pi_fd,
319                   const v_socket_t *const *restrict pp_vs,
320                   int i_fd, uint8_t *restrict p_data, int i_data,
321                   mtime_t i_wait )
322 {
323     if( pp_vs == NULL )
324     {
325         const v_socket_t *vsv[i_fd];
326         memset( vsv, 0, sizeof (vsv) );
327
328         return net_ReadInner( p_this, i_fd, pi_fd, vsv, p_data, i_data,
329                               i_wait / 1000, VLC_FALSE );
330     }
331
332     return net_ReadInner( p_this, i_fd, pi_fd, pp_vs, p_data, i_data,
333                           i_wait / 1000, VLC_FALSE );
334 }
335
336
337 /* Write exact amount requested */
338 int __net_Write( vlc_object_t *p_this, int fd, const v_socket_t *p_vs,
339                  const uint8_t *p_data, int i_data )
340 {
341     size_t i_total = 0;
342
343     while( i_data > 0 )
344     {
345         if( p_this->b_die )
346             return i_total;
347
348 #ifdef HAVE_POLL
349         struct pollfd ufd[1];
350         memset (ufd, 0, sizeof (ufd));
351         ufd[0].fd = fd;
352         ufd[0].events = POLLOUT;
353
354         int val = poll (ufd, 1, 500);
355         if ((val > 0) && (ufd[0].revents & POLLERR) && (i_total > 0))
356             return i_total; // error will be dequeued separately on next call
357 #else
358         fd_set set;
359         FD_ZERO (&set);
360
361 #if !defined(WIN32) && !defined(UNDER_CE)
362         if (fd >= FD_SETSIZE)
363         {
364             /* We don't want to overflow select() fd_set */
365             msg_Err (p_this, "select set overflow");
366             return -1;
367         }
368 #endif
369         FD_SET (fd, &set);
370
371         int val = select (fd + 1, NULL, &set, NULL,
372                           &(struct timeval){ 0, 500000 });
373 #endif
374         switch (val)
375         {
376             case -1:
377                 if (errno != EINTR)
378                 {
379                     msg_Err (p_this, "Write error: %s",
380                              net_strerror (net_errno));
381                     return i_total ? (int)i_total : -1;
382                 }
383
384             case 0:
385                 continue;
386         }
387
388         if (p_vs != NULL)
389             val = p_vs->pf_send (p_vs->p_sys, p_data, i_data);
390         else
391 #if defined(WIN32) || defined(UNDER_CE)
392             val = send (fd, p_data, i_data, 0);
393 #else
394             val = write (fd, p_data, i_data);
395 #endif
396
397         if (val == -1)
398             return i_total ? (int)i_total : -1;
399         if (val == 0)
400             return i_total;
401
402         p_data += val;
403         i_data -= val;
404         i_total += val;
405     }
406
407     return i_total;
408 }
409
410 char *__net_Gets( vlc_object_t *p_this, int fd, const v_socket_t *p_vs )
411 {
412     char *psz_line = NULL, *ptr = NULL;
413     size_t  i_line = 0, i_max = 0;
414
415
416     for( ;; )
417     {
418         if( i_line == i_max )
419         {
420             i_max += 1024;
421             psz_line = realloc( psz_line, i_max );
422             ptr = psz_line + i_line;
423         }
424
425         if( net_Read( p_this, fd, p_vs, (uint8_t *)ptr, 1, VLC_TRUE ) != 1 )
426         {
427             if( i_line == 0 )
428             {
429                 free( psz_line );
430                 return NULL;
431             }
432             break;
433         }
434
435         if ( *ptr == '\n' )
436             break;
437
438         i_line++;
439         ptr++;
440     }
441
442     *ptr-- = '\0';
443
444     if( ( ptr >= psz_line ) && ( *ptr == '\r' ) )
445         *ptr = '\0';
446
447     return psz_line;
448 }
449
450 int net_Printf( vlc_object_t *p_this, int fd, const v_socket_t *p_vs,
451                 const char *psz_fmt, ... )
452 {
453     int i_ret;
454     va_list args;
455     va_start( args, psz_fmt );
456     i_ret = net_vaPrintf( p_this, fd, p_vs, psz_fmt, args );
457     va_end( args );
458
459     return i_ret;
460 }
461
462 int __net_vaPrintf( vlc_object_t *p_this, int fd, const v_socket_t *p_vs,
463                     const char *psz_fmt, va_list args )
464 {
465     char    *psz;
466     int     i_size, i_ret;
467
468     i_size = vasprintf( &psz, psz_fmt, args );
469     i_ret = __net_Write( p_this, fd, p_vs, (uint8_t *)psz, i_size ) < i_size
470         ? -1 : i_size;
471     free( psz );
472
473     return i_ret;
474 }
475
476
477 /*****************************************************************************
478  * inet_pton replacement for obsolete and/or crap operating systems
479  *****************************************************************************/
480 #ifndef HAVE_INET_PTON
481 int inet_pton(int af, const char *src, void *dst)
482 {
483 # ifdef WIN32
484     /* As we already know, Microsoft always go its own way, so even if they do
485      * provide IPv6, they don't provide the API. */
486     struct sockaddr_storage addr;
487     int len = sizeof( addr );
488
489     /* Damn it, they didn't even put LPCSTR for the firs parameter!!! */
490 #ifdef UNICODE
491     wchar_t *workaround_for_ill_designed_api =
492         malloc( MAX_PATH * sizeof(wchar_t) );
493     mbstowcs( workaround_for_ill_designed_api, src, MAX_PATH );
494     workaround_for_ill_designed_api[MAX_PATH-1] = 0;
495 #else
496     char *workaround_for_ill_designed_api = strdup( src );
497 #endif
498
499     if( !WSAStringToAddress( workaround_for_ill_designed_api, af, NULL,
500                              (LPSOCKADDR)&addr, &len ) )
501     {
502         free( workaround_for_ill_designed_api );
503         return -1;
504     }
505     free( workaround_for_ill_designed_api );
506
507     switch( af )
508     {
509         case AF_INET6:
510             memcpy( dst, &((struct sockaddr_in6 *)&addr)->sin6_addr, 16 );
511             break;
512
513         case AF_INET:
514             memcpy( dst, &((struct sockaddr_in *)&addr)->sin_addr, 4 );
515             break;
516
517         default:
518             WSASetLastError( WSAEAFNOSUPPORT );
519             return -1;
520     }
521 # else
522     /* Assume IPv6 is not supported. */
523     /* Would be safer and more simpler to use inet_aton() but it is most
524      * likely not provided either. */
525     uint32_t ipv4;
526
527     if( af != AF_INET )
528     {
529         errno = EAFNOSUPPORT;
530         return -1;
531     }
532
533     ipv4 = inet_addr( src );
534     if( ipv4 == INADDR_NONE )
535         return -1;
536
537     memcpy( dst, &ipv4, 4 );
538 # endif /* WIN32 */
539     return 0;
540 }
541 #endif /* HAVE_INET_PTON */