X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=src%2Fnetwork%2Fudp.c;h=3b2f5454670a1b5fb26bdfcfb3b9dde58341f702;hb=2275df911220b4ae3525014fc711c7e467fcf69f;hp=abdc011319b0d2e2f0d14723dcfe55a254c4456a;hpb=b7110f8e4912bb8934a4e66a72a6fcedb3383a94;p=vlc diff --git a/src/network/udp.c b/src/network/udp.c index abdc011319..3b2f545467 100644 --- a/src/network/udp.c +++ b/src/network/udp.c @@ -2,7 +2,7 @@ * udp.c: ***************************************************************************** * Copyright (C) 2004-2006 the VideoLAN team - * Copyright © 2006 Rémi Denis-Courmont + * Copyright © 2006-2007 Rémi Denis-Courmont * * $Id$ * @@ -27,17 +27,15 @@ /***************************************************************************** * Preamble *****************************************************************************/ -#include -#include +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif -#include -#include +#include -#ifdef HAVE_SYS_TIME_H -# include -#endif +#include -#include "network.h" +#include #ifdef WIN32 # if defined(UNDER_CE) @@ -55,6 +53,13 @@ # endif #endif +#ifdef HAVE_LINUX_DCCP_H +# include +# ifndef SOCK_DCCP /* provisional API */ +# define SOCK_DCCP 6 +# endif +#endif + #ifndef SOL_IP # define SOL_IP IPPROTO_IP #endif @@ -62,24 +67,153 @@ # define SOL_IPV6 IPPROTO_IPV6 #endif #ifndef IPPROTO_IPV6 -# define IPPROTO_IPV6 41 +# define IPPROTO_IPV6 41 /* IANA */ +#endif +#ifndef SOL_DCCP +# define SOL_DCCP IPPROTO_DCCP +#endif +#ifndef IPPROTO_DCCP +# define IPPROTO_DCCP 33 /* IANA */ +#endif +#ifndef SOL_UDPLITE +# define SOL_UDPLITE IPPROTO_UDPLITE +#endif +#ifndef IPPROTO_UDPLITE +# define IPPROTO_UDPLITE 136 /* IANA */ +#endif + +#if defined (HAVE_NETINET_UDPLITE_H) +# include +#elif defined (__linux__) +/* still missing from glibc 2.6 */ +# define UDPLITE_SEND_CSCOV 10 +# define UDPLITE_RECV_CSCOV 11 #endif extern int net_Socket( vlc_object_t *p_this, int i_family, int i_socktype, int i_protocol ); +/* */ +static int net_SetupDgramSocket( vlc_object_t *p_obj, int fd, const struct addrinfo *ptr ) +{ +#ifdef SO_REUSEPORT + setsockopt (fd, SOL_SOCKET, SO_REUSEPORT, &(int){ 1 }, sizeof (int)); +#endif + +#ifdef SO_RCVBUF + /* Increase the receive buffer size to 1/2MB (8Mb/s during 1/2s) + * to avoid packet loss caused in case of scheduling hiccups */ + setsockopt (fd, SOL_SOCKET, SO_RCVBUF, + (void *)&(int){ 0x80000 }, sizeof (int)); + setsockopt (fd, SOL_SOCKET, SO_SNDBUF, + (void *)&(int){ 0x80000 }, sizeof (int)); +#endif + +#if defined (WIN32) || defined (UNDER_CE) + if (net_SockAddrIsMulticast (ptr->ai_addr, ptr->ai_addrlen) + && (sizeof (struct sockaddr_storage) >= ptr->ai_addrlen)) + { + // This works for IPv4 too - don't worry! + struct sockaddr_in6 dumb = + { + .sin6_family = ptr->ai_addr->sa_family, + .sin6_port = ((struct sockaddr_in *)(ptr->ai_addr))->sin_port + }; + + bind (fd, (struct sockaddr *)&dumb, ptr->ai_addrlen); + } + else +#endif + if (bind (fd, ptr->ai_addr, ptr->ai_addrlen)) + { + msg_Err( p_obj, "socket bind error (%m)" ); + net_Close (fd); + return -1; + } + return fd; +} + +/* */ +static int net_ListenSingle (vlc_object_t *obj, const char *host, int port, + int family, int protocol) +{ + struct addrinfo hints, *res; + + memset (&hints, 0, sizeof( hints )); + hints.ai_family = family; + hints.ai_socktype = SOCK_DGRAM; + hints.ai_protocol = protocol; + hints.ai_flags = AI_PASSIVE; + + if (host && !*host) + host = NULL; + + msg_Dbg (obj, "net: opening %s datagram port %d", + host ? host : "any", port); + + int val = vlc_getaddrinfo (obj, host, port, &hints, &res); + if (val) + { + msg_Err (obj, "Cannot resolve %s port %d : %s", host, port, + vlc_gai_strerror (val)); + return -1; + } + + val = -1; + + for (const struct addrinfo *ptr = res; ptr != NULL; ptr = ptr->ai_next) + { + int fd = net_Socket (obj, ptr->ai_family, ptr->ai_socktype, + ptr->ai_protocol); + if (fd == -1) + { + msg_Dbg (obj, "socket error: %m"); + continue; + } + +#ifdef IPV6_V6ONLY + /* If IPv6 was forced, set IPv6-only mode. + * If IPv4 was forced, do nothing extraordinary. + * If nothing was forced, try dual-mode IPv6. */ + if (ptr->ai_family == AF_INET6) + { + int on = (family == AF_INET6); + setsockopt (fd, SOL_IPV6, IPV6_V6ONLY, &on, sizeof (on)); + } + if (ptr->ai_family == AF_INET) +#endif + if (family == AF_UNSPEC && ptr->ai_next != NULL) + { + msg_Warn (obj, "ambiguous network protocol specification"); + msg_Warn (obj, "please select IP version explicitly"); + } + + fd = net_SetupDgramSocket( obj, fd, ptr ); + if( fd == -1 ) + continue; + + if (net_SockAddrIsMulticast (ptr->ai_addr, ptr->ai_addrlen) + && net_Subscribe (obj, fd, ptr->ai_addr, ptr->ai_addrlen)) + { + net_Close (fd); + continue; + } + + val = fd; + break; + } + + vlc_freeaddrinfo (res); + return val; +} -/* - * XXX: I am too lazy to put all these dual functions in “next generation” - * network plugins. - */ static int net_SetMcastHopLimit( vlc_object_t *p_this, int fd, int family, int hlim ) { int proto, cmd; - /* There is some confusion in the world whether IP_MULTICAST_TTL + /* There is some confusion in the world whether IP_MULTICAST_TTL * takes a byte or an int as an argument. * BSD seems to indicate byte so we are going with that and use * int as a fallback to be safe */ @@ -100,7 +234,8 @@ static int net_SetMcastHopLimit( vlc_object_t *p_this, #endif default: - msg_Warn( p_this, "%s", strerror( EAFNOSUPPORT ) ); + errno = EAFNOSUPPORT; + msg_Warn( p_this, "%m" ); return VLC_EGENERIC; } @@ -109,9 +244,13 @@ static int net_SetMcastHopLimit( vlc_object_t *p_this, /* BSD compatibility */ unsigned char buf; + msg_Dbg( p_this, "cannot set hop limit (%d): %m", hlim ); buf = (unsigned char)(( hlim > 255 ) ? 255 : hlim); if( setsockopt( fd, proto, cmd, &buf, sizeof( buf ) ) ) + { + msg_Err( p_this, "cannot set hop limit (%d): %m", hlim ); return VLC_EGENERIC; + } } return VLC_SUCCESS; @@ -170,7 +309,7 @@ static int net_SetMcastOut (vlc_object_t *p_this, int fd, int family, if (net_SetMcastOutIface (fd, family, scope) == 0) return 0; - msg_Err (p_this, "%s: %s", iface, net_strerror (net_errno)); + msg_Err (p_this, "%s: %m", iface); } if (addr != NULL) @@ -188,7 +327,7 @@ static int net_SetMcastOut (vlc_object_t *p_this, int fd, int family, if (net_SetMcastOutIPv4 (fd, ipv4) == 0) return 0; - msg_Err (p_this, "%s: %s", addr, net_strerror (net_errno)); + msg_Err (p_this, "%s: %m", addr); } } @@ -213,21 +352,19 @@ net_IPv4Join (vlc_object_t *obj, int fd, # endif } opt; int cmd; - struct in_addr id; + struct in_addr id = { .s_addr = INADDR_ANY }; socklen_t optlen; /* Multicast interface IPv4 address */ - char *iface = var_CreateGetString (obj, "miface-addr"); - if (iface != NULL) + char *iface = var_CreateGetNonEmptyString (obj, "miface-addr"); + if ((iface != NULL) + && (inet_pton (AF_INET, iface, &id) <= 0)) { - if ((*iface) - && (inet_pton (AF_INET, iface, &id) <= 0)) - { - msg_Err (obj, "invalid multicast interface address %s", iface); - free (iface); - goto error; - } + msg_Err (obj, "invalid multicast interface address %s", iface); + free (iface); + goto error; } + free (iface); memset (&opt, 0, sizeof (opt)); if (src != NULL) @@ -260,8 +397,7 @@ net_IPv4Join (vlc_object_t *obj, int fd, error: #endif - msg_Err (obj, "cannot join IPv4 multicast group (%s)", - net_strerror (net_errno)); + msg_Err (obj, "cannot join IPv4 multicast group (%m)"); return -1; } @@ -277,14 +413,13 @@ net_IPv6Join (vlc_object_t *obj, int fd, const struct sockaddr_in6 *src) msg_Dbg (obj, "IPV6_JOIN_GROUP multicast request"); - if (!setsockopt (fd, IPPROTO_IPV6, IPV6_JOIN_GROUP, &gr6, sizeof (gr6))) + if (!setsockopt (fd, SOL_IPV6, IPV6_JOIN_GROUP, &gr6, sizeof (gr6))) return 0; #else errno = ENOSYS; #endif - msg_Err (obj, "cannot join IPv6 any-source multicast group (%s)", - net_strerror (net_errno)); + msg_Err (obj, "cannot join IPv6 any-source multicast group (%m)"); return -1; } @@ -297,7 +432,13 @@ net_IPv6Join (vlc_object_t *obj, int fd, const struct sockaddr_in6 *src) */ # warning Your C headers are out-of-date. Please update. -/* Most (all?) Mingw32 versions in use are yet to pick up Vista stuff */ +# define MCAST_JOIN_GROUP 41 +struct group_req +{ + ULONG gr_interface; + struct sockaddr_storage gr_group; +}; + # define MCAST_JOIN_SOURCE_GROUP 45 /* from */ struct group_source_req { @@ -305,7 +446,7 @@ struct group_source_req struct sockaddr_storage gsr_group; struct sockaddr_storage gsr_source; }; -# endif +#endif /** * IP-agnostic multicast join, @@ -316,57 +457,33 @@ net_SourceSubscribe (vlc_object_t *obj, int fd, const struct sockaddr *src, socklen_t srclen, const struct sockaddr *grp, socklen_t grplen) { - /* Agnostic ASM/SSM multicast join */ -#ifdef MCAST_JOIN_SOURCE_GROUP - union - { - struct group_req gr; - struct group_source_req gsr; - } opt; - socklen_t optlen; int level, iid = 0; - vlc_bool_t ssm = VLC_TRUE; - - if (src == NULL) - ssm = VLC_FALSE; - memset (&opt, 0, sizeof (opt)); - - char *iface = var_CreateGetString (obj, "miface"); + char *iface = var_CreateGetNonEmptyString (obj, "miface"); if (iface != NULL) { - if (*iface) + iid = if_nametoindex (iface); + if (iid == 0) { - iid = if_nametoindex (iface); - if (iid == 0) - { - msg_Err (obj, "invalid multicast interface: %s", iface); - free (iface); - return -1; - } + msg_Err (obj, "invalid multicast interface: %s", iface); + free (iface); + return -1; } free (iface); } switch (grp->sa_family) { +#ifdef AF_INET6 case AF_INET6: level = SOL_IPV6; - if (ssm - && memcmp (&((const struct sockaddr_in6 *)src)->sin6_addr, - &in6addr_any, sizeof (in6addr_any)) == 0) - ssm = VLC_FALSE; - - if (((const struct sockaddr_in6 *)src)->sin6_scope_id) - iid = ((const struct sockaddr_in6 *)src)->sin6_scope_id; + if (((const struct sockaddr_in6 *)grp)->sin6_scope_id) + iid = ((const struct sockaddr_in6 *)grp)->sin6_scope_id; break; +#endif case AF_INET: level = SOL_IP; - if (ssm - && ((const struct sockaddr_in *)src)->sin_addr.s_addr - == INADDR_ANY) - ssm = VLC_FALSE; break; default: @@ -374,7 +491,37 @@ net_SourceSubscribe (vlc_object_t *obj, int fd, return -1; } - if (ssm) + if (src != NULL) + switch (src->sa_family) + { +#ifdef AF_INET6 + case AF_INET6: + if (memcmp (&((const struct sockaddr_in6 *)src)->sin6_addr, + &in6addr_any, sizeof (in6addr_any)) == 0) + src = NULL; + break; +#endif + + case AF_INET: + if (((const struct sockaddr_in *)src)->sin_addr.s_addr + == INADDR_ANY) + src = NULL; + break; + } + + + /* Agnostic ASM/SSM multicast join */ +#ifdef MCAST_JOIN_SOURCE_GROUP + union + { + struct group_req gr; + struct group_source_req gsr; + } opt; + socklen_t optlen; + + memset (&opt, 0, sizeof (opt)); + + if (src != NULL) { if ((grplen > sizeof (opt.gsr.gsr_group)) || (srclen > sizeof (opt.gsr.gsr_source))) @@ -395,23 +542,23 @@ net_SourceSubscribe (vlc_object_t *obj, int fd, optlen = sizeof (opt.gr); } - msg_Dbg (obj, "Multicast %sgroup join request", ssm ? "source " : ""); + msg_Dbg (obj, "Multicast %sgroup join request", src ? "source " : ""); if (setsockopt (fd, level, - ssm ? MCAST_JOIN_SOURCE_GROUP : MCAST_JOIN_GROUP, + src ? MCAST_JOIN_SOURCE_GROUP : MCAST_JOIN_GROUP, (void *)&opt, optlen) == 0) return 0; #endif /* Fallback to IPv-specific APIs */ - if (ssm && (src->sa_family != grp->sa_family)) + if ((src != NULL) && (src->sa_family != grp->sa_family)) return -1; switch (grp->sa_family) { case AF_INET: if ((grplen < sizeof (struct sockaddr_in)) - || (ssm && (srclen < sizeof (struct sockaddr_in)))) + || ((src != NULL) && (srclen < sizeof (struct sockaddr_in)))) return -1; if (net_IPv4Join (obj, fd, (const struct sockaddr_in *)src, @@ -422,11 +569,12 @@ net_SourceSubscribe (vlc_object_t *obj, int fd, #ifdef AF_INET6 case AF_INET6: if ((grplen < sizeof (struct sockaddr_in6)) - || (ssm && (srclen < sizeof (struct sockaddr_in6)))) + || ((src != NULL) && (srclen < sizeof (struct sockaddr_in6)))) return -1; - /* We don't provide IPv6-specific SSM at the moment. - * It seems all the OSes with IPv6 SSM have the new API anyway. */ + /* IPv6-specific SSM API does not exist. So if we're here + * it means IPv6 SSM is not supported on this OS and we + * directly fallback to ASM */ if (net_IPv6Join (obj, fd, (const struct sockaddr_in6 *)grp) == 0) return 0; @@ -434,10 +582,9 @@ net_SourceSubscribe (vlc_object_t *obj, int fd, #endif } - msg_Err (obj, "Multicast group join error (%s)", - net_strerror (net_errno)); + msg_Err (obj, "Multicast group join error (%m)"); - if (ssm) + if (src != NULL) { msg_Warn (obj, "Trying ASM instead of SSM..."); return net_Subscribe (obj, fd, grp, grplen); @@ -455,7 +602,7 @@ int net_Subscribe (vlc_object_t *obj, int fd, } -int net_SetDSCP( int fd, uint8_t dscp ) +static int net_SetDSCP( int fd, uint8_t dscp ) { struct sockaddr_storage addr; if( getsockname( fd, (struct sockaddr *)&addr, &(socklen_t){ sizeof (addr) }) ) @@ -487,35 +634,33 @@ int net_SetDSCP( int fd, uint8_t dscp ) return setsockopt( fd, level, cmd, &(int){ dscp }, sizeof (int)); } - +#undef net_ConnectDgram /***************************************************************************** - * __net_ConnectUDP: + * net_ConnectDgram: ***************************************************************************** - * Open a UDP socket to send data to a defined destination, with an optional - * hop limit. + * Open a datagram socket to send data to a defined destination, with an + * optional hop limit. *****************************************************************************/ -int __net_ConnectUDP( vlc_object_t *p_this, const char *psz_host, int i_port, - int i_hlim ) +int net_ConnectDgram( vlc_object_t *p_this, const char *psz_host, int i_port, + int i_hlim, int proto ) { struct addrinfo hints, *res, *ptr; int i_val, i_handle = -1; - vlc_bool_t b_unreach = VLC_FALSE; + bool b_unreach = false; - if( i_port == 0 ) - i_port = 1234; /* historical VLC thing */ - - if( i_hlim < 1 ) + if( i_hlim < 0 ) i_hlim = var_CreateGetInteger( p_this, "ttl" ); memset( &hints, 0, sizeof( hints ) ); hints.ai_socktype = SOCK_DGRAM; + hints.ai_protocol = proto; - msg_Dbg( p_this, "net: connecting to %s port %d", psz_host, i_port ); + msg_Dbg( p_this, "net: connecting to [%s]:%d", psz_host, i_port ); i_val = vlc_getaddrinfo( p_this, psz_host, i_port, &hints, &res ); if( i_val ) { - msg_Err( p_this, "cannot resolve %s port %d : %s", psz_host, i_port, + msg_Err( p_this, "cannot resolve [%s]:%d : %s", psz_host, i_port, vlc_gai_strerror( i_val ) ); return -1; } @@ -538,22 +683,20 @@ int __net_ConnectUDP( vlc_object_t *p_this, const char *psz_host, int i_port, setsockopt (fd, SOL_SOCKET, SO_BROADCAST, &(int){ 1 }, sizeof (int)); #endif - if( i_hlim > 0 ) + if( i_hlim >= 0 ) net_SetMcastHopLimit( p_this, fd, ptr->ai_family, i_hlim ); - str = var_CreateGetString (p_this, "miface"); + str = var_CreateGetNonEmptyString (p_this, "miface"); if (str != NULL) { - if (*str) - net_SetMcastOut (p_this, fd, ptr->ai_family, str, NULL); + net_SetMcastOut (p_this, fd, ptr->ai_family, str, NULL); free (str); } - str = var_CreateGetString (p_this, "miface-addr"); + str = var_CreateGetNonEmptyString (p_this, "miface-addr"); if (str != NULL) { - if (*str) - net_SetMcastOut (p_this, fd, ptr->ai_family, NULL, str); + net_SetMcastOut (p_this, fd, ptr->ai_family, NULL, str); free (str); } @@ -571,11 +714,10 @@ int __net_ConnectUDP( vlc_object_t *p_this, const char *psz_host, int i_port, #else if( errno == ENETUNREACH ) #endif - b_unreach = VLC_TRUE; + b_unreach = true; else { - msg_Warn( p_this, "%s port %d : %s", psz_host, i_port, - strerror( errno ) ); + msg_Warn( p_this, "%s port %d : %m", psz_host, i_port); net_Close( fd ); continue; } @@ -594,25 +736,29 @@ int __net_ConnectUDP( vlc_object_t *p_this, const char *psz_host, int i_port, return i_handle; } - +#undef net_OpenDgram /***************************************************************************** - * __net_OpenUDP: + * net_OpenDgram: ***************************************************************************** - * Open a UDP connection and return a handle + * OpenDgram a datagram socket and return a handle *****************************************************************************/ -int __net_OpenUDP( vlc_object_t *obj, const char *psz_bind, int i_bind, - const char *psz_server, int i_server ) +int net_OpenDgram( vlc_object_t *obj, const char *psz_bind, int i_bind, + const char *psz_server, int i_server, + int family, int protocol ) { + if ((psz_server == NULL) || (psz_server[0] == '\0')) + return net_ListenSingle (obj, psz_bind, i_bind, family, protocol); + + msg_Dbg (obj, "net: connecting to [%s]:%d from [%s]:%d", + psz_server, i_server, psz_bind, i_bind); + struct addrinfo hints, *loc, *rem; int val; - msg_Dbg( obj, "net: connecting to '[%s]:%d@[%s]:%d'", - psz_server, i_server, psz_bind, i_bind ); - memset (&hints, 0, sizeof (hints)); + hints.ai_family = family; hints.ai_socktype = SOCK_DGRAM; - hints.ai_protocol = IPPROTO_UDP; - hints.ai_flags = AI_PASSIVE; + hints.ai_protocol = protocol; val = vlc_getaddrinfo (obj, psz_server, i_server, &hints, &rem); if (val) @@ -622,6 +768,7 @@ int __net_OpenUDP( vlc_object_t *obj, const char *psz_bind, int i_bind, return -1; } + hints.ai_flags = AI_PASSIVE; val = vlc_getaddrinfo (obj, psz_bind, i_bind, &hints, &loc); if (val) { @@ -638,72 +785,106 @@ int __net_OpenUDP( vlc_object_t *obj, const char *psz_bind, int i_bind, if (fd == -1) continue; // usually, address family not supported -#ifdef SO_REUSEPORT - setsockopt (fd, SOL_SOCKET, SO_REUSEPORT, &(int){ 1 }, sizeof (int)); -#endif - -#ifdef SO_RCVBUF - /* Increase the receive buffer size to 1/2MB (8Mb/s during 1/2s) - * to avoid packet loss caused in case of scheduling hiccups */ - setsockopt (fd, SOL_SOCKET, SO_RCVBUF, - (void *)&(int){ 0x80000 }, sizeof (int)); - setsockopt (fd, SOL_SOCKET, SO_SNDBUF, - (void *)&(int){ 0x80000 }, sizeof (int)); -#endif - -#if defined (WIN32) || defined (UNDER_CE) - if (net_SockAddrIsMulticast (ptr->ai_addr, ptr->ai_addrlen) - && (sizeof (struct sockaddr_storage) >= ptr->ai_addrlen)) - { - // This works for IPv4 too - don't worry! - struct sockaddr_in6 dumb = - { - .sin6_family = ptr->ai_addr->sa_family, - .sin6_port = ((struct sockaddr_in *)(ptr->ai_addr))->sin_port - }; - - bind (fd, (struct sockaddr *)&dumb, ptr->ai_addrlen); - } - else -#endif - if (bind (fd, ptr->ai_addr, ptr->ai_addrlen)) - { - net_Close (fd); + fd = net_SetupDgramSocket( obj, fd, ptr ); + if( fd == -1 ) continue; - } - struct addrinfo *ptr2; - for (ptr2 = rem; ptr2 != NULL; ptr2 = ptr2->ai_next) + val = -1; + for (struct addrinfo *ptr2 = rem; ptr2 != NULL; ptr2 = ptr2->ai_next) { if ((ptr2->ai_family != ptr->ai_family) || (ptr2->ai_socktype != ptr->ai_socktype) || (ptr2->ai_protocol != ptr->ai_protocol)) continue; - if (net_SockAddrIsMulticast (ptr->ai_addr, ptr->ai_addrlen)) - { - if (net_SourceSubscribe (obj, fd, - ptr2->ai_addr, ptr2->ai_addrlen, - ptr->ai_addr, ptr->ai_addrlen) == 0) - break; - } - else + if (net_SockAddrIsMulticast (ptr->ai_addr, ptr->ai_addrlen) + ? net_SourceSubscribe (obj, fd, + ptr2->ai_addr, ptr2->ai_addrlen, + ptr->ai_addr, ptr->ai_addrlen) + : connect (fd, ptr2->ai_addr, ptr2->ai_addrlen)) { - if (connect (fd, ptr2->ai_addr, ptr2->ai_addrlen) == 0) - break; + msg_Err (obj, "cannot connect to %s port %d: %m", + psz_server, i_server); + continue; } + val = fd; + break; } - if (ptr2 == NULL) - { - msg_Err (obj, "cannot connect to %s port %d: %s", - psz_server, i_server, net_strerror (net_errno)); - close (fd); - continue; - } + if (val != -1) + break; - return fd; + net_Close (fd); } - return -1; + vlc_freeaddrinfo (rem); + vlc_freeaddrinfo (loc); + return val; +} + + +/** + * net_SetCSCov: + * Sets the send and receive checksum coverage of a socket: + * @param fd socket + * @param sendcov payload coverage of sent packets (bytes), -1 for full + * @param recvcov minimum payload coverage of received packets, -1 for full + */ +int net_SetCSCov (int fd, int sendcov, int recvcov) +{ + int type; + + if (getsockopt (fd, SOL_SOCKET, SO_TYPE, + &type, &(socklen_t){ sizeof (type) })) + return VLC_EGENERIC; + + switch (type) + { +#ifdef UDPLITE_RECV_CSCOV + case SOCK_DGRAM: /* UDP-Lite */ + if (sendcov == -1) + sendcov = 0; + else + sendcov += 8; /* partial */ + if (setsockopt (fd, SOL_UDPLITE, UDPLITE_SEND_CSCOV, &sendcov, + sizeof (sendcov))) + return VLC_EGENERIC; + + if (recvcov == -1) + recvcov = 0; + else + recvcov += 8; + if (setsockopt (fd, SOL_UDPLITE, UDPLITE_RECV_CSCOV, + &recvcov, sizeof (recvcov))) + return VLC_EGENERIC; + + return VLC_SUCCESS; +#endif +#ifdef DCCP_SOCKOPT_SEND_CSCOV + case SOCK_DCCP: /* DCCP and its ill-named socket type */ + if ((sendcov == -1) || (sendcov > 56)) + sendcov = 0; + else + sendcov = (sendcov + 3) / 4; + if (setsockopt (fd, SOL_DCCP, DCCP_SOCKOPT_SEND_CSCOV, + &sendcov, sizeof (sendcov))) + return VLC_EGENERIC; + + if ((recvcov == -1) || (recvcov > 56)) + recvcov = 0; + else + recvcov = (recvcov + 3) / 4; + if (setsockopt (fd, SOL_DCCP, DCCP_SOCKOPT_RECV_CSCOV, + &recvcov, sizeof (recvcov))) + return VLC_EGENERIC; + + return VLC_SUCCESS; +#endif + } +#if !defined( UDPLITE_RECV_CSCOV ) && !defined( DCCP_SOCKOPT_SEND_CSCOV ) + VLC_UNUSED(sendcov); + VLC_UNUSED(recvcov); +#endif + + return VLC_EGENERIC; }