diff options
author | ajs <ajs> | 2005-10-21 02:57:41 +0000 |
---|---|---|
committer | ajs <ajs> | 2005-10-21 02:57:41 +0000 |
commit | c188c37caaf589a17b22e9889e63ec96f2f57106 (patch) | |
tree | 018d7f024a08c986a5558425ede05590518c9a23 /lib/sockopt.c | |
parent | f9ad937f537df92bf3119686eee97db7b7176674 (diff) |
2005-10-20 Andrew J. Schorr <ajschorr@alumni.princeton.edu>
* sockopt.c: (setsockopt_multicast_ipv4) If IP_ADD_MEMBERSHIP
fails with errno equal to EADDRINUSE, then issue an info
message and try IP_DROP_MEMBERSHIP followed by IP_ADD_MEMBERSHIP.
Diffstat (limited to 'lib/sockopt.c')
-rw-r--r-- | lib/sockopt.c | 53 |
1 files changed, 47 insertions, 6 deletions
diff --git a/lib/sockopt.c b/lib/sockopt.c index 655ecdc0..6ddbded1 100644 --- a/lib/sockopt.c +++ b/lib/sockopt.c @@ -162,6 +162,16 @@ getsockopt_ipv6_ifindex (struct msghdr *msgh) * using a single socket. The limit is typically 20, derived from the * original BSD multicast implementation. Some systems have * mechanisms for increasing this limit. + * + * In many 4.4BSD-derived systems, multicast group operations are not + * allowed on interfaces that are not UP. Thus, a previous attempt to + * leave the group may have failed, leaving it still joined, and we + * drop/join quietly to recover. This may not be necessary, but aims to + * defend against unknown behavior in that we will still return an error + * if the second join fails. It is not clear how other systems + * (e.g. Linux, Solaris) behave when leaving groups on down interfaces, + * but this behavior should not be harmful if they behave the same way, + * allow leaves, or implicitly leave all groups joined to down interfaces. */ int setsockopt_multicast_ipv4(int sock, @@ -174,6 +184,7 @@ setsockopt_multicast_ipv4(int sock, #ifdef HAVE_STRUCT_IP_MREQN_IMR_IFINDEX /* This is better because it uses ifindex directly */ struct ip_mreqn mreqn; + int ret; switch (optname) { @@ -190,7 +201,24 @@ setsockopt_multicast_ipv4(int sock, else mreqn.imr_address = if_addr; - return setsockopt(sock, IPPROTO_IP, optname, (void *)&mreqn, sizeof(mreqn)); + ret = setsockopt(sock, IPPROTO_IP, optname, + (void *)&mreqn, sizeof(mreqn)); + if ((ret < 0) && (optname == IP_ADD_MEMBERSHIP) && (errno == EADDRINUSE)) + { + /* see above: handle possible problem when interface comes back up */ + char buf[2][INET_ADDRSTRLEN]; + zlog_info("setsockopt_multicast_ipv4 attempting to drop and " + "re-add (fd %d, ifaddr %s, mcast %s, ifindex %u)", + sock, + inet_ntop(AF_INET, &if_addr, buf[0], sizeof(buf[0])), + inet_ntop(AF_INET, &mreqn.imr_multiaddr, + buf[1], sizeof(buf[1])), ifindex); + setsockopt(sock, IPPROTO_IP, IP_DROP_MEMBERSHIP, + (void *)&mreqn, sizeof(mreqn)); + ret = setsockopt(sock, IPPROTO_IP, IP_ADD_MEMBERSHIP, + (void *)&mreqn, sizeof(mreqn)); + } + return ret; break; default: @@ -210,6 +238,7 @@ setsockopt_multicast_ipv4(int sock, struct in_addr m; struct ip_mreq mreq; + int ret; #ifdef HAVE_BSD_STRUCT_IP_MREQ_HACK if (ifindex) @@ -230,11 +259,23 @@ setsockopt_multicast_ipv4(int sock, mreq.imr_multiaddr.s_addr = mcast_addr; mreq.imr_interface = m; - return setsockopt (sock, - IPPROTO_IP, - optname, - (void *)&mreq, - sizeof(mreq)); + ret = setsockopt (sock, IPPROTO_IP, optname, (void *)&mreq, sizeof(mreq)); + if ((ret < 0) && (optname == IP_ADD_MEMBERSHIP) && (errno == EADDRINUSE)) + { + /* see above: handle possible problem when interface comes back up */ + char buf[2][INET_ADDRSTRLEN]; + zlog_info("setsockopt_multicast_ipv4 attempting to drop and " + "re-add (fd %d, ifaddr %s, mcast %s, ifindex %u)", + sock, + inet_ntop(AF_INET, &if_addr, buf[0], sizeof(buf[0])), + inet_ntop(AF_INET, &mreq.imr_multiaddr, + buf[1], sizeof(buf[1])), ifindex); + setsockopt (sock, IPPROTO_IP, IP_DROP_MEMBERSHIP, + (void *)&mreq, sizeof(mreq)); + ret = setsockopt (sock, IPPROTO_IP, IP_ADD_MEMBERSHIP, + (void *)&mreq, sizeof(mreq)); + } + return ret; break; default: |