summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorvitalybuka@chromium.org <vitalybuka@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-12-05 11:19:42 +0000
committervitalybuka@chromium.org <vitalybuka@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-12-05 11:19:42 +0000
commit7b29dac97993644a2da5e49898671c4a51b9d4c4 (patch)
tree9c7e29700cd83403899c4f6be048d652b3152761
parentef2992c7213fe547955c5b35418354cc1fc971e2 (diff)
downloadchromium_src-7b29dac97993644a2da5e49898671c4a51b9d4c4.zip
chromium_src-7b29dac97993644a2da5e49898671c4a51b9d4c4.tar.gz
chromium_src-7b29dac97993644a2da5e49898671c4a51b9d4c4.tar.bz2
Add support of IP_MULTICAST_IF in UDP sockets.
BUG=319068 Review URL: https://codereview.chromium.org/99923004 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@238939 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r--content/browser/renderer_host/p2p/socket_host_udp_unittest.cc5
-rw-r--r--net/dns/mock_mdns_socket_factory.h3
-rw-r--r--net/udp/datagram_server_socket.h6
-rw-r--r--net/udp/udp_server_socket.cc4
-rw-r--r--net/udp/udp_server_socket.h4
-rw-r--r--net/udp/udp_socket_libevent.cc89
-rw-r--r--net/udp/udp_socket_libevent.h9
-rw-r--r--net/udp/udp_socket_unittest.cc5
-rw-r--r--net/udp/udp_socket_win.cc49
-rw-r--r--net/udp/udp_socket_win.h9
10 files changed, 165 insertions, 18 deletions
diff --git a/content/browser/renderer_host/p2p/socket_host_udp_unittest.cc b/content/browser/renderer_host/p2p/socket_host_udp_unittest.cc
index 5657f47..3ccacfc 100644
--- a/content/browser/renderer_host/p2p/socket_host_udp_unittest.cc
+++ b/content/browser/renderer_host/p2p/socket_host_udp_unittest.cc
@@ -140,6 +140,11 @@ class FakeDatagramServerSocket : public net::DatagramServerSocket {
return net::ERR_NOT_IMPLEMENTED;
}
+ virtual int SetMulticastInterface(uint32 interface_index) OVERRIDE {
+ NOTIMPLEMENTED();
+ return net::ERR_NOT_IMPLEMENTED;
+ }
+
virtual int SetMulticastTimeToLive(int time_to_live) OVERRIDE {
NOTIMPLEMENTED();
return net::ERR_NOT_IMPLEMENTED;
diff --git a/net/dns/mock_mdns_socket_factory.h b/net/dns/mock_mdns_socket_factory.h
index 4d1c190..7cc8fed 100644
--- a/net/dns/mock_mdns_socket_factory.h
+++ b/net/dns/mock_mdns_socket_factory.h
@@ -46,11 +46,10 @@ class MockMDnsDatagramServerSocket : public DatagramServerSocket {
MOCK_METHOD0(AllowBroadcast, void());
MOCK_CONST_METHOD1(JoinGroup, int(const IPAddressNumber& group_address));
-
MOCK_CONST_METHOD1(LeaveGroup, int(const IPAddressNumber& address));
+ MOCK_METHOD1(SetMulticastInterface, int(uint32 interface_index));
MOCK_METHOD1(SetMulticastTimeToLive, int(int ttl));
-
MOCK_METHOD1(SetMulticastLoopbackMode, int(bool loopback));
MOCK_METHOD1(SetDiffServCodePoint, int(DiffServCodePoint dscp));
diff --git a/net/udp/datagram_server_socket.h b/net/udp/datagram_server_socket.h
index 0561d8a..ed5ab7a 100644
--- a/net/udp/datagram_server_socket.h
+++ b/net/udp/datagram_server_socket.h
@@ -80,6 +80,12 @@ class NET_EXPORT DatagramServerSocket : public DatagramSocket {
// Returns a network error code.
virtual int LeaveGroup(const IPAddressNumber& group_address) const = 0;
+ // Set interface to use for multicast. If |interface_index| set to 0, default
+ // interface is used.
+ // Should be called before Bind().
+ // Returns a network error code.
+ virtual int SetMulticastInterface(uint32 interface_index) = 0;
+
// Set the time-to-live option for UDP packets sent to the multicast
// group address. The default value of this option is 1.
// Cannot be negative or more than 255.
diff --git a/net/udp/udp_server_socket.cc b/net/udp/udp_server_socket.cc
index 79086f8..99d741b 100644
--- a/net/udp/udp_server_socket.cc
+++ b/net/udp/udp_server_socket.cc
@@ -77,6 +77,10 @@ int UDPServerSocket::LeaveGroup(const IPAddressNumber& group_address) const {
return socket_.LeaveGroup(group_address);
}
+int UDPServerSocket::SetMulticastInterface(uint32 interface_index) {
+ return socket_.SetMulticastInterface(interface_index);
+}
+
int UDPServerSocket::SetMulticastTimeToLive(int time_to_live) {
return socket_.SetMulticastTimeToLive(time_to_live);
}
diff --git a/net/udp/udp_server_socket.h b/net/udp/udp_server_socket.h
index 6586f7e..c593413 100644
--- a/net/udp/udp_server_socket.h
+++ b/net/udp/udp_server_socket.h
@@ -18,8 +18,7 @@ class BoundNetLog;
// A client socket that uses UDP as the transport layer.
class NET_EXPORT UDPServerSocket : public DatagramServerSocket {
public:
- UDPServerSocket(net::NetLog* net_log,
- const net::NetLog::Source& source);
+ UDPServerSocket(net::NetLog* net_log, const net::NetLog::Source& source);
virtual ~UDPServerSocket();
// Implement DatagramServerSocket:
@@ -42,6 +41,7 @@ class NET_EXPORT UDPServerSocket : public DatagramServerSocket {
virtual void AllowBroadcast() OVERRIDE;
virtual int JoinGroup(const IPAddressNumber& group_address) const OVERRIDE;
virtual int LeaveGroup(const IPAddressNumber& group_address) const OVERRIDE;
+ virtual int SetMulticastInterface(uint32 interface_index) OVERRIDE;
virtual int SetMulticastTimeToLive(int time_to_live) OVERRIDE;
virtual int SetMulticastLoopbackMode(bool loopback) OVERRIDE;
virtual int SetDiffServCodePoint(DiffServCodePoint dscp) OVERRIDE;
diff --git a/net/udp/udp_socket_libevent.cc b/net/udp/udp_socket_libevent.cc
index 7ef9c3c..2880fa13 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())
diff --git a/net/udp/udp_socket_libevent.h b/net/udp/udp_socket_libevent.h
index 6e737de..9dfbc8c 100644
--- a/net/udp/udp_socket_libevent.h
+++ b/net/udp/udp_socket_libevent.h
@@ -129,6 +129,12 @@ class NET_EXPORT UDPSocketLibevent : public base::NonThreadSafe {
// Return a network error code.
int LeaveGroup(const IPAddressNumber& group_address) const;
+ // Set interface to use for multicast. If |interface_index| set to 0, default
+ // interface is used.
+ // Should be called before Bind().
+ // Returns a network error code.
+ int SetMulticastInterface(uint32 interface_index);
+
// Set the time-to-live option for UDP packets sent to the multicast
// group address. The default value of this option is 1.
// Cannot be negative or more than 255.
@@ -237,6 +243,9 @@ class NET_EXPORT UDPSocketLibevent : public base::NonThreadSafe {
// options that should be applied to |socket_| before Bind().
int socket_options_;
+ // Multicast interface.
+ uint32 multicast_interface_;
+
// Multicast socket options cached for SetSocketOption.
// Cannot be used after Bind().
int multicast_time_to_live_;
diff --git a/net/udp/udp_socket_unittest.cc b/net/udp/udp_socket_unittest.cc
index ffb56d9..20e38ee 100644
--- a/net/udp/udp_socket_unittest.cc
+++ b/net/udp/udp_socket_unittest.cc
@@ -574,9 +574,14 @@ TEST_F(UDPSocketTest, MulticastOptions) {
EXPECT_EQ(OK, socket.SetMulticastTimeToLive(0));
EXPECT_EQ(OK, socket.SetMulticastTimeToLive(3));
EXPECT_NE(OK, socket.SetMulticastTimeToLive(-1));
+ EXPECT_EQ(OK, socket.SetMulticastInterface(0));
EXPECT_EQ(OK, socket.Bind(bind_address));
+ EXPECT_NE(OK, socket.SetMulticastLoopbackMode(false));
+ EXPECT_NE(OK, socket.SetMulticastTimeToLive(0));
+ EXPECT_NE(OK, socket.SetMulticastInterface(0));
+
socket.Close();
}
diff --git a/net/udp/udp_socket_win.cc b/net/udp/udp_socket_win.cc
index d2745b9..b4e4a4b 100644
--- a/net/udp/udp_socket_win.cc
+++ b/net/udp/udp_socket_win.cc
@@ -165,6 +165,7 @@ UDPSocketWin::UDPSocketWin(DatagramSocket::BindType bind_type,
: socket_(INVALID_SOCKET),
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),
@@ -621,6 +622,32 @@ int UDPSocketWin::SetSocketOptions() {
if (rv < 0)
return MapSystemError(WSAGetLastError());
}
+ if (multicast_interface_ != 0) {
+ switch (addr_family_) {
+ case AF_INET: {
+ in_addr address;
+ address.s_addr = htonl(multicast_interface_);
+ int rv = setsockopt(socket_, IPPROTO_IP, IP_MULTICAST_IF,
+ reinterpret_cast<const char*>(&address),
+ sizeof(address));
+ if (rv)
+ return MapSystemError(WSAGetLastError());
+ 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(WSAGetLastError());
+ break;
+ }
+ default:
+ NOTREACHED() << "Invalid address family";
+ return ERR_ADDRESS_INVALID;
+ }
+ }
return OK;
}
@@ -662,7 +689,7 @@ int UDPSocketWin::JoinGroup(
if (addr_family_ != AF_INET)
return ERR_ADDRESS_INVALID;
ip_mreq mreq;
- mreq.imr_interface.s_addr = INADDR_ANY;
+ mreq.imr_interface.s_addr = htonl(multicast_interface_);
memcpy(&mreq.imr_multiaddr, &group_address[0], kIPv4AddressSize);
int rv = setsockopt(socket_, IPPROTO_IP, IP_ADD_MEMBERSHIP,
reinterpret_cast<const char*>(&mreq),
@@ -675,7 +702,7 @@ int UDPSocketWin::JoinGroup(
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_ADD_MEMBERSHIP,
reinterpret_cast<const char*>(&mreq),
@@ -701,11 +728,10 @@ int UDPSocketWin::LeaveGroup(
if (addr_family_ != AF_INET)
return ERR_ADDRESS_INVALID;
ip_mreq mreq;
- mreq.imr_interface.s_addr = INADDR_ANY;
+ mreq.imr_interface.s_addr = htonl(multicast_interface_);
memcpy(&mreq.imr_multiaddr, &group_address[0], kIPv4AddressSize);
int rv = setsockopt(socket_, IPPROTO_IP, IP_DROP_MEMBERSHIP,
- reinterpret_cast<const char*>(&mreq),
- sizeof(mreq));
+ reinterpret_cast<const char*>(&mreq), sizeof(mreq));
if (rv)
return MapSystemError(WSAGetLastError());
return OK;
@@ -714,11 +740,10 @@ int UDPSocketWin::LeaveGroup(
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, IP_DROP_MEMBERSHIP,
- reinterpret_cast<const char*>(&mreq),
- sizeof(mreq));
+ reinterpret_cast<const char*>(&mreq), sizeof(mreq));
if (rv)
return MapSystemError(WSAGetLastError());
return OK;
@@ -729,6 +754,14 @@ int UDPSocketWin::LeaveGroup(
}
}
+int UDPSocketWin::SetMulticastInterface(uint32 interface_index) {
+ DCHECK(CalledOnValidThread());
+ if (is_connected())
+ return ERR_SOCKET_IS_CONNECTED;
+ multicast_interface_ = interface_index;
+ return OK;
+}
+
int UDPSocketWin::SetMulticastTimeToLive(int time_to_live) {
DCHECK(CalledOnValidThread());
if (is_connected())
diff --git a/net/udp/udp_socket_win.h b/net/udp/udp_socket_win.h
index 142c692..a8712a7 100644
--- a/net/udp/udp_socket_win.h
+++ b/net/udp/udp_socket_win.h
@@ -130,6 +130,12 @@ class NET_EXPORT UDPSocketWin : NON_EXPORTED_BASE(public base::NonThreadSafe) {
// Return a network error code.
int LeaveGroup(const IPAddressNumber& group_address) const;
+ // Set interface to use for multicast. If |interface_index| set to 0, default
+ // interface is used.
+ // Should be called before Bind().
+ // Returns a network error code.
+ int SetMulticastInterface(uint32 interface_index);
+
// Set the time-to-live option for UDP packets sent to the multicast
// group address. The default value of this option is 1.
// Cannot be negative or more than 255.
@@ -207,6 +213,9 @@ class NET_EXPORT UDPSocketWin : NON_EXPORTED_BASE(public base::NonThreadSafe) {
// options that should be applied to |socket_| before Bind().
int socket_options_;
+ // Multicast interface.
+ uint32 multicast_interface_;
+
// Multicast socket options cached for SetSocketOption.
// Cannot be used after Bind().
int multicast_time_to_live_;