]> git.sesse.net Git - vlc/blob - src/network/io.c
net_Printf: automagic cast to VLC object
[vlc] / src / network / io.c
1 /*****************************************************************************
2  * io.c: network I/O functions
3  *****************************************************************************
4  * Copyright (C) 2004-2005, 2007 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  *          Christophe Mutricy <xtophe at videolan dot org>
11  *
12  * This program is free software; you can redistribute it and/or modify
13  * it under the terms of the GNU General Public License as published by
14  * the Free Software Foundation; either version 2 of the License, or
15  * (at your option) any later version.
16  *
17  * This program is distributed in the hope that it will be useful,
18  * but WITHOUT ANY WARRANTY; without even the implied warranty of
19  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20  * GNU General Public License for more details.
21  *
22  * You should have received a copy of the GNU General Public License
23  * along with this program; if not, write to the Free Software
24  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
25  *****************************************************************************/
26
27 /*****************************************************************************
28  * Preamble
29  *****************************************************************************/
30
31 #ifdef HAVE_CONFIG_H
32 # include "config.h"
33 #endif
34
35 #include <vlc_common.h>
36
37 #include <stdlib.h>
38 #include <stdio.h>
39 #include <limits.h>
40
41 #include <errno.h>
42 #include <assert.h>
43
44 #ifdef HAVE_FCNTL_H
45 #   include <fcntl.h>
46 #endif
47 #ifdef HAVE_UNISTD_H
48 #   include <unistd.h>
49 #endif
50 #ifdef HAVE_POLL
51 #   include <poll.h>
52 #endif
53
54 #include <vlc_network.h>
55
56 #ifndef INADDR_ANY
57 #   define INADDR_ANY  0x00000000
58 #endif
59 #ifndef INADDR_NONE
60 #   define INADDR_NONE 0xFFFFFFFF
61 #endif
62
63 #if defined(WIN32) || defined(UNDER_CE)
64 # undef EAFNOSUPPORT
65 # define EAFNOSUPPORT WSAEAFNOSUPPORT
66 #endif
67
68 #ifdef HAVE_LINUX_DCCP_H
69 /* TODO: use glibc instead of linux-kernel headers */
70 # include <linux/dccp.h>
71 # define SOL_DCCP 269
72 #endif
73
74 #include "libvlc.h" /* vlc_object_waitpipe */
75
76 extern int rootwrap_bind (int family, int socktype, int protocol,
77                           const struct sockaddr *addr, size_t alen);
78
79 int net_SetupSocket (int fd)
80 {
81 #if defined (WIN32) || defined (UNDER_CE)
82     ioctlsocket (fd, FIONBIO, &(unsigned long){ 1 });
83 #else
84     fcntl (fd, F_SETFD, FD_CLOEXEC);
85     fcntl (fd, F_SETFL, fcntl (fd, F_GETFL, 0) | O_NONBLOCK);
86 #endif
87
88     setsockopt (fd, SOL_SOCKET, SO_REUSEADDR, &(int){ 1 }, sizeof (int));
89     return 0;
90 }
91
92
93 int net_Socket (vlc_object_t *p_this, int family, int socktype,
94                 int protocol)
95 {
96     int fd;
97
98 #ifdef SOCK_CLOEXEC
99     fd = socket (family, socktype | SOCK_NONBLOCK | SOCK_CLOEXEC, protocol);
100     if (fd == -1 && errno == EINVAL)
101 #endif
102     {
103         fd = socket (family, socktype, protocol);
104         if (fd == -1)
105         {
106             if (net_errno != EAFNOSUPPORT)
107                 msg_Err (p_this, "cannot create socket: %m");
108             return -1;
109         }
110 #ifndef WIN32
111         fcntl (fd, F_SETFD, FD_CLOEXEC);
112         fcntl (fd, F_SETFL, fcntl (fd, F_GETFL, 0) | O_NONBLOCK);
113 #else
114         ioctlsocket (fd, FIONBIO, &(unsigned long){ 1 });
115 #endif
116     }
117
118     setsockopt (fd, SOL_SOCKET, SO_REUSEADDR, &(int){ 1 }, sizeof (int));
119
120 #ifdef IPV6_V6ONLY
121     /*
122      * Accepts only IPv6 connections on IPv6 sockets.
123      * If possible, we should open two sockets, but it is not always possible.
124      */
125     if (family == AF_INET6)
126         setsockopt (fd, IPPROTO_IPV6, IPV6_V6ONLY, &(int){ 1 }, sizeof (int));
127 #endif
128
129 #if defined (WIN32) || defined (UNDER_CE)
130 # ifndef IPV6_PROTECTION_LEVEL
131 #  warning Please update your C library headers.
132 #  define IPV6_PROTECTION_LEVEL 23
133 #  define PROTECTION_LEVEL_UNRESTRICTED 10
134 # endif
135     if (family == AF_INET6)
136         setsockopt (fd, IPPROTO_IPV6, IPV6_PROTECTION_LEVEL,
137                     &(int){ PROTECTION_LEVEL_UNRESTRICTED }, sizeof (int));
138 #endif
139
140 #ifdef DCCP_SOCKOPT_SERVICE
141     if (socktype == SOL_DCCP)
142     {
143         char *dccps = var_CreateGetNonEmptyString (p_this, "dccp-service");
144         if (dccps != NULL)
145         {
146             setsockopt (fd, SOL_DCCP, DCCP_SOCKOPT_SERVICE, dccps,
147                         (strlen (dccps) + 3) & ~3);
148             free (dccps);
149         }
150     }
151 #endif
152
153     return fd;
154 }
155
156
157 int *net_Listen (vlc_object_t *p_this, const char *psz_host,
158                  int i_port, int protocol)
159 {
160     struct addrinfo hints, *res;
161
162     memset (&hints, 0, sizeof( hints ));
163     hints.ai_protocol = protocol;
164     hints.ai_flags = AI_PASSIVE;
165
166     msg_Dbg (p_this, "net: listening to %s port %d", psz_host, i_port);
167
168     int i_val = vlc_getaddrinfo (p_this, psz_host, i_port, &hints, &res);
169     if (i_val)
170     {
171         msg_Err (p_this, "Cannot resolve %s port %d : %s", psz_host, i_port,
172                  vlc_gai_strerror (i_val));
173         return NULL;
174     }
175
176     int *sockv = NULL;
177     unsigned sockc = 0;
178
179     for (struct addrinfo *ptr = res; ptr != NULL; ptr = ptr->ai_next)
180     {
181         int fd = net_Socket (p_this, ptr->ai_family, ptr->ai_socktype,
182                              ptr->ai_protocol);
183         if (fd == -1)
184         {
185             msg_Dbg (p_this, "socket error: %m");
186             continue;
187         }
188
189         /* Bind the socket */
190 #if defined (WIN32) || defined (UNDER_CE)
191         /*
192          * Under Win32 and for multicasting, we bind to INADDR_ANY.
193          * This is of course a severe bug, since the socket would logically
194          * receive unicast traffic, and multicast traffic of groups subscribed
195          * to via other sockets.
196          */
197         if (net_SockAddrIsMulticast (ptr->ai_addr, ptr->ai_addrlen)
198          && (sizeof (struct sockaddr_storage) >= ptr->ai_addrlen))
199         {
200             // This works for IPv4 too - don't worry!
201             struct sockaddr_in6 dumb =
202             {
203                 .sin6_family = ptr->ai_addr->sa_family,
204                 .sin6_port =  ((struct sockaddr_in *)(ptr->ai_addr))->sin_port
205             };
206
207             bind (fd, (struct sockaddr *)&dumb, ptr->ai_addrlen);
208         }
209         else
210 #endif
211         if (bind (fd, ptr->ai_addr, ptr->ai_addrlen))
212         {
213             net_Close (fd);
214 #if !defined(WIN32) && !defined(UNDER_CE)
215             fd = rootwrap_bind (ptr->ai_family, ptr->ai_socktype,
216                                 ptr->ai_protocol,
217                                 ptr->ai_addr, ptr->ai_addrlen);
218             if (fd != -1)
219             {
220                 msg_Dbg (p_this, "got socket %d from rootwrap", fd);
221             }
222             else
223 #endif
224             {
225                 msg_Err (p_this, "socket bind error (%m)");
226                 continue;
227             }
228         }
229
230         if (net_SockAddrIsMulticast (ptr->ai_addr, ptr->ai_addrlen))
231         {
232             if (net_Subscribe (p_this, fd, ptr->ai_addr, ptr->ai_addrlen))
233             {
234                 net_Close (fd);
235                 continue;
236             }
237         }
238
239         /* Listen */
240         switch (ptr->ai_socktype)
241         {
242             case SOCK_STREAM:
243             case SOCK_RDM:
244             case SOCK_SEQPACKET:
245 #ifdef SOCK_DCCP
246             case SOCK_DCCP:
247 #endif
248                 if (listen (fd, INT_MAX))
249                 {
250                     msg_Err (p_this, "socket listen error (%m)");
251                     net_Close (fd);
252                     continue;
253                 }
254         }
255
256         int *nsockv = (int *)realloc (sockv, (sockc + 2) * sizeof (int));
257         if (nsockv != NULL)
258         {
259             nsockv[sockc++] = fd;
260             sockv = nsockv;
261         }
262         else
263             net_Close (fd);
264     }
265
266     vlc_freeaddrinfo (res);
267
268     if (sockv != NULL)
269         sockv[sockc] = -1;
270
271     return sockv;
272 }
273
274 #undef net_Read
275 /*****************************************************************************
276  * net_Read:
277  *****************************************************************************
278  * Reads from a network socket. Cancellation point.
279  * If waitall is true, then we repeat until we have read the right amount of
280  * data; in that case, a short count means EOF has been reached or the VLC
281  * object has been signaled.
282  *****************************************************************************/
283 ssize_t
284 net_Read (vlc_object_t *restrict p_this, int fd, const v_socket_t *vs,
285           void *restrict p_buf, size_t i_buflen, bool waitall)
286 {
287     size_t i_total = 0;
288     struct pollfd ufd[2] = {
289         { .fd = fd,                           .events = POLLIN },
290         { .fd = vlc_object_waitpipe (p_this), .events = POLLIN },
291     };
292
293     if (ufd[1].fd == -1)
294         return -1; /* vlc_object_waitpipe() sets errno */
295
296     while (i_buflen > 0)
297     {
298         ufd[0].revents = ufd[1].revents = 0;
299
300         if (poll (ufd, sizeof (ufd) / sizeof (ufd[0]), -1) < 0)
301         {
302             if (errno != EINTR)
303                 goto error;
304             continue;
305         }
306
307 #ifndef POLLRDHUP /* This is nice but non-portable */
308 # define POLLRDHUP 0
309 #endif
310         if (i_total > 0)
311         {
312             /* Errors (-1) and EOF (0) will be returned on next call,
313              * otherwise we'd "hide" the error from the caller, which is a
314              * bad idea™. */
315             if (ufd[0].revents & (POLLERR|POLLNVAL|POLLRDHUP))
316                 break;
317             if (ufd[1].revents)
318                 break;
319         }
320         else
321         {
322             if (ufd[1].revents)
323             {
324                 assert (p_this->b_die);
325                 msg_Dbg (p_this, "socket %d polling interrupted", fd);
326 #if defined(WIN32) || defined(UNDER_CE)
327                 WSASetLastError (WSAEINTR);
328 #else
329                 errno = EINTR;
330 #endif
331                 goto silent;
332             }
333         }
334
335         assert (ufd[0].revents);
336
337         ssize_t n;
338         if (vs != NULL)
339         {
340             int canc = vlc_savecancel ();
341             n = vs->pf_recv (vs->p_sys, p_buf, i_buflen);
342             vlc_restorecancel (canc);
343         }
344         else
345         {
346 #ifdef WIN32
347             n = recv (fd, p_buf, i_buflen, 0);
348 #else
349             n = read (fd, p_buf, i_buflen);
350 #endif
351         }
352
353         if (n == -1)
354         {
355 #if defined(WIN32) || defined(UNDER_CE)
356             switch (WSAGetLastError ())
357             {
358                 case WSAEWOULDBLOCK:
359                 /* only happens with vs != NULL (TLS) - not really an error */
360                     continue;
361
362                 case WSAEMSGSIZE:
363                 /* For UDP only */
364                 /* On Win32, recv() fails if the datagram doesn't fit inside
365                  * the passed buffer, even though the buffer will be filled
366                  * with the first part of the datagram. */
367                     msg_Err (p_this, "Receive error: "
368                                      "Increase the mtu size (--mtu option)");
369                     n = i_buflen;
370                     break;
371             }
372 #else
373             switch (errno)
374             {
375                 case EAGAIN: /* spurious wakeup or no TLS data */
376 #if (EAGAIN != EWOULDBLOCK)
377                 case EWOULDBLOCK:
378 #endif
379                 case EINTR:  /* asynchronous signal */
380                     continue;
381             }
382 #endif
383             goto error;
384         }
385
386         if (n == 0)
387             /* For streams, this means end of file, and there will not be any
388              * further data ever on the stream. For datagram sockets, this
389              * means empty datagram, and there could be more data coming.
390              * However, it makes no sense to set <waitall> with datagrams in the
391              * first place.
392              */
393             break; // EOF
394
395         i_total += n;
396         p_buf = (char *)p_buf + n;
397         i_buflen -= n;
398
399         if (!waitall)
400             break;
401     }
402
403     return i_total;
404
405 error:
406     msg_Err (p_this, "Read error: %m");
407 silent:
408     return -1;
409 }
410
411 #undef net_Write
412 /* Write exact amount requested */
413 ssize_t net_Write( vlc_object_t *p_this, int fd, const v_socket_t *p_vs,
414                    const void *restrict p_data, size_t i_data )
415 {
416     size_t i_total = 0;
417     struct pollfd ufd[2] = {
418         { .fd = fd,                           .events = POLLOUT },
419         { .fd = vlc_object_waitpipe (p_this), .events = POLLIN  },
420     };
421
422     if (ufd[1].fd == -1)
423         return -1;
424
425     while( i_data > 0 )
426     {
427         ssize_t val;
428
429         ufd[0].revents = ufd[1].revents = 0;
430
431         if (poll (ufd, sizeof (ufd) / sizeof (ufd[0]), -1) == -1)
432         {
433             if (errno == EINTR)
434                 continue;
435             msg_Err (p_this, "Polling error: %m");
436             return -1;
437         }
438
439         if (i_total > 0)
440         {   /* If POLLHUP resp. POLLERR|POLLNVAL occurs while we have already
441              * read some data, it is important that we first return the number
442              * of bytes read, and then return 0 resp. -1 on the NEXT call. */
443             if (ufd[0].revents & (POLLHUP|POLLERR|POLLNVAL))
444                 break;
445             if (ufd[1].revents) /* VLC object signaled */
446                 break;
447         }
448         else
449         {
450             if (ufd[1].revents)
451             {
452                 assert (p_this->b_die);
453                 errno = EINTR;
454                 goto error;
455             }
456         }
457
458         if (p_vs != NULL)
459             val = p_vs->pf_send (p_vs->p_sys, p_data, i_data);
460         else
461 #ifdef WIN32
462             val = send (fd, p_data, i_data, 0);
463 #else
464             val = write (fd, p_data, i_data);
465 #endif
466
467         if (val == -1)
468         {
469             if (errno == EINTR)
470                 continue;
471             msg_Err (p_this, "Write error: %m");
472             break;
473         }
474
475         p_data = (const char *)p_data + val;
476         i_data -= val;
477         i_total += val;
478     }
479
480     if ((i_total > 0) || (i_data == 0))
481         return i_total;
482
483 error:
484     return -1;
485 }
486
487 #undef net_Gets
488 /**
489  * Reads a line from a file descriptor.
490  * This function is not thread-safe; the same file descriptor cI/O annot be read
491  * by another thread at the same time (although it can be written to).
492  *
493  * @return nul-terminated heap-allocated string, or NULL on I/O error.
494  */
495 char *net_Gets( vlc_object_t *p_this, int fd, const v_socket_t *p_vs )
496 {
497     char *psz_line = NULL, *ptr = NULL;
498     size_t  i_line = 0, i_max = 0;
499
500
501     for( ;; )
502     {
503         if( i_line == i_max )
504         {
505             i_max += 1024;
506             psz_line = xrealloc( psz_line, i_max );
507             ptr = psz_line + i_line;
508         }
509
510         if( net_Read( p_this, fd, p_vs, ptr, 1, true ) != 1 )
511         {
512             if( i_line == 0 )
513             {
514                 free( psz_line );
515                 return NULL;
516             }
517             break;
518         }
519
520         if ( *ptr == '\n' )
521             break;
522
523         i_line++;
524         ptr++;
525     }
526
527     *ptr-- = '\0';
528
529     if( ( ptr >= psz_line ) && ( *ptr == '\r' ) )
530         *ptr = '\0';
531
532     return psz_line;
533 }
534
535 #undef net_Printf
536 ssize_t net_Printf( vlc_object_t *p_this, int fd, const v_socket_t *p_vs,
537                     const char *psz_fmt, ... )
538 {
539     int i_ret;
540     va_list args;
541     va_start( args, psz_fmt );
542     i_ret = net_vaPrintf( p_this, fd, p_vs, psz_fmt, args );
543     va_end( args );
544
545     return i_ret;
546 }
547
548 #undef net_vaPrintf
549 ssize_t net_vaPrintf( vlc_object_t *p_this, int fd, const v_socket_t *p_vs,
550                       const char *psz_fmt, va_list args )
551 {
552     char    *psz;
553     int      i_ret;
554
555     int i_size = vasprintf( &psz, psz_fmt, args );
556     if( i_size == -1 )
557         return -1;
558     i_ret = net_Write( p_this, fd, p_vs, psz, i_size ) < i_size
559         ? -1 : i_size;
560     free( psz );
561
562     return i_ret;
563 }