PageRenderTime 67ms CodeModel.GetById 34ms RepoModel.GetById 1ms app.codeStats 0ms

/src/network/udp.c

https://gitlab.com/evilbinary/vlc
C | 744 lines | 568 code | 101 blank | 75 comment | 113 complexity | 0d9f75344e84344b9265f0ce307f2742 MD5 | raw file
  1. /*****************************************************************************
  2. * udp.c:
  3. *****************************************************************************
  4. * Copyright (C) 2004-2006 VLC authors and VideoLAN
  5. * Copyright © 2006-2007 Rémi Denis-Courmont
  6. *
  7. * $Id: 72bd34620b4d34aec8090961fdb58d6ee463aee5 $
  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 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.
  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 Lesser General Public License for more details.
  21. *
  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. *****************************************************************************/
  26. /*****************************************************************************
  27. * Preamble
  28. *****************************************************************************/
  29. #ifdef HAVE_CONFIG_H
  30. # include "config.h"
  31. #endif
  32. #include <vlc_common.h>
  33. #include <errno.h>
  34. #include <assert.h>
  35. #include <vlc_network.h>
  36. #ifdef _WIN32
  37. # undef EAFNOSUPPORT
  38. # define EAFNOSUPPORT WSAEAFNOSUPPORT
  39. #else
  40. # include <unistd.h>
  41. # ifdef HAVE_NET_IF_H
  42. # include <net/if.h>
  43. # endif
  44. #endif
  45. #ifdef HAVE_LINUX_DCCP_H
  46. # include <linux/dccp.h>
  47. # ifndef SOCK_DCCP /* provisional API */
  48. # define SOCK_DCCP 6
  49. # endif
  50. #endif
  51. #ifndef SOL_IP
  52. # define SOL_IP IPPROTO_IP
  53. #endif
  54. #ifndef SOL_IPV6
  55. # define SOL_IPV6 IPPROTO_IPV6
  56. #endif
  57. #ifndef IPPROTO_IPV6
  58. # define IPPROTO_IPV6 41 /* IANA */
  59. #endif
  60. #ifndef SOL_DCCP
  61. # define SOL_DCCP IPPROTO_DCCP
  62. #endif
  63. #ifndef IPPROTO_DCCP
  64. # define IPPROTO_DCCP 33 /* IANA */
  65. #endif
  66. #ifndef SOL_UDPLITE
  67. # define SOL_UDPLITE IPPROTO_UDPLITE
  68. #endif
  69. #ifndef IPPROTO_UDPLITE
  70. # define IPPROTO_UDPLITE 136 /* IANA */
  71. #endif
  72. #if defined (HAVE_NETINET_UDPLITE_H)
  73. # include <netinet/udplite.h>
  74. #elif defined (__linux__)
  75. /* still missing from glibc 2.6 */
  76. # define UDPLITE_SEND_CSCOV 10
  77. # define UDPLITE_RECV_CSCOV 11
  78. #endif
  79. extern int net_Socket( vlc_object_t *p_this, int i_family, int i_socktype,
  80. int i_protocol );
  81. /* */
  82. static int net_SetupDgramSocket (vlc_object_t *p_obj, int fd,
  83. const struct addrinfo *ptr)
  84. {
  85. #ifdef SO_REUSEPORT
  86. setsockopt (fd, SOL_SOCKET, SO_REUSEPORT, &(int){ 1 }, sizeof (int));
  87. #endif
  88. #if defined (_WIN32)
  89. /* Check windows version so we know if we need to increase receive buffers
  90. * for Windows 7 and earlier
  91. * SetSocketMediaStreamingMode is present in win 8 and later, so we set
  92. * receive buffer if that isn't present
  93. */
  94. #if _WIN32_WINNT < 0x602
  95. HINSTANCE h_Network = LoadLibraryW(L"Windows.Networking.dll");
  96. if( (h_Network == NULL) ||
  97. (GetProcAddress( h_Network, "SetSocketMediaStreamingMode" ) == NULL ) )
  98. {
  99. setsockopt (fd, SOL_SOCKET, SO_RCVBUF,
  100. (void *)&(int){ 0x80000 }, sizeof (int));
  101. }
  102. if( h_Network )
  103. FreeLibrary( h_Network );
  104. #endif
  105. if (net_SockAddrIsMulticast (ptr->ai_addr, ptr->ai_addrlen)
  106. && (sizeof (struct sockaddr_storage) >= ptr->ai_addrlen))
  107. {
  108. // This works for IPv4 too - don't worry!
  109. struct sockaddr_in6 dumb =
  110. {
  111. .sin6_family = ptr->ai_addr->sa_family,
  112. .sin6_port = ((struct sockaddr_in *)(ptr->ai_addr))->sin_port
  113. };
  114. bind (fd, (struct sockaddr *)&dumb, ptr->ai_addrlen);
  115. }
  116. else
  117. #endif
  118. if (bind (fd, ptr->ai_addr, ptr->ai_addrlen))
  119. {
  120. msg_Err( p_obj, "socket bind error: %s", vlc_strerror_c(net_errno) );
  121. net_Close (fd);
  122. return -1;
  123. }
  124. return fd;
  125. }
  126. /* */
  127. static int net_ListenSingle (vlc_object_t *obj, const char *host, int port,
  128. int protocol)
  129. {
  130. struct addrinfo hints = {
  131. .ai_socktype = SOCK_DGRAM,
  132. .ai_protocol = protocol,
  133. .ai_flags = AI_PASSIVE | AI_NUMERICSERV | AI_IDN,
  134. }, *res;
  135. if (host && !*host)
  136. host = NULL;
  137. msg_Dbg (obj, "net: opening %s datagram port %d",
  138. host ? host : "any", port);
  139. int val = vlc_getaddrinfo (host, port, &hints, &res);
  140. if (val)
  141. {
  142. msg_Err (obj, "Cannot resolve %s port %d : %s", host, port,
  143. gai_strerror (val));
  144. return -1;
  145. }
  146. val = -1;
  147. for (const struct addrinfo *ptr = res; ptr != NULL; ptr = ptr->ai_next)
  148. {
  149. int fd = net_Socket (obj, ptr->ai_family, ptr->ai_socktype,
  150. ptr->ai_protocol);
  151. if (fd == -1)
  152. {
  153. msg_Dbg (obj, "socket error: %s", vlc_strerror_c(net_errno));
  154. continue;
  155. }
  156. #ifdef IPV6_V6ONLY
  157. /* Try dual-mode IPv6 if available. */
  158. if (ptr->ai_family == AF_INET6)
  159. setsockopt (fd, SOL_IPV6, IPV6_V6ONLY, &(int){ 0 }, sizeof (int));
  160. #endif
  161. fd = net_SetupDgramSocket( obj, fd, ptr );
  162. if( fd == -1 )
  163. continue;
  164. if (net_SockAddrIsMulticast (ptr->ai_addr, ptr->ai_addrlen)
  165. && net_Subscribe (obj, fd, ptr->ai_addr, ptr->ai_addrlen))
  166. {
  167. net_Close (fd);
  168. continue;
  169. }
  170. val = fd;
  171. break;
  172. }
  173. freeaddrinfo (res);
  174. return val;
  175. }
  176. static int net_SetMcastHopLimit( vlc_object_t *p_this,
  177. int fd, int family, int hlim )
  178. {
  179. int proto, cmd;
  180. /* There is some confusion in the world whether IP_MULTICAST_TTL
  181. * takes a byte or an int as an argument.
  182. * BSD seems to indicate byte so we are going with that and use
  183. * int as a fallback to be safe */
  184. switch( family )
  185. {
  186. #ifdef IP_MULTICAST_TTL
  187. case AF_INET:
  188. proto = SOL_IP;
  189. cmd = IP_MULTICAST_TTL;
  190. break;
  191. #endif
  192. #ifdef IPV6_MULTICAST_HOPS
  193. case AF_INET6:
  194. proto = SOL_IPV6;
  195. cmd = IPV6_MULTICAST_HOPS;
  196. break;
  197. #endif
  198. default:
  199. errno = EAFNOSUPPORT;
  200. msg_Warn( p_this, "%s", vlc_strerror_c(EAFNOSUPPORT) );
  201. return VLC_EGENERIC;
  202. }
  203. if( setsockopt( fd, proto, cmd, &hlim, sizeof( hlim ) ) < 0 )
  204. {
  205. /* BSD compatibility */
  206. unsigned char buf;
  207. msg_Dbg( p_this, "cannot set hop limit (%d): %s", hlim,
  208. vlc_strerror_c(net_errno) );
  209. buf = (unsigned char)(( hlim > 255 ) ? 255 : hlim);
  210. if( setsockopt( fd, proto, cmd, &buf, sizeof( buf ) ) )
  211. {
  212. msg_Err( p_this, "cannot set hop limit (%d): %s", hlim,
  213. vlc_strerror_c(net_errno) );
  214. return VLC_EGENERIC;
  215. }
  216. }
  217. return VLC_SUCCESS;
  218. }
  219. static int net_SetMcastOut (vlc_object_t *p_this, int fd, int family,
  220. const char *iface)
  221. {
  222. int scope = if_nametoindex (iface);
  223. if (scope == 0)
  224. {
  225. msg_Err (p_this, "invalid multicast interface: %s", iface);
  226. return -1;
  227. }
  228. switch (family)
  229. {
  230. #ifdef IPV6_MULTICAST_IF
  231. case AF_INET6:
  232. if (setsockopt (fd, SOL_IPV6, IPV6_MULTICAST_IF,
  233. &scope, sizeof (scope)) == 0)
  234. return 0;
  235. break;
  236. #endif
  237. #ifdef __linux__
  238. case AF_INET:
  239. {
  240. struct ip_mreqn req = { .imr_ifindex = scope };
  241. if (setsockopt (fd, SOL_IP, IP_MULTICAST_IF,
  242. &req, sizeof (req)) == 0)
  243. return 0;
  244. break;
  245. }
  246. #endif
  247. default:
  248. errno = EAFNOSUPPORT;
  249. }
  250. msg_Err (p_this, "cannot force multicast interface %s: %s", iface,
  251. vlc_strerror_c(errno));
  252. return -1;
  253. }
  254. static unsigned var_GetIfIndex (vlc_object_t *obj)
  255. {
  256. char *ifname = var_InheritString (obj, "miface");
  257. if (ifname == NULL)
  258. return 0;
  259. unsigned ifindex = if_nametoindex (ifname);
  260. if (ifindex == 0)
  261. msg_Err (obj, "invalid multicast interface: %s", ifname);
  262. free (ifname);
  263. return ifindex;
  264. }
  265. /**
  266. * IP-agnostic multicast join,
  267. * with fallback to old APIs, and fallback from SSM to ASM.
  268. */
  269. static int
  270. net_SourceSubscribe (vlc_object_t *obj, int fd,
  271. const struct sockaddr *src, socklen_t srclen,
  272. const struct sockaddr *grp, socklen_t grplen)
  273. {
  274. /* MCAST_JOIN_SOURCE_GROUP was introduced to OS X in v10.7, but it doesn't work,
  275. * so ignore it to use the same code path as on 10.5 or 10.6 */
  276. #if defined (MCAST_JOIN_SOURCE_GROUP) && !defined (__APPLE__)
  277. /* Agnostic SSM multicast join */
  278. int level;
  279. struct group_source_req gsr;
  280. memset (&gsr, 0, sizeof (gsr));
  281. gsr.gsr_interface = var_GetIfIndex (obj);
  282. switch (grp->sa_family)
  283. {
  284. #ifdef AF_INET6
  285. case AF_INET6:
  286. {
  287. const struct sockaddr_in6 *g6 = (const struct sockaddr_in6 *)grp;
  288. level = SOL_IPV6;
  289. assert (grplen >= sizeof (struct sockaddr_in6));
  290. if (g6->sin6_scope_id != 0)
  291. gsr.gsr_interface = g6->sin6_scope_id;
  292. break;
  293. }
  294. #endif
  295. case AF_INET:
  296. level = SOL_IP;
  297. break;
  298. default:
  299. errno = EAFNOSUPPORT;
  300. return -1;
  301. }
  302. assert (grplen <= sizeof (gsr.gsr_group));
  303. memcpy (&gsr.gsr_source, src, srclen);
  304. assert (srclen <= sizeof (gsr.gsr_source));
  305. memcpy (&gsr.gsr_group, grp, grplen);
  306. if (setsockopt (fd, level, MCAST_JOIN_SOURCE_GROUP,
  307. &gsr, sizeof (gsr)) == 0)
  308. return 0;
  309. #else
  310. if (src->sa_family != grp->sa_family)
  311. {
  312. errno = EAFNOSUPPORT;
  313. return -1;
  314. }
  315. switch (grp->sa_family)
  316. {
  317. # ifdef IP_ADD_SOURCE_MEMBERSHIP
  318. /* IPv4-specific API */
  319. case AF_INET:
  320. {
  321. struct ip_mreq_source imr;
  322. memset (&imr, 0, sizeof (imr));
  323. assert (grplen >= sizeof (struct sockaddr_in));
  324. imr.imr_multiaddr = ((const struct sockaddr_in *)grp)->sin_addr;
  325. assert (srclen >= sizeof (struct sockaddr_in));
  326. imr.imr_sourceaddr = ((const struct sockaddr_in *)src)->sin_addr;
  327. if (setsockopt (fd, SOL_IP, IP_ADD_SOURCE_MEMBERSHIP,
  328. &imr, sizeof (imr)) == 0)
  329. return 0;
  330. break;
  331. }
  332. # endif
  333. default:
  334. errno = EAFNOSUPPORT;
  335. }
  336. #endif
  337. msg_Err (obj, "cannot join source multicast group: %s",
  338. vlc_strerror_c(net_errno));
  339. msg_Warn (obj, "trying ASM instead of SSM...");
  340. return net_Subscribe (obj, fd, grp, grplen);
  341. }
  342. int net_Subscribe (vlc_object_t *obj, int fd,
  343. const struct sockaddr *grp, socklen_t grplen)
  344. {
  345. /* MCAST_JOIN_GROUP was introduced to OS X in v10.7, but it doesn't work,
  346. * so ignore it to use the same code as on 10.5 or 10.6 */
  347. #if defined (MCAST_JOIN_GROUP) && !defined (__APPLE__)
  348. /* Agnostic SSM multicast join */
  349. int level;
  350. struct group_req gr;
  351. memset (&gr, 0, sizeof (gr));
  352. gr.gr_interface = var_GetIfIndex (obj);
  353. switch (grp->sa_family)
  354. {
  355. #ifdef AF_INET6
  356. case AF_INET6:
  357. {
  358. const struct sockaddr_in6 *g6 = (const struct sockaddr_in6 *)grp;
  359. level = SOL_IPV6;
  360. assert (grplen >= sizeof (struct sockaddr_in6));
  361. if (g6->sin6_scope_id != 0)
  362. gr.gr_interface = g6->sin6_scope_id;
  363. break;
  364. }
  365. #endif
  366. case AF_INET:
  367. level = SOL_IP;
  368. break;
  369. default:
  370. errno = EAFNOSUPPORT;
  371. return -1;
  372. }
  373. assert (grplen <= sizeof (gr.gr_group));
  374. memcpy (&gr.gr_group, grp, grplen);
  375. if (setsockopt (fd, level, MCAST_JOIN_GROUP, &gr, sizeof (gr)) == 0)
  376. return 0;
  377. #else
  378. switch (grp->sa_family)
  379. {
  380. # ifdef IPV6_JOIN_GROUP
  381. case AF_INET6:
  382. {
  383. struct ipv6_mreq ipv6mr;
  384. const struct sockaddr_in6 *g6 = (const struct sockaddr_in6 *)grp;
  385. memset (&ipv6mr, 0, sizeof (ipv6mr));
  386. assert (grplen >= sizeof (struct sockaddr_in6));
  387. ipv6mr.ipv6mr_multiaddr = g6->sin6_addr;
  388. ipv6mr.ipv6mr_interface = g6->sin6_scope_id;
  389. if (!setsockopt (fd, SOL_IPV6, IPV6_JOIN_GROUP,
  390. &ipv6mr, sizeof (ipv6mr)))
  391. return 0;
  392. break;
  393. }
  394. # endif
  395. # ifdef IP_ADD_MEMBERSHIP
  396. case AF_INET:
  397. {
  398. struct ip_mreq imr;
  399. memset (&imr, 0, sizeof (imr));
  400. assert (grplen >= sizeof (struct sockaddr_in));
  401. imr.imr_multiaddr = ((const struct sockaddr_in *)grp)->sin_addr;
  402. if (setsockopt (fd, SOL_IP, IP_ADD_MEMBERSHIP,
  403. &imr, sizeof (imr)) == 0)
  404. return 0;
  405. break;
  406. }
  407. # endif
  408. default:
  409. errno = EAFNOSUPPORT;
  410. }
  411. #endif
  412. msg_Err (obj, "cannot join multicast group: %s",
  413. vlc_strerror_c(net_errno));
  414. return -1;
  415. }
  416. static int net_SetDSCP( int fd, uint8_t dscp )
  417. {
  418. struct sockaddr_storage addr;
  419. if( getsockname( fd, (struct sockaddr *)&addr, &(socklen_t){ sizeof (addr) }) )
  420. return -1;
  421. int level, cmd;
  422. switch( addr.ss_family )
  423. {
  424. #ifdef IPV6_TCLASS
  425. case AF_INET6:
  426. level = SOL_IPV6;
  427. cmd = IPV6_TCLASS;
  428. break;
  429. #endif
  430. case AF_INET:
  431. level = SOL_IP;
  432. cmd = IP_TOS;
  433. break;
  434. default:
  435. #ifdef ENOPROTOOPT
  436. errno = ENOPROTOOPT;
  437. #endif
  438. return -1;
  439. }
  440. return setsockopt( fd, level, cmd, &(int){ dscp }, sizeof (int));
  441. }
  442. #undef net_ConnectDgram
  443. /*****************************************************************************
  444. * net_ConnectDgram:
  445. *****************************************************************************
  446. * Open a datagram socket to send data to a defined destination, with an
  447. * optional hop limit.
  448. *****************************************************************************/
  449. int net_ConnectDgram( vlc_object_t *p_this, const char *psz_host, int i_port,
  450. int i_hlim, int proto )
  451. {
  452. struct addrinfo hints = {
  453. .ai_socktype = SOCK_DGRAM,
  454. .ai_protocol = proto,
  455. .ai_flags = AI_NUMERICSERV | AI_IDN,
  456. }, *res;
  457. int i_handle = -1;
  458. bool b_unreach = false;
  459. if( i_hlim < 0 )
  460. i_hlim = var_InheritInteger( p_this, "ttl" );
  461. msg_Dbg( p_this, "net: connecting to [%s]:%d", psz_host, i_port );
  462. int val = vlc_getaddrinfo (psz_host, i_port, &hints, &res);
  463. if (val)
  464. {
  465. msg_Err (p_this, "cannot resolve [%s]:%d : %s", psz_host, i_port,
  466. gai_strerror (val));
  467. return -1;
  468. }
  469. for (struct addrinfo *ptr = res; ptr != NULL; ptr = ptr->ai_next)
  470. {
  471. char *str;
  472. int fd = net_Socket (p_this, ptr->ai_family, ptr->ai_socktype,
  473. ptr->ai_protocol);
  474. if (fd == -1)
  475. continue;
  476. /* Allow broadcast sending */
  477. setsockopt (fd, SOL_SOCKET, SO_BROADCAST, &(int){ 1 }, sizeof (int));
  478. if( i_hlim >= 0 )
  479. net_SetMcastHopLimit( p_this, fd, ptr->ai_family, i_hlim );
  480. str = var_InheritString (p_this, "miface");
  481. if (str != NULL)
  482. {
  483. net_SetMcastOut (p_this, fd, ptr->ai_family, str);
  484. free (str);
  485. }
  486. net_SetDSCP (fd, var_InheritInteger (p_this, "dscp"));
  487. if( connect( fd, ptr->ai_addr, ptr->ai_addrlen ) == 0 )
  488. {
  489. /* success */
  490. i_handle = fd;
  491. break;
  492. }
  493. #if defined( _WIN32 )
  494. if( WSAGetLastError () == WSAENETUNREACH )
  495. #else
  496. if( errno == ENETUNREACH )
  497. #endif
  498. b_unreach = true;
  499. else
  500. msg_Warn( p_this, "%s port %d : %s", psz_host, i_port,
  501. vlc_strerror_c(errno) );
  502. net_Close( fd );
  503. }
  504. freeaddrinfo( res );
  505. if( i_handle == -1 )
  506. {
  507. if( b_unreach )
  508. msg_Err( p_this, "Host %s port %d is unreachable", psz_host,
  509. i_port );
  510. return -1;
  511. }
  512. return i_handle;
  513. }
  514. #undef net_OpenDgram
  515. /*****************************************************************************
  516. * net_OpenDgram:
  517. *****************************************************************************
  518. * OpenDgram a datagram socket and return a handle
  519. *****************************************************************************/
  520. int net_OpenDgram( vlc_object_t *obj, const char *psz_bind, int i_bind,
  521. const char *psz_server, int i_server, int protocol )
  522. {
  523. if ((psz_server == NULL) || (psz_server[0] == '\0'))
  524. return net_ListenSingle (obj, psz_bind, i_bind, protocol);
  525. msg_Dbg (obj, "net: connecting to [%s]:%d from [%s]:%d",
  526. psz_server, i_server, psz_bind, i_bind);
  527. struct addrinfo hints = {
  528. .ai_socktype = SOCK_DGRAM,
  529. .ai_protocol = protocol,
  530. .ai_flags = AI_NUMERICSERV | AI_IDN,
  531. }, *loc, *rem;
  532. int val = vlc_getaddrinfo (psz_server, i_server, &hints, &rem);
  533. if (val)
  534. {
  535. msg_Err (obj, "cannot resolve %s port %d : %s", psz_bind, i_bind,
  536. gai_strerror (val));
  537. return -1;
  538. }
  539. hints.ai_flags |= AI_PASSIVE;
  540. val = vlc_getaddrinfo (psz_bind, i_bind, &hints, &loc);
  541. if (val)
  542. {
  543. msg_Err (obj, "cannot resolve %s port %d : %s", psz_bind, i_bind,
  544. gai_strerror (val));
  545. freeaddrinfo (rem);
  546. return -1;
  547. }
  548. val = -1;
  549. for (struct addrinfo *ptr = loc; ptr != NULL; ptr = ptr->ai_next)
  550. {
  551. int fd = net_Socket (obj, ptr->ai_family, ptr->ai_socktype,
  552. ptr->ai_protocol);
  553. if (fd == -1)
  554. continue; // usually, address family not supported
  555. fd = net_SetupDgramSocket( obj, fd, ptr );
  556. if( fd == -1 )
  557. continue;
  558. for (struct addrinfo *ptr2 = rem; ptr2 != NULL; ptr2 = ptr2->ai_next)
  559. {
  560. if ((ptr2->ai_family != ptr->ai_family)
  561. || (ptr2->ai_socktype != ptr->ai_socktype)
  562. || (ptr2->ai_protocol != ptr->ai_protocol))
  563. continue;
  564. if (net_SockAddrIsMulticast (ptr->ai_addr, ptr->ai_addrlen)
  565. ? net_SourceSubscribe (obj, fd,
  566. ptr2->ai_addr, ptr2->ai_addrlen,
  567. ptr->ai_addr, ptr->ai_addrlen)
  568. : connect (fd, ptr2->ai_addr, ptr2->ai_addrlen))
  569. {
  570. msg_Err (obj, "cannot connect to %s port %d: %s",
  571. psz_server, i_server, vlc_strerror_c(net_errno));
  572. continue;
  573. }
  574. val = fd;
  575. break;
  576. }
  577. if (val != -1)
  578. break;
  579. net_Close (fd);
  580. }
  581. freeaddrinfo (rem);
  582. freeaddrinfo (loc);
  583. return val;
  584. }
  585. /**
  586. * net_SetCSCov:
  587. * Sets the send and receive checksum coverage of a socket:
  588. * @param fd socket
  589. * @param sendcov payload coverage of sent packets (bytes), -1 for full
  590. * @param recvcov minimum payload coverage of received packets, -1 for full
  591. */
  592. int net_SetCSCov (int fd, int sendcov, int recvcov)
  593. {
  594. int type;
  595. if (getsockopt (fd, SOL_SOCKET, SO_TYPE,
  596. &type, &(socklen_t){ sizeof (type) }))
  597. return VLC_EGENERIC;
  598. switch (type)
  599. {
  600. #ifdef UDPLITE_RECV_CSCOV
  601. case SOCK_DGRAM: /* UDP-Lite */
  602. if (sendcov == -1)
  603. sendcov = 0;
  604. else
  605. sendcov += 8; /* partial */
  606. if (setsockopt (fd, SOL_UDPLITE, UDPLITE_SEND_CSCOV, &sendcov,
  607. sizeof (sendcov)))
  608. return VLC_EGENERIC;
  609. if (recvcov == -1)
  610. recvcov = 0;
  611. else
  612. recvcov += 8;
  613. if (setsockopt (fd, SOL_UDPLITE, UDPLITE_RECV_CSCOV,
  614. &recvcov, sizeof (recvcov)))
  615. return VLC_EGENERIC;
  616. return VLC_SUCCESS;
  617. #endif
  618. #ifdef DCCP_SOCKOPT_SEND_CSCOV
  619. case SOCK_DCCP: /* DCCP and its ill-named socket type */
  620. if ((sendcov == -1) || (sendcov > 56))
  621. sendcov = 0;
  622. else
  623. sendcov = (sendcov + 3) / 4;
  624. if (setsockopt (fd, SOL_DCCP, DCCP_SOCKOPT_SEND_CSCOV,
  625. &sendcov, sizeof (sendcov)))
  626. return VLC_EGENERIC;
  627. if ((recvcov == -1) || (recvcov > 56))
  628. recvcov = 0;
  629. else
  630. recvcov = (recvcov + 3) / 4;
  631. if (setsockopt (fd, SOL_DCCP, DCCP_SOCKOPT_RECV_CSCOV,
  632. &recvcov, sizeof (recvcov)))
  633. return VLC_EGENERIC;
  634. return VLC_SUCCESS;
  635. #endif
  636. }
  637. #if !defined( UDPLITE_RECV_CSCOV ) && !defined( DCCP_SOCKOPT_SEND_CSCOV )
  638. VLC_UNUSED(sendcov);
  639. VLC_UNUSED(recvcov);
  640. #endif
  641. return VLC_EGENERIC;
  642. }