packetizer: avparser: properly propagate flags
[vlc.git] / src / network / io.c
blob5285edc169a030a9c49be417f69fafcb44e1b211
1 /*****************************************************************************
2 * io.c: network I/O functions
3 *****************************************************************************
4 * Copyright (C) 2004-2005, 2007 VLC authors and VideoLAN
5 * Copyright © 2005-2006 Rémi Denis-Courmont
7 * Authors: Laurent Aimar <fenrir@videolan.org>
8 * Rémi Denis-Courmont
9 * Christophe Mutricy <xtophe at videolan dot org>
11 * This program is free software; you can redistribute it and/or modify it
12 * under the terms of the GNU Lesser General Public License as published by
13 * the Free Software Foundation; either version 2.1 of the License, or
14 * (at your option) any later version.
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 Lesser General Public License for more details.
21 * You should have received a copy of the GNU Lesser General Public License
22 * along with this program; if not, write to the Free Software Foundation,
23 * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
24 *****************************************************************************/
26 /*****************************************************************************
27 * Preamble
28 *****************************************************************************/
30 #ifdef HAVE_CONFIG_H
31 # include "config.h"
32 #endif
34 #include <stdlib.h>
35 #include <stdio.h>
36 #include <limits.h>
37 #include <errno.h>
38 #include <assert.h>
40 #include <unistd.h>
41 #ifdef HAVE_POLL_H
42 # include <poll.h>
43 #endif
44 #ifdef HAVE_LINUX_DCCP_H
45 /* TODO: use glibc instead of linux-kernel headers */
46 # include <linux/dccp.h>
47 # define SOL_DCCP 269
48 #endif
50 #include <vlc_common.h>
51 #include <vlc_network.h>
52 #include <vlc_interrupt.h>
53 #if defined (_WIN32)
54 # undef EINPROGRESS
55 # define EINPROGRESS WSAEWOULDBLOCK
56 # undef EWOULDBLOCK
57 # define EWOULDBLOCK WSAEWOULDBLOCK
58 # undef EAGAIN
59 # define EAGAIN WSAEWOULDBLOCK
60 #endif
62 extern int rootwrap_bind (int family, int socktype, int protocol,
63 const struct sockaddr *addr, size_t alen);
65 int net_Socket (vlc_object_t *p_this, int family, int socktype,
66 int protocol)
68 int fd = vlc_socket (family, socktype, protocol, true);
69 if (fd == -1)
71 if (net_errno != EAFNOSUPPORT)
72 msg_Err (p_this, "cannot create socket: %s",
73 vlc_strerror_c(net_errno));
74 return -1;
77 #ifdef _WIN32
78 // Windows expects a BOOL for some getsockopt/setsockopt options
79 static_assert(sizeof(int)==sizeof(BOOL), "mismatching type for setsockopt");
80 #endif
81 setsockopt (fd, SOL_SOCKET, SO_REUSEADDR, &(int){ 1 }, sizeof (int));
83 #ifdef IPV6_V6ONLY
85 * Accepts only IPv6 connections on IPv6 sockets.
86 * If possible, we should open two sockets, but it is not always possible.
88 if (family == AF_INET6)
89 setsockopt (fd, IPPROTO_IPV6, IPV6_V6ONLY, &(int){ 1 }, sizeof (int));
90 #endif
92 #if defined (_WIN32)
93 # ifndef IPV6_PROTECTION_LEVEL
94 # warning Please update your C library headers.
95 # define IPV6_PROTECTION_LEVEL 23
96 # define PROTECTION_LEVEL_UNRESTRICTED 10
97 # endif
98 if (family == AF_INET6)
99 setsockopt (fd, IPPROTO_IPV6, IPV6_PROTECTION_LEVEL,
100 &(int){ PROTECTION_LEVEL_UNRESTRICTED }, sizeof (int));
101 #endif
103 #ifdef DCCP_SOCKOPT_SERVICE
104 if (socktype == SOL_DCCP)
106 char *dccps = var_InheritString (p_this, "dccp-service");
107 if (dccps != NULL)
109 setsockopt (fd, SOL_DCCP, DCCP_SOCKOPT_SERVICE, dccps,
110 (strlen (dccps) + 3) & ~3);
111 free (dccps);
114 #endif
116 return fd;
119 int (net_Connect)(vlc_object_t *obj, const char *host, int serv,
120 int type, int proto)
122 struct addrinfo hints = {
123 .ai_socktype = type,
124 .ai_protocol = proto,
125 .ai_flags = AI_NUMERICSERV | AI_IDN,
126 }, *res;
127 int ret = -1;
129 int val = vlc_getaddrinfo_i11e(host, serv, &hints, &res);
130 if (val)
132 msg_Err(obj, "cannot resolve %s port %d : %s", host, serv,
133 gai_strerror (val));
134 return -1;
137 vlc_tick_t timeout = VLC_TICK_FROM_MS(var_InheritInteger(obj,
138 "ipv4-timeout"));
140 for (struct addrinfo *ptr = res; ptr != NULL; ptr = ptr->ai_next)
142 int fd = net_Socket(obj, ptr->ai_family,
143 ptr->ai_socktype, ptr->ai_protocol);
144 if (fd == -1)
146 msg_Dbg(obj, "socket error: %s", vlc_strerror_c(net_errno));
147 continue;
150 if (connect(fd, ptr->ai_addr, ptr->ai_addrlen))
152 if (net_errno != EINPROGRESS && errno != EINTR)
154 msg_Err(obj, "connection failed: %s",
155 vlc_strerror_c(net_errno));
156 goto next_ai;
159 struct pollfd ufd;
160 vlc_tick_t deadline = VLC_TICK_INVALID;
162 ufd.fd = fd;
163 ufd.events = POLLOUT;
164 deadline = vlc_tick_now() + timeout;
168 vlc_tick_t now = vlc_tick_now();
170 if (vlc_killed())
171 goto next_ai;
173 if (now > deadline)
174 now = deadline;
176 val = vlc_poll_i11e(&ufd, 1, MS_FROM_VLC_TICK(deadline - now));
178 while (val == -1 && errno == EINTR);
180 switch (val)
182 case -1: /* error */
183 msg_Err(obj, "polling error: %s",
184 vlc_strerror_c(net_errno));
185 goto next_ai;
187 case 0: /* timeout */
188 msg_Warn(obj, "connection timed out");
189 goto next_ai;
192 /* There is NO WAY around checking SO_ERROR.
193 * Don't ifdef it out!!! */
194 if (getsockopt(fd, SOL_SOCKET, SO_ERROR, &val,
195 &(socklen_t){ sizeof (val) }) || val)
197 msg_Err(obj, "connection failed: %s", vlc_strerror_c(val));
198 goto next_ai;
202 msg_Dbg(obj, "connection succeeded (socket = %d)", fd);
203 ret = fd; /* success! */
204 break;
206 next_ai: /* failure */
207 net_Close(fd);
210 freeaddrinfo(res);
211 return ret;
214 int *net_Listen (vlc_object_t *p_this, const char *psz_host,
215 unsigned i_port, int type, int protocol)
217 struct addrinfo hints = {
218 .ai_socktype = type,
219 .ai_protocol = protocol,
220 .ai_flags = AI_PASSIVE | AI_NUMERICSERV | AI_IDN,
221 }, *res;
223 msg_Dbg (p_this, "net: listening to %s port %u",
224 (psz_host != NULL) ? psz_host : "*", i_port);
226 int i_val = vlc_getaddrinfo (psz_host, i_port, &hints, &res);
227 if (i_val)
229 msg_Err (p_this, "Cannot resolve %s port %u : %s",
230 (psz_host != NULL) ? psz_host : "", i_port,
231 gai_strerror (i_val));
232 return NULL;
235 int *sockv = NULL;
236 unsigned sockc = 0;
238 for (struct addrinfo *ptr = res; ptr != NULL; ptr = ptr->ai_next)
240 int fd = net_Socket (p_this, ptr->ai_family, ptr->ai_socktype,
241 ptr->ai_protocol);
242 if (fd == -1)
244 msg_Dbg (p_this, "socket error: %s", vlc_strerror_c(net_errno));
245 continue;
248 /* Bind the socket */
249 if (bind (fd, ptr->ai_addr, ptr->ai_addrlen))
251 int err = net_errno;
252 net_Close (fd);
253 #if !defined(_WIN32)
254 fd = rootwrap_bind (ptr->ai_family, ptr->ai_socktype,
255 ptr->ai_protocol,
256 ptr->ai_addr, ptr->ai_addrlen);
257 if (fd != -1)
259 msg_Dbg (p_this, "got socket %d from rootwrap", fd);
261 else
262 #endif
264 msg_Err (p_this, "socket bind error: %s", vlc_strerror_c(err));
265 continue;
269 /* Listen */
270 if (listen(fd, INT_MAX))
272 msg_Err(p_this, "socket listen error: %s",
273 vlc_strerror_c(net_errno));
274 net_Close(fd);
275 continue;
278 int *nsockv = (int *)realloc (sockv, (sockc + 2) * sizeof (int));
279 if (nsockv != NULL)
281 nsockv[sockc++] = fd;
282 sockv = nsockv;
284 else
285 net_Close (fd);
288 freeaddrinfo (res);
290 if (sockv != NULL)
291 sockv[sockc] = -1;
293 return sockv;
296 void net_ListenClose(int *fds)
298 if (fds != NULL)
300 for (int *p = fds; *p != -1; p++)
301 net_Close(*p);
303 free(fds);
307 #undef net_Accept
308 int net_Accept(vlc_object_t *obj, int *fds)
310 assert(fds != NULL);
312 unsigned n = 0;
313 while (fds[n] != -1)
314 n++;
316 struct pollfd ufd[n];
317 /* Initialize file descriptor set */
318 for (unsigned i = 0; i < n; i++)
320 ufd[i].fd = fds[i];
321 ufd[i].events = POLLIN;
324 for (;;)
326 while (poll(ufd, n, -1) == -1)
328 if (net_errno != EINTR)
330 msg_Err(obj, "poll error: %s", vlc_strerror_c(net_errno));
331 return -1;
335 for (unsigned i = 0; i < n; i++)
337 if (ufd[i].revents == 0)
338 continue;
340 int sfd = ufd[i].fd;
341 int fd = vlc_accept(sfd, NULL, NULL, true);
342 if (fd == -1)
344 if (net_errno != EAGAIN)
345 #if (EAGAIN != EWOULDBLOCK)
346 if (net_errno != EWOULDBLOCK)
347 #endif
348 msg_Err(obj, "accept failed (from socket %d): %s", sfd,
349 vlc_strerror_c(net_errno));
350 continue;
353 msg_Dbg(obj, "accepted socket %d (from socket %d)", fd, sfd);
354 setsockopt(fd, SOL_SOCKET, SO_REUSEADDR,
355 &(int){ 1 }, sizeof (int));
357 * Move listening socket to the end to let the others in the
358 * set a chance next time.
360 memmove(fds + i, fds + i + 1, n - (i + 1));
361 fds[n - 1] = sfd;
362 return fd;
365 return -1;
368 ssize_t (net_Read)(vlc_object_t *restrict obj, int fd,
369 void *restrict buf, size_t len)
371 size_t rd = 0;
375 if (vlc_killed())
377 vlc_testcancel();
378 errno = EINTR;
379 return -1;
382 ssize_t val = vlc_recv_i11e(fd, buf, len, 0);
383 if (val < 0)
385 if (errno == EINTR || errno == EAGAIN)
386 continue;
387 #ifdef _WIN32
388 else if (WSAGetLastError() == WSAEMSGSIZE) /* datagram too big */
390 msg_Warn(obj, "read truncated to %zu bytes", len);
391 val = len;
393 #endif
394 else
396 msg_Err(obj, "read error: %s", vlc_strerror_c(errno));
397 return rd ? (ssize_t)rd : -1;
401 rd += val;
403 if (val == 0)
404 break;
406 assert(len >= (size_t)val);
407 len -= val;
408 buf = ((char *)buf) + val;
410 while (len > 0);
412 return rd;
415 ssize_t (net_Write)(vlc_object_t *obj, int fd, const void *buf, size_t len)
417 size_t written = 0;
421 if (vlc_killed())
423 vlc_testcancel();
424 errno = EINTR;
425 return -1;
428 ssize_t val = vlc_send_i11e(fd, buf, len, 0);
429 if (val == -1)
431 if (errno == EINTR || errno == EAGAIN)
432 continue;
434 msg_Err(obj, "write error: %s", vlc_strerror_c(errno));
435 return written ? (ssize_t)written : -1;
438 if (val == 0)
439 break;
441 written += val;
442 assert(len >= (size_t)val);
443 len -= val;
444 buf = ((const char *)buf) + val;
446 while (len > 0);
448 return written;