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>
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 /*****************************************************************************
28 *****************************************************************************/
44 #ifdef HAVE_LINUX_DCCP_H
45 /* TODO: use glibc instead of linux-kernel headers */
46 # include <linux/dccp.h>
50 #include <vlc_common.h>
51 #include <vlc_network.h>
52 #include <vlc_interrupt.h>
55 # define EINPROGRESS WSAEWOULDBLOCK
57 # define EWOULDBLOCK WSAEWOULDBLOCK
59 # define EAGAIN WSAEWOULDBLOCK
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
,
68 int fd
= vlc_socket (family
, socktype
, protocol
, true);
71 if (net_errno
!= EAFNOSUPPORT
)
72 msg_Err (p_this
, "cannot create socket: %s",
73 vlc_strerror_c(net_errno
));
78 // Windows expects a BOOL for some getsockopt/setsockopt options
79 static_assert(sizeof(int)==sizeof(BOOL
), "mismatching type for setsockopt");
81 setsockopt (fd
, SOL_SOCKET
, SO_REUSEADDR
, &(int){ 1 }, sizeof (int));
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));
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
98 if (family
== AF_INET6
)
99 setsockopt (fd
, IPPROTO_IPV6
, IPV6_PROTECTION_LEVEL
,
100 &(int){ PROTECTION_LEVEL_UNRESTRICTED
}, sizeof (int));
103 #ifdef DCCP_SOCKOPT_SERVICE
104 if (socktype
== SOL_DCCP
)
106 char *dccps
= var_InheritString (p_this
, "dccp-service");
109 setsockopt (fd
, SOL_DCCP
, DCCP_SOCKOPT_SERVICE
, dccps
,
110 (strlen (dccps
) + 3) & ~3);
119 int (net_Connect
)(vlc_object_t
*obj
, const char *host
, int serv
,
122 struct addrinfo hints
= {
124 .ai_protocol
= proto
,
125 .ai_flags
= AI_NUMERICSERV
| AI_IDN
,
129 int val
= vlc_getaddrinfo_i11e(host
, serv
, &hints
, &res
);
132 msg_Err(obj
, "cannot resolve %s port %d : %s", host
, serv
,
137 vlc_tick_t timeout
= VLC_TICK_FROM_MS(var_InheritInteger(obj
,
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
);
146 msg_Dbg(obj
, "socket error: %s", vlc_strerror_c(net_errno
));
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
));
160 vlc_tick_t deadline
= VLC_TICK_INVALID
;
163 ufd
.events
= POLLOUT
;
164 deadline
= vlc_tick_now() + timeout
;
168 vlc_tick_t now
= vlc_tick_now();
176 val
= vlc_poll_i11e(&ufd
, 1, MS_FROM_VLC_TICK(deadline
- now
));
178 while (val
== -1 && errno
== EINTR
);
183 msg_Err(obj
, "polling error: %s",
184 vlc_strerror_c(net_errno
));
187 case 0: /* timeout */
188 msg_Warn(obj
, "connection timed out");
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
));
202 msg_Dbg(obj
, "connection succeeded (socket = %d)", fd
);
203 ret
= fd
; /* success! */
206 next_ai
: /* failure */
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
= {
219 .ai_protocol
= protocol
,
220 .ai_flags
= AI_PASSIVE
| AI_NUMERICSERV
| AI_IDN
,
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
);
229 msg_Err (p_this
, "Cannot resolve %s port %u : %s",
230 (psz_host
!= NULL
) ? psz_host
: "", i_port
,
231 gai_strerror (i_val
));
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
,
244 msg_Dbg (p_this
, "socket error: %s", vlc_strerror_c(net_errno
));
248 /* Bind the socket */
249 if (bind (fd
, ptr
->ai_addr
, ptr
->ai_addrlen
))
254 fd
= rootwrap_bind (ptr
->ai_family
, ptr
->ai_socktype
,
256 ptr
->ai_addr
, ptr
->ai_addrlen
);
259 msg_Dbg (p_this
, "got socket %d from rootwrap", fd
);
264 msg_Err (p_this
, "socket bind error: %s", vlc_strerror_c(err
));
270 if (listen(fd
, INT_MAX
))
272 msg_Err(p_this
, "socket listen error: %s",
273 vlc_strerror_c(net_errno
));
278 int *nsockv
= (int *)realloc (sockv
, (sockc
+ 2) * sizeof (int));
281 nsockv
[sockc
++] = fd
;
296 void net_ListenClose(int *fds
)
300 for (int *p
= fds
; *p
!= -1; p
++)
308 int net_Accept(vlc_object_t
*obj
, int *fds
)
316 struct pollfd ufd
[n
];
317 /* Initialize file descriptor set */
318 for (unsigned i
= 0; i
< n
; i
++)
321 ufd
[i
].events
= POLLIN
;
326 while (poll(ufd
, n
, -1) == -1)
328 if (net_errno
!= EINTR
)
330 msg_Err(obj
, "poll error: %s", vlc_strerror_c(net_errno
));
335 for (unsigned i
= 0; i
< n
; i
++)
337 if (ufd
[i
].revents
== 0)
341 int fd
= vlc_accept(sfd
, NULL
, NULL
, true);
344 if (net_errno
!= EAGAIN
)
345 #if (EAGAIN != EWOULDBLOCK)
346 if (net_errno
!= EWOULDBLOCK
)
348 msg_Err(obj
, "accept failed (from socket %d): %s", sfd
,
349 vlc_strerror_c(net_errno
));
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));
368 ssize_t (net_Read
)(vlc_object_t
*restrict obj
, int fd
,
369 void *restrict buf
, size_t len
)
382 ssize_t val
= vlc_recv_i11e(fd
, buf
, len
, 0);
385 if (errno
== EINTR
|| errno
== EAGAIN
)
388 else if (WSAGetLastError() == WSAEMSGSIZE
) /* datagram too big */
390 msg_Warn(obj
, "read truncated to %zu bytes", len
);
396 msg_Err(obj
, "read error: %s", vlc_strerror_c(errno
));
397 return rd
? (ssize_t
)rd
: -1;
406 assert(len
>= (size_t)val
);
408 buf
= ((char *)buf
) + val
;
415 ssize_t (net_Write
)(vlc_object_t
*obj
, int fd
, const void *buf
, size_t len
)
428 ssize_t val
= vlc_send_i11e(fd
, buf
, len
, 0);
431 if (errno
== EINTR
|| errno
== EAGAIN
)
434 msg_Err(obj
, "write error: %s", vlc_strerror_c(errno
));
435 return written
? (ssize_t
)written
: -1;
442 assert(len
>= (size_t)val
);
444 buf
= ((const char *)buf
) + val
;