diff options
author | willchan@chromium.org <willchan@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-04-17 23:59:33 +0000 |
---|---|---|
committer | willchan@chromium.org <willchan@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-04-17 23:59:33 +0000 |
commit | b391fb3da5e5af2388b71076234d2982327ceb48 (patch) | |
tree | f7d75fbb0b7def6fc8ca48578e825490e25fcaa5 /net | |
parent | 5f78651f721e01b6b064697e6a513d44eaef8c90 (diff) | |
download | chromium_src-b391fb3da5e5af2388b71076234d2982327ceb48.zip chromium_src-b391fb3da5e5af2388b71076234d2982327ceb48.tar.gz chromium_src-b391fb3da5e5af2388b71076234d2982327ceb48.tar.bz2 |
Reverting 13983.
Review URL: http://codereview.chromium.org/79066
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@13987 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'net')
-rw-r--r-- | net/base/tcp_client_socket.h | 122 | ||||
-rw-r--r-- | net/base/tcp_client_socket_libevent.cc | 105 | ||||
-rw-r--r-- | net/base/tcp_client_socket_libevent.h | 92 | ||||
-rw-r--r-- | net/base/tcp_client_socket_unittest.cc | 152 | ||||
-rw-r--r-- | net/base/tcp_client_socket_win.cc | 243 | ||||
-rw-r--r-- | net/base/tcp_client_socket_win.h | 114 | ||||
-rw-r--r-- | net/net.gyp | 2 |
7 files changed, 320 insertions, 510 deletions
diff --git a/net/base/tcp_client_socket.h b/net/base/tcp_client_socket.h index 820e586..729bbbc 100644 --- a/net/base/tcp_client_socket.h +++ b/net/base/tcp_client_socket.h @@ -1,4 +1,4 @@ -// Copyright (c) 2006-2009 The Chromium Authors. All rights reserved. +// Copyright (c) 2006-2008 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. @@ -8,20 +8,132 @@ #include "build/build_config.h" #if defined(OS_WIN) -#include "net/base/tcp_client_socket_win.h" +#include <ws2tcpip.h> +#include "base/object_watcher.h" #elif defined(OS_POSIX) -#include "net/base/tcp_client_socket_libevent.h" +struct event; // From libevent +#include <sys/socket.h> // for struct sockaddr +#define SOCKET int +#include "base/message_loop.h" #endif +#include "net/base/address_list.h" +#include "net/base/client_socket.h" +#include "net/base/completion_callback.h" + namespace net { // A client socket that uses TCP as the transport layer. +// +// NOTE: The windows implementation supports half duplex only. +// Read and Write calls must not be in progress at the same time. +// The libevent implementation supports full duplex because that +// made it slightly easier to implement ssl. +class TCPClientSocket : public ClientSocket, +#if defined(OS_WIN) + public base::ObjectWatcher::Delegate +#elif defined(OS_POSIX) + public MessageLoopForIO::Watcher +#endif +{ + public: + // The IP address(es) and port number to connect to. The TCP socket will try + // each IP address in the list until it succeeds in establishing a + // connection. + explicit TCPClientSocket(const AddressList& addresses); + + ~TCPClientSocket(); + + // ClientSocket methods: + virtual int Connect(CompletionCallback* callback); + virtual void Disconnect(); + virtual bool IsConnected() const; + virtual bool IsConnectedAndIdle() const; + + // Socket methods: + // Multiple outstanding requests are not supported. + // Full duplex mode (reading and writing at the same time) is not supported + // on Windows (but is supported on Linux and Mac for ease of implementation + // of SSLClientSocket) + virtual int Read(char* buf, int buf_len, CompletionCallback* callback); + virtual int Write(const char* buf, int buf_len, CompletionCallback* callback); + +#if defined(OS_POSIX) + // Identical to posix system call of same name + // Needed by ssl_client_socket_nss + virtual int GetPeerName(struct sockaddr *name, socklen_t *namelen); +#endif + + private: + SOCKET socket_; + + // The list of addresses we should try in order to establish a connection. + AddressList addresses_; + + // Where we are in above list, or NULL if all addrinfos have been tried. + const struct addrinfo* current_ai_; + #if defined(OS_WIN) -typedef TCPClientSocketWin TCPClientSocket; + enum WaitState { + NOT_WAITING, + WAITING_CONNECT, + WAITING_READ, + WAITING_WRITE + }; + WaitState wait_state_; + + // base::ObjectWatcher::Delegate methods: + virtual void OnObjectSignaled(HANDLE object); + + // Waits for the (manual-reset) event object to become signaled and resets + // it. Called after a Winsock function succeeds synchronously + // + // Our testing shows that except in rare cases (when running inside QEMU), + // the event object is already signaled at this point, so we just call this + // method on the IO thread to avoid a context switch. + void WaitForAndResetEvent(); + + OVERLAPPED overlapped_; + WSABUF buffer_; + + base::ObjectWatcher watcher_; + + void DidCompleteIO(); #elif defined(OS_POSIX) -typedef TCPClientSocketLibevent TCPClientSocket; + // Whether we're currently waiting for connect() to complete + bool waiting_connect_; + + // The socket's libevent wrapper + MessageLoopForIO::FileDescriptorWatcher socket_watcher_; + + // Called by MessagePumpLibevent when the socket is ready to do I/O + void OnFileCanReadWithoutBlocking(int fd); + void OnFileCanWriteWithoutBlocking(int fd); + + // The buffer used by OnSocketReady to retry Read requests + char* buf_; + int buf_len_; + + // The buffer used by OnSocketReady to retry Write requests + const char* write_buf_; + int write_buf_len_; + + // External callback; called when write is complete. + CompletionCallback* write_callback_; + + void DoWriteCallback(int rv); + void DidCompleteRead(); + void DidCompleteWrite(); #endif + // External callback; called when read (and on Windows, write) is complete. + CompletionCallback* callback_; + + int CreateSocket(const struct addrinfo* ai); + void DoCallback(int rv); + void DidCompleteConnect(); +}; + } // namespace net #endif // NET_BASE_TCP_CLIENT_SOCKET_H_ diff --git a/net/base/tcp_client_socket_libevent.cc b/net/base/tcp_client_socket_libevent.cc index 112536d..8d51dbf 100644 --- a/net/base/tcp_client_socket_libevent.cc +++ b/net/base/tcp_client_socket_libevent.cc @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "net/base/tcp_client_socket_libevent.h" +#include "net/base/tcp_client_socket.h" #include <errno.h> #include <fcntl.h> @@ -65,20 +65,20 @@ static int MapPosixError(int err) { //----------------------------------------------------------------------------- -TCPClientSocketLibevent::TCPClientSocketLibevent(const AddressList& addresses) - : socket_(kInvalidSocket), - addresses_(addresses), - current_ai_(addresses_.head()), - waiting_connect_(false), - read_callback_(NULL), - write_callback_(NULL) { +TCPClientSocket::TCPClientSocket(const AddressList& addresses) + : socket_(kInvalidSocket), + addresses_(addresses), + current_ai_(addresses_.head()), + waiting_connect_(false), + write_callback_(NULL), + callback_(NULL) { } -TCPClientSocketLibevent::~TCPClientSocketLibevent() { +TCPClientSocket::~TCPClientSocket() { Disconnect(); } -int TCPClientSocketLibevent::Connect(CompletionCallback* callback) { +int TCPClientSocket::Connect(CompletionCallback* callback) { // If already connected, then just return OK. if (socket_ != kInvalidSocket) return OK; @@ -122,11 +122,11 @@ int TCPClientSocketLibevent::Connect(CompletionCallback* callback) { } waiting_connect_ = true; - read_callback_ = callback; + callback_ = callback; return ERR_IO_PENDING; } -void TCPClientSocketLibevent::Disconnect() { +void TCPClientSocket::Disconnect() { if (socket_ == kInvalidSocket) return; @@ -141,7 +141,7 @@ void TCPClientSocketLibevent::Disconnect() { current_ai_ = addresses_.head(); } -bool TCPClientSocketLibevent::IsConnected() const { +bool TCPClientSocket::IsConnected() const { if (socket_ == kInvalidSocket || waiting_connect_) return false; @@ -156,7 +156,7 @@ bool TCPClientSocketLibevent::IsConnected() const { return true; } -bool TCPClientSocketLibevent::IsConnectedAndIdle() const { +bool TCPClientSocket::IsConnectedAndIdle() const { if (socket_ == kInvalidSocket || waiting_connect_) return false; @@ -172,12 +172,12 @@ bool TCPClientSocketLibevent::IsConnectedAndIdle() const { return true; } -int TCPClientSocketLibevent::Read(char* buf, - int buf_len, - CompletionCallback* callback) { - DCHECK_NE(socket_, kInvalidSocket); +int TCPClientSocket::Read(char* buf, + int buf_len, + CompletionCallback* callback) { + DCHECK(socket_ != kInvalidSocket); DCHECK(!waiting_connect_); - DCHECK(!read_callback_); + DCHECK(!callback_); // Synchronous operation not supported DCHECK(callback); DCHECK(buf_len > 0); @@ -194,27 +194,27 @@ int TCPClientSocketLibevent::Read(char* buf, } if (!MessageLoopForIO::current()->WatchFileDescriptor( - socket_, true, MessageLoopForIO::WATCH_READ, - &socket_watcher_, this)) { + socket_, true, MessageLoopForIO::WATCH_READ, &socket_watcher_, this)) + { DLOG(INFO) << "WatchFileDescriptor failed on read, errno " << errno; return MapPosixError(errno); } - read_buf_ = buf; - read_buf_len_ = buf_len; - read_callback_ = callback; + buf_ = buf; + buf_len_ = buf_len; + callback_ = callback; return ERR_IO_PENDING; } -int TCPClientSocketLibevent::Write(const char* buf, - int buf_len, - CompletionCallback* callback) { +int TCPClientSocket::Write(const char* buf, + int buf_len, + CompletionCallback* callback) { DCHECK(socket_ != kInvalidSocket); DCHECK(!waiting_connect_); DCHECK(!write_callback_); // Synchronous operation not supported DCHECK(callback); - DCHECK_GT(buf_len, 0); + DCHECK(buf_len > 0); TRACE_EVENT_BEGIN("socket.write", this, ""); int nwrite = write(socket_, buf, buf_len); @@ -226,8 +226,8 @@ int TCPClientSocketLibevent::Write(const char* buf, return MapPosixError(errno); if (!MessageLoopForIO::current()->WatchFileDescriptor( - socket_, true, MessageLoopForIO::WATCH_WRITE, - &socket_watcher_, this)) { + socket_, true, MessageLoopForIO::WATCH_WRITE, &socket_watcher_, this)) + { DLOG(INFO) << "WatchFileDescriptor failed on write, errno " << errno; return MapPosixError(errno); } @@ -239,7 +239,7 @@ int TCPClientSocketLibevent::Write(const char* buf, return ERR_IO_PENDING; } -int TCPClientSocketLibevent::CreateSocket(const addrinfo* ai) { +int TCPClientSocket::CreateSocket(const addrinfo* ai) { socket_ = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol); if (socket_ == kInvalidSocket) return MapPosixError(errno); @@ -250,18 +250,18 @@ int TCPClientSocketLibevent::CreateSocket(const addrinfo* ai) { return OK; } -void TCPClientSocketLibevent::DoReadCallback(int rv) { - DCHECK_NE(rv, ERR_IO_PENDING); - DCHECK(read_callback_); +void TCPClientSocket::DoCallback(int rv) { + DCHECK(rv != ERR_IO_PENDING); + DCHECK(callback_); - // since Run may result in Read being called, clear read_callback_ up front. - CompletionCallback* c = read_callback_; - read_callback_ = NULL; + // since Run may result in Read being called, clear callback_ up front. + CompletionCallback* c = callback_; + callback_ = NULL; c->Run(rv); } -void TCPClientSocketLibevent::DoWriteCallback(int rv) { - DCHECK_NE(rv, ERR_IO_PENDING); +void TCPClientSocket::DoWriteCallback(int rv) { + DCHECK(rv != ERR_IO_PENDING); DCHECK(write_callback_); // since Run may result in Write being called, clear write_callback_ up front. @@ -270,7 +270,7 @@ void TCPClientSocketLibevent::DoWriteCallback(int rv) { c->Run(rv); } -void TCPClientSocketLibevent::DidCompleteConnect() { +void TCPClientSocket::DidCompleteConnect() { int result = ERR_UNEXPECTED; TRACE_EVENT_END("socket.connect", this, ""); @@ -295,7 +295,7 @@ void TCPClientSocketLibevent::DidCompleteConnect() { const addrinfo* next = current_ai_->ai_next; Disconnect(); current_ai_ = next; - result = Connect(read_callback_); + result = Connect(callback_); } else { result = MapPosixError(error_code); socket_watcher_.StopWatchingFileDescriptor(); @@ -303,13 +303,13 @@ void TCPClientSocketLibevent::DidCompleteConnect() { } if (result != ERR_IO_PENDING) { - DoReadCallback(result); + DoCallback(result); } } -void TCPClientSocketLibevent::DidCompleteRead() { +void TCPClientSocket::DidCompleteRead() { int bytes_transferred; - bytes_transferred = read(socket_, read_buf_, read_buf_len_); + bytes_transferred = read(socket_, buf_, buf_len_); int result; if (bytes_transferred >= 0) { @@ -321,14 +321,14 @@ void TCPClientSocketLibevent::DidCompleteRead() { } if (result != ERR_IO_PENDING) { - read_buf_ = NULL; - read_buf_len_ = 0; + buf_ = NULL; + buf_len_ = 0; socket_watcher_.StopWatchingFileDescriptor(); - DoReadCallback(result); + DoCallback(result); } } -void TCPClientSocketLibevent::DidCompleteWrite() { +void TCPClientSocket::DidCompleteWrite() { int bytes_transferred; bytes_transferred = write(socket_, write_buf_, write_buf_len_); @@ -349,15 +349,15 @@ void TCPClientSocketLibevent::DidCompleteWrite() { } } -void TCPClientSocketLibevent::OnFileCanReadWithoutBlocking(int fd) { +void TCPClientSocket::OnFileCanReadWithoutBlocking(int fd) { // When a socket connects it signals both Read and Write, we handle // DidCompleteConnect() in the write handler. - if (!waiting_connect_ && read_callback_) { + if (!waiting_connect_ && callback_) { DidCompleteRead(); } } -void TCPClientSocketLibevent::OnFileCanWriteWithoutBlocking(int fd) { +void TCPClientSocket::OnFileCanWriteWithoutBlocking(int fd) { if (waiting_connect_) { DidCompleteConnect(); } else if (write_callback_) { @@ -365,8 +365,7 @@ void TCPClientSocketLibevent::OnFileCanWriteWithoutBlocking(int fd) { } } -int TCPClientSocketLibevent::GetPeerName(struct sockaddr *name, - socklen_t *namelen) { +int TCPClientSocket::GetPeerName(struct sockaddr *name, socklen_t *namelen) { return ::getpeername(socket_, name, namelen); } diff --git a/net/base/tcp_client_socket_libevent.h b/net/base/tcp_client_socket_libevent.h deleted file mode 100644 index c933bfa..0000000 --- a/net/base/tcp_client_socket_libevent.h +++ /dev/null @@ -1,92 +0,0 @@ -// Copyright (c) 2006-2009 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_BASE_TCP_CLIENT_SOCKET_LIBEVENT_H_ -#define NET_BASE_TCP_CLIENT_SOCKET_LIBEVENT_H_ - -#include <sys/socket.h> // for struct sockaddr - -#include "base/message_loop.h" -#include "net/base/address_list.h" -#include "net/base/client_socket.h" -#include "net/base/completion_callback.h" - -struct event; // From libevent - -namespace net { - -// A client socket that uses TCP as the transport layer. -class TCPClientSocketLibevent : public ClientSocket, - public MessageLoopForIO::Watcher { - public: - // The IP address(es) and port number to connect to. The TCP socket will try - // each IP address in the list until it succeeds in establishing a - // connection. - explicit TCPClientSocketLibevent(const AddressList& addresses); - - ~TCPClientSocketLibevent(); - - // ClientSocket methods: - virtual int Connect(CompletionCallback* callback); - virtual void Disconnect(); - virtual bool IsConnected() const; - virtual bool IsConnectedAndIdle() const; - - // Socket methods: - // Multiple outstanding requests are not supported. - // Full duplex mode (reading and writing at the same time) is supported - virtual int Read(char* buf, int buf_len, CompletionCallback* callback); - virtual int Write(const char* buf, int buf_len, CompletionCallback* callback); - - // Identical to posix system call of same name - // Needed by ssl_client_socket_nss - virtual int GetPeerName(struct sockaddr *name, socklen_t *namelen); - - private: - // Called by MessagePumpLibevent when the socket is ready to do I/O - void OnFileCanReadWithoutBlocking(int fd); - void OnFileCanWriteWithoutBlocking(int fd); - - void DoReadCallback(int rv); - void DoWriteCallback(int rv); - void DidCompleteRead(); - void DidCompleteWrite(); - void DidCompleteConnect(); - - int CreateSocket(const struct addrinfo* ai); - - int socket_; - - // The list of addresses we should try in order to establish a connection. - AddressList addresses_; - - // Where we are in above list, or NULL if all addrinfos have been tried. - const struct addrinfo* current_ai_; - - // Whether we're currently waiting for connect() to complete - bool waiting_connect_; - - // The socket's libevent wrapper - MessageLoopForIO::FileDescriptorWatcher socket_watcher_; - - // The buffer used by OnSocketReady to retry Read requests - char* read_buf_; - int read_buf_len_; - - // The buffer used by OnSocketReady to retry Write requests - const char* write_buf_; - int write_buf_len_; - - // External callback; called when read is complete. - CompletionCallback* read_callback_; - - // External callback; called when write is complete. - CompletionCallback* write_callback_; - - DISALLOW_COPY_AND_ASSIGN(TCPClientSocketLibevent); -}; - -} // namespace net - -#endif // NET_BASE_TCP_CLIENT_SOCKET_LIBEVENT_H_ diff --git a/net/base/tcp_client_socket_unittest.cc b/net/base/tcp_client_socket_unittest.cc index 1c40ac6..536528b 100644 --- a/net/base/tcp_client_socket_unittest.cc +++ b/net/base/tcp_client_socket_unittest.cc @@ -35,7 +35,6 @@ class TCPClientSocketTest protected: int listen_port_; - scoped_ptr<net::TCPClientSocket> sock_; private: scoped_refptr<ListenSocket> listen_sock_; @@ -49,32 +48,34 @@ void TCPClientSocketTest::SetUp() { ListenSocket *sock = NULL; int port; // Range of ports to listen on. Shouldn't need to try many. - const int kMinPort = 10100; - const int kMaxPort = 10200; + static const int kMinPort = 10100; + static const int kMaxPort = 10200; #if defined(OS_WIN) net::EnsureWinsockInit(); #endif for (port = kMinPort; port < kMaxPort; port++) { sock = ListenSocket::Listen("127.0.0.1", port, this); if (sock) - break; + break; } ASSERT_TRUE(sock != NULL); listen_sock_ = sock; listen_port_ = port; +} +TEST_F(TCPClientSocketTest, Connect) { net::AddressList addr; net::HostResolver resolver; + TestCompletionCallback callback; + int rv = resolver.Resolve("localhost", listen_port_, &addr, NULL); - CHECK(rv == net::OK); - sock_.reset(new net::TCPClientSocket(addr)); -} + EXPECT_EQ(rv, net::OK); -TEST_F(TCPClientSocketTest, Connect) { - TestCompletionCallback callback; - EXPECT_FALSE(sock_->IsConnected()); + net::TCPClientSocket sock(addr); + + EXPECT_FALSE(sock.IsConnected()); - int rv = sock_->Connect(&callback); + rv = sock.Connect(&callback); if (rv != net::OK) { ASSERT_EQ(rv, net::ERR_IO_PENDING); @@ -82,10 +83,10 @@ TEST_F(TCPClientSocketTest, Connect) { EXPECT_EQ(rv, net::OK); } - EXPECT_TRUE(sock_->IsConnected()); + EXPECT_TRUE(sock.IsConnected()); - sock_->Disconnect(); - EXPECT_FALSE(sock_->IsConnected()); + sock.Disconnect(); + EXPECT_FALSE(sock.IsConnected()); } // TODO(wtc): Add unit tests for IsConnectedAndIdle: @@ -93,8 +94,19 @@ TEST_F(TCPClientSocketTest, Connect) { // - Server sends data unexpectedly. TEST_F(TCPClientSocketTest, Read) { + net::AddressList addr; + net::HostResolver resolver; TestCompletionCallback callback; - int rv = sock_->Connect(&callback); + + int rv = resolver.Resolve("localhost", listen_port_, &addr, &callback); + EXPECT_EQ(rv, net::ERR_IO_PENDING); + + rv = callback.WaitForResult(); + EXPECT_EQ(rv, net::OK); + + net::TCPClientSocket sock(addr); + + rv = sock.Connect(&callback); if (rv != net::OK) { ASSERT_EQ(rv, net::ERR_IO_PENDING); @@ -103,7 +115,7 @@ TEST_F(TCPClientSocketTest, Read) { } const char request_text[] = "GET / HTTP/1.0\r\n\r\n"; - rv = sock_->Write(request_text, arraysize(request_text) - 1, &callback); + rv = sock.Write(request_text, arraysize(request_text) - 1, &callback); EXPECT_TRUE(rv >= 0 || rv == net::ERR_IO_PENDING); if (rv == net::ERR_IO_PENDING) { @@ -113,7 +125,7 @@ TEST_F(TCPClientSocketTest, Read) { char buf[4096]; for (;;) { - rv = sock_->Read(buf, sizeof(buf), &callback); + rv = sock.Read(buf, sizeof(buf), &callback); EXPECT_TRUE(rv >= 0 || rv == net::ERR_IO_PENDING); if (rv == net::ERR_IO_PENDING) @@ -126,8 +138,16 @@ TEST_F(TCPClientSocketTest, Read) { } TEST_F(TCPClientSocketTest, Read_SmallChunks) { + net::AddressList addr; + net::HostResolver resolver; TestCompletionCallback callback; - int rv = sock_->Connect(&callback); + + int rv = resolver.Resolve("localhost", listen_port_, &addr, NULL); + EXPECT_EQ(rv, net::OK); + + net::TCPClientSocket sock(addr); + + rv = sock.Connect(&callback); if (rv != net::OK) { ASSERT_EQ(rv, net::ERR_IO_PENDING); @@ -136,7 +156,7 @@ TEST_F(TCPClientSocketTest, Read_SmallChunks) { } const char request_text[] = "GET / HTTP/1.0\r\n\r\n"; - rv = sock_->Write(request_text, arraysize(request_text) - 1, &callback); + rv = sock.Write(request_text, arraysize(request_text) - 1, &callback); EXPECT_TRUE(rv >= 0 || rv == net::ERR_IO_PENDING); if (rv == net::ERR_IO_PENDING) { @@ -146,7 +166,7 @@ TEST_F(TCPClientSocketTest, Read_SmallChunks) { char buf[1]; for (;;) { - rv = sock_->Read(buf, sizeof(buf), &callback); + rv = sock.Read(buf, sizeof(buf), &callback); EXPECT_TRUE(rv >= 0 || rv == net::ERR_IO_PENDING); if (rv == net::ERR_IO_PENDING) @@ -159,8 +179,16 @@ TEST_F(TCPClientSocketTest, Read_SmallChunks) { } TEST_F(TCPClientSocketTest, Read_Interrupted) { + net::AddressList addr; + net::HostResolver resolver; TestCompletionCallback callback; - int rv = sock_->Connect(&callback); + + int rv = resolver.Resolve("localhost", listen_port_, &addr, NULL); + EXPECT_EQ(rv, net::OK); + + net::TCPClientSocket sock(addr); + + rv = sock.Connect(&callback); if (rv != net::OK) { ASSERT_EQ(rv, net::ERR_IO_PENDING); @@ -169,7 +197,7 @@ TEST_F(TCPClientSocketTest, Read_Interrupted) { } const char request_text[] = "GET / HTTP/1.0\r\n\r\n"; - rv = sock_->Write(request_text, arraysize(request_text) - 1, &callback); + rv = sock.Write(request_text, arraysize(request_text) - 1, &callback); EXPECT_TRUE(rv >= 0 || rv == net::ERR_IO_PENDING); if (rv == net::ERR_IO_PENDING) { @@ -179,7 +207,7 @@ TEST_F(TCPClientSocketTest, Read_Interrupted) { // Do a partial read and then exit. This test should not crash! char buf[512]; - rv = sock_->Read(buf, sizeof(buf), &callback); + rv = sock.Read(buf, sizeof(buf), &callback); EXPECT_TRUE(rv >= 0 || rv == net::ERR_IO_PENDING); if (rv == net::ERR_IO_PENDING) @@ -187,81 +215,3 @@ TEST_F(TCPClientSocketTest, Read_Interrupted) { EXPECT_NE(rv, 0); } - -TEST_F(TCPClientSocketTest, FullDuplex_ReadFirst) { - TestCompletionCallback callback; - int rv = sock_->Connect(&callback); - if (rv != net::OK) { - ASSERT_EQ(rv, net::ERR_IO_PENDING); - - rv = callback.WaitForResult(); - EXPECT_EQ(rv, net::OK); - } - - char buf[4096]; - rv = sock_->Read(buf, sizeof(buf), &callback); - EXPECT_EQ(net::ERR_IO_PENDING, rv); - - const char request_text[] = "GET / HTTP/1.0\r\n\r\n"; - TestCompletionCallback write_callback; - rv = sock_->Write(request_text, arraysize(request_text) - 1, &write_callback); - EXPECT_TRUE(rv >= 0 || rv == net::ERR_IO_PENDING); - - if (rv == net::ERR_IO_PENDING) { - rv = write_callback.WaitForResult(); - EXPECT_EQ(rv, static_cast<int>(arraysize(request_text) - 1)); - } - - rv = callback.WaitForResult(); - EXPECT_GE(rv, 0); - while (rv > 0) { - rv = sock_->Read(buf, sizeof(buf), &callback); - EXPECT_TRUE(rv >= 0 || rv == net::ERR_IO_PENDING); - - if (rv == net::ERR_IO_PENDING) - rv = callback.WaitForResult(); - - EXPECT_GE(rv, 0); - if (rv <= 0) - break; - } -} - -TEST_F(TCPClientSocketTest, FullDuplex_WriteFirst) { - TestCompletionCallback callback; - int rv = sock_->Connect(&callback); - if (rv != net::OK) { - ASSERT_EQ(rv, net::ERR_IO_PENDING); - - rv = callback.WaitForResult(); - EXPECT_EQ(rv, net::OK); - } - - const char request_text[] = "GET / HTTP/1.0\r\n\r\n"; - TestCompletionCallback write_callback; - rv = sock_->Write(request_text, arraysize(request_text) - 1, &write_callback); - EXPECT_TRUE(rv >= 0 || rv == net::ERR_IO_PENDING); - - char buf[4096]; - int read_rv = sock_->Read(buf, sizeof(buf), &callback); - EXPECT_TRUE(read_rv >= 0 || read_rv == net::ERR_IO_PENDING); - - if (rv == net::ERR_IO_PENDING) { - rv = write_callback.WaitForResult(); - EXPECT_EQ(static_cast<int>(arraysize(request_text) - 1), rv); - } - - rv = callback.WaitForResult(); - EXPECT_GE(rv, 0); - while (rv > 0) { - rv = sock_->Read(buf, sizeof(buf), &callback); - EXPECT_TRUE(rv >= 0 || rv == net::ERR_IO_PENDING); - - if (rv == net::ERR_IO_PENDING) - rv = callback.WaitForResult(); - - EXPECT_GE(rv, 0); - if (rv <= 0) - break; - } -} diff --git a/net/base/tcp_client_socket_win.cc b/net/base/tcp_client_socket_win.cc index 50e99a3..9d69505 100644 --- a/net/base/tcp_client_socket_win.cc +++ b/net/base/tcp_client_socket_win.cc @@ -2,10 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "net/base/tcp_client_socket_win.h" +#include "net/base/tcp_client_socket.h" -#include "base/basictypes.h" -#include "base/compiler_specific.h" #include "base/memory_debug.h" #include "base/string_util.h" #include "base/sys_info.h" @@ -15,25 +13,9 @@ namespace net { -namespace { - -// Waits for the (manual-reset) event object to become signaled and resets -// it. Called after a Winsock function succeeds synchronously -// -// Our testing shows that except in rare cases (when running inside QEMU), -// the event object is already signaled at this point, so we just call this -// method on the IO thread to avoid a context switch. -void WaitForAndResetEvent(WSAEVENT hEvent) { - // TODO(wtc): Remove the CHECKs after enough testing. - DWORD wait_rv = WaitForSingleObject(hEvent, INFINITE); - CHECK(wait_rv == WAIT_OBJECT_0); - BOOL ok = WSAResetEvent(hEvent); - CHECK(ok); -} - //----------------------------------------------------------------------------- -int MapWinsockError(DWORD err) { +static int MapWinsockError(DWORD err) { // There are numerous Winsock error codes, but these are the ones we thus far // find interesting. switch (err) { @@ -70,31 +52,23 @@ int MapWinsockError(DWORD err) { } } -} // namespace - //----------------------------------------------------------------------------- -TCPClientSocketWin::TCPClientSocketWin(const AddressList& addresses) +TCPClientSocket::TCPClientSocket(const AddressList& addresses) : socket_(INVALID_SOCKET), addresses_(addresses), current_ai_(addresses_.head()), - waiting_connect_(false), - waiting_read_(false), - waiting_write_(false), - ALLOW_THIS_IN_INITIALIZER_LIST(reader_(this)), - ALLOW_THIS_IN_INITIALIZER_LIST(writer_(this)), - read_callback_(NULL), - write_callback_(NULL) { - memset(&read_overlapped_, 0, sizeof(read_overlapped_)); - memset(&write_overlapped_, 0, sizeof(write_overlapped_)); + wait_state_(NOT_WAITING), + callback_(NULL) { + memset(&overlapped_, 0, sizeof(overlapped_)); EnsureWinsockInit(); } -TCPClientSocketWin::~TCPClientSocketWin() { +TCPClientSocket::~TCPClientSocket() { Disconnect(); } -int TCPClientSocketWin::Connect(CompletionCallback* callback) { +int TCPClientSocket::Connect(CompletionCallback* callback) { // If already connected, then just return OK. if (socket_ != INVALID_SOCKET) return OK; @@ -108,16 +82,14 @@ int TCPClientSocketWin::Connect(CompletionCallback* callback) { return rv; // WSACreateEvent creates a manual-reset event object. - read_overlapped_.hEvent = WSACreateEvent(); + overlapped_.hEvent = WSACreateEvent(); // WSAEventSelect sets the socket to non-blocking mode as a side effect. // Our connect() and recv() calls require that the socket be non-blocking. - WSAEventSelect(socket_, read_overlapped_.hEvent, FD_CONNECT); - - write_overlapped_.hEvent = WSACreateEvent(); + WSAEventSelect(socket_, overlapped_.hEvent, FD_CONNECT); if (!connect(socket_, ai->ai_addr, static_cast<int>(ai->ai_addrlen))) { // Connected without waiting! - WaitForAndResetEvent(read_overlapped_.hEvent); + WaitForAndResetEvent(); TRACE_EVENT_END("socket.connect", this, ""); return OK; } @@ -128,29 +100,26 @@ int TCPClientSocketWin::Connect(CompletionCallback* callback) { return MapWinsockError(err); } - read_watcher_.StartWatching(read_overlapped_.hEvent, &reader_); - waiting_connect_ = true; - read_callback_ = callback; + watcher_.StartWatching(overlapped_.hEvent, this); + wait_state_ = WAITING_CONNECT; + callback_ = callback; return ERR_IO_PENDING; } -void TCPClientSocketWin::Disconnect() { +void TCPClientSocket::Disconnect() { if (socket_ == INVALID_SOCKET) return; TRACE_EVENT_INSTANT("socket.disconnect", this, ""); // Make sure the message loop is not watching this object anymore. - read_watcher_.StopWatching(); - write_watcher_.StopWatching(); + watcher_.StopWatching(); // Cancel any pending IO and wait for it to be aborted. - if (waiting_read_ || waiting_write_) { + if (wait_state_ == WAITING_READ || wait_state_ == WAITING_WRITE) { CancelIo(reinterpret_cast<HANDLE>(socket_)); - if (waiting_read_) - WaitForSingleObject(read_overlapped_.hEvent, INFINITE); - if (waiting_write_) - WaitForSingleObject(write_overlapped_.hEvent, INFINITE); + WaitForSingleObject(overlapped_.hEvent, INFINITE); + wait_state_ = NOT_WAITING; } // In most socket implementations, closing a socket results in a graceful @@ -162,21 +131,15 @@ void TCPClientSocketWin::Disconnect() { closesocket(socket_); socket_ = INVALID_SOCKET; - WSACloseEvent(read_overlapped_.hEvent); - memset(&read_overlapped_, 0, sizeof(read_overlapped_)); - WSACloseEvent(write_overlapped_.hEvent); - memset(&write_overlapped_, 0, sizeof(write_overlapped_)); + WSACloseEvent(overlapped_.hEvent); + memset(&overlapped_, 0, sizeof(overlapped_)); // Reset for next time. current_ai_ = addresses_.head(); - - waiting_read_ = false; - waiting_write_ = false; - waiting_connect_ = false; } -bool TCPClientSocketWin::IsConnected() const { - if (socket_ == INVALID_SOCKET || waiting_connect_) +bool TCPClientSocket::IsConnected() const { + if (socket_ == INVALID_SOCKET || wait_state_ == WAITING_CONNECT) return false; // Check if connection is alive. @@ -190,8 +153,8 @@ bool TCPClientSocketWin::IsConnected() const { return true; } -bool TCPClientSocketWin::IsConnectedAndIdle() const { - if (socket_ == INVALID_SOCKET || waiting_connect_) +bool TCPClientSocket::IsConnectedAndIdle() const { + if (socket_ == INVALID_SOCKET || wait_state_ == WAITING_CONNECT) return false; // Check if connection is alive and we haven't received any data @@ -206,24 +169,23 @@ bool TCPClientSocketWin::IsConnectedAndIdle() const { return true; } -int TCPClientSocketWin::Read(char* buf, - int buf_len, - CompletionCallback* callback) { - DCHECK_NE(socket_, INVALID_SOCKET); - DCHECK(!waiting_read_); - DCHECK(!read_callback_); +int TCPClientSocket::Read(char* buf, + int buf_len, + CompletionCallback* callback) { + DCHECK(socket_ != INVALID_SOCKET); + DCHECK(wait_state_ == NOT_WAITING); + DCHECK(!callback_); - read_buffer_.len = buf_len; - read_buffer_.buf = buf; + buffer_.len = buf_len; + buffer_.buf = buf; TRACE_EVENT_BEGIN("socket.read", this, ""); // TODO(wtc): Remove the CHECK after enough testing. - CHECK(WaitForSingleObject(read_overlapped_.hEvent, 0) == WAIT_TIMEOUT); + CHECK(WaitForSingleObject(overlapped_.hEvent, 0) == WAIT_TIMEOUT); DWORD num, flags = 0; - int rv = WSARecv( - socket_, &read_buffer_, 1, &num, &flags, &read_overlapped_, NULL); + int rv = WSARecv(socket_, &buffer_, 1, &num, &flags, &overlapped_, NULL); if (rv == 0) { - WaitForAndResetEvent(read_overlapped_.hEvent); + WaitForAndResetEvent(); TRACE_EVENT_END("socket.read", this, StringPrintf("%d bytes", num)); // Because of how WSARecv fills memory when used asynchronously, Purify @@ -232,52 +194,51 @@ int TCPClientSocketWin::Read(char* buf, // individual bytes. We override that in PURIFY builds to avoid the false // error reports. // See bug 5297. - base::MemoryDebug::MarkAsInitialized(read_buffer_.buf, num); + base::MemoryDebug::MarkAsInitialized(buffer_.buf, num); return static_cast<int>(num); } int err = WSAGetLastError(); if (err == WSA_IO_PENDING) { - read_watcher_.StartWatching(read_overlapped_.hEvent, &reader_); - waiting_read_ = true; - read_callback_ = callback; + watcher_.StartWatching(overlapped_.hEvent, this); + wait_state_ = WAITING_READ; + callback_ = callback; return ERR_IO_PENDING; } return MapWinsockError(err); } -int TCPClientSocketWin::Write(const char* buf, - int buf_len, - CompletionCallback* callback) { - DCHECK_NE(socket_, INVALID_SOCKET); - DCHECK(!waiting_write_); - DCHECK(!write_callback_); - DCHECK_GT(buf_len, 0); +int TCPClientSocket::Write(const char* buf, + int buf_len, + CompletionCallback* callback) { + DCHECK(socket_ != INVALID_SOCKET); + DCHECK(wait_state_ == NOT_WAITING); + DCHECK(!callback_); + DCHECK(buf_len > 0); - write_buffer_.len = buf_len; - write_buffer_.buf = const_cast<char*>(buf); + buffer_.len = buf_len; + buffer_.buf = const_cast<char*>(buf); TRACE_EVENT_BEGIN("socket.write", this, ""); // TODO(wtc): Remove the CHECK after enough testing. - CHECK(WaitForSingleObject(write_overlapped_.hEvent, 0) == WAIT_TIMEOUT); + CHECK(WaitForSingleObject(overlapped_.hEvent, 0) == WAIT_TIMEOUT); DWORD num; - int rv = - WSASend(socket_, &write_buffer_, 1, &num, 0, &write_overlapped_, NULL); + int rv = WSASend(socket_, &buffer_, 1, &num, 0, &overlapped_, NULL); if (rv == 0) { - WaitForAndResetEvent(write_overlapped_.hEvent); + WaitForAndResetEvent(); TRACE_EVENT_END("socket.write", this, StringPrintf("%d bytes", num)); return static_cast<int>(num); } int err = WSAGetLastError(); if (err == WSA_IO_PENDING) { - read_watcher_.StartWatching(read_overlapped_.hEvent, &writer_); - waiting_write_ = true; - read_callback_ = callback; + watcher_.StartWatching(overlapped_.hEvent, this); + wait_state_ = WAITING_WRITE; + callback_ = callback; return ERR_IO_PENDING; } return MapWinsockError(err); } -int TCPClientSocketWin::CreateSocket(const struct addrinfo* ai) { +int TCPClientSocket::CreateSocket(const struct addrinfo* ai) { socket_ = WSASocket(ai->ai_family, ai->ai_socktype, ai->ai_protocol, NULL, 0, WSA_FLAG_OVERLAPPED); if (socket_ == INVALID_SOCKET) { @@ -341,38 +302,29 @@ int TCPClientSocketWin::CreateSocket(const struct addrinfo* ai) { return OK; } -void TCPClientSocketWin::DoReadCallback(int rv) { - DCHECK_NE(rv, ERR_IO_PENDING); - DCHECK(read_callback_); - - // since Run may result in Read being called, clear read_callback_ up front. - CompletionCallback* c = read_callback_; - read_callback_ = NULL; - c->Run(rv); -} - -void TCPClientSocketWin::DoWriteCallback(int rv) { - DCHECK_NE(rv, ERR_IO_PENDING); - DCHECK(write_callback_); +void TCPClientSocket::DoCallback(int rv) { + DCHECK(rv != ERR_IO_PENDING); + DCHECK(callback_); - // since Run may result in Read being called, clear read_callback_ up front. - CompletionCallback* c = write_callback_; - write_callback_ = NULL; + // since Run may result in Read being called, clear callback_ up front. + CompletionCallback* c = callback_; + callback_ = NULL; c->Run(rv); } -void TCPClientSocketWin::DidCompleteConnect() { +void TCPClientSocket::DidCompleteConnect() { int result; TRACE_EVENT_END("socket.connect", this, ""); - waiting_connect_ = false; + wait_state_ = NOT_WAITING; WSANETWORKEVENTS events; - int rv = WSAEnumNetworkEvents(socket_, read_overlapped_.hEvent, &events); + int rv = WSAEnumNetworkEvents(socket_, overlapped_.hEvent, &events); if (rv == SOCKET_ERROR) { NOTREACHED(); result = MapWinsockError(WSAGetLastError()); } else if (events.lNetworkEvents & FD_CONNECT) { + wait_state_ = NOT_WAITING; DWORD error_code = static_cast<DWORD>(events.iErrorCode[FD_CONNECT_BIT]); if (current_ai_->ai_next && ( error_code == WSAEADDRNOTAVAIL || @@ -385,7 +337,7 @@ void TCPClientSocketWin::DidCompleteConnect() { const struct addrinfo* next = current_ai_->ai_next; Disconnect(); current_ai_ = next; - result = Connect(read_callback_); + result = Connect(callback_); } else { result = MapWinsockError(error_code); } @@ -395,41 +347,46 @@ void TCPClientSocketWin::DidCompleteConnect() { } if (result != ERR_IO_PENDING) - DoReadCallback(result); + DoCallback(result); } -void TCPClientSocketWin::ReadDelegate::OnObjectSignaled(HANDLE object) { - DCHECK_EQ(object, tcp_socket_->read_overlapped_.hEvent); - - if (tcp_socket_->waiting_connect_) { - tcp_socket_->DidCompleteConnect(); +void TCPClientSocket::DidCompleteIO() { + DWORD num_bytes, flags; + BOOL ok = WSAGetOverlappedResult( + socket_, &overlapped_, &num_bytes, FALSE, &flags); + WSAResetEvent(overlapped_.hEvent); + if (wait_state_ == WAITING_READ) { + TRACE_EVENT_END("socket.read", this, StringPrintf("%d bytes", num_bytes)); } else { - DWORD num_bytes, flags; - BOOL ok = WSAGetOverlappedResult( - tcp_socket_->socket_, &tcp_socket_->read_overlapped_, &num_bytes, - FALSE, &flags); - WSAResetEvent(object); - TRACE_EVENT_END("socket.read", tcp_socket_, - StringPrintf("%d bytes", num_bytes)); - tcp_socket_->waiting_read_ = false; - tcp_socket_->DoReadCallback( - ok ? num_bytes : MapWinsockError(WSAGetLastError())); + TRACE_EVENT_END("socket.write", this, StringPrintf("%d bytes", num_bytes)); } + wait_state_ = NOT_WAITING; + DoCallback(ok ? num_bytes : MapWinsockError(WSAGetLastError())); } -void TCPClientSocketWin::WriteDelegate::OnObjectSignaled(HANDLE object) { - DCHECK_EQ(object, tcp_socket_->write_overlapped_.hEvent); +void TCPClientSocket::OnObjectSignaled(HANDLE object) { + DCHECK(object == overlapped_.hEvent); + + switch (wait_state_) { + case WAITING_CONNECT: + DidCompleteConnect(); + break; + case WAITING_READ: + case WAITING_WRITE: + DidCompleteIO(); + break; + default: + NOTREACHED(); + break; + } +} - DWORD num_bytes, flags; - BOOL ok = WSAGetOverlappedResult( - tcp_socket_->socket_, &tcp_socket_->write_overlapped_, &num_bytes, - FALSE, &flags); - WSAResetEvent(object); - TRACE_EVENT_END("socket.write", tcp_socket_, - StringPrintf("%d bytes", num_bytes)); - tcp_socket_->waiting_write_ = false; - tcp_socket_->DoWriteCallback( - ok ? num_bytes : MapWinsockError(WSAGetLastError())); +void TCPClientSocket::WaitForAndResetEvent() { + // TODO(wtc): Remove the CHECKs after enough testing. + DWORD wait_rv = WaitForSingleObject(overlapped_.hEvent, INFINITE); + CHECK(wait_rv == WAIT_OBJECT_0); + BOOL ok = WSAResetEvent(overlapped_.hEvent); + CHECK(ok); } } // namespace net diff --git a/net/base/tcp_client_socket_win.h b/net/base/tcp_client_socket_win.h deleted file mode 100644 index 63f2b93..0000000 --- a/net/base/tcp_client_socket_win.h +++ /dev/null @@ -1,114 +0,0 @@ -// Copyright (c) 2006-2009 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_BASE_TCP_CLIENT_SOCKET_WIN_H_ -#define NET_BASE_TCP_CLIENT_SOCKET_WIN_H_ - -#include <ws2tcpip.h> - -#include "base/object_watcher.h" -#include "net/base/address_list.h" -#include "net/base/client_socket.h" -#include "net/base/completion_callback.h" - -namespace net { - -class TCPClientSocketWin : public ClientSocket { - public: - // The IP address(es) and port number to connect to. The TCP socket will try - // each IP address in the list until it succeeds in establishing a - // connection. - explicit TCPClientSocketWin(const AddressList& addresses); - - ~TCPClientSocketWin(); - - // ClientSocket methods: - virtual int Connect(CompletionCallback* callback); - virtual void Disconnect(); - virtual bool IsConnected() const; - virtual bool IsConnectedAndIdle() const; - - // Socket methods: - // Multiple outstanding requests are not supported. - // Full duplex mode (reading and writing at the same time) is supported - virtual int Read(char* buf, int buf_len, CompletionCallback* callback); - virtual int Write(const char* buf, int buf_len, CompletionCallback* callback); - - private: - class ReadDelegate : public base::ObjectWatcher::Delegate { - public: - explicit ReadDelegate(TCPClientSocketWin* tcp_socket) - : tcp_socket_(tcp_socket) { } - virtual ~ReadDelegate() { } - - // base::ObjectWatcher::Delegate methods: - virtual void OnObjectSignaled(HANDLE object); - - private: - TCPClientSocketWin* const tcp_socket_; - }; - - class WriteDelegate : public base::ObjectWatcher::Delegate { - public: - explicit WriteDelegate(TCPClientSocketWin* tcp_socket) - : tcp_socket_(tcp_socket) { } - virtual ~WriteDelegate() { } - - // base::ObjectWatcher::Delegate methods: - virtual void OnObjectSignaled(HANDLE object); - - private: - TCPClientSocketWin* const tcp_socket_; - }; - - int CreateSocket(const struct addrinfo* ai); - void DoReadCallback(int rv); - void DoWriteCallback(int rv); - void DidCompleteConnect(); - - SOCKET socket_; - - // The list of addresses we should try in order to establish a connection. - AddressList addresses_; - - // Where we are in above list, or NULL if all addrinfos have been tried. - const struct addrinfo* current_ai_; - - // The various states that the socket could be in. - bool waiting_connect_; - bool waiting_read_; - bool waiting_write_; - - // The separate OVERLAPPED variables for asynchronous operation. - // |read_overlapped_| is used for both Connect() and Read(). - // |write_overlapped_| is only used for Write(); - OVERLAPPED read_overlapped_; - OVERLAPPED write_overlapped_; - - // The buffers used in Read() and Write(). - WSABUF read_buffer_; - WSABUF write_buffer_; - - // |reader_| handles the signals from |read_watcher_|. - ReadDelegate reader_; - // |writer_| handles the signals from |write_watcher_|. - WriteDelegate writer_; - - // |read_watcher_| watches for events from Connect() and Read(). - base::ObjectWatcher read_watcher_; - // |write_watcher_| watches for events from Write(); - base::ObjectWatcher write_watcher_; - - // External callback; called when connect or read is complete. - CompletionCallback* read_callback_; - - // External callback; called when write is complete. - CompletionCallback* write_callback_; - - DISALLOW_COPY_AND_ASSIGN(TCPClientSocketWin); -}; - -} // namespace net - -#endif // NET_BASE_TCP_CLIENT_SOCKET_WIN_H_ diff --git a/net/net.gyp b/net/net.gyp index fa6c804..f1a4805 100644 --- a/net/net.gyp +++ b/net/net.gyp @@ -121,9 +121,7 @@ 'base/ssl_test_util.cc', 'base/tcp_client_socket.h', 'base/tcp_client_socket_libevent.cc', - 'base/tcp_client_socket_libevent.h', 'base/tcp_client_socket_win.cc', - 'base/tcp_client_socket_win.h', 'base/telnet_server.cc', 'base/telnet_server.h', 'base/upload_data.cc', |