Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(73)

Unified Diff: net/udp/udp_socket_libevent.cc

Issue 99923004: Add support of IP_MULTICAST_IF in UDP sockets. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Created 7 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: net/udp/udp_socket_libevent.cc
diff --git a/net/udp/udp_socket_libevent.cc b/net/udp/udp_socket_libevent.cc
index 990aa5758cca8f463ec0caf615432091a2847ac1..6a589364134e57bcb501de9096d107be02834763 100644
--- a/net/udp/udp_socket_libevent.cc
+++ b/net/udp/udp_socket_libevent.cc
@@ -7,8 +7,10 @@
#include <errno.h>
#include <fcntl.h>
#include <netdb.h>
-#include <sys/socket.h>
+#include <net/if.h>
#include <netinet/in.h>
+#include <sys/ioctl.h>
+#include <sys/socket.h>
#include "base/callback.h"
#include "base/logging.h"
@@ -30,6 +32,20 @@ const int kBindRetries = 10;
const int kPortStart = 1024;
const int kPortEnd = 65535;
+#if defined(OS_MACOSX)
+uint32 GetIPv4AddressFromIndex(int socket, uint32 index){
szym 2013/12/04 00:52:15 Add comment: // Returns IPv4 address in network or
Vitaly Buka (NO REVIEWS) 2013/12/04 09:39:36 Done.
+ if (!index)
+ return htonl(INADDR_ANY);
+ ifreq ifr;
+ ifr.ifr_addr.sa_family = AF_INET;
+ if (!if_indextoname(index, ifr.ifr_name))
+ return htonl(INADDR_ANY);
+ if (ioctl(socket, SIOCGIFADDR, &ifr))
+ return htonl(INADDR_ANY);
szym 2013/12/04 00:52:15 I am a bit concerned about this failure mode. If
Vitaly Buka (NO REVIEWS) 2013/12/04 01:00:49 For current use-cases returning error is not a pro
Vitaly Buka (NO REVIEWS) 2013/12/04 09:39:36 Done.
+ return reinterpret_cast<sockaddr_in*>(&ifr.ifr_addr)->sin_addr.s_addr;
+}
+#endif // OS_MACOSX
+
} // namespace
namespace net {
@@ -42,6 +58,7 @@ UDPSocketLibevent::UDPSocketLibevent(
: socket_(kInvalidSocket),
addr_family_(0),
socket_options_(SOCKET_OPTION_MULTICAST_LOOP),
+ multicast_interface_(0),
multicast_time_to_live_(1),
bind_type_(bind_type),
rand_int_cb_(rand_int_cb),
@@ -524,7 +541,7 @@ int UDPSocketLibevent::SetSocketOptions() {
rv = setsockopt(socket_, IPPROTO_IP, IP_MULTICAST_TTL,
&ttl, sizeof(ttl));
} else {
- // Signed interger. -1 to use route default.
+ // Signed integer. -1 to use route default.
int ttl = multicast_time_to_live_;
rv = setsockopt(socket_, IPPROTO_IPV6, IPV6_MULTICAST_HOPS,
&ttl, sizeof(ttl));
@@ -532,6 +549,38 @@ int UDPSocketLibevent::SetSocketOptions() {
if (rv < 0)
return MapSystemError(errno);
}
+ if (multicast_interface_ != 0) {
+ switch (addr_family_) {
+ case AF_INET: {
+#if !defined(OS_MACOSX)
+ ip_mreqn mreq;
+ mreq.imr_ifindex = multicast_interface_;
+ mreq.imr_address.s_addr = htonl(INADDR_ANY);
+#else
+ ip_mreq mreq;
+ mreq.imr_interface.s_addr =
+ GetIPv4AddressFromIndex(socket_, multicast_interface_);
+#endif
+ int rv = setsockopt(socket_, IPPROTO_IP, IP_MULTICAST_IF,
+ reinterpret_cast<const char*>(&mreq), sizeof(mreq));
+ if (rv)
+ return MapSystemError(errno);
+ break;
+ }
+ case AF_INET6: {
+ uint32 interface_index = multicast_interface_;
+ int rv = setsockopt(socket_, IPPROTO_IPV6, IPV6_MULTICAST_IF,
+ reinterpret_cast<const char*>(&interface_index),
+ sizeof(interface_index));
+ if (rv)
+ return MapSystemError(errno);
+ break;
+ }
+ default:
+ NOTREACHED() << "Invalid address family";
+ return ERR_ADDRESS_INVALID;
+ }
+ }
return OK;
}
@@ -566,8 +615,16 @@ int UDPSocketLibevent::JoinGroup(const IPAddressNumber& group_address) const {
case kIPv4AddressSize: {
if (addr_family_ != AF_INET)
return ERR_ADDRESS_INVALID;
+
+#if !defined(OS_MACOSX)
+ ip_mreqn mreq;
+ mreq.imr_ifindex = multicast_interface_;
+ mreq.imr_address.s_addr = htonl(INADDR_ANY);
+#else
ip_mreq mreq;
- mreq.imr_interface.s_addr = INADDR_ANY;
+ mreq.imr_interface.s_addr =
+ GetIPv4AddressFromIndex(socket_, multicast_interface_);
+#endif
memcpy(&mreq.imr_multiaddr, &group_address[0], kIPv4AddressSize);
int rv = setsockopt(socket_, IPPROTO_IP, IP_ADD_MEMBERSHIP,
&mreq, sizeof(mreq));
@@ -579,7 +636,7 @@ int UDPSocketLibevent::JoinGroup(const IPAddressNumber& group_address) const {
if (addr_family_ != AF_INET6)
return ERR_ADDRESS_INVALID;
ipv6_mreq mreq;
- mreq.ipv6mr_interface = 0; // 0 indicates default multicast interface.
+ mreq.ipv6mr_interface = multicast_interface_;
memcpy(&mreq.ipv6mr_multiaddr, &group_address[0], kIPv6AddressSize);
int rv = setsockopt(socket_, IPPROTO_IPV6, IPV6_JOIN_GROUP,
&mreq, sizeof(mreq));
@@ -630,6 +687,14 @@ int UDPSocketLibevent::LeaveGroup(const IPAddressNumber& group_address) const {
}
}
+int UDPSocketLibevent::SetMulticastInterface(uint32 interface_index) {
+ DCHECK(CalledOnValidThread());
+ if (is_connected())
+ return ERR_SOCKET_IS_CONNECTED;
+ multicast_interface_ = interface_index;
+ return OK;
+}
+
int UDPSocketLibevent::SetMulticastTimeToLive(int time_to_live) {
DCHECK(CalledOnValidThread());
if (is_connected())

Powered by Google App Engine
This is Rietveld 408576698