summaryrefslogtreecommitdiffstats
path: root/net/udp
diff options
context:
space:
mode:
authorygorshenin@chromium.org <ygorshenin@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2012-07-16 11:52:34 +0000
committerygorshenin@chromium.org <ygorshenin@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2012-07-16 11:52:34 +0000
commita1781d7b57ead009cd69fed51dd1185ab1844404 (patch)
tree826c1c20f94c24dd9adb2d0134d17f5381c4105c /net/udp
parentb0b902f2aa03f2fe861456d720c7c82007e37b9f (diff)
downloadchromium_src-a1781d7b57ead009cd69fed51dd1185ab1844404.zip
chromium_src-a1781d7b57ead009cd69fed51dd1185ab1844404.tar.gz
chromium_src-a1781d7b57ead009cd69fed51dd1185ab1844404.tar.bz2
Added broadcasting feature to UDP server sockets.
BUG=136797 TEST=net_unittests:UDPSocketTest.Broadcast Review URL: https://chromiumcodereview.appspot.com/10739002 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@146790 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'net/udp')
-rw-r--r--net/udp/datagram_server_socket.h10
-rw-r--r--net/udp/udp_server_socket.cc10
-rw-r--r--net/udp/udp_server_socket.h4
-rw-r--r--net/udp/udp_socket_libevent.cc41
-rw-r--r--net/udp/udp_socket_libevent.h22
-rw-r--r--net/udp/udp_socket_unittest.cc39
-rw-r--r--net/udp/udp_socket_win.cc37
-rw-r--r--net/udp/udp_socket_win.h22
8 files changed, 182 insertions, 3 deletions
diff --git a/net/udp/datagram_server_socket.h b/net/udp/datagram_server_socket.h
index 759b0e4..206f2f5 100644
--- a/net/udp/datagram_server_socket.h
+++ b/net/udp/datagram_server_socket.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -59,6 +59,14 @@ class NET_EXPORT DatagramServerSocket : public DatagramSocket {
// Set the send buffer size (in bytes) for the socket.
virtual bool SetSendBufferSize(int32 size) = 0;
+
+ // Allow the socket to share the local address to which socket will
+ // be bound with other processes. Should be called before Listen().
+ virtual void AllowAddressReuse() = 0;
+
+ // Allow sending and receiving packets sent to and from broadcast
+ // addresses. Should be called before Listen().
+ virtual void AllowBroadcast() = 0;
};
} // namespace net
diff --git a/net/udp/udp_server_socket.cc b/net/udp/udp_server_socket.cc
index b4395d2..cec5173 100644
--- a/net/udp/udp_server_socket.cc
+++ b/net/udp/udp_server_socket.cc
@@ -1,4 +1,4 @@
-// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -61,4 +61,12 @@ const BoundNetLog& UDPServerSocket::NetLog() const {
return socket_.NetLog();
}
+void UDPServerSocket::AllowAddressReuse() {
+ socket_.AllowAddressReuse();
+}
+
+void UDPServerSocket::AllowBroadcast() {
+ socket_.AllowBroadcast();
+}
+
} // namespace net
diff --git a/net/udp/udp_server_socket.h b/net/udp/udp_server_socket.h
index 56a5459..4f87d24 100644
--- a/net/udp/udp_server_socket.h
+++ b/net/udp/udp_server_socket.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -37,6 +37,8 @@ class NET_EXPORT UDPServerSocket : public DatagramServerSocket {
virtual int GetPeerAddress(IPEndPoint* address) const OVERRIDE;
virtual int GetLocalAddress(IPEndPoint* address) const OVERRIDE;
virtual const BoundNetLog& NetLog() const OVERRIDE;
+ virtual void AllowAddressReuse() OVERRIDE;
+ virtual void AllowBroadcast() OVERRIDE;
private:
UDPSocket socket_;
diff --git a/net/udp/udp_socket_libevent.cc b/net/udp/udp_socket_libevent.cc
index bb1cf91..3782db3 100644
--- a/net/udp/udp_socket_libevent.cc
+++ b/net/udp/udp_socket_libevent.cc
@@ -41,6 +41,7 @@ UDPSocketLibevent::UDPSocketLibevent(
net::NetLog* net_log,
const net::NetLog::Source& source)
: socket_(kInvalidSocket),
+ socket_options_(0),
bind_type_(bind_type),
rand_int_cb_(rand_int_cb),
read_watcher_(this),
@@ -251,6 +252,9 @@ int UDPSocketLibevent::Bind(const IPEndPoint& address) {
int rv = CreateSocket(address);
if (rv < 0)
return rv;
+ rv = SetSocketOptions();
+ if (rv < 0)
+ return rv;
rv = DoBind(address);
if (rv < 0)
return rv;
@@ -274,6 +278,20 @@ bool UDPSocketLibevent::SetSendBufferSize(int32 size) {
return rv == 0;
}
+void UDPSocketLibevent::AllowAddressReuse() {
+ DCHECK(CalledOnValidThread());
+ DCHECK(!is_connected());
+
+ socket_options_ |= SOCKET_OPTION_REUSE_ADDRESS;
+}
+
+void UDPSocketLibevent::AllowBroadcast() {
+ DCHECK(CalledOnValidThread());
+ DCHECK(!is_connected());
+
+ socket_options_ |= SOCKET_OPTION_BROADCAST;
+}
+
void UDPSocketLibevent::DoReadCallback(int rv) {
DCHECK_NE(rv, ERR_IO_PENDING);
DCHECK(!read_callback_.is_null());
@@ -430,6 +448,29 @@ int UDPSocketLibevent::InternalSendTo(IOBuffer* buf, int buf_len,
return result;
}
+int UDPSocketLibevent::SetSocketOptions() {
+ int true_value = 1;
+ if (socket_options_ & SOCKET_OPTION_REUSE_ADDRESS) {
+ int rv = setsockopt(socket_, SOL_SOCKET, SO_REUSEADDR, &true_value,
+ sizeof(true_value));
+ if (rv < 0)
+ return MapSystemError(errno);
+#if defined(SO_REUSEPORT)
+ rv = setsockopt(socket_, SOL_SOCKET, SO_REUSEPORT, &true_value,
+ sizeof(true_value));
+ if (rv < 0)
+ return MapSystemError(errno);
+#endif
+ }
+ if (socket_options_ & SOCKET_OPTION_BROADCAST) {
+ int rv = setsockopt(socket_, SOL_SOCKET, SO_BROADCAST, &true_value,
+ sizeof(true_value));
+ if (rv < 0)
+ return MapSystemError(errno);
+ }
+ return OK;
+}
+
int UDPSocketLibevent::DoBind(const IPEndPoint& address) {
SockaddrStorage storage;
if (!address.ToSockAddr(storage.addr, &storage.addr_len))
diff --git a/net/udp/udp_socket_libevent.h b/net/udp/udp_socket_libevent.h
index 3242e18..2c19841 100644
--- a/net/udp/udp_socket_libevent.h
+++ b/net/udp/udp_socket_libevent.h
@@ -103,9 +103,24 @@ class NET_EXPORT UDPSocketLibevent : public base::NonThreadSafe {
const BoundNetLog& NetLog() const { return net_log_; }
+ // Sets corresponding flags in |socket_options_| to allow the socket
+ // to share the local address to which socket will be bound with
+ // other processes. Should be called before Bind().
+ void AllowAddressReuse();
+
+ // Sets corresponding flags in |socket_options_| to allow sending
+ // and receiving packets sent to and from broadcast
+ // addresses. Should be called before Bind().
+ void AllowBroadcast();
+
private:
static const int kInvalidSocket = -1;
+ enum SocketOptions {
+ SOCKET_OPTION_REUSE_ADDRESS = 1 << 0,
+ SOCKET_OPTION_BROADCAST = 1 << 1
+ };
+
class ReadWatcher : public MessageLoopForIO::Watcher {
public:
explicit ReadWatcher(UDPSocketLibevent* socket) : socket_(socket) {}
@@ -172,11 +187,18 @@ class NET_EXPORT UDPSocketLibevent : public base::NonThreadSafe {
int InternalRecvFrom(IOBuffer* buf, int buf_len, IPEndPoint* address);
int InternalSendTo(IOBuffer* buf, int buf_len, const IPEndPoint* address);
+ // Applies |socket_options_| to |socket_|. Should be called before
+ // Bind().
+ int SetSocketOptions();
int DoBind(const IPEndPoint& address);
int RandomBind(const IPEndPoint& address);
int socket_;
+ // Bitwise-or'd combination of SocketOptions. Specifies set of
+ // options that should be applied to |socket_| before bind.
+ int socket_options_;
+
// How to do source port binding, used only when UDPSocket is part of
// UDPClientSocket, since UDPServerSocket provides Bind.
DatagramSocket::BindType bind_type_;
diff --git a/net/udp/udp_socket_unittest.cc b/net/udp/udp_socket_unittest.cc
index 1650709..2da866d 100644
--- a/net/udp/udp_socket_unittest.cc
+++ b/net/udp/udp_socket_unittest.cc
@@ -201,6 +201,45 @@ TEST_F(UDPSocketTest, Connect) {
client_entries, 5, NetLog::TYPE_SOCKET_ALIVE));
}
+TEST_F(UDPSocketTest, Broadcast) {
+ const int kPort = 9999;
+ std::string first_message("first message"), second_message("second message");
+
+ IPEndPoint broadcast_address;
+ CreateUDPAddress("255.255.255.255", kPort, &broadcast_address);
+ IPEndPoint listen_address;
+ CreateUDPAddress("0.0.0.0", kPort, &listen_address);
+
+ CapturingNetLog server1_log, server2_log;
+ scoped_ptr<UDPServerSocket> server1(
+ new UDPServerSocket(&server1_log, NetLog::Source()));
+ scoped_ptr<UDPServerSocket> server2(
+ new UDPServerSocket(&server2_log, NetLog::Source()));
+ server1->AllowAddressReuse();
+ server1->AllowBroadcast();
+ server2->AllowAddressReuse();
+ server2->AllowBroadcast();
+
+ int rv = server1->Listen(listen_address);
+ EXPECT_EQ(OK, rv);
+ rv = server2->Listen(listen_address);
+ EXPECT_EQ(OK, rv);
+
+ rv = SendToSocket(server1.get(), first_message, broadcast_address);
+ EXPECT_EQ(static_cast<int>(first_message.size()), rv);
+ std::string str = RecvFromSocket(server1.get());
+ ASSERT_EQ(first_message, str);
+ str = RecvFromSocket(server2.get());
+ ASSERT_EQ(first_message, str);
+
+ rv = SendToSocket(server2.get(), second_message, broadcast_address);
+ EXPECT_EQ(static_cast<int>(second_message.size()), rv);
+ str = RecvFromSocket(server1.get());
+ ASSERT_EQ(second_message, str);
+ str = RecvFromSocket(server2.get());
+ ASSERT_EQ(second_message, str);
+}
+
// In this test, we verify that random binding logic works, which attempts
// to bind to a random port and returns if succeeds, otherwise retries for
// |kBindRetries| number of times.
diff --git a/net/udp/udp_socket_win.cc b/net/udp/udp_socket_win.cc
index a7a11bf..03c724e 100644
--- a/net/udp/udp_socket_win.cc
+++ b/net/udp/udp_socket_win.cc
@@ -46,6 +46,7 @@ UDPSocketWin::UDPSocketWin(DatagramSocket::BindType bind_type,
net::NetLog* net_log,
const net::NetLog::Source& source)
: socket_(INVALID_SOCKET),
+ socket_options_(0),
bind_type_(bind_type),
rand_int_cb_(rand_int_cb),
ALLOW_THIS_IN_INITIALIZER_LIST(read_delegate_(this)),
@@ -229,6 +230,9 @@ int UDPSocketWin::Bind(const IPEndPoint& address) {
int rv = CreateSocket(address);
if (rv < 0)
return rv;
+ rv = SetSocketOptions();
+ if (rv < 0)
+ return rv;
rv = DoBind(address);
if (rv < 0)
return rv;
@@ -260,6 +264,20 @@ bool UDPSocketWin::SetSendBufferSize(int32 size) {
return rv == 0;
}
+void UDPSocketWin::AllowAddressReuse() {
+ DCHECK(CalledOnValidThread());
+ DCHECK(!is_connected());
+
+ socket_options_ |= SOCKET_OPTION_REUSE_ADDRESS;
+}
+
+void UDPSocketWin::AllowBroadcast() {
+ DCHECK(CalledOnValidThread());
+ DCHECK(!is_connected());
+
+ socket_options_ |= SOCKET_OPTION_BROADCAST;
+}
+
void UDPSocketWin::DoReadCallback(int rv) {
DCHECK_NE(rv, ERR_IO_PENDING);
DCHECK(!read_callback_.is_null());
@@ -431,6 +449,25 @@ int UDPSocketWin::InternalSendTo(IOBuffer* buf, int buf_len,
return ERR_IO_PENDING;
}
+int UDPSocketWin::SetSocketOptions() {
+ BOOL true_value = 1;
+ if (socket_options_ & SOCKET_OPTION_REUSE_ADDRESS) {
+ int rv = setsockopt(socket_, SOL_SOCKET, SO_REUSEADDR,
+ reinterpret_cast<const char*>(&true_value),
+ sizeof(true_value));
+ if (rv < 0)
+ return MapSystemError(errno);
+ }
+ if (socket_options_ & SOCKET_OPTION_BROADCAST) {
+ int rv = setsockopt(socket_, SOL_SOCKET, SO_BROADCAST,
+ reinterpret_cast<const char*>(&true_value),
+ sizeof(true_value));
+ if (rv < 0)
+ return MapSystemError(errno);
+ }
+ return OK;
+}
+
int UDPSocketWin::DoBind(const IPEndPoint& address) {
SockaddrStorage storage;
if (!address.ToSockAddr(storage.addr, &storage.addr_len))
diff --git a/net/udp/udp_socket_win.h b/net/udp/udp_socket_win.h
index bd47496..a82860f 100644
--- a/net/udp/udp_socket_win.h
+++ b/net/udp/udp_socket_win.h
@@ -105,7 +105,22 @@ class NET_EXPORT UDPSocketWin : NON_EXPORTED_BASE(public base::NonThreadSafe) {
const BoundNetLog& NetLog() const { return net_log_; }
+ // Sets corresponding flags in |socket_options_| to allow the socket
+ // to share the local address to which socket will be bound with
+ // other processes. Should be called before Bind().
+ void AllowAddressReuse();
+
+ // Sets corresponding flags in |socket_options_| to allow sending
+ // and receiving packets sent to and from broadcast
+ // addresses. Should be called before Bind().
+ void AllowBroadcast();
+
private:
+ enum SocketOptions {
+ SOCKET_OPTION_REUSE_ADDRESS = 1 << 0,
+ SOCKET_OPTION_BROADCAST = 1 << 1
+ };
+
class ReadDelegate : public base::win::ObjectWatcher::Delegate {
public:
explicit ReadDelegate(UDPSocketWin* socket) : socket_(socket) {}
@@ -156,6 +171,9 @@ class NET_EXPORT UDPSocketWin : NON_EXPORTED_BASE(public base::NonThreadSafe) {
int InternalRecvFrom(IOBuffer* buf, int buf_len, IPEndPoint* address);
int InternalSendTo(IOBuffer* buf, int buf_len, const IPEndPoint* address);
+ // Applies |socket_options_| to |socket_|. Should be called before
+ // Bind().
+ int SetSocketOptions();
int DoBind(const IPEndPoint& address);
int RandomBind(const IPEndPoint& address);
@@ -165,6 +183,10 @@ class NET_EXPORT UDPSocketWin : NON_EXPORTED_BASE(public base::NonThreadSafe) {
SOCKET socket_;
+ // Bitwise-or'd combination of SocketOptions. Specifies set of
+ // options that should be applied to |socket_| before bind.
+ int socket_options_;
+
// How to do source port binding, used only when UDPSocket is part of
// UDPClientSocket, since UDPServerSocket provides Bind.
DatagramSocket::BindType bind_type_;