]> git.sesse.net Git - vlc/blob - src/network/udp.c
Fix the most common strerror() usages (threads, network, input) - refs #1297
[vlc] / src / network / udp.c
1 /*****************************************************************************
2  * udp.c:
3  *****************************************************************************
4  * Copyright (C) 2004-2006 the VideoLAN team
5  * Copyright © 2006-2007 Rémi Denis-Courmont
6  *
7  * $Id$
8  *
9  * Authors: Laurent Aimar <fenrir@videolan.org>
10  *          Rémi Denis-Courmont <rem # videolan.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 #include <vlc/vlc.h>
31
32 #include <errno.h>
33
34 #ifdef HAVE_SYS_TIME_H
35 #    include <sys/time.h>
36 #endif
37
38 #include <vlc_network.h>
39
40 #ifdef WIN32
41 #   if defined(UNDER_CE)
42 #       undef IP_MULTICAST_TTL
43 #       define IP_MULTICAST_TTL 3
44 #       undef IP_ADD_MEMBERSHIP
45 #       define IP_ADD_MEMBERSHIP 5
46 #   endif
47 #   define EAFNOSUPPORT WSAEAFNOSUPPORT
48 #   define if_nametoindex( str ) atoi( str )
49 #else
50 #   include <unistd.h>
51 #   ifdef HAVE_NET_IF_H
52 #       include <net/if.h>
53 #   endif
54 #endif
55
56 #ifndef SOL_IP
57 # define SOL_IP IPPROTO_IP
58 #endif
59 #ifndef SOL_IPV6
60 # define SOL_IPV6 IPPROTO_IPV6
61 #endif
62 #ifndef IPPROTO_IPV6
63 # define IPPROTO_IPV6 41 /* IANA */
64 #endif
65 #ifndef SOL_DCCP
66 # define SOL_DCCP IPPROTO_DCCP
67 #endif
68 #ifndef IPPROTO_DCCP
69 # define IPPROTO_DCCP 33 /* IANA */
70 #endif
71 #ifndef SOL_UDPLITE
72 # define SOL_UDPLITE IPPROTO_UDPLITE
73 #endif
74 #ifndef IPPROTO_UDPLITE
75 # define IPPROTO_UDPLITE 136 /* IANA */
76 #endif
77
78 #ifdef HAVE_LINUX_DCCP_H
79 # include <linux/dccp.h>
80 # ifndef SOCK_DCCP /* provisional API */
81 #  define SOCK_DCCP 6
82 # endif
83 #endif
84
85 #if defined (HAVE_NETINET_UDPLITE_H)
86 # include <netinet/udplite.h>
87 #elif defined (__linux__)
88 /* still missing from glibc 2.6 */
89 # define UDPLITE_SEND_CSCOV     10
90 # define UDPLITE_RECV_CSCOV     11
91 #endif
92
93 extern int net_Socket( vlc_object_t *p_this, int i_family, int i_socktype,
94                        int i_protocol );
95
96 static int net_ListenSingle (vlc_object_t *obj, const char *host, int port,
97                              int family, int protocol)
98 {
99     struct addrinfo hints, *res;
100
101     memset (&hints, 0, sizeof( hints ));
102     hints.ai_family = family;
103     hints.ai_socktype = SOCK_DGRAM;
104     hints.ai_flags = AI_PASSIVE;
105
106     if (host && !*host)
107         host = NULL;
108
109     msg_Dbg (obj, "net: opening %s datagram port %d", host ?: "any", port);
110
111     int val = vlc_getaddrinfo (obj, host, port, &hints, &res);
112     if (val)
113     {
114         msg_Err (obj, "Cannot resolve %s port %d : %s", host, port,
115                  vlc_gai_strerror (val));
116         return -1;
117     }
118
119     val = -1;
120
121     for (const struct addrinfo *ptr = res; ptr != NULL; ptr = ptr->ai_next)
122     {
123         int fd = net_Socket (obj, ptr->ai_family, ptr->ai_socktype,
124                              protocol ?: ptr->ai_protocol);
125         if (fd == -1)
126         {
127             msg_Dbg (obj, "socket error: %m");
128             continue;
129         }
130
131         if (ptr->ai_next != NULL)
132         {
133 #ifdef IPV6_V6ONLY
134             if ((ptr->ai_family != AF_INET6)
135              || setsockopt (fd, SOL_IPV6, IPV6_V6ONLY, &(int){ 0 },
136                             sizeof (int)))
137 #endif
138             {
139                 msg_Err (obj, "Multiple network protocols present");
140                 msg_Err (obj, "Please select network protocol manually");
141             }
142         }
143
144         /* Bind the socket */
145 #if defined (WIN32) || defined (UNDER_CE)
146         if (net_SockAddrIsMulticast (ptr->ai_addr, ptr->ai_addrlen)
147          && (sizeof (struct sockaddr_storage) >= ptr->ai_addrlen))
148         {
149             struct sockaddr_in6 dumb =
150             {
151                 .sin6_family = ptr->ai_addr->sa_family,
152                 .sin6_port =  ((struct sockaddr_in *)(ptr->ai_addr))->sin_port
153             };
154             bind (fd, (struct sockaddr *)&dumb, ptr->ai_addrlen);
155         }
156         else
157 #endif
158         if (bind (fd, ptr->ai_addr, ptr->ai_addrlen))
159         {
160             msg_Err (obj, "socket bind error (%m)");
161             net_Close (fd);
162             continue;
163         }
164
165         if (net_SockAddrIsMulticast (ptr->ai_addr, ptr->ai_addrlen)
166          && net_Subscribe (obj, fd, ptr->ai_addr, ptr->ai_addrlen))
167         {
168             net_Close (fd);
169             continue;
170         }
171
172         val = fd;
173         break;
174     }
175
176     vlc_freeaddrinfo (res);
177     return val;
178 }
179
180
181 static int net_SetMcastHopLimit( vlc_object_t *p_this,
182                                  int fd, int family, int hlim )
183 {
184     int proto, cmd;
185
186     /* There is some confusion in the world whether IP_MULTICAST_TTL
187      * takes a byte or an int as an argument.
188      * BSD seems to indicate byte so we are going with that and use
189      * int as a fallback to be safe */
190     switch( family )
191     {
192 #ifdef IP_MULTICAST_TTL
193         case AF_INET:
194             proto = SOL_IP;
195             cmd = IP_MULTICAST_TTL;
196             break;
197 #endif
198
199 #ifdef IPV6_MULTICAST_HOPS
200         case AF_INET6:
201             proto = SOL_IPV6;
202             cmd = IPV6_MULTICAST_HOPS;
203             break;
204 #endif
205
206         default:
207             errno = EAFNOSUPPORT;
208             msg_Warn( p_this, "%m" );
209             return VLC_EGENERIC;
210     }
211
212     if( setsockopt( fd, proto, cmd, &hlim, sizeof( hlim ) ) < 0 )
213     {
214         /* BSD compatibility */
215         unsigned char buf;
216
217         buf = (unsigned char)(( hlim > 255 ) ? 255 : hlim);
218         if( setsockopt( fd, proto, cmd, &buf, sizeof( buf ) ) )
219             return VLC_EGENERIC;
220     }
221
222     return VLC_SUCCESS;
223 }
224
225
226 static int net_SetMcastOutIface (int fd, int family, int scope)
227 {
228     switch (family)
229     {
230 #ifdef IPV6_MULTICAST_IF
231         case AF_INET6:
232             return setsockopt (fd, SOL_IPV6, IPV6_MULTICAST_IF,
233                                &scope, sizeof (scope));
234 #endif
235
236 #ifdef __linux__
237         case AF_INET:
238         {
239             struct ip_mreqn req = { .imr_ifindex = scope };
240
241             return setsockopt (fd, SOL_IP, IP_MULTICAST_IF, &req,
242                                sizeof (req));
243         }
244 #endif
245     }
246
247     errno = EAFNOSUPPORT;
248     return -1;
249 }
250
251
252 static inline int net_SetMcastOutIPv4 (int fd, struct in_addr ipv4)
253 {
254 #ifdef IP_MULTICAST_IF
255     return setsockopt( fd, SOL_IP, IP_MULTICAST_IF, &ipv4, sizeof (ipv4));
256 #else
257     errno = EAFNOSUPPORT;
258     return -1;
259 #endif
260 }
261
262
263 static int net_SetMcastOut (vlc_object_t *p_this, int fd, int family,
264                             const char *iface, const char *addr)
265 {
266     if (iface != NULL)
267     {
268         int scope = if_nametoindex (iface);
269         if (scope == 0)
270         {
271             msg_Err (p_this, "invalid multicast interface: %s", iface);
272             return -1;
273         }
274
275         if (net_SetMcastOutIface (fd, family, scope) == 0)
276             return 0;
277
278         msg_Err (p_this, "%s: %m", iface);
279     }
280
281     if (addr != NULL)
282     {
283         if (family == AF_INET)
284         {
285             struct in_addr ipv4;
286             if (inet_pton (AF_INET, addr, &ipv4) <= 0)
287             {
288                 msg_Err (p_this, "invalid IPv4 address for multicast: %s",
289                          addr);
290                 return -1;
291             }
292
293             if (net_SetMcastOutIPv4 (fd, ipv4) == 0)
294                 return 0;
295
296             msg_Err (p_this, "%s: %m", addr);
297         }
298     }
299
300     return -1;
301 }
302
303
304 /**
305  * Old-style any-source multicast join.
306  * In use on Windows XP/2003 and older.
307  */
308 static int
309 net_IPv4Join (vlc_object_t *obj, int fd,
310               const struct sockaddr_in *src, const struct sockaddr_in *grp)
311 {
312 #ifdef IP_ADD_MEMBERSHIP
313     union
314     {
315         struct ip_mreq gr4;
316 # ifdef IP_ADD_SOURCE_MEMBERSHIP
317         struct ip_mreq_source gsr4;
318 # endif
319     } opt;
320     int cmd;
321     struct in_addr id = { .s_addr = INADDR_ANY };
322     socklen_t optlen;
323
324     /* Multicast interface IPv4 address */
325     char *iface = var_CreateGetNonEmptyString (obj, "miface-addr");
326     if ((iface != NULL)
327      && (inet_pton (AF_INET, iface, &id) <= 0))
328     {
329         msg_Err (obj, "invalid multicast interface address %s", iface);
330         free (iface);
331         goto error;
332     }
333     free (iface);
334
335     memset (&opt, 0, sizeof (opt));
336     if (src != NULL)
337     {
338 # ifdef IP_ADD_SOURCE_MEMBERSHIP
339         cmd = IP_ADD_SOURCE_MEMBERSHIP;
340         opt.gsr4.imr_multiaddr = grp->sin_addr;
341         opt.gsr4.imr_sourceaddr = src->sin_addr;
342         opt.gsr4.imr_interface = id;
343         optlen = sizeof (opt.gsr4);
344 # else
345         errno = ENOSYS;
346         goto error;
347 # endif
348     }
349     else
350     {
351         cmd = IP_ADD_MEMBERSHIP;
352         opt.gr4.imr_multiaddr = grp->sin_addr;
353         opt.gr4.imr_interface = id;
354         optlen = sizeof (opt.gr4);
355     }
356
357     msg_Dbg (obj, "IP_ADD_%sMEMBERSHIP multicast request",
358              (src != NULL) ? "SOURCE_" : "");
359
360     if (setsockopt (fd, SOL_IP, cmd, &opt, optlen) == 0)
361         return 0;
362
363 error:
364 #endif
365
366     msg_Err (obj, "cannot join IPv4 multicast group (%m)");
367     return -1;
368 }
369
370
371 static int
372 net_IPv6Join (vlc_object_t *obj, int fd, const struct sockaddr_in6 *src)
373 {
374 #ifdef IPV6_JOIN_GROUP
375     struct ipv6_mreq gr6;
376     memset (&gr6, 0, sizeof (gr6));
377     gr6.ipv6mr_interface = src->sin6_scope_id;
378     memcpy (&gr6.ipv6mr_multiaddr, &src->sin6_addr, 16);
379
380     msg_Dbg (obj, "IPV6_JOIN_GROUP multicast request");
381
382     if (!setsockopt (fd, IPPROTO_IPV6, IPV6_JOIN_GROUP, &gr6, sizeof (gr6)))
383         return 0;
384 #else
385     errno = ENOSYS;
386 #endif
387
388     msg_Err (obj, "cannot join IPv6 any-source multicast group (%m)");
389     return -1;
390 }
391
392
393 #if defined (WIN32) && !defined (MCAST_JOIN_SOURCE_GROUP)
394 /*
395  * I hate manual definitions: Error-prone. Portability hell.
396  * Developers shall use UP-TO-DATE compilers. Full point.
397  * If you remove the warning, you remove the whole ifndef.
398  */
399 #  warning Your C headers are out-of-date. Please update.
400
401 #  define MCAST_JOIN_GROUP 41
402 struct group_req
403 {
404     ULONG gr_interface;
405     struct sockaddr_storage gr_group;
406 };
407
408 #  define MCAST_JOIN_SOURCE_GROUP 45 /* from <ws2ipdef.h> */
409 struct group_source_req
410 {
411     uint32_t gsr_interface;
412     struct sockaddr_storage gsr_group;
413     struct sockaddr_storage gsr_source;
414 };
415 #endif
416
417 /**
418  * IP-agnostic multicast join,
419  * with fallback to old APIs, and fallback from SSM to ASM.
420  */
421 static int
422 net_SourceSubscribe (vlc_object_t *obj, int fd,
423                      const struct sockaddr *src, socklen_t srclen,
424                      const struct sockaddr *grp, socklen_t grplen)
425 {
426     int level, iid = 0;
427
428     char *iface = var_CreateGetNonEmptyString (obj, "miface");
429     if (iface != NULL)
430     {
431         iid = if_nametoindex (iface);
432         if (iid == 0)
433         {
434             msg_Err (obj, "invalid multicast interface: %s", iface);
435             free (iface);
436             return -1;
437         }
438         free (iface);
439     }
440
441     switch (grp->sa_family)
442     {
443 #ifdef AF_INET6
444         case AF_INET6:
445             level = SOL_IPV6;
446             if (((const struct sockaddr_in6 *)grp)->sin6_scope_id)
447                 iid = ((const struct sockaddr_in6 *)grp)->sin6_scope_id;
448             break;
449 #endif
450
451         case AF_INET:
452             level = SOL_IP;
453             break;
454
455         default:
456             errno = EAFNOSUPPORT;
457             return -1;
458     }
459
460     if (src != NULL)
461         switch (src->sa_family)
462         {
463 #ifdef AF_INET6
464             case AF_INET6:
465                 if (memcmp (&((const struct sockaddr_in6 *)src)->sin6_addr,
466                             &in6addr_any, sizeof (in6addr_any)) == 0)
467                     src = NULL;
468             break;
469 #endif
470
471             case AF_INET:
472                 if (((const struct sockaddr_in *)src)->sin_addr.s_addr
473                      == INADDR_ANY)
474                     src = NULL;
475                 break;
476         }
477
478
479     /* Agnostic ASM/SSM multicast join */
480 #ifdef MCAST_JOIN_SOURCE_GROUP
481     union
482     {
483         struct group_req gr;
484         struct group_source_req gsr;
485     } opt;
486     socklen_t optlen;
487
488     memset (&opt, 0, sizeof (opt));
489
490     if (src != NULL)
491     {
492         if ((grplen > sizeof (opt.gsr.gsr_group))
493          || (srclen > sizeof (opt.gsr.gsr_source)))
494             return -1;
495
496         opt.gsr.gsr_interface = iid;
497         memcpy (&opt.gsr.gsr_source, src, srclen);
498         memcpy (&opt.gsr.gsr_group,  grp, grplen);
499         optlen = sizeof (opt.gsr);
500     }
501     else
502     {
503         if (grplen > sizeof (opt.gr.gr_group))
504             return -1;
505
506         opt.gr.gr_interface = iid;
507         memcpy (&opt.gr.gr_group, grp, grplen);
508         optlen = sizeof (opt.gr);
509     }
510
511     msg_Dbg (obj, "Multicast %sgroup join request", src ? "source " : "");
512
513     if (setsockopt (fd, level,
514                     src ? MCAST_JOIN_SOURCE_GROUP : MCAST_JOIN_GROUP,
515                     (void *)&opt, optlen) == 0)
516         return 0;
517 #endif
518
519     /* Fallback to IPv-specific APIs */
520     if ((src != NULL) && (src->sa_family != grp->sa_family))
521         return -1;
522
523     switch (grp->sa_family)
524     {
525         case AF_INET:
526             if ((grplen < sizeof (struct sockaddr_in))
527              || ((src != NULL) && (srclen < sizeof (struct sockaddr_in))))
528                 return -1;
529
530             if (net_IPv4Join (obj, fd, (const struct sockaddr_in *)src,
531                               (const struct sockaddr_in *)grp) == 0)
532                 return 0;
533             break;
534
535 #ifdef AF_INET6
536         case AF_INET6:
537             if ((grplen < sizeof (struct sockaddr_in6))
538              || ((src != NULL) && (srclen < sizeof (struct sockaddr_in6))))
539                 return -1;
540
541             /* IPv6-specific SSM API does not exist. So if we're here
542              * it means IPv6 SSM is not supported on this OS and we
543              * directly fallback to ASM */
544
545             if (net_IPv6Join (obj, fd, (const struct sockaddr_in6 *)grp) == 0)
546                 return 0;
547             break;
548 #endif
549     }
550
551     msg_Err (obj, "Multicast group join error (%m)");
552
553     if (src != NULL)
554     {
555         msg_Warn (obj, "Trying ASM instead of SSM...");
556         return net_Subscribe (obj, fd, grp, grplen);
557     }
558
559     msg_Err (obj, "Multicast not supported");
560     return -1;
561 }
562
563
564 int net_Subscribe (vlc_object_t *obj, int fd,
565                    const struct sockaddr *addr, socklen_t addrlen)
566 {
567     return net_SourceSubscribe (obj, fd, NULL, 0, addr, addrlen);
568 }
569
570
571 static int net_SetDSCP( int fd, uint8_t dscp )
572 {
573     struct sockaddr_storage addr;
574     if( getsockname( fd, (struct sockaddr *)&addr, &(socklen_t){ sizeof (addr) }) )
575         return -1;
576
577     int level, cmd;
578
579     switch( addr.ss_family )
580     {
581 #ifdef IPV6_TCLASS
582         case AF_INET6:
583             level = SOL_IPV6;
584             cmd = IPV6_TCLASS;
585             break;
586 #endif
587
588         case AF_INET:
589             level = SOL_IP;
590             cmd = IP_TOS;
591             break;
592
593         default:
594 #ifdef ENOPROTOOPT
595             errno = ENOPROTOOPT;
596 #endif
597             return -1;
598     }
599
600     return setsockopt( fd, level, cmd, &(int){ dscp }, sizeof (int));
601 }
602
603
604 /*****************************************************************************
605  * __net_ConnectDgram:
606  *****************************************************************************
607  * Open a datagram socket to send data to a defined destination, with an
608  * optional hop limit.
609  *****************************************************************************/
610 int __net_ConnectDgram( vlc_object_t *p_this, const char *psz_host, int i_port,
611                         int i_hlim, int proto )
612 {
613     struct addrinfo hints, *res, *ptr;
614     int             i_val, i_handle = -1;
615     vlc_bool_t      b_unreach = VLC_FALSE;
616
617     if( i_port == 0 )
618         i_port = 1234; /* historical VLC thing */
619
620     if( i_hlim < 1 )
621         i_hlim = var_CreateGetInteger( p_this, "ttl" );
622
623     memset( &hints, 0, sizeof( hints ) );
624     hints.ai_socktype = SOCK_DGRAM;
625
626     msg_Dbg( p_this, "net: connecting to %s port %d", psz_host, i_port );
627
628     i_val = vlc_getaddrinfo( p_this, psz_host, i_port, &hints, &res );
629     if( i_val )
630     {
631         msg_Err( p_this, "cannot resolve %s port %d : %s", psz_host, i_port,
632                  vlc_gai_strerror( i_val ) );
633         return -1;
634     }
635
636     for( ptr = res; ptr != NULL; ptr = ptr->ai_next )
637     {
638         char *str;
639         int fd = net_Socket (p_this, ptr->ai_family, ptr->ai_socktype,
640                              proto ?: ptr->ai_protocol);
641         if (fd == -1)
642             continue;
643
644 #if !defined( SYS_BEOS )
645         /* Increase the receive buffer size to 1/2MB (8Mb/s during 1/2s)
646         * to avoid packet loss caused by scheduling problems */
647         setsockopt (fd, SOL_SOCKET, SO_RCVBUF, &(int){ 0x80000 }, sizeof (int));
648         setsockopt (fd, SOL_SOCKET, SO_SNDBUF, &(int){ 0x80000 }, sizeof (int));
649
650         /* Allow broadcast sending */
651         setsockopt (fd, SOL_SOCKET, SO_BROADCAST, &(int){ 1 }, sizeof (int));
652 #endif
653
654         if( i_hlim > 0 )
655             net_SetMcastHopLimit( p_this, fd, ptr->ai_family, i_hlim );
656
657         str = var_CreateGetNonEmptyString (p_this, "miface");
658         if (str != NULL)
659         {
660             net_SetMcastOut (p_this, fd, ptr->ai_family, str, NULL);
661             free (str);
662         }
663
664         str = var_CreateGetNonEmptyString (p_this, "miface-addr");
665         if (str != NULL)
666         {
667             net_SetMcastOut (p_this, fd, ptr->ai_family, NULL, str);
668             free (str);
669         }
670
671         net_SetDSCP (fd, var_CreateGetInteger (p_this, "dscp"));
672
673         if( connect( fd, ptr->ai_addr, ptr->ai_addrlen ) == 0 )
674         {
675             /* success */
676             i_handle = fd;
677             break;
678         }
679
680 #if defined( WIN32 ) || defined( UNDER_CE )
681         if( WSAGetLastError () == WSAENETUNREACH )
682 #else
683         if( errno == ENETUNREACH )
684 #endif
685             b_unreach = VLC_TRUE;
686         else
687         {
688             msg_Warn( p_this, "%s port %d : %m", psz_host, i_port);
689             net_Close( fd );
690             continue;
691         }
692     }
693
694     vlc_freeaddrinfo( res );
695
696     if( i_handle == -1 )
697     {
698         if( b_unreach )
699             msg_Err( p_this, "Host %s port %d is unreachable", psz_host,
700                      i_port );
701         return -1;
702     }
703
704     return i_handle;
705 }
706
707
708 /*****************************************************************************
709  * __net_OpenDgram:
710  *****************************************************************************
711  * OpenDgram a datagram socket and return a handle
712  *****************************************************************************/
713 int __net_OpenDgram( vlc_object_t *obj, const char *psz_bind, int i_bind,
714                      const char *psz_server, int i_server,
715                      int family, int protocol )
716 {
717     if ((psz_server == NULL) || (psz_server[0] == '\0'))
718         return net_ListenSingle (obj, psz_bind, i_bind, family, protocol);
719
720     msg_Dbg (obj, "net: connecting to [%s]:%d from [%s]:%d",
721              psz_server, i_server, psz_bind, i_bind);
722
723     struct addrinfo hints, *loc, *rem;
724     int val;
725
726     memset (&hints, 0, sizeof (hints));
727     hints.ai_family = family;
728     hints.ai_socktype = SOCK_DGRAM;
729
730     val = vlc_getaddrinfo (obj, psz_server, i_server, &hints, &rem);
731     if (val)
732     {
733         msg_Err (obj, "cannot resolve %s port %d : %s", psz_bind, i_bind,
734                  vlc_gai_strerror (val));
735         return -1;
736     }
737
738     hints.ai_flags = AI_PASSIVE;
739     val = vlc_getaddrinfo (obj, psz_bind, i_bind, &hints, &loc);
740     if (val)
741     {
742         msg_Err (obj, "cannot resolve %s port %d : %s", psz_bind, i_bind,
743                  vlc_gai_strerror (val));
744         vlc_freeaddrinfo (rem);
745         return -1;
746     }
747
748     for (struct addrinfo *ptr = loc; ptr != NULL; ptr = ptr->ai_next)
749     {
750         int fd = net_Socket (obj, ptr->ai_family, ptr->ai_socktype,
751                              protocol ?: ptr->ai_protocol);
752         if (fd == -1)
753             continue; // usually, address family not supported
754
755 #ifdef SO_REUSEPORT
756         setsockopt (fd, SOL_SOCKET, SO_REUSEPORT, &(int){ 1 }, sizeof (int));
757 #endif
758
759 #ifdef SO_RCVBUF
760         /* Increase the receive buffer size to 1/2MB (8Mb/s during 1/2s)
761          * to avoid packet loss caused in case of scheduling hiccups */
762         setsockopt (fd, SOL_SOCKET, SO_RCVBUF,
763                     (void *)&(int){ 0x80000 }, sizeof (int));
764         setsockopt (fd, SOL_SOCKET, SO_SNDBUF,
765                     (void *)&(int){ 0x80000 }, sizeof (int));
766 #endif
767
768 #if defined (WIN32) || defined (UNDER_CE)
769         if (net_SockAddrIsMulticast (ptr->ai_addr, ptr->ai_addrlen)
770          && (sizeof (struct sockaddr_storage) >= ptr->ai_addrlen))
771         {
772             // This works for IPv4 too - don't worry!
773             struct sockaddr_in6 dumb =
774             {
775                 .sin6_family = ptr->ai_addr->sa_family,
776                 .sin6_port =  ((struct sockaddr_in *)(ptr->ai_addr))->sin_port
777             };
778
779             bind (fd, (struct sockaddr *)&dumb, ptr->ai_addrlen);
780         }
781         else
782 #endif
783         if (bind (fd, ptr->ai_addr, ptr->ai_addrlen))
784         {
785             net_Close (fd);
786             continue;
787         }
788
789         val = -1;
790         for (struct addrinfo *ptr2 = rem; ptr2 != NULL; ptr2 = ptr2->ai_next)
791         {
792             if ((ptr2->ai_family != ptr->ai_family)
793              || (ptr2->ai_socktype != ptr->ai_socktype)
794              || (ptr2->ai_protocol != ptr->ai_protocol))
795                 continue;
796
797             if (net_SockAddrIsMulticast (ptr->ai_addr, ptr->ai_addrlen)
798               ? net_SourceSubscribe (obj, fd,
799                                      ptr2->ai_addr, ptr2->ai_addrlen,
800                                      ptr->ai_addr, ptr->ai_addrlen)
801               : connect (fd, ptr2->ai_addr, ptr2->ai_addrlen))
802             {
803                 msg_Err (obj, "cannot connect to %s port %d: %m",
804                          psz_server, i_server);
805                 continue;
806             }
807             val = fd;
808             break;
809         }
810
811         if (val != -1)
812             break;
813
814         close (fd);
815     }
816
817     vlc_freeaddrinfo (rem);
818     vlc_freeaddrinfo (loc);
819     return val;
820 }
821
822
823 /**
824  * net_SetCSCov:
825  * Sets the send and receive checksum coverage of a socket:
826  * @param fd socket
827  * @param sendcov payload coverage of sent packets (bytes), -1 for full
828  * @param recvcov minimum payload coverage of received packets, -1 for full
829  */
830 int net_SetCSCov (int fd, int sendcov, int recvcov)
831 {
832     int type;
833
834     if (getsockopt (fd, SOL_SOCKET, SO_TYPE,
835                     &type, &(socklen_t){ sizeof (type) }))
836         return VLC_EGENERIC;
837
838     switch (type)
839     {
840 #ifdef UDPLITE_RECV_CSCOV
841         case SOCK_DGRAM: /* UDP-Lite */
842             if (sendcov == -1)
843                 sendcov = 0;
844             else
845                 sendcov += 8; /* partial */
846             if (setsockopt (fd, SOL_UDPLITE, UDPLITE_SEND_CSCOV, &sendcov,
847                             sizeof (sendcov)))
848                 return VLC_EGENERIC;
849
850             if (recvcov == -1)
851                 recvcov = 0;
852             else
853                 recvcov += 8;
854             if (setsockopt (fd, SOL_UDPLITE, UDPLITE_RECV_CSCOV,
855                             &recvcov, sizeof (recvcov)))
856                 return VLC_EGENERIC;
857
858             return VLC_SUCCESS;
859 #endif
860 #ifdef DCCP_SOCKOPT_SEND_CSCOV
861         case SOCK_DCCP: /* DCCP and its ill-named socket type */
862             if ((sendcov == -1) || (sendcov > 56))
863                 sendcov = 0;
864             else
865                 sendcov = (sendcov + 3) / 4;
866             if (setsockopt (fd, SOL_DCCP, DCCP_SOCKOPT_SEND_CSCOV,
867                             &sendcov, sizeof (sendcov)))
868                 return VLC_EGENERIC;
869
870             if ((recvcov == -1) || (recvcov > 56))
871                 recvcov = 0;
872             else
873                 recvcov = (recvcov + 3) / 4;
874             if (setsockopt (fd, SOL_DCCP, DCCP_SOCKOPT_RECV_CSCOV,
875                             &recvcov, sizeof (recvcov)))
876                 return VLC_EGENERIC;
877
878             return VLC_SUCCESS;
879 #endif
880     }
881
882     return VLC_EGENERIC;
883 }