summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDmitrij Tejblum <tejblum@yandex-team.ru>2011-08-22 11:39:35 +0400
committerDenis Ovsienko <infrastation@yandex.ru>2011-09-27 21:39:12 +0400
commit10d04cdb4198b69073ea0cdd4c26a64d6697b33e (patch)
treef5b06a3be2a574d92bd7b4c0c90815cffedcdc43
parentee7e75d38bdb139b10f3a1d35209758409db7fb5 (diff)
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
-rwxr-xr-xconfigure.ac9
-rw-r--r--lib/sockopt.c26
2 files changed, 31 insertions, 4 deletions
diff --git a/configure.ac b/configure.ac
index 899108d9..63e8dcf0 100755
--- a/configure.ac
+++ b/configure.ac
@@ -943,6 +943,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 <sys/types.h>
+#include <netinet/in.h>
+], [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,