network: net_Listen() doesn't accept a negative port
[vlc.git] / src / network / io.c
blob33fa12ba6635fa97c3db394957aa2a9323d602b4
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
6 * $Id$
8 * Authors: Laurent Aimar <fenrir@videolan.org>
9 * Rémi Denis-Courmont <rem # videolan.org>
10 * Christophe Mutricy <xtophe at videolan dot org>
12 * This program is free software; you can redistribute it and/or modify it
13 * under the terms of the GNU Lesser General Public License as published by
14 * the Free Software Foundation; either version 2.1 of the License, or
15 * (at your option) any later version.
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 Lesser General Public License for more details.
22 * You should have received a copy of the GNU Lesser General Public License
23 * along with this program; if not, write to the Free Software Foundation,
24 * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
25 *****************************************************************************/
27 /*****************************************************************************
28 * Preamble
29 *****************************************************************************/
31 #ifdef HAVE_CONFIG_H
32 # include "config.h"
33 #endif
35 #include <stdlib.h>
36 #include <stdio.h>
37 #include <limits.h>
38 #include <errno.h>
39 #include <assert.h>
41 #include <unistd.h>
42 #ifdef HAVE_LINUX_DCCP_H
43 /* TODO: use glibc instead of linux-kernel headers */
44 # include <linux/dccp.h>
45 # define SOL_DCCP 269
46 #endif
48 #include <vlc_common.h>
49 #include <vlc_network.h>
50 #include <vlc_interrupt.h>
52 extern int rootwrap_bind (int family, int socktype, int protocol,
53 const struct sockaddr *addr, size_t alen);
55 int net_Socket (vlc_object_t *p_this, int family, int socktype,
56 int protocol)
58 int fd = vlc_socket (family, socktype, protocol, true);
59 if (fd == -1)
61 if (net_errno != EAFNOSUPPORT)
62 msg_Err (p_this, "cannot create socket: %s",
63 vlc_strerror_c(net_errno));
64 return -1;
67 setsockopt (fd, SOL_SOCKET, SO_REUSEADDR, &(int){ 1 }, sizeof (int));
69 #ifdef IPV6_V6ONLY
71 * Accepts only IPv6 connections on IPv6 sockets.
72 * If possible, we should open two sockets, but it is not always possible.
74 if (family == AF_INET6)
75 setsockopt (fd, IPPROTO_IPV6, IPV6_V6ONLY, &(int){ 1 }, sizeof (int));
76 #endif
78 #if defined (_WIN32)
79 # ifndef IPV6_PROTECTION_LEVEL
80 # warning Please update your C library headers.
81 # define IPV6_PROTECTION_LEVEL 23
82 # define PROTECTION_LEVEL_UNRESTRICTED 10
83 # endif
84 if (family == AF_INET6)
85 setsockopt (fd, IPPROTO_IPV6, IPV6_PROTECTION_LEVEL,
86 &(int){ PROTECTION_LEVEL_UNRESTRICTED }, sizeof (int));
87 #endif
89 #ifdef DCCP_SOCKOPT_SERVICE
90 if (socktype == SOL_DCCP)
92 char *dccps = var_InheritString (p_this, "dccp-service");
93 if (dccps != NULL)
95 setsockopt (fd, SOL_DCCP, DCCP_SOCKOPT_SERVICE, dccps,
96 (strlen (dccps) + 3) & ~3);
97 free (dccps);
100 #endif
102 return fd;
106 int *net_Listen (vlc_object_t *p_this, const char *psz_host,
107 unsigned i_port, int type, int protocol)
109 struct addrinfo hints = {
110 .ai_socktype = type,
111 .ai_protocol = protocol,
112 .ai_flags = AI_PASSIVE | AI_NUMERICSERV | AI_IDN,
113 }, *res;
115 msg_Dbg (p_this, "net: listening to %s port %d",
116 (psz_host != NULL) ? psz_host : "*", i_port);
118 int i_val = vlc_getaddrinfo (psz_host, i_port, &hints, &res);
119 if (i_val)
121 msg_Err (p_this, "Cannot resolve %s port %d : %s",
122 (psz_host != NULL) ? psz_host : "", i_port,
123 gai_strerror (i_val));
124 return NULL;
127 int *sockv = NULL;
128 unsigned sockc = 0;
130 for (struct addrinfo *ptr = res; ptr != NULL; ptr = ptr->ai_next)
132 int fd = net_Socket (p_this, ptr->ai_family, ptr->ai_socktype,
133 ptr->ai_protocol);
134 if (fd == -1)
136 msg_Dbg (p_this, "socket error: %s", vlc_strerror_c(net_errno));
137 continue;
140 /* Bind the socket */
141 #if defined (_WIN32)
143 * Under Win32 and for multicasting, we bind to INADDR_ANY.
144 * This is of course a severe bug, since the socket would logically
145 * receive unicast traffic, and multicast traffic of groups subscribed
146 * to via other sockets.
148 if (net_SockAddrIsMulticast (ptr->ai_addr, ptr->ai_addrlen)
149 && (sizeof (struct sockaddr_storage) >= ptr->ai_addrlen))
151 // This works for IPv4 too - don't worry!
152 struct sockaddr_in6 dumb =
154 .sin6_family = ptr->ai_addr->sa_family,
155 .sin6_port = ((struct sockaddr_in *)(ptr->ai_addr))->sin_port
158 bind (fd, (struct sockaddr *)&dumb, ptr->ai_addrlen);
160 else
161 #endif
162 if (bind (fd, ptr->ai_addr, ptr->ai_addrlen))
164 int err = net_errno;
165 net_Close (fd);
166 #if !defined(_WIN32)
167 fd = rootwrap_bind (ptr->ai_family, ptr->ai_socktype,
168 ptr->ai_protocol,
169 ptr->ai_addr, ptr->ai_addrlen);
170 if (fd != -1)
172 msg_Dbg (p_this, "got socket %d from rootwrap", fd);
174 else
175 #endif
177 msg_Err (p_this, "socket bind error: %s", vlc_strerror_c(err));
178 continue;
182 if (net_SockAddrIsMulticast (ptr->ai_addr, ptr->ai_addrlen))
184 if (net_Subscribe (p_this, fd, ptr->ai_addr, ptr->ai_addrlen))
186 net_Close (fd);
187 continue;
191 /* Listen */
192 switch (ptr->ai_socktype)
194 case SOCK_STREAM:
195 case SOCK_RDM:
196 case SOCK_SEQPACKET:
197 #ifdef SOCK_DCCP
198 case SOCK_DCCP:
199 #endif
200 if (listen (fd, INT_MAX))
202 msg_Err (p_this, "socket listen error: %s",
203 vlc_strerror_c(net_errno));
204 net_Close (fd);
205 continue;
209 int *nsockv = (int *)realloc (sockv, (sockc + 2) * sizeof (int));
210 if (nsockv != NULL)
212 nsockv[sockc++] = fd;
213 sockv = nsockv;
215 else
216 net_Close (fd);
219 freeaddrinfo (res);
221 if (sockv != NULL)
222 sockv[sockc] = -1;
224 return sockv;
228 * Reads data from a socket, blocking until all requested data is received or
229 * the end of the stream is reached.
230 * This function is a cancellation point.
231 * @return -1 on error, or the number of bytes of read.
233 ssize_t (net_Read)(vlc_object_t *restrict obj, int fd,
234 void *restrict buf, size_t len)
236 size_t rd = 0;
240 if (vlc_killed())
242 vlc_testcancel();
243 errno = EINTR;
244 return -1;
247 ssize_t val = vlc_recv_i11e(fd, buf, len, 0);
248 if (val < 0)
250 if (errno == EINTR || errno == EAGAIN)
251 continue;
252 #ifdef _WIN32
253 else if (WSAGetLastError() == WSAEMSGSIZE) /* datagram too big */
255 msg_Warn(obj, "read truncated to %zu bytes", len);
256 val = len;
258 #endif
259 else
261 msg_Err(obj, "read error: %s", vlc_strerror_c(errno));
262 return rd ? (ssize_t)rd : -1;
266 rd += val;
268 if (val == 0)
269 break;
271 assert(len >= (size_t)val);
272 len -= val;
273 buf = ((char *)buf) + val;
275 while (len > 0);
277 return rd;
281 * Writes data to a socket.
282 * This blocks until all data is written or an error occurs.
284 * This function is a cancellation point.
286 * @return the total number of bytes written, or -1 if an error occurs
287 * before any data is written.
289 ssize_t (net_Write)(vlc_object_t *obj, int fd, const void *buf, size_t len)
291 size_t written = 0;
295 if (vlc_killed())
297 vlc_testcancel();
298 errno = EINTR;
299 return -1;
302 ssize_t val = vlc_send_i11e (fd, buf, len, MSG_NOSIGNAL);
303 if (val == -1)
305 if (errno == EINTR || errno == EAGAIN)
306 continue;
308 msg_Err(obj, "write error: %s", vlc_strerror_c(errno));
309 return written ? (ssize_t)written : -1;
312 if (val == 0)
313 break;
315 written += val;
316 assert(len >= (size_t)val);
317 len -= val;
318 buf = ((const char *)buf) + val;
320 while (len > 0);
322 return written;
325 #undef net_Gets
327 * Reads a line from a file descriptor.
328 * This function is not thread-safe; the same file descriptor I/O cannot be
329 * read by another thread at the same time (although it can be written to).
331 * @note This only works with stream-oriented file descriptors, not with
332 * datagram or packet-oriented ones.
334 * @return nul-terminated heap-allocated string, or NULL on I/O error.
336 char *net_Gets(vlc_object_t *obj, int fd)
338 char *buf = NULL;
339 size_t size = 0, len = 0;
341 for (;;)
343 if (len == size)
345 if (unlikely(size >= (1 << 16)))
347 errno = EMSGSIZE;
348 goto error; /* put sane buffer size limit */
351 char *newbuf = realloc(buf, size + 1024);
352 if (unlikely(newbuf == NULL))
353 goto error;
354 buf = newbuf;
355 size += 1024;
357 assert(len < size);
359 ssize_t val = vlc_recv_i11e(fd, buf + len, size - len, MSG_PEEK);
360 if (val <= 0)
361 goto error;
363 char *end = memchr(buf + len, '\n', val);
364 if (end != NULL)
365 val = (end + 1) - (buf + len);
366 if (recv(fd, buf + len, val, 0) != val)
367 goto error;
368 len += val;
369 if (end != NULL)
370 break;
373 assert(len > 0);
374 buf[--len] = '\0';
375 if (len > 0 && buf[--len] == '\r')
376 buf[len] = '\0';
377 return buf;
378 error:
379 msg_Err(obj, "read error: %s", vlc_strerror_c(errno));
380 free(buf);
381 return NULL;
384 #undef net_Printf
385 ssize_t net_Printf( vlc_object_t *p_this, int fd, const char *psz_fmt, ... )
387 int i_ret;
388 va_list args;
389 va_start( args, psz_fmt );
390 i_ret = net_vaPrintf( p_this, fd, psz_fmt, args );
391 va_end( args );
393 return i_ret;
396 #undef net_vaPrintf
397 ssize_t net_vaPrintf( vlc_object_t *p_this, int fd,
398 const char *psz_fmt, va_list args )
400 char *psz;
401 int i_ret;
403 int i_size = vasprintf( &psz, psz_fmt, args );
404 if( i_size == -1 )
405 return -1;
406 i_ret = net_Write( p_this, fd, psz, i_size ) < i_size
407 ? -1 : i_size;
408 free( psz );
410 return i_ret;