Commit 7141dbc7 authored by Eric Orth's avatar Eric Orth Committed by Commit Bot

Better setup for non-windows multicast sockets.

In addition to SO_REUSEADDR, that we were setting before, via
AllowAddressReuse(), for sockets for use with multicast, now also set
SO_REUSEPORT whenever that option is defined. On some non-Windows
platforms, this is needed for multicast messages to be received by all
sockets listening for them. This option is only set in a new
AllowAddressSharingForMulticast() method as the SO_REUSEADDR and
AllowAddressReuse() have other non-multicast uses where SO_REUSEPORT
would not be appropriate.

Also, for non-Windows platforms, bind the multicast sockets to the
multicast group address rather than to a wildcard. This will make us
more likely to only get messages from the relevant multicast group as
some platforms will otherwise give the socket any multicast messages
from groups joined by any sockets in the system. No change on Windows
where binding to a multicast group is not allowed.

TBR=thestig@chromium.org

Change-Id: I24d9d4a0d85134074b2deb14914a41109d7f724a
Bug: 899310
Reviewed-on: https://chromium-review.googlesource.com/c/1298298
Commit-Queue: Eric Orth <ericorth@chromium.org>
Reviewed-by: default avatarLei Zhang <thestig@chromium.org>
Reviewed-by: default avatarMatt Menke <mmenke@chromium.org>
Reviewed-by: default avatarTom Sepez <tsepez@chromium.org>
Cr-Commit-Position: refs/heads/master@{#603180}
parent 9126cd60
......@@ -163,29 +163,25 @@ void PrivetTrafficDetector::Helper::Bind() {
base::BindOnce(&CreateUDPSocketOnUIThread, profile_,
mojo::MakeRequest(&socket_), std::move(receiver_ptr)));
net::IPEndPoint multicast_addr =
net::GetMDnsIPEndPoint(net::ADDRESS_FAMILY_IPV4);
net::IPEndPoint bind_endpoint(
net::IPAddress::AllZeros(multicast_addr.address().size()),
multicast_addr.port());
network::mojom::UDPSocketOptionsPtr socket_options =
network::mojom::UDPSocketOptions::New();
socket_options->allow_address_reuse = true;
socket_options->allow_address_sharing_for_multicast = true;
socket_options->multicast_loopback_mode = false;
socket_->Bind(bind_endpoint, std::move(socket_options),
base::BindOnce(&Helper::OnBindComplete,
weak_ptr_factory_.GetWeakPtr(), multicast_addr));
socket_->Bind(
net::GetMDnsReceiveEndPoint(net::ADDRESS_FAMILY_IPV4),
std::move(socket_options),
base::BindOnce(&Helper::OnBindComplete, weak_ptr_factory_.GetWeakPtr(),
net::GetMDnsGroupEndPoint(net::ADDRESS_FAMILY_IPV4)));
}
void PrivetTrafficDetector::Helper::OnBindComplete(
net::IPEndPoint multicast_addr,
net::IPEndPoint multicast_group_addr,
int rv,
const base::Optional<net::IPEndPoint>& ip_endpoint) {
DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
if (rv == net::OK) {
socket_->JoinGroup(multicast_addr.address(),
socket_->JoinGroup(multicast_group_addr.address(),
base::BindOnce(&Helper::OnJoinGroupComplete,
weak_ptr_factory_.GetWeakPtr()));
return;
......
......@@ -27,20 +27,17 @@ IPEndPoint GetMDnsIPEndPoint(const char* address) {
dns_protocol::kDefaultPortMulticast);
}
int Bind(const IPEndPoint& multicast_addr,
int Bind(AddressFamily address_family,
uint32_t interface_index,
DatagramServerSocket* socket) {
IPAddress address_any(IPAddress::AllZeros(multicast_addr.address().size()));
IPEndPoint bind_endpoint(address_any, multicast_addr.port());
socket->AllowAddressReuse();
socket->AllowAddressSharingForMulticast();
socket->SetMulticastInterface(interface_index);
int rv = socket->Listen(bind_endpoint);
int rv = socket->Listen(GetMDnsReceiveEndPoint(address_family));
if (rv < OK)
return rv;
return socket->JoinGroup(multicast_addr.address());
return socket->JoinGroup(GetMDnsGroupEndPoint(address_family).address());
}
} // namespace
......@@ -58,7 +55,7 @@ std::unique_ptr<MDnsClient> MDnsClient::CreateDefault() {
return std::unique_ptr<MDnsClient>(new MDnsClientImpl());
}
IPEndPoint GetMDnsIPEndPoint(AddressFamily address_family) {
IPEndPoint GetMDnsGroupEndPoint(AddressFamily address_family) {
switch (address_family) {
case ADDRESS_FAMILY_IPV4:
return GetMDnsIPEndPoint(kMDnsMulticastGroupIPv4);
......@@ -70,6 +67,31 @@ IPEndPoint GetMDnsIPEndPoint(AddressFamily address_family) {
}
}
IPEndPoint GetMDnsReceiveEndPoint(AddressFamily address_family) {
#ifdef OS_WIN
// With Windows, binding to a mulitcast group address is not allowed.
// Multicast messages will be received appropriate to the multicast groups the
// socket has joined. Sockets intending to receive multicast messages should
// bind to a wildcard address (e.g. 0.0.0.0).
switch (address_family) {
case ADDRESS_FAMILY_IPV4:
return IPEndPoint(IPAddress::IPv4AllZeros(),
dns_protocol::kDefaultPortMulticast);
case ADDRESS_FAMILY_IPV6:
return IPEndPoint(IPAddress::IPv6AllZeros(),
dns_protocol::kDefaultPortMulticast);
default:
NOTREACHED();
return IPEndPoint();
}
#else // !OS_WIN
// With POSIX, any socket can receive messages for multicast groups joined by
// any socket on the system. Sockets intending to receive messages for a
// specific multicast group should bind to that group address.
return GetMDnsGroupEndPoint(address_family);
#endif // !OS_WIN
}
InterfaceIndexFamilyList GetMDnsInterfacesToBind() {
NetworkInterfaceList network_list;
InterfaceIndexFamilyList interfaces;
......@@ -96,11 +118,10 @@ std::unique_ptr<DatagramServerSocket> CreateAndBindMDnsSocket(
std::unique_ptr<DatagramServerSocket> socket(
new UDPServerSocket(net_log, NetLogSource()));
IPEndPoint multicast_addr = GetMDnsIPEndPoint(address_family);
int rv = Bind(multicast_addr, interface_index, socket.get());
int rv = Bind(address_family, interface_index, socket.get());
if (rv != OK) {
socket.reset();
VLOG(1) << "Bind failed, endpoint=" << multicast_addr.ToStringWithoutPort()
VLOG(1) << "MDNS bind failed, address_family=" << address_family
<< ", error=" << rv;
}
return socket;
......
......@@ -177,7 +177,16 @@ class NET_EXPORT MDnsClient {
static std::unique_ptr<MDnsClient> CreateDefault();
};
NET_EXPORT IPEndPoint GetMDnsIPEndPoint(AddressFamily address_family);
// Gets the endpoint for the multicast group a socket should join to receive
// MDNS messages. Such sockets should also bind to the endpoint from
// GetMDnsReceiveEndPoint().
//
// This is also the endpoint messages should be sent to to send MDNS messages.
NET_EXPORT IPEndPoint GetMDnsGroupEndPoint(AddressFamily address_family);
// Gets the endpoint sockets should be bound to to receive MDNS messages. Such
// sockets should also join the multicast group from GetMDnsGroupEndPoint().
NET_EXPORT IPEndPoint GetMDnsReceiveEndPoint(AddressFamily address_family);
typedef std::vector<std::pair<uint32_t, AddressFamily>>
InterfaceIndexFamilyList;
......
......@@ -70,7 +70,7 @@ int MDnsConnection::SocketHandler::Start() {
return rv;
DCHECK(end_point.GetFamily() == ADDRESS_FAMILY_IPV4 ||
end_point.GetFamily() == ADDRESS_FAMILY_IPV6);
multicast_addr_ = GetMDnsIPEndPoint(end_point.GetFamily());
multicast_addr_ = GetMDnsGroupEndPoint(end_point.GetFamily());
return DoLoop(0);
}
......
......@@ -20,7 +20,7 @@ namespace net {
MockMDnsDatagramServerSocket::MockMDnsDatagramServerSocket(
AddressFamily address_family) {
local_address_ = GetMDnsIPEndPoint(address_family);
local_address_ = GetMDnsReceiveEndPoint(address_family);
}
MockMDnsDatagramServerSocket::~MockMDnsDatagramServerSocket() = default;
......
......@@ -69,6 +69,7 @@ class MockMDnsDatagramServerSocket : public DatagramServerSocket {
MOCK_METHOD0(AllowAddressReuse, void());
MOCK_METHOD0(AllowBroadcast, void());
MOCK_METHOD0(AllowAddressSharingForMulticast, void());
MOCK_CONST_METHOD1(JoinGroup, int(const IPAddress& group_address));
MOCK_CONST_METHOD1(LeaveGroup, int(const IPAddress& address));
......
......@@ -63,14 +63,31 @@ class NET_EXPORT DatagramServerSocket : public DatagramSocket {
// Returns a net error code.
virtual int SetSendBufferSize(int32_t size) = 0;
// Allow the socket to share the local address to which the socket will
// be bound with other processes. Should be called before Listen().
// Allow the socket to share the local address to which the socket will be
// bound with other processes. If multiple processes are bound to the same
// local address at the same time, behavior is undefined; e.g., it is not
// guaranteed that incoming messages will be sent to all listening sockets.
//
// Should be called before Listen().
virtual void AllowAddressReuse() = 0;
// Allow sending and receiving packets to and from broadcast addresses.
// Should be called before Listen().
virtual void AllowBroadcast() = 0;
// Allow the socket to share the local address to which the socket will be
// bound with other processes and attempt to allow all such sockets to receive
// the same multicast messages.
//
// For best cross-platform results in allowing the messages to be shared, all
// sockets sharing the same address should join the same multicast group and
// interface. Also, the socket should listen to the specific multicast group
// address rather than a wildcard address (e.g. 0.0.0.0) on platforms where
// doing so is allowed.
//
// Should be called before Listen().
virtual void AllowAddressSharingForMulticast() = 0;
// Join the multicast group with address |group_address|.
// Returns a network error code.
virtual int JoinGroup(const IPAddress& group_address) const = 0;
......
......@@ -14,7 +14,8 @@ UDPServerSocket::UDPServerSocket(net::NetLog* net_log,
const net::NetLogSource& source)
: socket_(DatagramSocket::DEFAULT_BIND, net_log, source),
allow_address_reuse_(false),
allow_broadcast_(false) {}
allow_broadcast_(false),
allow_address_sharing_for_multicast_(false) {}
UDPServerSocket::~UDPServerSocket() = default;
......@@ -39,6 +40,14 @@ int UDPServerSocket::Listen(const IPEndPoint& address) {
}
}
if (allow_address_sharing_for_multicast_) {
rv = socket_.AllowAddressSharingForMulticast();
if (rv != OK) {
socket_.Close();
return rv;
}
}
return socket_.Bind(address);
}
......@@ -96,6 +105,10 @@ void UDPServerSocket::AllowBroadcast() {
allow_broadcast_ = true;
}
void UDPServerSocket::AllowAddressSharingForMulticast() {
allow_address_sharing_for_multicast_ = true;
}
int UDPServerSocket::JoinGroup(const IPAddress& group_address) const {
return socket_.JoinGroup(group_address);
}
......
......@@ -47,6 +47,7 @@ class NET_EXPORT UDPServerSocket : public DatagramServerSocket {
const NetLogWithSource& NetLog() const override;
void AllowAddressReuse() override;
void AllowBroadcast() override;
void AllowAddressSharingForMulticast() override;
int JoinGroup(const IPAddress& group_address) const override;
int LeaveGroup(const IPAddress& group_address) const override;
int SetMulticastInterface(uint32_t interface_index) override;
......@@ -59,6 +60,7 @@ class NET_EXPORT UDPServerSocket : public DatagramServerSocket {
UDPSocket socket_;
bool allow_address_reuse_;
bool allow_broadcast_;
bool allow_address_sharing_for_multicast_;
DISALLOW_COPY_AND_ASSIGN(UDPServerSocket);
};
......
......@@ -669,6 +669,30 @@ int UDPSocketPosix::SetBroadcast(bool broadcast) {
return rv == 0 ? OK : MapSystemError(errno);
}
int UDPSocketPosix::AllowAddressSharingForMulticast() {
DCHECK_NE(socket_, kInvalidSocket);
DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
DCHECK(!is_connected());
int rv = AllowAddressReuse();
if (rv != OK)
return rv;
#ifdef SO_REUSEPORT
// Attempt to set SO_REUSEPORT if available. On some platforms, this is
// necessary to allow the address to be fully shared between separate sockets.
// On platforms where the option does not exist, SO_REUSEADDR should be
// sufficient to share multicast packets if such sharing is at all possible.
int value = 1;
rv = setsockopt(socket_, SOL_SOCKET, SO_REUSEPORT, &value, sizeof(value));
// Ignore errors that the option does not exist.
if (rv != 0 && rv != ENOPROTOOPT)
return MapSystemError(errno);
#endif // SO_REUSEPORT
return OK;
}
void UDPSocketPosix::ReadWatcher::OnFileCanReadWithoutBlocking(int) {
TRACE_EVENT0(kNetTracingCategory,
"UDPSocketPosix::ReadWatcher::OnFileCanReadWithoutBlocking");
......
......@@ -81,7 +81,7 @@ const int kWriteAsyncCallbackBuffersThreshold = kWriteAsyncMaxBuffersThreshold;
class NET_EXPORT UDPSocketPosixSender
: public base::RefCountedThreadSafe<UDPSocketPosixSender> {
public:
explicit UDPSocketPosixSender();
UDPSocketPosixSender();
SendResult SendBuffers(int fd, DatagramBuffers buffers);
......@@ -290,6 +290,19 @@ class NET_EXPORT UDPSocketPosix {
// Returns a net error code.
int SetBroadcast(bool broadcast);
// Sets socket options to allow the socket to share the local address to which
// the socket will be bound with other processes and attempt to allow all such
// sockets to receive the same multicast messages. Returns a net error code.
//
// Ability and requirements for different sockets to receive the same messages
// varies between POSIX platforms. For best results in allowing the messages
// to be shared, all sockets sharing the same address should join the same
// multicast group and interface. Also, the socket should listen to the
// specific multicast address rather than a wildcard address (e.g. 0.0.0.0).
//
// Should be called between Open() and Bind().
int AllowAddressSharingForMulticast();
// Joins the multicast group.
// |group_address| is the group address to join, could be either
// an IPv4 or IPv6 address.
......@@ -371,7 +384,7 @@ class NET_EXPORT UDPSocketPosix {
void enable_experimental_recv_optimization() {
DCHECK_EQ(kInvalidSocket, socket_);
experimental_recv_optimization_enabled_ = true;
};
}
protected:
// WriteAsync batching etc. are to improve throughput of large high
......
......@@ -74,8 +74,8 @@ class UDPSocketTest : public PlatformTest, public WithScopedTaskEnvironment {
std::string RecvFromSocket(UDPServerSocket* socket) {
TestCompletionCallback callback;
int rv = socket->RecvFrom(
buffer_.get(), kMaxRead, &recv_from_address_, callback.callback());
int rv = socket->RecvFrom(buffer_.get(), kMaxRead, &recv_from_address_,
callback.callback());
rv = callback.GetResult(rv);
if (rv < 0)
return std::string();
......@@ -475,13 +475,11 @@ TEST_F(UDPSocketTest, VerifyConnectBindsAddr) {
EXPECT_THAT(rv, IsOk());
// Server2 sends reply.
rv = SendToSocket(&server2, foreign_message,
client_address);
rv = SendToSocket(&server2, foreign_message, client_address);
EXPECT_EQ(foreign_message.length(), static_cast<size_t>(rv));
// Server1 sends reply.
rv = SendToSocket(&server1, simple_message,
client_address);
rv = SendToSocket(&server1, simple_message, client_address);
EXPECT_EQ(simple_message.length(), static_cast<size_t>(rv));
// Client waits for response.
......@@ -495,17 +493,17 @@ TEST_F(UDPSocketTest, ClientGetLocalPeerAddresses) {
std::string local_address;
bool may_fail;
} tests[] = {
{ "127.0.00.1", "127.0.0.1", false },
{ "::1", "::1", true },
{"127.0.00.1", "127.0.0.1", false},
{"::1", "::1", true},
#if !defined(OS_ANDROID) && !defined(OS_IOS)
// Addresses below are disabled on Android. See crbug.com/161248
// They are also disabled on iOS. See https://crbug.com/523225
{ "192.168.1.1", "127.0.0.1", false },
{ "2001:db8:0::42", "::1", true },
{"192.168.1.1", "127.0.0.1", false},
{"2001:db8:0::42", "::1", true},
#endif
};
for (size_t i = 0; i < arraysize(tests); i++) {
SCOPED_TRACE(std::string("Connecting from ") + tests[i].local_address +
SCOPED_TRACE(std::string("Connecting from ") + tests[i].local_address +
std::string(" to ") + tests[i].remote_address);
IPAddress ip_address;
......@@ -533,7 +531,7 @@ TEST_F(UDPSocketTest, ClientGetLocalPeerAddresses) {
// The port is dynamically generated by the udp stack.
// The IP is the real IP of the client, not necessarily
// loopback.
//EXPECT_EQ(local_address.address(), fetched_local_address.address());
// EXPECT_EQ(local_address.address(), fetched_local_address.address());
IPEndPoint fetched_remote_address;
rv = client.GetPeerAddress(&fetched_remote_address);
......@@ -629,23 +627,21 @@ TEST_F(UDPSocketTest, CloseWithPendingRead) {
EXPECT_FALSE(callback.have_result());
}
#if defined(OS_ANDROID)
// Some Android devices do not support multicast socket.
// The ones supporting multicast need WifiManager.MulitcastLock to enable it.
// http://goo.gl/jjAk9
#define MAYBE_JoinMulticastGroup DISABLED_JoinMulticastGroup
#else
#define MAYBE_JoinMulticastGroup JoinMulticastGroup
#endif // defined(OS_ANDROID)
TEST_F(UDPSocketTest, MAYBE_JoinMulticastGroup) {
#ifndef OS_ANDROID
TEST_F(UDPSocketTest, JoinMulticastGroup) {
const uint16_t kPort = 9999;
const char kGroup[] = "237.132.100.17";
IPEndPoint bind_address;
ASSERT_TRUE(CreateUDPAddress("0.0.0.0", kPort, &bind_address));
IPAddress group_ip;
EXPECT_TRUE(group_ip.AssignFromIPLiteral(kGroup));
#ifdef OS_WIN
IPEndPoint bind_address(IPAddress::AllZeros(group_ip.size()), kPort);
#else
IPEndPoint bind_address(group_ip, kPort);
#endif // OS_WIN
UDPSocket socket(DatagramSocket::DEFAULT_BIND, nullptr, NetLogSource());
EXPECT_THAT(socket.Open(bind_address.GetFamily()), IsOk());
......@@ -672,6 +668,58 @@ TEST_F(UDPSocketTest, MAYBE_JoinMulticastGroup) {
socket.Close();
}
TEST_F(UDPSocketTest, SharedMulticastAddress) {
const uint16_t kPort = 9999;
const char kGroup[] = "224.0.0.251";
IPAddress group_ip;
ASSERT_TRUE(group_ip.AssignFromIPLiteral(kGroup));
IPEndPoint send_address(group_ip, kPort);
#ifdef OS_WIN
IPEndPoint receive_address(IPAddress::AllZeros(group_ip.size()), kPort);
#else
IPEndPoint receive_address(send_address);
#endif // OS_WINDOWS
NetworkInterfaceList interfaces;
ASSERT_TRUE(GetNetworkList(&interfaces, 0));
ASSERT_FALSE(interfaces.empty());
// Setup first receiving socket.
UDPServerSocket socket1(nullptr, NetLogSource());
socket1.AllowAddressSharingForMulticast();
ASSERT_THAT(socket1.SetMulticastInterface(interfaces[0].interface_index),
IsOk());
ASSERT_THAT(socket1.Listen(receive_address), IsOk());
ASSERT_THAT(socket1.JoinGroup(group_ip), IsOk());
// Setup second receiving socket.
UDPServerSocket socket2(nullptr, NetLogSource());
socket2.AllowAddressSharingForMulticast(), IsOk();
ASSERT_THAT(socket2.SetMulticastInterface(interfaces[0].interface_index),
IsOk());
ASSERT_THAT(socket2.Listen(receive_address), IsOk());
ASSERT_THAT(socket2.JoinGroup(group_ip), IsOk());
// Setup client socket.
UDPClientSocket client_socket(DatagramSocket::DEFAULT_BIND, nullptr,
NetLogSource());
ASSERT_THAT(client_socket.Connect(send_address), IsOk());
#ifndef OS_CHROMEOS
// Send a message via the multicast group. That message is expected be be
// received by both receving sockets.
//
// Skip on ChromeOS where it's known to sometimes not work.
// TODO(crbug.com/898964): If possible, fix and reenable.
const char kMessage[] = "hello!";
ASSERT_GE(WriteSocket(&client_socket, kMessage), 0);
EXPECT_EQ(kMessage, RecvFromSocket(&socket1));
EXPECT_EQ(kMessage, RecvFromSocket(&socket2));
#endif // OS_CHROMEOS
}
#endif // OS_ANDROID
TEST_F(UDPSocketTest, MulticastOptions) {
const uint16_t kPort = 9999;
IPEndPoint bind_address;
......@@ -741,9 +789,9 @@ TEST_F(UDPSocketTest, TestBindToNetwork) {
base::android::SDK_VERSION_LOLLIPOP) {
EXPECT_EQ(ERR_NOT_IMPLEMENTED, rv);
} else if (base::android::BuildInfo::GetInstance()->sdk_int() >=
base::android::SDK_VERSION_LOLLIPOP &&
base::android::SDK_VERSION_LOLLIPOP &&
base::android::BuildInfo::GetInstance()->sdk_int() <
base::android::SDK_VERSION_MARSHMALLOW) {
base::android::SDK_VERSION_MARSHMALLOW) {
// On Lollipop, we assume if the user has a NetworkHandle that they must
// have gotten it from a legitimate source, so if binding to the network
// fails it's assumed to be because the network went away so
......@@ -861,9 +909,9 @@ std::unique_ptr<UDPSocket> UnconnectedDscpTestClient(QwaveAPI& qos) {
} // namespace
using ::testing::_;
using ::testing::Return;
using ::testing::SetArgPointee;
using ::testing::_;
TEST_F(UDPSocketTest, SetDSCPNoopIfPassedNoChange) {
MockQwaveAPI qos;
......
......@@ -600,6 +600,13 @@ int UDPSocketWin::SetBroadcast(bool broadcast) {
return rv == 0 ? OK : MapSystemError(WSAGetLastError());
}
int UDPSocketWin::AllowAddressSharingForMulticast() {
// When proper multicast groups are used, Windows further defines the address
// resuse option (SO_REUSEADDR) to ensure all listening sockets can receive
// all incoming messages for the multicast group.
return AllowAddressReuse();
}
void UDPSocketWin::DoReadCallback(int rv) {
DCHECK_NE(rv, ERR_IO_PENDING);
DCHECK(!read_callback_.is_null());
......
......@@ -250,16 +250,30 @@ class NET_EXPORT UDPSocketWin : public base::win::ObjectWatcher::Delegate {
const NetLogWithSource& NetLog() const { return net_log_; }
// Sets corresponding flags in |socket_options_| to allow the socket
// to share the local address to which the socket will be bound with
// other processes. Should be called between Open() and Bind().
// Returns a net error code.
// Sets socket options to allow the socket to share the local address to which
// the socket will be bound with other processes. If multiple processes are
// bound to the same local address at the same time, behavior is undefined;
// e.g., it is not guaranteed that incoming messages will be sent to all
// listening sockets. Returns a net error code.
//
// Should be called between Open() and Bind().
int AllowAddressReuse();
// Sets corresponding flags in |socket_options_| to allow sending
// and receiving packets to and from broadcast addresses.
// Sets socket options to allow sending and receiving packets to and from
// broadcast addresses.
int SetBroadcast(bool broadcast);
// Sets socket options to allow the socket to share the local address to which
// the socket will be bound with other processes and attempt to allow all such
// sockets to receive the same multicast messages. Returns a net error code.
//
// For Windows, multicast messages should always be shared between sockets
// configured thusly as long as the sockets join the same multicast group and
// interface.
//
// Should be called between Open() and Bind().
int AllowAddressSharingForMulticast();
// Joins the multicast group.
// |group_address| is the group address to join, could be either
// an IPv4 or IPv6 address.
......
......@@ -148,6 +148,8 @@ class FakeDatagramServerSocket : public net::DatagramServerSocket {
void AllowBroadcast() override { NOTIMPLEMENTED(); }
void AllowAddressSharingForMulticast() override { NOTIMPLEMENTED(); }
int JoinGroup(const net::IPAddress& group_address) const override {
NOTIMPLEMENTED();
return net::ERR_NOT_IMPLEMENTED;
......
......@@ -16,12 +16,23 @@ struct UDPSocketOptions {
// If true, this enables SO_REUSEADDR on the underlying socket.
bool allow_address_reuse = false;
// It true, allows sending and receiving packets to and from broadcast
// If true, allows sending and receiving packets to and from broadcast
// addresses. It's recommended this be used instead of SetBroadcast(), as
// Bind() may fail on some platforms when reusing a UDP port and broadcast
// is not enabled when the socket is created.
bool allow_broadcast = false;
// If true, allows the socket to share the local address to which the socket
// will be bound with other processes and attempts to allow all such sockets
// to receive the same multicast messages.
//
// For best cross-platform results in allowing the messages to be shared, all
// sockets sharing the same address should join the same multicast group (via
// UDPSocket::JoinGroup()) and set the same |multicast_interface|. Also, the
// socket should bind to the specific multicast group address rather than a
// wildcard address (e.g. 0.0.0.0) on platforms where doing so is allowed.
bool allow_address_sharing_for_multicast = false;
// Sets interface to use for multicast. Default value is 0, in which case the
// default interface is used.
uint32 multicast_interface = 0;
......
......@@ -116,6 +116,8 @@ class SocketWrapperImpl : public UDPSocket::SocketWrapper {
int result = net::OK;
if (options->allow_address_reuse)
result = socket_.AllowAddressReuse();
if (result == net::OK && options->allow_address_sharing_for_multicast)
result = socket_.AllowAddressSharingForMulticast();
if (result == net::OK && options->allow_broadcast)
result = socket_.SetBroadcast(true);
if (result == net::OK && options->multicast_interface != 0)
......
......@@ -688,11 +688,13 @@ TEST_F(UDPSocketTest, MAYBE_JoinMulticastGroup) {
// See https://fuchsia.atlassian.net/browse/NET-195 .
options->multicast_interface = 1;
#endif // defined(OS_FUCHSIA)
options->allow_address_sharing_for_multicast = true;
net::IPAddress bind_ip_address;
EXPECT_TRUE(bind_ip_address.AssignFromIPLiteral("0.0.0.0"));
net::IPEndPoint socket_address(bind_ip_address, 0);
ASSERT_EQ(net::OK, helper.BindSync(socket_address, nullptr, &socket_address));
ASSERT_EQ(net::OK, helper.BindSync(socket_address, std::move(options),
&socket_address));
int port = socket_address.port();
EXPECT_NE(0, port);
EXPECT_EQ(net::OK, helper.JoinGroupSync(group_ip));
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment