summaryrefslogtreecommitdiffstats
path: root/net/socket
diff options
context:
space:
mode:
authorsergeyu@chromium.org <sergeyu@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2011-04-18 23:03:32 +0000
committersergeyu@chromium.org <sergeyu@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2011-04-18 23:03:32 +0000
commit3871252036dec25ea2dca4622be40264a25b61d3 (patch)
tree67d45091d78abb5234b286437567f217dcd275cf /net/socket
parent2b4f812537173e2ab27a9f9b94de3b4da4a5d22e (diff)
downloadchromium_src-3871252036dec25ea2dca4622be40264a25b61d3.zip
chromium_src-3871252036dec25ea2dca4622be40264a25b61d3.tar.gz
chromium_src-3871252036dec25ea2dca4622be40264a25b61d3.tar.bz2
Added TCPServerSocket.
BUG=None TEST=Unittests Review URL: http://codereview.chromium.org/6820057 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@82020 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'net/socket')
-rw-r--r--net/socket/server_socket.h39
-rw-r--r--net/socket/tcp_client_socket_libevent.h3
-rw-r--r--net/socket/tcp_client_socket_win.cc1
-rw-r--r--net/socket/tcp_client_socket_win.h3
-rw-r--r--net/socket/tcp_server_socket.h26
-rw-r--r--net/socket/tcp_server_socket_libevent.cc194
-rw-r--r--net/socket/tcp_server_socket_libevent.h53
-rw-r--r--net/socket/tcp_server_socket_unittest.cc146
-rw-r--r--net/socket/tcp_server_socket_win.cc185
-rw-r--r--net/socket/tcp_server_socket_win.h55
10 files changed, 703 insertions, 2 deletions
diff --git a/net/socket/server_socket.h b/net/socket/server_socket.h
new file mode 100644
index 0000000..f037b036
--- /dev/null
+++ b/net/socket/server_socket.h
@@ -0,0 +1,39 @@
+// Copyright (c) 2011 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.
+
+#ifndef NET_SOCKET_SERVER_SOCKET_H_
+#define NET_SOCKET_SERVER_SOCKET_H_
+
+#include "base/scoped_ptr.h"
+#include "net/base/completion_callback.h"
+
+namespace net {
+
+class ClientSocket;
+class IPEndPoint;
+
+class ServerSocket {
+ public:
+ ServerSocket() { }
+ virtual ~ServerSocket() { }
+
+ // Bind the socket and start listening. Destroy the socket to stop
+ // listening.
+ virtual int Listen(const net::IPEndPoint& address, int backlog) = 0;
+
+ // Gets current address the socket is bound to.
+ virtual int GetLocalAddress(IPEndPoint* address) const = 0;
+
+ // Accept connection. Callback is called when new connection is
+ // accepted.
+ virtual int Accept(scoped_ptr<ClientSocket>* socket,
+ CompletionCallback* callback) = 0;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(ServerSocket);
+};
+
+} // namespace net
+
+#endif // NET_SOCKET_TCP_SERVER_SOCKET_H_
diff --git a/net/socket/tcp_client_socket_libevent.h b/net/socket/tcp_client_socket_libevent.h
index 2d9ea2b..796a4a8 100644
--- a/net/socket/tcp_client_socket_libevent.h
+++ b/net/socket/tcp_client_socket_libevent.h
@@ -36,7 +36,8 @@ class TCPClientSocketLibevent : public ClientSocket, base::NonThreadSafe {
// AdoptSocket causes the given, connected socket to be adopted as a TCP
// socket. This object must not be connected. This object takes ownership of
// the given socket and then acts as if Connect() had been called. This
- // function is intended for testing only.
+ // function is used by TCPServerSocket() to adopt accepted connections
+ // and for testing.
void AdoptSocket(int socket);
// ClientSocket methods:
diff --git a/net/socket/tcp_client_socket_win.cc b/net/socket/tcp_client_socket_win.cc
index 9d28254..eec7dbb 100644
--- a/net/socket/tcp_client_socket_win.cc
+++ b/net/socket/tcp_client_socket_win.cc
@@ -239,6 +239,7 @@ void TCPClientSocketWin::AdoptSocket(SOCKET socket) {
socket_ = socket;
int error = SetupSocket();
DCHECK_EQ(0, error);
+ core_ = new Core(this);
current_ai_ = addresses_.head();
use_history_.set_was_ever_connected();
}
diff --git a/net/socket/tcp_client_socket_win.h b/net/socket/tcp_client_socket_win.h
index aa8abd1..bca0d30 100644
--- a/net/socket/tcp_client_socket_win.h
+++ b/net/socket/tcp_client_socket_win.h
@@ -32,7 +32,8 @@ class TCPClientSocketWin : public ClientSocket, base::NonThreadSafe {
// AdoptSocket causes the given, connected socket to be adopted as a TCP
// socket. This object must not be connected. This object takes ownership of
// the given socket and then acts as if Connect() had been called. This
- // function is intended for testing only.
+ // function is used by TCPServerSocket() to adopt accepted connections
+ // and for testing.
void AdoptSocket(SOCKET socket);
// ClientSocket methods:
diff --git a/net/socket/tcp_server_socket.h b/net/socket/tcp_server_socket.h
new file mode 100644
index 0000000..4970a15
--- /dev/null
+++ b/net/socket/tcp_server_socket.h
@@ -0,0 +1,26 @@
+// Copyright (c) 2011 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.
+
+#ifndef NET_SOCKET_TCP_SERVER_SOCKET_H_
+#define NET_SOCKET_TCP_SERVER_SOCKET_H_
+
+#include "build/build_config.h"
+
+#if defined(OS_WIN)
+#include "net/socket/tcp_server_socket_win.h"
+#elif defined(OS_POSIX)
+#include "net/socket/tcp_server_socket_libevent.h"
+#endif
+
+namespace net {
+
+#if defined(OS_WIN)
+typedef TCPServerSocketWin TCPServerSocket;
+#elif defined(OS_POSIX)
+typedef TCPServerSocketLibevent TCPServerSocket;
+#endif
+
+} // namespace net
+
+#endif // NET_SOCKET_TCP_SERVER_SOCKET_H_
diff --git a/net/socket/tcp_server_socket_libevent.cc b/net/socket/tcp_server_socket_libevent.cc
new file mode 100644
index 0000000..40a01f0
--- /dev/null
+++ b/net/socket/tcp_server_socket_libevent.cc
@@ -0,0 +1,194 @@
+// Copyright (c) 2011 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.
+
+#include "net/socket/tcp_server_socket_libevent.h"
+
+#include <errno.h>
+#include <fcntl.h>
+#include <netdb.h>
+#include <sys/socket.h>
+
+#include "build/build_config.h"
+
+#if defined(OS_POSIX)
+#include <netinet/in.h>
+#endif
+#if defined(USE_SYSTEM_LIBEVENT)
+#include <event.h>
+#else
+#include "third_party/libevent/event.h"
+#endif
+
+#include "base/eintr_wrapper.h"
+#include "net/base/ip_endpoint.h"
+#include "net/base/net_errors.h"
+#include "net/base/net_util.h"
+#include "net/socket/tcp_client_socket.h"
+
+namespace net {
+
+namespace {
+
+const int kInvalidSocket = -1;
+
+} // namespace
+
+TCPServerSocketLibevent::TCPServerSocketLibevent(
+ net::NetLog* net_log,
+ const net::NetLog::Source& source)
+ : socket_(kInvalidSocket),
+ accept_socket_(NULL),
+ accept_callback_(NULL),
+ net_log_(BoundNetLog::Make(net_log, NetLog::SOURCE_SOCKET)) {
+ scoped_refptr<NetLog::EventParameters> params;
+ if (source.is_valid())
+ params = new NetLogSourceParameter("source_dependency", source);
+ net_log_.BeginEvent(NetLog::TYPE_SOCKET_ALIVE, params);
+}
+
+TCPServerSocketLibevent::~TCPServerSocketLibevent() {
+ if (socket_ != kInvalidSocket)
+ Close();
+ net_log_.EndEvent(NetLog::TYPE_SOCKET_ALIVE, NULL);
+}
+
+int TCPServerSocketLibevent::Listen(const IPEndPoint& address, int backlog) {
+ DCHECK(CalledOnValidThread());
+ DCHECK_GT(backlog, 0);
+ DCHECK_EQ(socket_, kInvalidSocket);
+
+ socket_ = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
+ if (socket_ < 0) {
+ PLOG(ERROR) << "socket() returned an error";
+ return MapSystemError(errno);
+ }
+
+ if (SetNonBlocking(socket_)) {
+ int result = MapSystemError(errno);
+ Close();
+ return result;
+ }
+
+ struct sockaddr_storage addr_storage;
+ size_t addr_len = sizeof(addr_storage);
+ struct sockaddr* addr = reinterpret_cast<struct sockaddr*>(&addr_storage);
+ if (!address.ToSockAddr(addr, &addr_len))
+ return ERR_INVALID_ARGUMENT;
+
+ int result = bind(socket_, addr, addr_len);
+ if (result < 0) {
+ PLOG(ERROR) << "bind() returned an error";
+ result = MapSystemError(errno);
+ Close();
+ return result;
+ }
+
+ result = listen(socket_, backlog);
+ if (result < 0) {
+ PLOG(ERROR) << "listen() returned an error";
+ result = MapSystemError(errno);
+ Close();
+ return result;
+ }
+
+ return OK;
+}
+
+int TCPServerSocketLibevent::GetLocalAddress(IPEndPoint* address) const {
+ DCHECK(CalledOnValidThread());
+ DCHECK(address);
+
+ struct sockaddr_storage addr_storage;
+ socklen_t addr_len = sizeof(addr_storage);
+ struct sockaddr* addr = reinterpret_cast<struct sockaddr*>(&addr_storage);
+ if (getsockname(socket_, addr, &addr_len) < 0)
+ return MapSystemError(errno);
+ if (!address->FromSockAddr(addr, addr_len))
+ return ERR_FAILED;
+
+ return OK;
+}
+
+int TCPServerSocketLibevent::Accept(
+ scoped_ptr<ClientSocket>* socket, CompletionCallback* callback) {
+ DCHECK(CalledOnValidThread());
+ DCHECK(socket);
+ DCHECK(callback);
+ DCHECK(!accept_callback_);
+
+ net_log_.BeginEvent(NetLog::TYPE_TCP_ACCEPT, NULL);
+
+ int result = AcceptInternal(socket);
+
+ if (result == ERR_IO_PENDING) {
+ if (!MessageLoopForIO::current()->WatchFileDescriptor(
+ socket_, true, MessageLoopForIO::WATCH_READ,
+ &accept_socket_watcher_, this)) {
+ PLOG(ERROR) << "WatchFileDescriptor failed on read";
+ return MapSystemError(errno);
+ }
+
+ accept_socket_ = socket;
+ accept_callback_ = callback;
+ }
+
+ return result;
+}
+
+int TCPServerSocketLibevent::AcceptInternal(
+ scoped_ptr<ClientSocket>* socket) {
+ struct sockaddr_storage addr_storage;
+ socklen_t addr_len = sizeof(addr_storage);
+ struct sockaddr* addr = reinterpret_cast<struct sockaddr*>(&addr_storage);
+
+ int result = HANDLE_EINTR(accept(socket_, addr, &addr_len));
+ if (result < 0) {
+ int net_error = MapSystemError(errno);
+ if (net_error != ERR_IO_PENDING)
+ net_log_.EndEventWithNetErrorCode(NetLog::TYPE_TCP_ACCEPT, net_error);
+ return net_error;
+ }
+
+ IPEndPoint address;
+ if (!address.FromSockAddr(addr, addr_len)) {
+ NOTREACHED();
+ HANDLE_EINTR(close(result));
+ net_log_.EndEventWithNetErrorCode(NetLog::TYPE_TCP_ACCEPT, ERR_FAILED);
+ return ERR_FAILED;
+ }
+ TCPClientSocket* tcp_socket = new TCPClientSocket(
+ AddressList(address.address(), address.port(), false),
+ net_log_.net_log(), net_log_.source());
+ tcp_socket->AdoptSocket(result);
+ socket->reset(tcp_socket);
+ net_log_.EndEvent(NetLog::TYPE_TCP_ACCEPT,
+ make_scoped_refptr(new NetLogStringParameter(
+ "address", address.ToString())));
+ return OK;
+}
+
+void TCPServerSocketLibevent::Close() {
+ if (socket_ != kInvalidSocket) {
+ HANDLE_EINTR(close(socket_));
+ socket_ = kInvalidSocket;
+ }
+}
+
+void TCPServerSocketLibevent::OnFileCanReadWithoutBlocking(int fd) {
+ DCHECK(CalledOnValidThread());
+
+ int result = AcceptInternal(accept_socket_);
+ if (result != ERR_IO_PENDING) {
+ CompletionCallback* c = accept_callback_;
+ accept_callback_ = NULL;
+ accept_socket_ = NULL;
+ c->Run(result);
+ }
+}
+
+void TCPServerSocketLibevent::OnFileCanWriteWithoutBlocking(int fd) {
+ NOTREACHED();
+}
+
+} // namespace net
diff --git a/net/socket/tcp_server_socket_libevent.h b/net/socket/tcp_server_socket_libevent.h
new file mode 100644
index 0000000..9d30953
--- /dev/null
+++ b/net/socket/tcp_server_socket_libevent.h
@@ -0,0 +1,53 @@
+// Copyright (c) 2011 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.
+
+#ifndef NET_SOCKET_TCP_SERVER_SOCKET_LIBEVENT_H_
+#define NET_SOCKET_TCP_SERVER_SOCKET_LIBEVENT_H_
+
+#include "base/message_loop.h"
+#include "base/scoped_ptr.h"
+#include "base/threading/non_thread_safe.h"
+#include "net/base/completion_callback.h"
+#include "net/base/net_log.h"
+#include "net/socket/server_socket.h"
+
+namespace net {
+
+class IPEndPoint;
+
+class TCPServerSocketLibevent : public ServerSocket,
+ public base::NonThreadSafe,
+ public MessageLoopForIO::Watcher {
+ public:
+ TCPServerSocketLibevent(net::NetLog* net_log,
+ const net::NetLog::Source& source);
+ ~TCPServerSocketLibevent();
+
+ // net::ServerSocket implementation.
+ virtual int Listen(const net::IPEndPoint& address, int backlog);
+ virtual int GetLocalAddress(IPEndPoint* address) const;
+ virtual int Accept(scoped_ptr<ClientSocket>* socket,
+ CompletionCallback* callback);
+
+ // MessageLoopForIO::Watcher implementation.
+ virtual void OnFileCanReadWithoutBlocking(int fd);
+ virtual void OnFileCanWriteWithoutBlocking(int fd);
+
+ private:
+ int AcceptInternal(scoped_ptr<ClientSocket>* socket);
+ void Close();
+
+ int socket_;
+
+ MessageLoopForIO::FileDescriptorWatcher accept_socket_watcher_;
+
+ scoped_ptr<ClientSocket>* accept_socket_;
+ CompletionCallback* accept_callback_;
+
+ BoundNetLog net_log_;
+};
+
+} // namespace net
+
+#endif // NET_SOCKET_TCP_SERVER_SOCKET_LIBEVENT_H_
diff --git a/net/socket/tcp_server_socket_unittest.cc b/net/socket/tcp_server_socket_unittest.cc
new file mode 100644
index 0000000..59fa4c0
--- /dev/null
+++ b/net/socket/tcp_server_socket_unittest.cc
@@ -0,0 +1,146 @@
+// Copyright (c) 2011 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.
+
+#include "net/socket/tcp_server_socket.h"
+
+#include "base/compiler_specific.h"
+#include "base/scoped_ptr.h"
+#include "net/base/address_list.h"
+#include "net/base/ip_endpoint.h"
+#include "net/base/net_errors.h"
+#include "net/base/sys_addrinfo.h"
+#include "net/base/test_completion_callback.h"
+#include "net/socket/tcp_client_socket.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "testing/platform_test.h"
+
+namespace net {
+
+namespace {
+const int kListenBacklog = 5;
+
+class TCPServerSocketTest : public PlatformTest {
+ protected:
+ TCPServerSocketTest()
+ : socket_(NULL, NetLog::Source()) {
+ }
+
+ void SetUp() OVERRIDE {
+ IPEndPoint address;
+ ParseAddress("127.0.0.1", 0, &address);
+ ASSERT_EQ(OK, socket_.Listen(address, kListenBacklog));
+ ASSERT_EQ(OK, socket_.GetLocalAddress(&local_address_));
+ }
+
+ void ParseAddress(std::string ip_str, int port, IPEndPoint* address) {
+ IPAddressNumber ip_number;
+ bool rv = ParseIPLiteralToNumber(ip_str, &ip_number);
+ if (!rv)
+ return;
+ *address = IPEndPoint(ip_number, port);
+ }
+
+ static IPEndPoint GetPeerAddress(ClientSocket* socket) {
+ AddressList address;
+ EXPECT_EQ(OK, socket->GetPeerAddress(&address));
+ IPEndPoint endpoint;
+ EXPECT_TRUE(endpoint.FromSockAddr(
+ address.head()->ai_addr, address.head()->ai_addrlen));
+ return endpoint;
+ }
+
+ TCPServerSocket socket_;
+ IPEndPoint local_address_;
+};
+
+TEST_F(TCPServerSocketTest, Accept) {
+ TestCompletionCallback connect_callback;
+ TCPClientSocket connecting_socket(AddressList(local_address_.address(),
+ local_address_.port(), false),
+ NULL, NetLog::Source());
+ connecting_socket.Connect(&connect_callback);
+
+ TestCompletionCallback accept_callback;
+ scoped_ptr<ClientSocket> accepted_socket;
+ int result = socket_.Accept(&accepted_socket, &accept_callback);
+ if (result == ERR_IO_PENDING)
+ result = accept_callback.WaitForResult();
+ ASSERT_EQ(OK, result);
+
+ ASSERT_TRUE(accepted_socket.get() != NULL);
+
+ // Both sockets should be on the loopback network interface.
+ EXPECT_EQ(GetPeerAddress(accepted_socket.get()).address(),
+ local_address_.address());
+
+ EXPECT_EQ(OK, connect_callback.WaitForResult());
+}
+
+// Test Accept() callback.
+TEST_F(TCPServerSocketTest, AcceptAsync) {
+ TestCompletionCallback accept_callback;
+ scoped_ptr<ClientSocket> accepted_socket;
+
+ ASSERT_EQ(ERR_IO_PENDING, socket_.Accept(&accepted_socket, &accept_callback));
+
+ TestCompletionCallback connect_callback;
+ TCPClientSocket connecting_socket(AddressList(local_address_.address(),
+ local_address_.port(), false),
+ NULL, NetLog::Source());
+ connecting_socket.Connect(&connect_callback);
+
+ EXPECT_EQ(OK, connect_callback.WaitForResult());
+ EXPECT_EQ(OK, accept_callback.WaitForResult());
+
+ EXPECT_TRUE(accepted_socket != NULL);
+
+ // Both sockets should be on the loopback network interface.
+ EXPECT_EQ(GetPeerAddress(accepted_socket.get()).address(),
+ local_address_.address());
+}
+
+// Accept two connections simultaneously.
+TEST_F(TCPServerSocketTest, Accept2Connections) {
+ TestCompletionCallback accept_callback;
+ scoped_ptr<ClientSocket> accepted_socket;
+
+ ASSERT_EQ(ERR_IO_PENDING,
+ socket_.Accept(&accepted_socket, &accept_callback));
+
+ TestCompletionCallback connect_callback;
+ TCPClientSocket connecting_socket(AddressList(local_address_.address(),
+ local_address_.port(), false),
+ NULL, NetLog::Source());
+ connecting_socket.Connect(&connect_callback);
+
+ TestCompletionCallback connect_callback2;
+ TCPClientSocket connecting_socket2(AddressList(local_address_.address(),
+ local_address_.port(), false),
+ NULL, NetLog::Source());
+ connecting_socket2.Connect(&connect_callback2);
+
+ EXPECT_EQ(OK, accept_callback.WaitForResult());
+
+ TestCompletionCallback accept_callback2;
+ scoped_ptr<ClientSocket> accepted_socket2;
+ int result = socket_.Accept(&accepted_socket2, &accept_callback2);
+ if (result == ERR_IO_PENDING)
+ result = accept_callback2.WaitForResult();
+ ASSERT_EQ(OK, result);
+
+ EXPECT_EQ(OK, connect_callback.WaitForResult());
+
+ EXPECT_TRUE(accepted_socket != NULL);
+ EXPECT_TRUE(accepted_socket2 != NULL);
+ EXPECT_NE(accepted_socket.get(), accepted_socket2.get());
+
+ EXPECT_EQ(GetPeerAddress(accepted_socket.get()).address(),
+ local_address_.address());
+ EXPECT_EQ(GetPeerAddress(accepted_socket2.get()).address(),
+ local_address_.address());
+}
+
+} // namespace
+
+} // namespace net
diff --git a/net/socket/tcp_server_socket_win.cc b/net/socket/tcp_server_socket_win.cc
new file mode 100644
index 0000000..0edbe92
--- /dev/null
+++ b/net/socket/tcp_server_socket_win.cc
@@ -0,0 +1,185 @@
+// Copyright (c) 2011 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.
+
+#include "net/socket/tcp_server_socket_win.h"
+
+#include <mstcpip.h>
+
+#include "net/base/ip_endpoint.h"
+#include "net/base/net_errors.h"
+#include "net/base/net_util.h"
+#include "net/base/winsock_init.h"
+#include "net/base/winsock_util.h"
+#include "net/socket/tcp_client_socket.h"
+
+namespace net {
+
+TCPServerSocketWin::TCPServerSocketWin(net::NetLog* net_log,
+ const net::NetLog::Source& source)
+ : socket_(INVALID_SOCKET),
+ socket_event_(WSA_INVALID_EVENT),
+ accept_socket_(NULL),
+ accept_callback_(NULL),
+ net_log_(BoundNetLog::Make(net_log, NetLog::SOURCE_SOCKET)) {
+ scoped_refptr<NetLog::EventParameters> params;
+ if (source.is_valid())
+ params = new NetLogSourceParameter("source_dependency", source);
+ net_log_.BeginEvent(NetLog::TYPE_SOCKET_ALIVE, params);
+ EnsureWinsockInit();
+}
+
+TCPServerSocketWin::~TCPServerSocketWin() {
+ Close();
+ net_log_.EndEvent(NetLog::TYPE_SOCKET_ALIVE, NULL);
+}
+
+int TCPServerSocketWin::Listen(const IPEndPoint& address, int backlog) {
+ DCHECK(CalledOnValidThread());
+ DCHECK_GT(backlog, 0);
+ DCHECK_EQ(socket_, INVALID_SOCKET);
+ DCHECK_EQ(socket_event_, WSA_INVALID_EVENT);
+
+ socket_event_ = WSACreateEvent();
+ if (socket_event_ == WSA_INVALID_EVENT) {
+ PLOG(ERROR) << "WSACreateEvent()";
+ return ERR_FAILED;
+ }
+
+ socket_ = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
+ if (socket_ < 0) {
+ PLOG(ERROR) << "socket() returned an error";
+ return MapSystemError(WSAGetLastError());
+ }
+
+ if (SetNonBlocking(socket_)) {
+ int result = MapSystemError(WSAGetLastError());
+ Close();
+ return result;
+ }
+
+ struct sockaddr_storage addr_storage;
+ size_t addr_len = sizeof(addr_storage);
+ struct sockaddr* addr = reinterpret_cast<struct sockaddr*>(&addr_storage);
+ if (!address.ToSockAddr(addr, &addr_len))
+ return ERR_INVALID_ARGUMENT;
+
+ int result = bind(socket_, addr, addr_len);
+ if (result < 0) {
+ PLOG(ERROR) << "bind() returned an error";
+ result = MapSystemError(WSAGetLastError());
+ Close();
+ return result;
+ }
+
+ result = listen(socket_, backlog);
+ if (result < 0) {
+ PLOG(ERROR) << "listen() returned an error";
+ result = MapSystemError(WSAGetLastError());
+ Close();
+ return result;
+ }
+
+ return OK;
+}
+
+int TCPServerSocketWin::GetLocalAddress(IPEndPoint* address) const {
+ DCHECK(CalledOnValidThread());
+ DCHECK(address);
+
+ struct sockaddr_storage addr_storage;
+ socklen_t addr_len = sizeof(addr_storage);
+ struct sockaddr* addr = reinterpret_cast<struct sockaddr*>(&addr_storage);
+ if (getsockname(socket_, addr, &addr_len))
+ return MapSystemError(WSAGetLastError());
+ if (!address->FromSockAddr(addr, addr_len))
+ return ERR_FAILED;
+
+ return OK;
+}
+
+int TCPServerSocketWin::Accept(
+ scoped_ptr<ClientSocket>* socket, CompletionCallback* callback) {
+ DCHECK(CalledOnValidThread());
+ DCHECK(socket);
+ DCHECK(callback);
+ DCHECK(!accept_callback_);
+
+ net_log_.BeginEvent(NetLog::TYPE_TCP_ACCEPT, NULL);
+
+ int result = AcceptInternal(socket);
+
+ if (result == ERR_IO_PENDING) {
+ // Start watching
+ WSAEventSelect(socket_, socket_event_, FD_ACCEPT);
+ accept_watcher_.StartWatching(socket_event_, this);
+
+ accept_socket_ = socket;
+ accept_callback_ = callback;
+ }
+
+ return result;
+}
+
+int TCPServerSocketWin::AcceptInternal(scoped_ptr<ClientSocket>* socket) {
+ struct sockaddr_storage addr_storage;
+ socklen_t addr_len = sizeof(addr_storage);
+ struct sockaddr* addr = reinterpret_cast<struct sockaddr*>(&addr_storage);
+
+ int result = accept(socket_, addr, &addr_len);
+ if (result < 0) {
+ int net_error = MapSystemError(WSAGetLastError());
+ if (net_error != ERR_IO_PENDING)
+ net_log_.EndEventWithNetErrorCode(NetLog::TYPE_TCP_ACCEPT, net_error);
+ return net_error;
+ }
+
+ IPEndPoint address;
+ if (!address.FromSockAddr(addr, addr_len)) {
+ NOTREACHED();
+ closesocket(result);
+ net_log_.EndEventWithNetErrorCode(NetLog::TYPE_TCP_ACCEPT, ERR_FAILED);
+ return ERR_FAILED;
+ }
+ TCPClientSocket* tcp_socket = new TCPClientSocket(
+ AddressList(address.address(), address.port(), false),
+ net_log_.net_log(), net_log_.source());
+ tcp_socket->AdoptSocket(result);
+ socket->reset(tcp_socket);
+ net_log_.EndEvent(NetLog::TYPE_TCP_ACCEPT,
+ make_scoped_refptr(new NetLogStringParameter(
+ "address", address.ToString())));
+ return OK;
+}
+
+void TCPServerSocketWin::Close() {
+ if (socket_ != INVALID_SOCKET) {
+ closesocket(socket_);
+ socket_ = INVALID_SOCKET;
+ }
+
+ if (socket_event_) {
+ WSACloseEvent(socket_event_);
+ socket_event_ = WSA_INVALID_EVENT;
+ }
+}
+
+void TCPServerSocketWin::OnObjectSignaled(HANDLE object) {
+ WSANETWORKEVENTS ev;
+ if (WSAEnumNetworkEvents(socket_, socket_event_, &ev) == SOCKET_ERROR) {
+ PLOG(ERROR) << "WSAEnumNetworkEvents()";
+ return;
+ }
+
+ if (ev.lNetworkEvents & FD_ACCEPT) {
+ int result = AcceptInternal(accept_socket_);
+ if (result != ERR_IO_PENDING) {
+ CompletionCallback* c = accept_callback_;
+ accept_callback_ = NULL;
+ accept_socket_ = NULL;
+ c->Run(result);
+ }
+ }
+}
+
+} // namespace net
diff --git a/net/socket/tcp_server_socket_win.h b/net/socket/tcp_server_socket_win.h
new file mode 100644
index 0000000..fbe61fa
--- /dev/null
+++ b/net/socket/tcp_server_socket_win.h
@@ -0,0 +1,55 @@
+// Copyright (c) 2011 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.
+
+#ifndef NET_SOCKET_TCP_SERVER_SOCKET_WIN_H_
+#define NET_SOCKET_TCP_SERVER_SOCKET_WIN_H_
+
+#include <winsock2.h>
+
+#include "base/message_loop.h"
+#include "base/scoped_ptr.h"
+#include "base/win/object_watcher.h"
+#include "base/threading/non_thread_safe.h"
+#include "net/base/net_log.h"
+#include "net/socket/server_socket.h"
+
+namespace net {
+
+class IPEndPoint;
+
+class TCPServerSocketWin : public ServerSocket,
+ public base::NonThreadSafe,
+ public base::win::ObjectWatcher::Delegate {
+ public:
+ TCPServerSocketWin(net::NetLog* net_log,
+ const net::NetLog::Source& source);
+ ~TCPServerSocketWin();
+
+ // net::ServerSocket implementation.
+ virtual int Listen(const net::IPEndPoint& address, int backlog);
+ virtual int GetLocalAddress(IPEndPoint* address) const;
+ virtual int Accept(scoped_ptr<ClientSocket>* socket,
+ CompletionCallback* callback);
+
+ // base::ObjectWatcher::Delegate implementation.
+ virtual void OnObjectSignaled(HANDLE object);
+
+ private:
+ int AcceptInternal(scoped_ptr<ClientSocket>* socket);
+ void Close();
+
+ SOCKET socket_;
+ HANDLE socket_event_;
+
+ base::win::ObjectWatcher accept_watcher_;
+
+ scoped_ptr<ClientSocket>* accept_socket_;
+ CompletionCallback* accept_callback_;
+
+ BoundNetLog net_log_;
+};
+
+} // namespace net
+
+#endif // NET_SOCKET_TCP_SERVER_SOCKET_WIN_H_