diff options
author | ygorshenin@chromium.org <ygorshenin@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-07-16 11:52:34 +0000 |
---|---|---|
committer | ygorshenin@chromium.org <ygorshenin@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-07-16 11:52:34 +0000 |
commit | a1781d7b57ead009cd69fed51dd1185ab1844404 (patch) | |
tree | 826c1c20f94c24dd9adb2d0134d17f5381c4105c /net/udp | |
parent | b0b902f2aa03f2fe861456d720c7c82007e37b9f (diff) | |
download | chromium_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.h | 10 | ||||
-rw-r--r-- | net/udp/udp_server_socket.cc | 10 | ||||
-rw-r--r-- | net/udp/udp_server_socket.h | 4 | ||||
-rw-r--r-- | net/udp/udp_socket_libevent.cc | 41 | ||||
-rw-r--r-- | net/udp/udp_socket_libevent.h | 22 | ||||
-rw-r--r-- | net/udp/udp_socket_unittest.cc | 39 | ||||
-rw-r--r-- | net/udp/udp_socket_win.cc | 37 | ||||
-rw-r--r-- | net/udp/udp_socket_win.h | 22 |
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_; |