summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorjustinlin@chromium.org <justinlin@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2012-09-17 06:59:40 +0000
committerjustinlin@chromium.org <justinlin@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2012-09-17 06:59:40 +0000
commit68f2a23a4c269a19e6305598ae097ec652b3313a (patch)
tree6d5d571e5e252baf38bea75b90cffda84a58eb54
parent77c3fcde3f4fce9d1dca8a9b917d4e0a08c1ae2a (diff)
downloadchromium_src-68f2a23a4c269a19e6305598ae097ec652b3313a.zip
chromium_src-68f2a23a4c269a19e6305598ae097ec652b3313a.tar.gz
chromium_src-68f2a23a4c269a19e6305598ae097ec652b3313a.tar.bz2
Allow server sockets to rebind to same port if there is nothing actively listening on that port.
BUG= Review URL: https://chromiumcodereview.appspot.com/10907154 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@157087 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r--content/browser/renderer_host/p2p/socket_host_tcp_server_unittest.cc3
-rw-r--r--net/socket/server_socket.h4
-rw-r--r--net/socket/tcp_server_socket_libevent.cc25
-rw-r--r--net/socket/tcp_server_socket_libevent.h4
-rw-r--r--net/socket/tcp_server_socket_win.cc27
-rw-r--r--net/socket/tcp_server_socket_win.h10
6 files changed, 68 insertions, 5 deletions
diff --git a/content/browser/renderer_host/p2p/socket_host_tcp_server_unittest.cc b/content/browser/renderer_host/p2p/socket_host_tcp_server_unittest.cc
index 87f3ab4..ce77102 100644
--- a/content/browser/renderer_host/p2p/socket_host_tcp_server_unittest.cc
+++ b/content/browser/renderer_host/p2p/socket_host_tcp_server_unittest.cc
@@ -46,6 +46,9 @@ class FakeServerSocket : public net::ServerSocket {
}
// net::ServerSocket implementation.
+ virtual void AllowAddressReuse() {
+ }
+
virtual int Listen(const net::IPEndPoint& address, int backlog) OVERRIDE {
local_address_ = address;
listening_ = true;
diff --git a/net/socket/server_socket.h b/net/socket/server_socket.h
index 11151ee..a48ebec 100644
--- a/net/socket/server_socket.h
+++ b/net/socket/server_socket.h
@@ -19,6 +19,10 @@ class NET_EXPORT ServerSocket {
ServerSocket() { }
virtual ~ServerSocket() { }
+ // Allows the socket to share the local address to which the socket will be
+ // bound with other processes. Should be called before Listen().
+ virtual void AllowAddressReuse() = 0;
+
// Bind the socket and start listening. Destroy the socket to stop
// listening.
virtual int Listen(const net::IPEndPoint& address, int backlog) = 0;
diff --git a/net/socket/tcp_server_socket_libevent.cc b/net/socket/tcp_server_socket_libevent.cc
index ef8d1b1..879ec8e 100644
--- a/net/socket/tcp_server_socket_libevent.cc
+++ b/net/socket/tcp_server_socket_libevent.cc
@@ -35,6 +35,7 @@ TCPServerSocketLibevent::TCPServerSocketLibevent(
const net::NetLog::Source& source)
: socket_(kInvalidSocket),
accept_socket_(NULL),
+ reuse_address_(false),
net_log_(BoundNetLog::Make(net_log, NetLog::SOURCE_SOCKET)) {
net_log_.BeginEvent(NetLog::TYPE_SOCKET_ALIVE,
source.ToEventParametersCallback());
@@ -46,6 +47,13 @@ TCPServerSocketLibevent::~TCPServerSocketLibevent() {
net_log_.EndEvent(NetLog::TYPE_SOCKET_ALIVE);
}
+void TCPServerSocketLibevent::AllowAddressReuse() {
+ DCHECK(CalledOnValidThread());
+ DCHECK_EQ(socket_, kInvalidSocket);
+
+ reuse_address_ = true;
+}
+
int TCPServerSocketLibevent::Listen(const IPEndPoint& address, int backlog) {
DCHECK(CalledOnValidThread());
DCHECK_GT(backlog, 0);
@@ -63,11 +71,15 @@ int TCPServerSocketLibevent::Listen(const IPEndPoint& address, int backlog) {
return result;
}
+ int result = SetSocketOptions();
+ if (result != OK)
+ return result;
+
SockaddrStorage storage;
if (!address.ToSockAddr(storage.addr, &storage.addr_len))
return ERR_INVALID_ARGUMENT;
- int result = bind(socket_, storage.addr, storage.addr_len);
+ result = bind(socket_, storage.addr, storage.addr_len);
if (result < 0) {
PLOG(ERROR) << "bind() returned an error";
result = MapSystemError(errno);
@@ -125,6 +137,17 @@ int TCPServerSocketLibevent::Accept(
return result;
}
+int TCPServerSocketLibevent::SetSocketOptions() {
+ int true_value = 1;
+ if (reuse_address_) {
+ int rv = setsockopt(socket_, SOL_SOCKET, SO_REUSEADDR, &true_value,
+ sizeof(true_value));
+ if (rv < 0)
+ return MapSystemError(errno);
+ }
+ return OK;
+}
+
int TCPServerSocketLibevent::AcceptInternal(
scoped_ptr<StreamSocket>* socket) {
SockaddrStorage storage;
diff --git a/net/socket/tcp_server_socket_libevent.h b/net/socket/tcp_server_socket_libevent.h
index 946cc50..3b8d71e 100644
--- a/net/socket/tcp_server_socket_libevent.h
+++ b/net/socket/tcp_server_socket_libevent.h
@@ -26,6 +26,7 @@ class NET_EXPORT_PRIVATE TCPServerSocketLibevent
virtual ~TCPServerSocketLibevent();
// net::ServerSocket implementation.
+ virtual void AllowAddressReuse() OVERRIDE;
virtual int Listen(const net::IPEndPoint& address, int backlog) OVERRIDE;
virtual int GetLocalAddress(IPEndPoint* address) const OVERRIDE;
virtual int Accept(scoped_ptr<StreamSocket>* socket,
@@ -36,6 +37,7 @@ class NET_EXPORT_PRIVATE TCPServerSocketLibevent
virtual void OnFileCanWriteWithoutBlocking(int fd) OVERRIDE;
private:
+ int SetSocketOptions();
int AcceptInternal(scoped_ptr<StreamSocket>* socket);
void Close();
@@ -46,6 +48,8 @@ class NET_EXPORT_PRIVATE TCPServerSocketLibevent
scoped_ptr<StreamSocket>* accept_socket_;
CompletionCallback accept_callback_;
+ bool reuse_address_;
+
BoundNetLog net_log_;
};
diff --git a/net/socket/tcp_server_socket_win.cc b/net/socket/tcp_server_socket_win.cc
index eb15ffb..817e73a 100644
--- a/net/socket/tcp_server_socket_win.cc
+++ b/net/socket/tcp_server_socket_win.cc
@@ -21,6 +21,7 @@ TCPServerSocketWin::TCPServerSocketWin(net::NetLog* net_log,
: socket_(INVALID_SOCKET),
socket_event_(WSA_INVALID_EVENT),
accept_socket_(NULL),
+ reuse_address_(false),
net_log_(BoundNetLog::Make(net_log, NetLog::SOURCE_SOCKET)) {
net_log_.BeginEvent(NetLog::TYPE_SOCKET_ALIVE,
source.ToEventParametersCallback());
@@ -32,6 +33,14 @@ TCPServerSocketWin::~TCPServerSocketWin() {
net_log_.EndEvent(NetLog::TYPE_SOCKET_ALIVE);
}
+void TCPServerSocketWin::AllowAddressReuse() {
+ DCHECK(CalledOnValidThread());
+ DCHECK_EQ(socket_, INVALID_SOCKET);
+ DCHECK_EQ(socket_event_, WSA_INVALID_EVENT);
+
+ reuse_address_ = true;
+}
+
int TCPServerSocketWin::Listen(const IPEndPoint& address, int backlog) {
DCHECK(CalledOnValidThread());
DCHECK_GT(backlog, 0);
@@ -56,11 +65,15 @@ int TCPServerSocketWin::Listen(const IPEndPoint& address, int backlog) {
return result;
}
+ int result = SetSocketOptions();
+ if (result != OK)
+ return result;
+
SockaddrStorage storage;
if (!address.ToSockAddr(storage.addr, &storage.addr_len))
return ERR_INVALID_ARGUMENT;
- int result = bind(socket_, storage.addr, storage.addr_len);
+ result = bind(socket_, storage.addr, storage.addr_len);
if (result < 0) {
PLOG(ERROR) << "bind() returned an error";
result = MapSystemError(WSAGetLastError());
@@ -115,6 +128,18 @@ int TCPServerSocketWin::Accept(
return result;
}
+int TCPServerSocketWin::SetSocketOptions() {
+ BOOL true_value = 1;
+ if (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);
+ }
+ return OK;
+}
+
int TCPServerSocketWin::AcceptInternal(scoped_ptr<StreamSocket>* socket) {
SockaddrStorage storage;
int new_socket = accept(socket_, storage.addr, &storage.addr_len);
diff --git a/net/socket/tcp_server_socket_win.h b/net/socket/tcp_server_socket_win.h
index a7ab78c..fab8bf0 100644
--- a/net/socket/tcp_server_socket_win.h
+++ b/net/socket/tcp_server_socket_win.h
@@ -29,15 +29,17 @@ class NET_EXPORT_PRIVATE TCPServerSocketWin
~TCPServerSocketWin();
// net::ServerSocket implementation.
- virtual int Listen(const net::IPEndPoint& address, int backlog);
- virtual int GetLocalAddress(IPEndPoint* address) const;
+ virtual void AllowAddressReuse() OVERRIDE;
+ virtual int Listen(const net::IPEndPoint& address, int backlog) OVERRIDE;
+ virtual int GetLocalAddress(IPEndPoint* address) const OVERRIDE;
virtual int Accept(scoped_ptr<StreamSocket>* socket,
- const CompletionCallback& callback);
+ const CompletionCallback& callback) OVERRIDE;
// base::ObjectWatcher::Delegate implementation.
virtual void OnObjectSignaled(HANDLE object);
private:
+ int SetSocketOptions();
int AcceptInternal(scoped_ptr<StreamSocket>* socket);
void Close();
@@ -49,6 +51,8 @@ class NET_EXPORT_PRIVATE TCPServerSocketWin
scoped_ptr<StreamSocket>* accept_socket_;
CompletionCallback accept_callback_;
+ bool reuse_address_;
+
BoundNetLog net_log_;
};