From d6af701250915fdc7449500d9191f4eb2e6cfa4d Mon Sep 17 00:00:00 2001 From: Dmitrij Tejblum Date: Mon, 22 Aug 2011 11:39:35 +0400 Subject: lib: use "protocol-independed API" from RFC3678, if that is available (This commit is based on the patch from BZ#420, and should fix that bug.) * configure.ac: detect availability of that API * sockopt.c (setsockopt_ipv4_multicast): use it for join/leave IPv4 multicast groups --- configure.ac | 9 +++++++++ lib/sockopt.c | 26 ++++++++++++++++++++++---- 2 files changed, 31 insertions(+), 4 deletions(-) diff --git a/configure.ac b/configure.ac index a5b9dc43..40e31f25 100755 --- a/configure.ac +++ b/configure.ac @@ -944,6 +944,15 @@ AC_TRY_COMPILE([#ifdef HAVE_SYS_PARAM_H AC_DEFINE(HAVE_BSD_STRUCT_IP_MREQ_HACK,,[Can pass ifindex in struct ip_mreq])], AC_MSG_RESULT(no)) +AC_MSG_CHECKING([for RFC3678 protocol-independed API]) +AC_TRY_COMPILE([ +#include +#include +], [struct group_req gr; int sock; setsockopt(sock, IPPROTO_IP, MCAST_JOIN_GROUP, (void*)&gr, sizeof(gr)); +], [AC_MSG_RESULT(yes) +AC_DEFINE(HAVE_RFC3678,1,[Have RFC3678 protocol-independed API])], +AC_MSG_RESULT(no)) + dnl --------------------------------------------------------------- dnl figure out how to check link-state dnl --------------------------------------------------------------- diff --git a/lib/sockopt.c b/lib/sockopt.c index 8a1eec12..9ff15ca6 100644 --- a/lib/sockopt.c +++ b/lib/sockopt.c @@ -209,17 +209,35 @@ setsockopt_ipv4_multicast(int sock, unsigned int mcast_addr, unsigned int ifindex) { +#ifdef HAVE_RFC3678 + struct group_req gr; + struct sockaddr_in *si; + int ret; + memset (&gr, 0, sizeof(gr)); + si = (struct sockaddr_in *)&gr.gr_group; + gr.gr_interface = ifindex; + si->sin_family = AF_INET; +#ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN + si->sin_len = sizeof(struct sockaddr_in); +#endif /* HAVE_STRUCT_SOCKADDR_IN_SIN_LEN */ + si->sin_addr.s_addr = mcast_addr; + ret = setsockopt(sock, IPPROTO_IP, (optname == IP_ADD_MEMBERSHIP) ? + MCAST_JOIN_GROUP : MCAST_LEAVE_GROUP, (void *)&gr, sizeof(gr)); + if ((ret < 0) && (optname == IP_ADD_MEMBERSHIP) && (errno == EADDRINUSE)) + { + setsockopt(sock, IPPROTO_IP, MCAST_LEAVE_GROUP, (void *)&gr, sizeof(gr)); + ret = setsockopt(sock, IPPROTO_IP, MCAST_JOIN_GROUP, (void *)&gr, sizeof(gr)); + } + return ret; -#ifdef HAVE_STRUCT_IP_MREQN_IMR_IFINDEX +#elif defined(HAVE_STRUCT_IP_MREQN_IMR_IFINDEX) && !defined(__FreeBSD__) struct ip_mreqn mreqn; int ret; assert(optname == IP_ADD_MEMBERSHIP || optname == IP_DROP_MEMBERSHIP); memset (&mreqn, 0, sizeof(mreqn)); - if (mcast_addr) - mreqn.imr_multiaddr.s_addr = mcast_addr; - + mreqn.imr_multiaddr.s_addr = mcast_addr; mreqn.imr_ifindex = ifindex; ret = setsockopt(sock, IPPROTO_IP, optname, -- cgit v1.2.1