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