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

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
« no previous file with comments | « net/udp/udp_socket_libevent.h ('k') | net/udp/udp_socket_unittest.cc » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: net/udp/udp_socket_libevent.cc
diff --git a/net/udp/udp_socket_libevent.cc b/net/udp/udp_socket_libevent.cc
index 7ef9c3c6b79681cfa99a5e2acafd7325a8ac66ad..2880fa13248a4464ae1905274e00535f961ee7b8 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"
@@ -24,15 +26,37 @@
#include "net/socket/socket_descriptor.h"
#include "net/udp/udp_net_log_parameters.h"
+
+namespace net {
+
namespace {
const int kBindRetries = 10;
const int kPortStart = 1024;
const int kPortEnd = 65535;
-} // namespace
+#if defined(OS_MACOSX)
-namespace net {
+// Returns IPv4 address in network order.
+int GetIPv4AddressFromIndex(int socket, uint32 index, uint32* address){
+ if (!index) {
+ *address = htonl(INADDR_ANY);
+ return OK;
+ }
+ ifreq ifr;
+ ifr.ifr_addr.sa_family = AF_INET;
+ if (!if_indextoname(index, ifr.ifr_name))
+ return ERR_FAILED;
+ int rv = ioctl(socket, SIOCGIFADDR, &ifr);
+ if (!rv)
+ return MapSystemError(rv);
+ *address = reinterpret_cast<sockaddr_in*>(&ifr.ifr_addr)->sin_addr.s_addr;
+ return OK;
+}
+
+#endif // OS_MACOSX
+
+} // namespace
UDPSocketLibevent::UDPSocketLibevent(
DatagramSocket::BindType bind_type,
@@ -42,6 +66,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 +549,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 +557,40 @@ 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;
+ int error = GetIPv4AddressFromIndex(socket_, multicast_interface_,
+ &mreq.imr_interface.s_addr);
+ if (error != OK)
+ return error;
+#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 +625,18 @@ 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;
+ int error = GetIPv4AddressFromIndex(socket_, multicast_interface_,
+ &mreq.imr_interface.s_addr);
+ if (error != OK)
+ return error;
+#endif
memcpy(&mreq.imr_multiaddr, &group_address[0], kIPv4AddressSize);
int rv = setsockopt(socket_, IPPROTO_IP, IP_ADD_MEMBERSHIP,
&mreq, sizeof(mreq));
@@ -579,7 +648,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 +699,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())
« no previous file with comments | « net/udp/udp_socket_libevent.h ('k') | net/udp/udp_socket_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698