diff options
Diffstat (limited to 'net/socket')
25 files changed, 491 insertions, 196 deletions
diff --git a/net/socket/client_socket.h b/net/socket/client_socket.h index 6594f33..ce0cf2a 100644 --- a/net/socket/client_socket.h +++ b/net/socket/client_socket.h @@ -15,6 +15,8 @@ namespace net { +class LoadLog; + class ClientSocket : public Socket { public: // Called to establish a connection. Returns OK if the connection could be @@ -31,7 +33,7 @@ class ClientSocket : public Socket { // // Connect may also be called again after a call to the Disconnect method. // - virtual int Connect(CompletionCallback* callback) = 0; + virtual int Connect(CompletionCallback* callback, LoadLog* load_log) = 0; // Called to disconnect a socket. Does nothing if the socket is already // disconnected. After calling Disconnect it is possible to call Connect diff --git a/net/socket/client_socket_pool_base_unittest.cc b/net/socket/client_socket_pool_base_unittest.cc index be502af..5f0695a 100644 --- a/net/socket/client_socket_pool_base_unittest.cc +++ b/net/socket/client_socket_pool_base_unittest.cc @@ -47,7 +47,7 @@ class MockClientSocket : public ClientSocket { // ClientSocket methods: - virtual int Connect(CompletionCallback* callback) { + virtual int Connect(CompletionCallback* callback, LoadLog* load_log) { connected_ = true; return OK; } @@ -197,7 +197,7 @@ class TestConnectJob : public ConnectJob { int result = ERR_CONNECTION_FAILED; if (succeed) { result = OK; - socket()->Connect(NULL); + socket()->Connect(NULL, NULL); } else { set_socket(NULL); } diff --git a/net/socket/socket_test_util.cc b/net/socket/socket_test_util.cc index 60ef70c..5433a65 100644 --- a/net/socket/socket_test_util.cc +++ b/net/socket/socket_test_util.cc @@ -72,7 +72,8 @@ MockTCPClientSocket::MockTCPClientSocket(const net::AddressList& addresses, data_->Reset(); } -int MockTCPClientSocket::Connect(net::CompletionCallback* callback) { +int MockTCPClientSocket::Connect(net::CompletionCallback* callback, + LoadLog* load_log) { if (connected_) return net::OK; connected_ = true; @@ -176,10 +177,11 @@ void MockSSLClientSocket::GetSSLInfo(net::SSLInfo* ssl_info) { ssl_info->Reset(); } -int MockSSLClientSocket::Connect(net::CompletionCallback* callback) { +int MockSSLClientSocket::Connect(net::CompletionCallback* callback, + LoadLog* load_log) { ConnectCallback* connect_callback = new ConnectCallback( this, callback, data_->connect.result); - int rv = transport_->Connect(connect_callback); + int rv = transport_->Connect(connect_callback, load_log); if (rv == net::OK) { delete connect_callback; if (data_->connect.async) { diff --git a/net/socket/socket_test_util.h b/net/socket/socket_test_util.h index 23cadec..cfbdda8 100644 --- a/net/socket/socket_test_util.h +++ b/net/socket/socket_test_util.h @@ -26,6 +26,7 @@ namespace net { class ClientSocket; +class LoadLog; class SSLClientSocket; struct MockConnect { @@ -232,7 +233,7 @@ class MockClientSocket : public net::SSLClientSocket { MockClientSocket(); // ClientSocket methods: - virtual int Connect(net::CompletionCallback* callback) = 0; + virtual int Connect(net::CompletionCallback* callback, LoadLog* load_log) = 0; // SSLClientSocket methods: virtual void GetSSLInfo(net::SSLInfo* ssl_info); @@ -268,7 +269,8 @@ class MockTCPClientSocket : public MockClientSocket { net::MockSocket* socket); // ClientSocket methods: - virtual int Connect(net::CompletionCallback* callback); + virtual int Connect(net::CompletionCallback* callback, + LoadLog* load_log); // Socket methods: virtual int Read(net::IOBuffer* buf, int buf_len, @@ -298,7 +300,7 @@ class MockSSLClientSocket : public MockClientSocket { virtual void GetSSLInfo(net::SSLInfo* ssl_info); - virtual int Connect(net::CompletionCallback* callback); + virtual int Connect(net::CompletionCallback* callback, LoadLog* load_log); virtual void Disconnect(); // Socket methods: diff --git a/net/socket/socks5_client_socket.cc b/net/socket/socks5_client_socket.cc index cc12a3c..ef3e9d0 100644 --- a/net/socket/socks5_client_socket.cc +++ b/net/socket/socks5_client_socket.cc @@ -14,6 +14,7 @@ #include "base/compiler_specific.h" #include "base/trace_event.h" #include "net/base/io_buffer.h" +#include "net/base/load_log.h" #include "net/base/net_util.h" namespace net { @@ -49,7 +50,8 @@ SOCKS5ClientSocket::~SOCKS5ClientSocket() { Disconnect(); } -int SOCKS5ClientSocket::Connect(CompletionCallback* callback) { +int SOCKS5ClientSocket::Connect(CompletionCallback* callback, + LoadLog* load_log) { DCHECK(transport_.get()); DCHECK(transport_->IsConnected()); DCHECK_EQ(STATE_NONE, next_state_); @@ -60,10 +62,17 @@ int SOCKS5ClientSocket::Connect(CompletionCallback* callback) { return OK; next_state_ = STATE_RESOLVE_HOST; + load_log_ = load_log; + + LoadLog::BeginEvent(load_log, LoadLog::TYPE_SOCKS5_CONNECT); int rv = DoLoop(OK); - if (rv == ERR_IO_PENDING) + if (rv == ERR_IO_PENDING) { user_callback_ = callback; + } else { + LoadLog::EndEvent(load_log, LoadLog::TYPE_SOCKS5_CONNECT); + load_log_ = NULL; + } return rv; } @@ -125,8 +134,11 @@ void SOCKS5ClientSocket::DoCallback(int result) { void SOCKS5ClientSocket::OnIOComplete(int result) { DCHECK_NE(STATE_NONE, next_state_); int rv = DoLoop(result); - if (rv != ERR_IO_PENDING) + if (rv != ERR_IO_PENDING) { + LoadLog::EndEvent(load_log_, LoadLog::TYPE_SOCKS5_CONNECT); + load_log_ = NULL; DoCallback(rv); + } } int SOCKS5ClientSocket::DoLoop(int last_io_result) { @@ -185,7 +197,7 @@ int SOCKS5ClientSocket::DoResolveHost() { next_state_ = STATE_RESOLVE_HOST_COMPLETE; return host_resolver_.Resolve( - host_request_info_, &addresses_, &io_callback_, NULL); + host_request_info_, &addresses_, &io_callback_, load_log_); } int SOCKS5ClientSocket::DoResolveHostComplete(int result) { diff --git a/net/socket/socks5_client_socket.h b/net/socket/socks5_client_socket.h index 395d3e9..a5db645 100644 --- a/net/socket/socks5_client_socket.h +++ b/net/socket/socks5_client_socket.h @@ -20,6 +20,8 @@ namespace net { +class LoadLog; + // This ClientSocket is used to setup a SOCKSv5 handshake with a socks proxy. // Currently no SOCKSv5 authentication is supported. class SOCKS5ClientSocket : public ClientSocket { @@ -39,7 +41,7 @@ class SOCKS5ClientSocket : public ClientSocket { // ClientSocket methods: // Does the SOCKS handshake and completes the protocol. - virtual int Connect(CompletionCallback* callback); + virtual int Connect(CompletionCallback* callback, LoadLog* load_log); virtual void Disconnect(); virtual bool IsConnected() const; virtual bool IsConnectedAndIdle() const; @@ -145,10 +147,11 @@ class SOCKS5ClientSocket : public ClientSocket { AddressList addresses_; HostResolver::RequestInfo host_request_info_; + scoped_refptr<LoadLog> load_log_; + DISALLOW_COPY_AND_ASSIGN(SOCKS5ClientSocket); }; } // namespace net #endif // NET_SOCKET_SOCKS5_CLIENT_SOCKET_H_ - diff --git a/net/socket/socks5_client_socket_unittest.cc b/net/socket/socks5_client_socket_unittest.cc index 9dedc39..1b079e7 100644 --- a/net/socket/socks5_client_socket_unittest.cc +++ b/net/socket/socks5_client_socket_unittest.cc @@ -12,6 +12,8 @@ #include <netdb.h> #endif #include "net/base/address_list.h" +#include "net/base/load_log.h" +#include "net/base/load_log_unittest.h" #include "net/base/mock_host_resolver.h" #include "net/base/test_completion_callback.h" #include "net/base/winsock_init.h" @@ -73,7 +75,7 @@ SOCKS5ClientSocket* SOCKS5ClientSocketTest::BuildMockSocket( mock_socket_.reset(new StaticMockSocket(reads, writes)); tcp_sock_ = new MockTCPClientSocket(address_list_, mock_socket_.get()); - int rv = tcp_sock_->Connect(&callback); + int rv = tcp_sock_->Connect(&callback, NULL); EXPECT_EQ(ERR_IO_PENDING, rv); rv = callback.WaitForResult(); EXPECT_EQ(OK, rv); @@ -112,15 +114,21 @@ TEST_F(SOCKS5ClientSocketTest, CompleteHandshake) { EXPECT_TRUE(tcp_sock_->IsConnected()); EXPECT_FALSE(user_sock_->IsConnected()); - int rv = user_sock_->Connect(&callback_); + scoped_refptr<LoadLog> log(new LoadLog); + int rv = user_sock_->Connect(&callback_, log); EXPECT_EQ(ERR_IO_PENDING, rv); EXPECT_FALSE(user_sock_->IsConnected()); + EXPECT_TRUE( + LogContains(*log, 0, LoadLog::TYPE_SOCKS5_CONNECT, LoadLog::PHASE_BEGIN)); + rv = callback_.WaitForResult(); EXPECT_EQ(OK, rv); EXPECT_TRUE(user_sock_->IsConnected()); EXPECT_EQ(SOCKS5ClientSocket::kEndPointResolvedIPv4, user_sock_->address_type_); + EXPECT_TRUE(LogContains( + *log, -1, LoadLog::TYPE_SOCKS5_CONNECT, LoadLog::PHASE_END)); scoped_refptr<IOBuffer> buffer = new IOBuffer(payload_write.size()); memcpy(buffer->data(), payload_write.data(), payload_write.size()); @@ -163,13 +171,18 @@ TEST_F(SOCKS5ClientSocketTest, FailedDNS) { user_sock_.reset(BuildMockSocket(data_reads, data_writes, hostname, 80)); - int rv = user_sock_->Connect(&callback_); + scoped_refptr<LoadLog> log(new LoadLog); + int rv = user_sock_->Connect(&callback_, log); EXPECT_EQ(ERR_IO_PENDING, rv); + EXPECT_TRUE(LogContains( + *log, 0, LoadLog::TYPE_SOCKS5_CONNECT, LoadLog::PHASE_BEGIN)); rv = callback_.WaitForResult(); EXPECT_EQ(OK, rv); EXPECT_TRUE(user_sock_->IsConnected()); EXPECT_EQ(SOCKS5ClientSocket::kEndPointFailedDomain, user_sock_->address_type_); + EXPECT_TRUE(LogContains( + *log, -1, LoadLog::TYPE_SOCKS5_CONNECT, LoadLog::PHASE_END)); } // Tries to connect to a domain that resolves to IPv6. @@ -195,13 +208,18 @@ TEST_F(SOCKS5ClientSocketTest, IPv6Domain) { user_sock_.reset(BuildMockSocket(data_reads, data_writes, hostname, 80)); - int rv = user_sock_->Connect(&callback_); + scoped_refptr<LoadLog> log(new LoadLog); + int rv = user_sock_->Connect(&callback_, log); EXPECT_EQ(ERR_IO_PENDING, rv); + EXPECT_TRUE(LogContains( + *log, 0, LoadLog::TYPE_SOCKS5_CONNECT, LoadLog::PHASE_BEGIN)); rv = callback_.WaitForResult(); EXPECT_EQ(OK, rv); EXPECT_TRUE(user_sock_->IsConnected()); EXPECT_EQ(SOCKS5ClientSocket::kEndPointResolvedIPv6, user_sock_->address_type_); + EXPECT_TRUE(LogContains( + *log, -1, LoadLog::TYPE_SOCKS5_CONNECT, LoadLog::PHASE_END)); } TEST_F(SOCKS5ClientSocketTest, PartialReadWrites) { @@ -219,11 +237,16 @@ TEST_F(SOCKS5ClientSocketTest, PartialReadWrites) { MockRead(true, kSOCKS5GreetResponse, arraysize(kSOCKS5GreetResponse)), MockRead(true, kSOCKS5OkResponse, arraysize(kSOCKS5OkResponse)) }; user_sock_.reset(BuildMockSocket(data_reads, data_writes, hostname, 80)); - int rv = user_sock_->Connect(&callback_); + scoped_refptr<LoadLog> log(new LoadLog); + int rv = user_sock_->Connect(&callback_, log); EXPECT_EQ(ERR_IO_PENDING, rv); + EXPECT_TRUE(LogContains( + *log, 0, LoadLog::TYPE_SOCKS5_CONNECT, LoadLog::PHASE_BEGIN)); rv = callback_.WaitForResult(); EXPECT_EQ(OK, rv); EXPECT_TRUE(user_sock_->IsConnected()); + EXPECT_TRUE(LogContains( + *log, -1, LoadLog::TYPE_SOCKS5_CONNECT, LoadLog::PHASE_END)); } // Test for partial greet response read @@ -238,11 +261,16 @@ TEST_F(SOCKS5ClientSocketTest, PartialReadWrites) { MockRead(true, partial2, arraysize(partial2)), MockRead(true, kSOCKS5OkResponse, arraysize(kSOCKS5OkResponse)) }; user_sock_.reset(BuildMockSocket(data_reads, data_writes, hostname, 80)); - int rv = user_sock_->Connect(&callback_); + scoped_refptr<LoadLog> log(new LoadLog); + int rv = user_sock_->Connect(&callback_, log); EXPECT_EQ(ERR_IO_PENDING, rv); + EXPECT_TRUE(LogContains( + *log, 0, LoadLog::TYPE_SOCKS5_CONNECT, LoadLog::PHASE_BEGIN)); rv = callback_.WaitForResult(); EXPECT_EQ(OK, rv); EXPECT_TRUE(user_sock_->IsConnected()); + EXPECT_TRUE(LogContains( + *log, -1, LoadLog::TYPE_SOCKS5_CONNECT, LoadLog::PHASE_END)); } // Test for partial handshake request write @@ -257,11 +285,16 @@ TEST_F(SOCKS5ClientSocketTest, PartialReadWrites) { MockRead(true, kSOCKS5GreetResponse, arraysize(kSOCKS5GreetResponse)), MockRead(true, kSOCKS5OkResponse, arraysize(kSOCKS5OkResponse)) }; user_sock_.reset(BuildMockSocket(data_reads, data_writes, hostname, 80)); - int rv = user_sock_->Connect(&callback_); + scoped_refptr<LoadLog> log(new LoadLog); + int rv = user_sock_->Connect(&callback_, log); EXPECT_EQ(ERR_IO_PENDING, rv); + EXPECT_TRUE(LogContains( + *log, 0, LoadLog::TYPE_SOCKS5_CONNECT, LoadLog::PHASE_BEGIN)); rv = callback_.WaitForResult(); EXPECT_EQ(OK, rv); EXPECT_TRUE(user_sock_->IsConnected()); + EXPECT_TRUE(LogContains( + *log, -1, LoadLog::TYPE_SOCKS5_CONNECT, LoadLog::PHASE_END)); } // Test for partial handshake response read @@ -276,11 +309,16 @@ TEST_F(SOCKS5ClientSocketTest, PartialReadWrites) { MockRead(true, partial1, arraysize(partial1)), MockRead(true, partial2, arraysize(partial2)) }; user_sock_.reset(BuildMockSocket(data_reads, data_writes, hostname, 80)); - int rv = user_sock_->Connect(&callback_); + scoped_refptr<LoadLog> log(new LoadLog); + int rv = user_sock_->Connect(&callback_, log); EXPECT_EQ(ERR_IO_PENDING, rv); + EXPECT_TRUE(LogContains( + *log, 0, LoadLog::TYPE_SOCKS5_CONNECT, LoadLog::PHASE_BEGIN)); rv = callback_.WaitForResult(); EXPECT_EQ(OK, rv); EXPECT_TRUE(user_sock_->IsConnected()); + EXPECT_TRUE(LogContains( + *log, -1, LoadLog::TYPE_SOCKS5_CONNECT, LoadLog::PHASE_END)); } } diff --git a/net/socket/socks_client_socket.cc b/net/socket/socks_client_socket.cc index ace53d9..09c1dbd 100644 --- a/net/socket/socks_client_socket.cc +++ b/net/socket/socks_client_socket.cc @@ -14,6 +14,7 @@ #include "base/compiler_specific.h" #include "base/trace_event.h" #include "net/base/io_buffer.h" +#include "net/base/load_log.h" #include "net/base/net_util.h" namespace net { @@ -83,7 +84,8 @@ SOCKSClientSocket::~SOCKSClientSocket() { Disconnect(); } -int SOCKSClientSocket::Connect(CompletionCallback* callback) { +int SOCKSClientSocket::Connect(CompletionCallback* callback, + LoadLog* load_log) { DCHECK(transport_.get()); DCHECK(transport_->IsConnected()); DCHECK_EQ(STATE_NONE, next_state_); @@ -94,10 +96,17 @@ int SOCKSClientSocket::Connect(CompletionCallback* callback) { return OK; next_state_ = STATE_RESOLVE_HOST; + load_log_ = load_log; + + LoadLog::BeginEvent(load_log, LoadLog::TYPE_SOCKS_CONNECT); int rv = DoLoop(OK); - if (rv == ERR_IO_PENDING) + if (rv == ERR_IO_PENDING) { user_callback_ = callback; + } else { + LoadLog::EndEvent(load_log, LoadLog::TYPE_SOCKS_CONNECT); + load_log_ = NULL; + } return rv; } @@ -159,8 +168,11 @@ void SOCKSClientSocket::DoCallback(int result) { void SOCKSClientSocket::OnIOComplete(int result) { DCHECK_NE(STATE_NONE, next_state_); int rv = DoLoop(result); - if (rv != ERR_IO_PENDING) + if (rv != ERR_IO_PENDING) { + LoadLog::EndEvent(load_log_, LoadLog::TYPE_SOCKS_CONNECT); + load_log_ = NULL; DoCallback(rv); + } } int SOCKSClientSocket::DoLoop(int last_io_result) { @@ -205,7 +217,7 @@ int SOCKSClientSocket::DoResolveHost() { next_state_ = STATE_RESOLVE_HOST_COMPLETE; return host_resolver_.Resolve( - host_request_info_, &addresses_, &io_callback_, NULL); + host_request_info_, &addresses_, &io_callback_, load_log_); } int SOCKSClientSocket::DoResolveHostComplete(int result) { diff --git a/net/socket/socks_client_socket.h b/net/socket/socks_client_socket.h index 9b53c11..c099c4c 100644 --- a/net/socket/socks_client_socket.h +++ b/net/socket/socks_client_socket.h @@ -20,6 +20,8 @@ namespace net { +class LoadLog; + // The SOCKS client socket implementation class SOCKSClientSocket : public ClientSocket { public: @@ -38,7 +40,7 @@ class SOCKSClientSocket : public ClientSocket { // ClientSocket methods: // Does the SOCKS handshake and completes the protocol. - virtual int Connect(CompletionCallback* callback); + virtual int Connect(CompletionCallback* callback, LoadLog* load_log); virtual void Disconnect(); virtual bool IsConnected() const; virtual bool IsConnectedAndIdle() const; @@ -126,10 +128,11 @@ class SOCKSClientSocket : public ClientSocket { AddressList addresses_; HostResolver::RequestInfo host_request_info_; + scoped_refptr<LoadLog> load_log_; + DISALLOW_COPY_AND_ASSIGN(SOCKSClientSocket); }; } // namespace net #endif // NET_SOCKET_SOCKS_CLIENT_SOCKET_H_ - diff --git a/net/socket/socks_client_socket_unittest.cc b/net/socket/socks_client_socket_unittest.cc index 7bb7ab7..56d84a8 100644 --- a/net/socket/socks_client_socket_unittest.cc +++ b/net/socket/socks_client_socket_unittest.cc @@ -5,6 +5,8 @@ #include "net/socket/socks_client_socket.h" #include "net/base/address_list.h" +#include "net/base/load_log.h" +#include "net/base/load_log_unittest.h" #include "net/base/mock_host_resolver.h" #include "net/base/test_completion_callback.h" #include "net/base/winsock_init.h" @@ -62,7 +64,7 @@ SOCKSClientSocket* SOCKSClientSocketTest::BuildMockSocket( mock_socket_.reset(new StaticMockSocket(reads, writes)); tcp_sock_ = new MockTCPClientSocket(address_list_, mock_socket_.get()); - int rv = tcp_sock_->Connect(&callback); + int rv = tcp_sock_->Connect(&callback, NULL); EXPECT_EQ(ERR_IO_PENDING, rv); rv = callback.WaitForResult(); EXPECT_EQ(OK, rv); @@ -91,14 +93,19 @@ TEST_F(SOCKSClientSocketTest, CompleteHandshake) { EXPECT_TRUE(tcp_sock_->IsConnected()); EXPECT_FALSE(user_sock_->IsConnected()); - int rv = user_sock_->Connect(&callback_); + scoped_refptr<LoadLog> log(new LoadLog); + int rv = user_sock_->Connect(&callback_, log); EXPECT_EQ(ERR_IO_PENDING, rv); + EXPECT_TRUE( + LogContains(*log, 0, LoadLog::TYPE_SOCKS_CONNECT, LoadLog::PHASE_BEGIN)); EXPECT_FALSE(user_sock_->IsConnected()); rv = callback_.WaitForResult(); EXPECT_EQ(OK, rv); EXPECT_TRUE(user_sock_->IsConnected()); EXPECT_EQ(SOCKSClientSocket::kSOCKS4, user_sock_->socks_version_); + EXPECT_TRUE(LogContains( + *log, -1, LoadLog::TYPE_SOCKS_CONNECT, LoadLog::PHASE_END)); scoped_refptr<IOBuffer> buffer = new IOBuffer(payload_write.size()); memcpy(buffer->data(), payload_write.data(), payload_write.size()); @@ -147,13 +154,18 @@ TEST_F(SOCKSClientSocketTest, HandshakeFailures) { MockRead(false, tests[i].fail_reply, arraysize(tests[i].fail_reply)) }; user_sock_.reset(BuildMockSocket(data_reads, data_writes, "localhost", 80)); + scoped_refptr<LoadLog> log(new LoadLog); - int rv = user_sock_->Connect(&callback_); + int rv = user_sock_->Connect(&callback_, log); EXPECT_EQ(ERR_IO_PENDING, rv); + EXPECT_TRUE(LogContains( + *log, 0, LoadLog::TYPE_SOCKS_CONNECT, LoadLog::PHASE_BEGIN)); rv = callback_.WaitForResult(); EXPECT_EQ(tests[i].fail_code, rv); EXPECT_FALSE(user_sock_->IsConnected()); EXPECT_TRUE(tcp_sock_->IsConnected()); + EXPECT_TRUE(LogContains( + *log, -1, LoadLog::TYPE_SOCKS_CONNECT, LoadLog::PHASE_END)); } } @@ -170,12 +182,17 @@ TEST_F(SOCKSClientSocketTest, PartialServerReads) { MockRead(true, kSOCKSPartialReply2, arraysize(kSOCKSPartialReply2)) }; user_sock_.reset(BuildMockSocket(data_reads, data_writes, "localhost", 80)); + scoped_refptr<LoadLog> log(new LoadLog); - int rv = user_sock_->Connect(&callback_); + int rv = user_sock_->Connect(&callback_, log); EXPECT_EQ(ERR_IO_PENDING, rv); + EXPECT_TRUE(LogContains( + *log, 0, LoadLog::TYPE_SOCKS_CONNECT, LoadLog::PHASE_BEGIN)); rv = callback_.WaitForResult(); EXPECT_EQ(OK, rv); EXPECT_TRUE(user_sock_->IsConnected()); + EXPECT_TRUE(LogContains( + *log, -1, LoadLog::TYPE_SOCKS_CONNECT, LoadLog::PHASE_END)); } // Tests scenario when the client sends the handshake request in @@ -195,12 +212,17 @@ TEST_F(SOCKSClientSocketTest, PartialClientWrites) { MockRead(true, kSOCKSOkReply, arraysize(kSOCKSOkReply)) }; user_sock_.reset(BuildMockSocket(data_reads, data_writes, "localhost", 80)); + scoped_refptr<LoadLog> log(new LoadLog); - int rv = user_sock_->Connect(&callback_); + int rv = user_sock_->Connect(&callback_, log); EXPECT_EQ(ERR_IO_PENDING, rv); + EXPECT_TRUE(LogContains( + *log, 0, LoadLog::TYPE_SOCKS_CONNECT, LoadLog::PHASE_BEGIN)); rv = callback_.WaitForResult(); EXPECT_EQ(OK, rv); EXPECT_TRUE(user_sock_->IsConnected()); + EXPECT_TRUE(LogContains( + *log, -1, LoadLog::TYPE_SOCKS_CONNECT, LoadLog::PHASE_END)); } // Tests the case when the server sends a smaller sized handshake data @@ -214,12 +236,17 @@ TEST_F(SOCKSClientSocketTest, FailedSocketRead) { MockRead(false, 0) }; user_sock_.reset(BuildMockSocket(data_reads, data_writes, "localhost", 80)); + scoped_refptr<LoadLog> log(new LoadLog); - int rv = user_sock_->Connect(&callback_); + int rv = user_sock_->Connect(&callback_, log); EXPECT_EQ(ERR_IO_PENDING, rv); + EXPECT_TRUE(LogContains( + *log, 0, LoadLog::TYPE_SOCKS_CONNECT, LoadLog::PHASE_BEGIN)); rv = callback_.WaitForResult(); EXPECT_EQ(ERR_CONNECTION_CLOSED, rv); EXPECT_FALSE(user_sock_->IsConnected()); + EXPECT_TRUE(LogContains( + *log, -1, LoadLog::TYPE_SOCKS_CONNECT, LoadLog::PHASE_END)); } // Tries to connect to an unknown DNS and on failure should revert to SOCKS4A. @@ -238,13 +265,18 @@ TEST_F(SOCKSClientSocketTest, SOCKS4AFailedDNS) { MockRead(false, kSOCKSOkReply, arraysize(kSOCKSOkReply)) }; user_sock_.reset(BuildMockSocket(data_reads, data_writes, hostname, 80)); + scoped_refptr<LoadLog> log(new LoadLog); - int rv = user_sock_->Connect(&callback_); + int rv = user_sock_->Connect(&callback_, log); EXPECT_EQ(ERR_IO_PENDING, rv); + EXPECT_TRUE(LogContains( + *log, 0, LoadLog::TYPE_SOCKS_CONNECT, LoadLog::PHASE_BEGIN)); rv = callback_.WaitForResult(); EXPECT_EQ(OK, rv); EXPECT_TRUE(user_sock_->IsConnected()); EXPECT_EQ(SOCKSClientSocket::kSOCKS4a, user_sock_->socks_version_); + EXPECT_TRUE(LogContains( + *log, -1, LoadLog::TYPE_SOCKS_CONNECT, LoadLog::PHASE_END)); } // Tries to connect to a domain that resolves to IPv6. @@ -264,14 +296,18 @@ TEST_F(SOCKSClientSocketTest, SOCKS4AIfDomainInIPv6) { MockRead(false, kSOCKSOkReply, arraysize(kSOCKSOkReply)) }; user_sock_.reset(BuildMockSocket(data_reads, data_writes, hostname, 80)); + scoped_refptr<LoadLog> log(new LoadLog); - int rv = user_sock_->Connect(&callback_); + int rv = user_sock_->Connect(&callback_, log); EXPECT_EQ(ERR_IO_PENDING, rv); + EXPECT_TRUE(LogContains( + *log, 0, LoadLog::TYPE_SOCKS_CONNECT, LoadLog::PHASE_BEGIN)); rv = callback_.WaitForResult(); EXPECT_EQ(OK, rv); EXPECT_TRUE(user_sock_->IsConnected()); EXPECT_EQ(SOCKSClientSocket::kSOCKS4a, user_sock_->socks_version_); + EXPECT_TRUE(LogContains( + *log, -1, LoadLog::TYPE_SOCKS_CONNECT, LoadLog::PHASE_END)); } } // namespace net - diff --git a/net/socket/ssl_client_socket_mac.cc b/net/socket/ssl_client_socket_mac.cc index 5e1cf76..1e9a96c 100644 --- a/net/socket/ssl_client_socket_mac.cc +++ b/net/socket/ssl_client_socket_mac.cc @@ -9,6 +9,7 @@ #include "base/string_util.h" #include "net/base/cert_verifier.h" #include "net/base/io_buffer.h" +#include "net/base/load_log.h" #include "net/base/net_errors.h" #include "net/base/ssl_info.h" @@ -326,108 +327,28 @@ SSLClientSocketMac::~SSLClientSocketMac() { Disconnect(); } -int SSLClientSocketMac::Connect(CompletionCallback* callback) { +int SSLClientSocketMac::Connect(CompletionCallback* callback, + LoadLog* load_log) { DCHECK(transport_.get()); DCHECK(next_handshake_state_ == STATE_NONE); DCHECK(!user_connect_callback_); - OSStatus status = noErr; - - status = SSLNewContext(false, &ssl_context_); - if (status) - return NetErrorFromOSStatus(status); - - status = SSLSetProtocolVersionEnabled(ssl_context_, - kSSLProtocol2, - ssl_config_.ssl2_enabled); - if (status) - return NetErrorFromOSStatus(status); - - status = SSLSetProtocolVersionEnabled(ssl_context_, - kSSLProtocol3, - ssl_config_.ssl3_enabled); - if (status) - return NetErrorFromOSStatus(status); - - status = SSLSetProtocolVersionEnabled(ssl_context_, - kTLSProtocol1, - ssl_config_.tls1_enabled); - if (status) - return NetErrorFromOSStatus(status); - - status = SSLSetIOFuncs(ssl_context_, SSLReadCallback, SSLWriteCallback); - if (status) - return NetErrorFromOSStatus(status); - - status = SSLSetConnection(ssl_context_, this); - if (status) - return NetErrorFromOSStatus(status); - - // Disable certificate verification within Secure Transport; we'll - // be handling that ourselves. - status = SSLSetEnableCertVerify(ssl_context_, false); - if (status) - return NetErrorFromOSStatus(status); - - // SSLSetSessionOption() was introduced in Mac OS X 10.5.7. It allows us - // to perform certificate validation during the handshake, which is - // required in order to properly enable session resumption. - // - // With the kSSLSessionOptionBreakOnServerAuth option set, SSLHandshake() - // will return errSSLServerAuthCompleted after receiving the server's - // Certificate during the handshake. That gives us an opportunity to verify - // the server certificate and then re-enter that handshake (assuming the - // certificate successfully validated). - // - // If SSLSetSessionOption() is not present, we do not enable session - // resumption, because in that case we are verifying the server's certificate - // after the handshake completes (but before any application data is - // exchanged). If we were to enable session resumption in this situation, - // the session would be cached before we verified the certificate, leaving - // the potential for a session in which the certificate failed to validate - // to still be able to be resumed. - CFBundleRef bundle = - CFBundleGetBundleWithIdentifier(CFSTR("com.apple.security")); - if (bundle) { - SSLSetSessionOptionFuncPtr ssl_set_session_options = - reinterpret_cast<SSLSetSessionOptionFuncPtr>( - CFBundleGetFunctionPointerForName(bundle, - CFSTR("SSLSetSessionOption"))); - if (ssl_set_session_options) { - status = ssl_set_session_options(ssl_context_, - kSSLSessionOptionBreakOnServerAuthFlag, - true); - if (status) - return NetErrorFromOSStatus(status); - - // Concatenate the hostname and peer address to use as the peer ID. To - // resume a session, we must connect to the same server on the same port - // using the same hostname (i.e., localhost and 127.0.0.1 are considered - // different peers, which puts us through certificate validation again - // and catches hostname/certificate name mismatches. - struct sockaddr_storage addr; - socklen_t addr_length = sizeof(struct sockaddr_storage); - memset(&addr, 0, sizeof(addr)); - if (!transport_->GetPeerName(reinterpret_cast<struct sockaddr*>(&addr), - &addr_length)) { - // Assemble the socket hostname and address into a single buffer. - std::vector<char> peer_id(hostname_.begin(), hostname_.end()); - peer_id.insert(peer_id.end(), reinterpret_cast<char*>(&addr), - reinterpret_cast<char*>(&addr) + addr_length); + LoadLog::BeginEvent(load_log, LoadLog::TYPE_SSL_CONNECT); - // SSLSetPeerID() treats peer_id as a binary blob, and makes its - // own copy. - status = SSLSetPeerID(ssl_context_, &peer_id[0], peer_id.size()); - if (status) - return NetErrorFromOSStatus(status); - } - } + int rv = InitializeSSLContext(); + if (rv != OK) { + LoadLog::EndEvent(load_log, LoadLog::TYPE_SSL_CONNECT); + return rv; } next_handshake_state_ = STATE_HANDSHAKE_START; - int rv = DoHandshakeLoop(OK); - if (rv == ERR_IO_PENDING) + rv = DoHandshakeLoop(OK); + if (rv == ERR_IO_PENDING) { + load_log_ = load_log; user_connect_callback_ = callback; + } else { + LoadLog::EndEvent(load_log, LoadLog::TYPE_SSL_CONNECT); + } return rv; } @@ -535,6 +456,103 @@ void SSLClientSocketMac::GetSSLCertRequestInfo( // TODO(wtc): implement this. } +int SSLClientSocketMac::InitializeSSLContext() { + OSStatus status = noErr; + + status = SSLNewContext(false, &ssl_context_); + if (status) + return NetErrorFromOSStatus(status); + + status = SSLSetProtocolVersionEnabled(ssl_context_, + kSSLProtocol2, + ssl_config_.ssl2_enabled); + if (status) + return NetErrorFromOSStatus(status); + + status = SSLSetProtocolVersionEnabled(ssl_context_, + kSSLProtocol3, + ssl_config_.ssl3_enabled); + if (status) + return NetErrorFromOSStatus(status); + + status = SSLSetProtocolVersionEnabled(ssl_context_, + kTLSProtocol1, + ssl_config_.tls1_enabled); + if (status) + return NetErrorFromOSStatus(status); + + status = SSLSetIOFuncs(ssl_context_, SSLReadCallback, SSLWriteCallback); + if (status) + return NetErrorFromOSStatus(status); + + status = SSLSetConnection(ssl_context_, this); + if (status) + return NetErrorFromOSStatus(status); + + // Disable certificate verification within Secure Transport; we'll + // be handling that ourselves. + status = SSLSetEnableCertVerify(ssl_context_, false); + if (status) + return NetErrorFromOSStatus(status); + + // SSLSetSessionOption() was introduced in Mac OS X 10.5.7. It allows us + // to perform certificate validation during the handshake, which is + // required in order to properly enable session resumption. + // + // With the kSSLSessionOptionBreakOnServerAuth option set, SSLHandshake() + // will return errSSLServerAuthCompleted after receiving the server's + // Certificate during the handshake. That gives us an opportunity to verify + // the server certificate and then re-enter that handshake (assuming the + // certificate successfully validated). + // + // If SSLSetSessionOption() is not present, we do not enable session + // resumption, because in that case we are verifying the server's certificate + // after the handshake completes (but before any application data is + // exchanged). If we were to enable session resumption in this situation, + // the session would be cached before we verified the certificate, leaving + // the potential for a session in which the certificate failed to validate + // to still be able to be resumed. + CFBundleRef bundle = + CFBundleGetBundleWithIdentifier(CFSTR("com.apple.security")); + if (bundle) { + SSLSetSessionOptionFuncPtr ssl_set_session_options = + reinterpret_cast<SSLSetSessionOptionFuncPtr>( + CFBundleGetFunctionPointerForName(bundle, + CFSTR("SSLSetSessionOption"))); + if (ssl_set_session_options) { + status = ssl_set_session_options(ssl_context_, + kSSLSessionOptionBreakOnServerAuthFlag, + true); + if (status) + return NetErrorFromOSStatus(status); + + // Concatenate the hostname and peer address to use as the peer ID. To + // resume a session, we must connect to the same server on the same port + // using the same hostname (i.e., localhost and 127.0.0.1 are considered + // different peers, which puts us through certificate validation again + // and catches hostname/certificate name mismatches. + struct sockaddr_storage addr; + socklen_t addr_length = sizeof(struct sockaddr_storage); + memset(&addr, 0, sizeof(addr)); + if (!transport_->GetPeerName(reinterpret_cast<struct sockaddr*>(&addr), + &addr_length)) { + // Assemble the socket hostname and address into a single buffer. + std::vector<char> peer_id(hostname_.begin(), hostname_.end()); + peer_id.insert(peer_id.end(), reinterpret_cast<char*>(&addr), + reinterpret_cast<char*>(&addr) + addr_length); + + // SSLSetPeerID() treats peer_id as a binary blob, and makes its + // own copy. + status = SSLSetPeerID(ssl_context_, &peer_id[0], peer_id.size()); + if (status) + return NetErrorFromOSStatus(status); + } + } + } + + return OK; +} + void SSLClientSocketMac::DoConnectCallback(int rv) { DCHECK(rv != ERR_IO_PENDING); DCHECK(user_connect_callback_); @@ -574,8 +592,11 @@ void SSLClientSocketMac::DoWriteCallback(int rv) { void SSLClientSocketMac::OnHandshakeIOComplete(int result) { DCHECK(next_handshake_state_ != STATE_NONE); int rv = DoHandshakeLoop(result); - if (rv != ERR_IO_PENDING) + if (rv != ERR_IO_PENDING) { + LoadLog::EndEvent(load_log_, LoadLog::TYPE_SSL_CONNECT); + load_log_ = NULL; DoConnectCallback(rv); + } } void SSLClientSocketMac::OnTransportReadComplete(int result) { @@ -589,8 +610,11 @@ void SSLClientSocketMac::OnTransportReadComplete(int result) { if (next_handshake_state_ != STATE_NONE) { int rv = DoHandshakeLoop(result); - if (rv != ERR_IO_PENDING) + if (rv != ERR_IO_PENDING) { + LoadLog::EndEvent(load_log_, LoadLog::TYPE_SSL_CONNECT); + load_log_ = NULL; DoConnectCallback(rv); + } return; } if (user_read_buf_) { diff --git a/net/socket/ssl_client_socket_mac.h b/net/socket/ssl_client_socket_mac.h index 06bbdb5..c99ef8b 100644 --- a/net/socket/ssl_client_socket_mac.h +++ b/net/socket/ssl_client_socket_mac.h @@ -19,6 +19,7 @@ namespace net { class CertVerifier; +class LoadLog; // An SSL client socket implemented with Secure Transport. class SSLClientSocketMac : public SSLClientSocket { @@ -37,7 +38,7 @@ class SSLClientSocketMac : public SSLClientSocket { virtual void GetSSLCertRequestInfo(SSLCertRequestInfo* cert_request_info); // ClientSocket methods: - virtual int Connect(CompletionCallback* callback); + virtual int Connect(CompletionCallback* callback, LoadLog* load_log); virtual void Disconnect(); virtual bool IsConnected() const; virtual bool IsConnectedAndIdle() const; @@ -49,6 +50,9 @@ class SSLClientSocketMac : public SSLClientSocket { virtual bool SetSendBufferSize(int32 size); private: + // Initializes the SSLContext. Returns a net error code. + int InitializeSSLContext(); + void DoConnectCallback(int result); void DoReadCallback(int result); void DoWriteCallback(int result); @@ -122,6 +126,8 @@ class SSLClientSocketMac : public SSLClientSocket { // This buffer holds data for Read() operations on the underlying transport // (ClientSocket::Read()). scoped_refptr<IOBuffer> read_io_buf_; + + scoped_refptr<LoadLog> load_log_; }; } // namespace net diff --git a/net/socket/ssl_client_socket_nss.cc b/net/socket/ssl_client_socket_nss.cc index 72c1bc3..ca523d5 100644 --- a/net/socket/ssl_client_socket_nss.cc +++ b/net/socket/ssl_client_socket_nss.cc @@ -69,6 +69,7 @@ #include "base/string_util.h" #include "net/base/cert_verifier.h" #include "net/base/io_buffer.h" +#include "net/base/load_log.h" #include "net/base/net_errors.h" #include "net/base/ssl_cert_request_info.h" #include "net/base/ssl_info.h" @@ -236,7 +237,8 @@ int SSLClientSocketNSS::Init() { return OK; } -int SSLClientSocketNSS::Connect(CompletionCallback* callback) { +int SSLClientSocketNSS::Connect(CompletionCallback* callback, + LoadLog* load_log) { EnterFunction(""); DCHECK(transport_.get()); DCHECK(next_handshake_state_ == STATE_NONE); @@ -246,10 +248,32 @@ int SSLClientSocketNSS::Connect(CompletionCallback* callback) { DCHECK(!user_read_buf_); DCHECK(!user_write_buf_); + LoadLog::BeginEvent(load_log, LoadLog::TYPE_SSL_CONNECT); + if (Init() != OK) { NOTREACHED() << "Couldn't initialize nss"; } + int rv = InitializeSSLOptions(); + if (rv != OK) { + LoadLog::EndEvent(load_log, LoadLog::TYPE_SSL_CONNECT); + return rv; + } + + GotoState(STATE_HANDSHAKE); + rv = DoHandshakeLoop(OK); + if (rv == ERR_IO_PENDING) { + user_connect_callback_ = callback; + load_log_ = load_log; + } else { + LoadLog::EndEvent(load_log, LoadLog::TYPE_SSL_CONNECT); + } + + LeaveFunction(""); + return rv > OK ? OK : rv; +} + +int SSLClientSocketNSS::InitializeSSLOptions() { // Transport connected, now hook it up to nss // TODO(port): specify rx and tx buffer sizes separately nss_fd_ = memio_CreateIOLayer(kRecvBufferSize); @@ -337,13 +361,7 @@ int SSLClientSocketNSS::Connect(CompletionCallback* callback) { // Tell SSL we're a client; needed if not letting NSPR do socket I/O SSL_ResetHandshake(nss_fd_, 0); - GotoState(STATE_HANDSHAKE); - rv = DoHandshakeLoop(OK); - if (rv == ERR_IO_PENDING) - user_connect_callback_ = callback; - - LeaveFunction(""); - return rv > OK ? OK : rv; + return OK; } void SSLClientSocketNSS::InvalidateSessionIfBadCertificate() { @@ -576,8 +594,11 @@ void SSLClientSocketNSS::DoConnectCallback(int rv) { void SSLClientSocketNSS::OnHandshakeIOComplete(int result) { EnterFunction(result); int rv = DoHandshakeLoop(result); - if (rv != ERR_IO_PENDING) + if (rv != ERR_IO_PENDING) { + LoadLog::EndEvent(load_log_, net::LoadLog::TYPE_SSL_CONNECT); + load_log_ = NULL; DoConnectCallback(rv); + } LeaveFunction(""); } diff --git a/net/socket/ssl_client_socket_nss.h b/net/socket/ssl_client_socket_nss.h index 5fd04c6..6e871b5 100644 --- a/net/socket/ssl_client_socket_nss.h +++ b/net/socket/ssl_client_socket_nss.h @@ -27,6 +27,7 @@ namespace net { class CertVerifier; +class LoadLog; class X509Certificate; // An SSL client socket implemented with Mozilla NSS. @@ -46,7 +47,7 @@ class SSLClientSocketNSS : public SSLClientSocket { virtual void GetSSLCertRequestInfo(SSLCertRequestInfo* cert_request_info); // ClientSocket methods: - virtual int Connect(CompletionCallback* callback); + virtual int Connect(CompletionCallback* callback, LoadLog* load_log); virtual void Disconnect(); virtual bool IsConnected() const; virtual bool IsConnectedAndIdle() const; @@ -58,6 +59,9 @@ class SSLClientSocketNSS : public SSLClientSocket { virtual bool SetSendBufferSize(int32 size); private: + // Initializes NSS SSL options. Returns a net error code. + int InitializeSSLOptions(); + void InvalidateSessionIfBadCertificate(); X509Certificate* UpdateServerCert(); void DoReadCallback(int result); @@ -148,6 +152,8 @@ class SSLClientSocketNSS : public SSLClientSocket { // Buffers for the network end of the SSL state machine memio_Private* nss_bufs_; + scoped_refptr<LoadLog> load_log_; + static bool nss_options_initialized_; }; diff --git a/net/socket/ssl_client_socket_unittest.cc b/net/socket/ssl_client_socket_unittest.cc index aa94ff8..611a604 100644 --- a/net/socket/ssl_client_socket_unittest.cc +++ b/net/socket/ssl_client_socket_unittest.cc @@ -7,6 +7,8 @@ #include "net/base/address_list.h" #include "net/base/host_resolver.h" #include "net/base/io_buffer.h" +#include "net/base/load_log.h" +#include "net/base/load_log_unittest.h" #include "net/base/net_errors.h" #include "net/base/ssl_config_service.h" #include "net/base/test_completion_callback.h" @@ -67,7 +69,7 @@ TEST_F(SSLClientSocketTest, Connect) { EXPECT_EQ(net::OK, rv); net::ClientSocket *transport = new net::TCPClientSocket(addr); - rv = transport->Connect(&callback); + rv = transport->Connect(&callback, NULL); if (rv == net::ERR_IO_PENDING) rv = callback.WaitForResult(); EXPECT_EQ(net::OK, rv); @@ -78,16 +80,23 @@ TEST_F(SSLClientSocketTest, Connect) { EXPECT_FALSE(sock->IsConnected()); - rv = sock->Connect(&callback); + scoped_refptr<net::LoadLog> log(new net::LoadLog); + rv = sock->Connect(&callback, log); + EXPECT_TRUE(net::LogContains( + *log, 0, net::LoadLog::TYPE_SSL_CONNECT, net::LoadLog::PHASE_BEGIN)); if (rv != net::OK) { ASSERT_EQ(net::ERR_IO_PENDING, rv); EXPECT_FALSE(sock->IsConnected()); + EXPECT_FALSE(net::LogContains( + *log, -1, net::LoadLog::TYPE_SSL_CONNECT, net::LoadLog::PHASE_END)); rv = callback.WaitForResult(); EXPECT_EQ(net::OK, rv); } EXPECT_TRUE(sock->IsConnected()); + EXPECT_TRUE(net::LogContains( + *log, -1, net::LoadLog::TYPE_SSL_CONNECT, net::LoadLog::PHASE_END)); sock->Disconnect(); EXPECT_FALSE(sock->IsConnected()); @@ -104,7 +113,7 @@ TEST_F(SSLClientSocketTest, ConnectExpired) { EXPECT_EQ(net::OK, rv); net::ClientSocket *transport = new net::TCPClientSocket(addr); - rv = transport->Connect(&callback); + rv = transport->Connect(&callback, NULL); if (rv == net::ERR_IO_PENDING) rv = callback.WaitForResult(); EXPECT_EQ(net::OK, rv); @@ -115,10 +124,15 @@ TEST_F(SSLClientSocketTest, ConnectExpired) { EXPECT_FALSE(sock->IsConnected()); - rv = sock->Connect(&callback); + scoped_refptr<net::LoadLog> log(new net::LoadLog); + rv = sock->Connect(&callback, log); + EXPECT_TRUE(net::LogContains( + *log, 0, net::LoadLog::TYPE_SSL_CONNECT, net::LoadLog::PHASE_BEGIN)); if (rv != net::OK) { ASSERT_EQ(net::ERR_IO_PENDING, rv); EXPECT_FALSE(sock->IsConnected()); + EXPECT_FALSE(net::LogContains( + *log, -1, net::LoadLog::TYPE_SSL_CONNECT, net::LoadLog::PHASE_END)); rv = callback.WaitForResult(); EXPECT_EQ(net::ERR_CERT_DATE_INVALID, rv); @@ -127,6 +141,9 @@ TEST_F(SSLClientSocketTest, ConnectExpired) { // We cannot test sock->IsConnected(), as the NSS implementation disconnects // the socket when it encounters an error, whereas other implementations // leave it connected. + + EXPECT_TRUE(net::LogContains( + *log, -1, net::LoadLog::TYPE_SSL_CONNECT, net::LoadLog::PHASE_END)); } TEST_F(SSLClientSocketTest, ConnectMismatched) { @@ -141,7 +158,7 @@ TEST_F(SSLClientSocketTest, ConnectMismatched) { EXPECT_EQ(net::OK, rv); net::ClientSocket *transport = new net::TCPClientSocket(addr); - rv = transport->Connect(&callback); + rv = transport->Connect(&callback, NULL); if (rv == net::ERR_IO_PENDING) rv = callback.WaitForResult(); EXPECT_EQ(net::OK, rv); @@ -152,10 +169,15 @@ TEST_F(SSLClientSocketTest, ConnectMismatched) { EXPECT_FALSE(sock->IsConnected()); - rv = sock->Connect(&callback); + scoped_refptr<net::LoadLog> log(new net::LoadLog); + rv = sock->Connect(&callback, log); + EXPECT_TRUE(net::LogContains( + *log, 0, net::LoadLog::TYPE_SSL_CONNECT, net::LoadLog::PHASE_BEGIN)); if (rv != net::ERR_CERT_COMMON_NAME_INVALID) { ASSERT_EQ(net::ERR_IO_PENDING, rv); EXPECT_FALSE(sock->IsConnected()); + EXPECT_FALSE(net::LogContains( + *log, -1, net::LoadLog::TYPE_SSL_CONNECT, net::LoadLog::PHASE_END)); rv = callback.WaitForResult(); EXPECT_EQ(net::ERR_CERT_COMMON_NAME_INVALID, rv); @@ -164,6 +186,9 @@ TEST_F(SSLClientSocketTest, ConnectMismatched) { // We cannot test sock->IsConnected(), as the NSS implementation disconnects // the socket when it encounters an error, whereas other implementations // leave it connected. + + EXPECT_TRUE(net::LogContains( + *log, -1, net::LoadLog::TYPE_SSL_CONNECT, net::LoadLog::PHASE_END)); } // TODO(wtc): Add unit tests for IsConnectedAndIdle: @@ -185,7 +210,7 @@ TEST_F(SSLClientSocketTest, Read) { EXPECT_EQ(net::OK, rv); net::ClientSocket *transport = new net::TCPClientSocket(addr); - rv = transport->Connect(&callback); + rv = transport->Connect(&callback, NULL); if (rv == net::ERR_IO_PENDING) rv = callback.WaitForResult(); EXPECT_EQ(net::OK, rv); @@ -195,7 +220,7 @@ TEST_F(SSLClientSocketTest, Read) { server_.kHostName, kDefaultSSLConfig)); - rv = sock->Connect(&callback); + rv = sock->Connect(&callback, NULL); if (rv != net::OK) { ASSERT_EQ(net::ERR_IO_PENDING, rv); @@ -242,7 +267,7 @@ TEST_F(SSLClientSocketTest, Read_SmallChunks) { EXPECT_EQ(net::OK, rv); net::ClientSocket *transport = new net::TCPClientSocket(addr); - rv = transport->Connect(&callback); + rv = transport->Connect(&callback, NULL); if (rv == net::ERR_IO_PENDING) rv = callback.WaitForResult(); EXPECT_EQ(net::OK, rv); @@ -251,7 +276,7 @@ TEST_F(SSLClientSocketTest, Read_SmallChunks) { socket_factory_->CreateSSLClientSocket(transport, server_.kHostName, kDefaultSSLConfig)); - rv = sock->Connect(&callback); + rv = sock->Connect(&callback, NULL); if (rv != net::OK) { ASSERT_EQ(net::ERR_IO_PENDING, rv); @@ -297,7 +322,7 @@ TEST_F(SSLClientSocketTest, Read_Interrupted) { EXPECT_EQ(net::OK, rv); net::ClientSocket *transport = new net::TCPClientSocket(addr); - rv = transport->Connect(&callback); + rv = transport->Connect(&callback, NULL); if (rv == net::ERR_IO_PENDING) rv = callback.WaitForResult(); EXPECT_EQ(net::OK, rv); @@ -306,7 +331,7 @@ TEST_F(SSLClientSocketTest, Read_Interrupted) { socket_factory_->CreateSSLClientSocket(transport, server_.kHostName, kDefaultSSLConfig)); - rv = sock->Connect(&callback); + rv = sock->Connect(&callback, NULL); if (rv != net::OK) { ASSERT_EQ(net::ERR_IO_PENDING, rv); diff --git a/net/socket/ssl_client_socket_win.cc b/net/socket/ssl_client_socket_win.cc index 03b8bfe..7212095 100644 --- a/net/socket/ssl_client_socket_win.cc +++ b/net/socket/ssl_client_socket_win.cc @@ -14,6 +14,7 @@ #include "net/base/cert_verifier.h" #include "net/base/connection_type_histograms.h" #include "net/base/io_buffer.h" +#include "net/base/load_log.h" #include "net/base/net_errors.h" #include "net/base/ssl_cert_request_info.h" #include "net/base/ssl_info.h" @@ -426,11 +427,33 @@ void SSLClientSocketWin::GetSSLCertRequestInfo( DCHECK(ok); } -int SSLClientSocketWin::Connect(CompletionCallback* callback) { +int SSLClientSocketWin::Connect(CompletionCallback* callback, + LoadLog* load_log) { DCHECK(transport_.get()); DCHECK(next_state_ == STATE_NONE); DCHECK(!user_connect_callback_); + LoadLog::BeginEvent(load_log, LoadLog::TYPE_SSL_CONNECT); + + int rv = InitializeSSLContext(); + if (rv != OK) { + LoadLog::EndEvent(load_log, LoadLog::TYPE_SSL_CONNECT); + return rv; + } + + writing_first_token_ = true; + next_state_ = STATE_HANDSHAKE_WRITE; + rv = DoLoop(OK); + if (rv == ERR_IO_PENDING) { + user_connect_callback_ = callback; + load_log_ = load_log; + } else { + LoadLog::EndEvent(load_log, LoadLog::TYPE_SSL_CONNECT); + } + return rv; +} + +int SSLClientSocketWin::InitializeSSLContext() { int ssl_version_mask = 0; if (ssl_config_.ssl2_enabled) ssl_version_mask |= SSL2; @@ -487,14 +510,10 @@ int SSLClientSocketWin::Connect(CompletionCallback* callback) { return MapSecurityError(status); } - writing_first_token_ = true; - next_state_ = STATE_HANDSHAKE_WRITE; - int rv = DoLoop(OK); - if (rv == ERR_IO_PENDING) - user_connect_callback_ = callback; - return rv; + return OK; } + void SSLClientSocketWin::Disconnect() { // TODO(wtc): Send SSL close_notify alert. next_state_ = STATE_NONE; @@ -618,6 +637,9 @@ void SSLClientSocketWin::OnHandshakeIOComplete(int result) { // The SSL handshake has some round trips. Any error, other than waiting // for IO, means that we've failed and need to notify the caller. if (rv != ERR_IO_PENDING) { + LoadLog::EndEvent(load_log_, LoadLog::TYPE_SSL_CONNECT); + load_log_ = NULL; + // If there is no connect callback available to call, it had better be // because we are renegotiating (which occurs because we are in the middle // of a Read when the renegotiation process starts). We need to inform the diff --git a/net/socket/ssl_client_socket_win.h b/net/socket/ssl_client_socket_win.h index 6b81001..2007844 100644 --- a/net/socket/ssl_client_socket_win.h +++ b/net/socket/ssl_client_socket_win.h @@ -22,6 +22,7 @@ namespace net { class CertVerifier; +class LoadLog; // An SSL client socket implemented with the Windows Schannel. class SSLClientSocketWin : public SSLClientSocket { @@ -40,7 +41,7 @@ class SSLClientSocketWin : public SSLClientSocket { virtual void GetSSLCertRequestInfo(SSLCertRequestInfo* cert_request_info); // ClientSocket methods: - virtual int Connect(CompletionCallback* callback); + virtual int Connect(CompletionCallback* callback, LoadLog* load_log); virtual void Disconnect(); virtual bool IsConnected() const; virtual bool IsConnectedAndIdle() const; @@ -57,6 +58,9 @@ class SSLClientSocketWin : public SSLClientSocket { return next_state_ == STATE_COMPLETED_HANDSHAKE; } + // Initializes the SSL options and security context. Returns a net error code. + int InitializeSSLContext(); + void OnHandshakeIOComplete(int result); void OnReadComplete(int result); void OnWriteComplete(int result); @@ -176,6 +180,8 @@ class SSLClientSocketWin : public SSLClientSocket { // True when the decrypter needs more data in order to decrypt. bool need_more_data_; + + scoped_refptr<LoadLog> load_log_; }; } // namespace net diff --git a/net/socket/tcp_client_socket_libevent.cc b/net/socket/tcp_client_socket_libevent.cc index 165c4cd..abf66bc 100644 --- a/net/socket/tcp_client_socket_libevent.cc +++ b/net/socket/tcp_client_socket_libevent.cc @@ -14,6 +14,7 @@ #include "base/string_util.h" #include "base/trace_event.h" #include "net/base/io_buffer.h" +#include "net/base/load_log.h" #include "net/base/net_errors.h" #include "third_party/libevent/event.h" @@ -117,15 +118,37 @@ TCPClientSocketLibevent::~TCPClientSocketLibevent() { Disconnect(); } -int TCPClientSocketLibevent::Connect(CompletionCallback* callback) { +int TCPClientSocketLibevent::Connect(CompletionCallback* callback, + LoadLog* load_log) { // If already connected, then just return OK. if (socket_ != kInvalidSocket) return OK; DCHECK(!waiting_connect_); + DCHECK(!load_log_); TRACE_EVENT_BEGIN("socket.connect", this, ""); + LoadLog::BeginEvent(load_log, LoadLog::TYPE_TCP_CONNECT); + + int rv = DoConnect(); + + if (rv == ERR_IO_PENDING) { + // Synchronous operation not supported. + DCHECK(callback); + + load_log_ = load_log; + waiting_connect_ = true; + write_callback_ = callback; + } else { + TRACE_EVENT_END("socket.connect", this, ""); + LoadLog::EndEvent(load_log, LoadLog::TYPE_TCP_CONNECT); + } + + return rv; +} + +int TCPClientSocketLibevent::DoConnect() { while (true) { DCHECK(current_ai_); @@ -135,7 +158,6 @@ int TCPClientSocketLibevent::Connect(CompletionCallback* callback) { if (!HANDLE_EINTR(connect(socket_, current_ai_->ai_addr, static_cast<int>(current_ai_->ai_addrlen)))) { - TRACE_EVENT_END("socket.connect", this, ""); // Connected without waiting! return OK; } @@ -158,9 +180,6 @@ int TCPClientSocketLibevent::Connect(CompletionCallback* callback) { } } - // Synchronous operation not supported - DCHECK(callback); - // Initialize write_socket_watcher_ and link it to our MessagePump. // POLLOUT is set if the connection is established. // POLLIN is set if the connection fails. @@ -173,8 +192,6 @@ int TCPClientSocketLibevent::Connect(CompletionCallback* callback) { return MapPosixError(errno); } - waiting_connect_ = true; - write_callback_ = callback; return ERR_IO_PENDING; } @@ -345,8 +362,6 @@ void TCPClientSocketLibevent::DoWriteCallback(int rv) { void TCPClientSocketLibevent::DidCompleteConnect() { int result = ERR_UNEXPECTED; - TRACE_EVENT_END("socket.connect", this, ""); - // Check to see if connect succeeded int error_code = 0; socklen_t len = sizeof(error_code); @@ -361,12 +376,19 @@ void TCPClientSocketLibevent::DidCompleteConnect() { const addrinfo* next = current_ai_->ai_next; Disconnect(); current_ai_ = next; - result = Connect(write_callback_); + scoped_refptr<LoadLog> load_log; + load_log.swap(load_log_); + TRACE_EVENT_END("socket.connect", this, ""); + LoadLog::EndEvent(load_log, LoadLog::TYPE_TCP_CONNECT); + result = Connect(write_callback_, load_log); } else { result = MapConnectError(error_code); bool ok = write_socket_watcher_.StopWatchingFileDescriptor(); DCHECK(ok); waiting_connect_ = false; + TRACE_EVENT_END("socket.connect", this, ""); + LoadLog::EndEvent(load_log_, LoadLog::TYPE_TCP_CONNECT); + load_log_ = NULL; } if (result != ERR_IO_PENDING) { diff --git a/net/socket/tcp_client_socket_libevent.h b/net/socket/tcp_client_socket_libevent.h index bfb5767..10b1c31 100644 --- a/net/socket/tcp_client_socket_libevent.h +++ b/net/socket/tcp_client_socket_libevent.h @@ -18,6 +18,8 @@ struct event; // From libevent namespace net { +class LoadLog; + // A client socket that uses TCP as the transport layer. class TCPClientSocketLibevent : public ClientSocket { public: @@ -29,7 +31,7 @@ class TCPClientSocketLibevent : public ClientSocket { virtual ~TCPClientSocketLibevent(); // ClientSocket methods: - virtual int Connect(CompletionCallback* callback); + virtual int Connect(CompletionCallback* callback, LoadLog* load_log); virtual void Disconnect(); virtual bool IsConnected() const; virtual bool IsConnectedAndIdle() const; @@ -85,6 +87,9 @@ class TCPClientSocketLibevent : public ClientSocket { DISALLOW_COPY_AND_ASSIGN(WriteWatcher); }; + // Performs the actual connect(). Returns a net error code. + int DoConnect(); + void DoReadCallback(int rv); void DoWriteCallback(int rv); void DidCompleteRead(); @@ -126,6 +131,8 @@ class TCPClientSocketLibevent : public ClientSocket { // External callback; called when write is complete. CompletionCallback* write_callback_; + scoped_refptr<LoadLog> load_log_; + DISALLOW_COPY_AND_ASSIGN(TCPClientSocketLibevent); }; diff --git a/net/socket/tcp_client_socket_pool.cc b/net/socket/tcp_client_socket_pool.cc index ca92073..37d2d8c 100644 --- a/net/socket/tcp_client_socket_pool.cc +++ b/net/socket/tcp_client_socket_pool.cc @@ -8,6 +8,7 @@ #include "base/logging.h" #include "base/message_loop.h" #include "base/time.h" +#include "net/base/load_log.h" #include "net/base/net_errors.h" #include "net/socket/client_socket_factory.h" #include "net/socket/client_socket_handle.h" @@ -123,8 +124,7 @@ int TCPConnectJob::DoTCPConnect() { next_state_ = kStateTCPConnectComplete; set_socket(client_socket_factory_->CreateTCPClientSocket(addresses_)); connect_start_time_ = base::TimeTicks::Now(); - // TODO(eroman): Socket::Connect() should take a LoadLog. - return socket()->Connect(&callback_); + return socket()->Connect(&callback_, load_log()); } int TCPConnectJob::DoTCPConnectComplete(int result) { diff --git a/net/socket/tcp_client_socket_pool_unittest.cc b/net/socket/tcp_client_socket_pool_unittest.cc index 5e1b0eeb1..e73b7d3 100644 --- a/net/socket/tcp_client_socket_pool_unittest.cc +++ b/net/socket/tcp_client_socket_pool_unittest.cc @@ -28,7 +28,7 @@ class MockClientSocket : public ClientSocket { MockClientSocket() : connected_(false) {} // ClientSocket methods: - virtual int Connect(CompletionCallback* callback) { + virtual int Connect(CompletionCallback* callback, LoadLog* /* load_log */) { connected_ = true; return OK; } @@ -63,7 +63,7 @@ class MockFailingClientSocket : public ClientSocket { MockFailingClientSocket() {} // ClientSocket methods: - virtual int Connect(CompletionCallback* callback) { + virtual int Connect(CompletionCallback* callback, LoadLog* /* load_log */) { return ERR_CONNECTION_FAILED; } @@ -98,7 +98,7 @@ class MockPendingClientSocket : public ClientSocket { is_connected_(false) {} // ClientSocket methods: - virtual int Connect(CompletionCallback* callback) { + virtual int Connect(CompletionCallback* callback, LoadLog* /* load_log */) { MessageLoop::current()->PostTask( FROM_HERE, method_factory_.NewRunnableMethod( diff --git a/net/socket/tcp_client_socket_unittest.cc b/net/socket/tcp_client_socket_unittest.cc index 14d2305..80b0496 100644 --- a/net/socket/tcp_client_socket_unittest.cc +++ b/net/socket/tcp_client_socket_unittest.cc @@ -9,6 +9,8 @@ #include "net/base/host_resolver.h" #include "net/base/io_buffer.h" #include "net/base/listen_socket.h" +#include "net/base/load_log.h" +#include "net/base/load_log_unittest.h" #include "net/base/net_errors.h" #include "net/base/test_completion_callback.h" #include "net/base/winsock_init.h" @@ -97,15 +99,22 @@ TEST_F(TCPClientSocketTest, Connect) { TestCompletionCallback callback; EXPECT_FALSE(sock_->IsConnected()); - int rv = sock_->Connect(&callback); + scoped_refptr<LoadLog> log(new LoadLog); + int rv = sock_->Connect(&callback, log); + EXPECT_TRUE(net::LogContains( + *log, 0, net::LoadLog::TYPE_TCP_CONNECT, net::LoadLog::PHASE_BEGIN)); if (rv != OK) { ASSERT_EQ(rv, ERR_IO_PENDING); + EXPECT_FALSE(net::LogContains( + *log, -1, net::LoadLog::TYPE_TCP_CONNECT, net::LoadLog::PHASE_END)); rv = callback.WaitForResult(); EXPECT_EQ(rv, OK); } EXPECT_TRUE(sock_->IsConnected()); + EXPECT_TRUE(net::LogContains( + *log, -1, net::LoadLog::TYPE_TCP_CONNECT, net::LoadLog::PHASE_END)); sock_->Disconnect(); EXPECT_FALSE(sock_->IsConnected()); @@ -117,7 +126,7 @@ TEST_F(TCPClientSocketTest, Connect) { TEST_F(TCPClientSocketTest, Read) { TestCompletionCallback callback; - int rv = sock_->Connect(&callback); + int rv = sock_->Connect(&callback, NULL); if (rv != OK) { ASSERT_EQ(rv, ERR_IO_PENDING); @@ -162,7 +171,7 @@ TEST_F(TCPClientSocketTest, Read) { TEST_F(TCPClientSocketTest, Read_SmallChunks) { TestCompletionCallback callback; - int rv = sock_->Connect(&callback); + int rv = sock_->Connect(&callback, NULL); if (rv != OK) { ASSERT_EQ(rv, ERR_IO_PENDING); @@ -207,7 +216,7 @@ TEST_F(TCPClientSocketTest, Read_SmallChunks) { TEST_F(TCPClientSocketTest, Read_Interrupted) { TestCompletionCallback callback; - int rv = sock_->Connect(&callback); + int rv = sock_->Connect(&callback, NULL); if (rv != OK) { ASSERT_EQ(ERR_IO_PENDING, rv); @@ -241,7 +250,7 @@ TEST_F(TCPClientSocketTest, Read_Interrupted) { TEST_F(TCPClientSocketTest, DISABLED_FullDuplex_ReadFirst) { TestCompletionCallback callback; - int rv = sock_->Connect(&callback); + int rv = sock_->Connect(&callback, NULL); if (rv != OK) { ASSERT_EQ(rv, ERR_IO_PENDING); @@ -283,7 +292,7 @@ TEST_F(TCPClientSocketTest, DISABLED_FullDuplex_ReadFirst) { TEST_F(TCPClientSocketTest, DISABLED_FullDuplex_WriteFirst) { TestCompletionCallback callback; - int rv = sock_->Connect(&callback); + int rv = sock_->Connect(&callback, NULL); if (rv != OK) { ASSERT_EQ(ERR_IO_PENDING, rv); diff --git a/net/socket/tcp_client_socket_win.cc b/net/socket/tcp_client_socket_win.cc index 600c8ee..407ea44 100644 --- a/net/socket/tcp_client_socket_win.cc +++ b/net/socket/tcp_client_socket_win.cc @@ -13,6 +13,7 @@ #include "base/sys_info.h" #include "base/trace_event.h" #include "net/base/io_buffer.h" +#include "net/base/load_log.h" #include "net/base/net_errors.h" #include "net/base/winsock_init.h" @@ -271,15 +272,39 @@ TCPClientSocketWin::~TCPClientSocketWin() { Disconnect(); } -int TCPClientSocketWin::Connect(CompletionCallback* callback) { +int TCPClientSocketWin::Connect(CompletionCallback* callback, + LoadLog* load_log) { // If already connected, then just return OK. if (socket_ != INVALID_SOCKET) return OK; + DCHECK(!load_log_); + static StatsCounter connects("tcp.connect"); connects.Increment(); TRACE_EVENT_BEGIN("socket.connect", this, ""); + + LoadLog::BeginEvent(load_log, LoadLog::TYPE_TCP_CONNECT); + + int rv = DoConnect(); + + if (rv == ERR_IO_PENDING) { + // Synchronous operation not supported. + DCHECK(callback); + + load_log_ = load_log; + waiting_connect_ = true; + read_callback_ = callback; + } else { + TRACE_EVENT_END("socket.connect", this, ""); + LoadLog::EndEvent(load_log, LoadLog::TYPE_TCP_CONNECT); + } + + return rv; +} + +int TCPClientSocketWin::DoConnect() { const struct addrinfo* ai = current_ai_; DCHECK(ai); @@ -311,10 +336,8 @@ int TCPClientSocketWin::Connect(CompletionCallback* callback) { // and we don't know if it's correct. NOTREACHED(); - if (ResetEventIfSignaled(core_->read_overlapped_.hEvent)) { - TRACE_EVENT_END("socket.connect", this, ""); + if (ResetEventIfSignaled(core_->read_overlapped_.hEvent)) return OK; - } } else { DWORD err = WSAGetLastError(); if (err != WSAEWOULDBLOCK) { @@ -324,8 +347,6 @@ int TCPClientSocketWin::Connect(CompletionCallback* callback) { } core_->WatchForRead(); - waiting_connect_ = true; - read_callback_ = callback; return ERR_IO_PENDING; } @@ -587,7 +608,6 @@ void TCPClientSocketWin::DidCompleteConnect() { DCHECK(waiting_connect_); int result; - TRACE_EVENT_END("socket.connect", this, ""); waiting_connect_ = false; WSANETWORKEVENTS events; @@ -609,13 +629,23 @@ void TCPClientSocketWin::DidCompleteConnect() { const struct addrinfo* next = current_ai_->ai_next; Disconnect(); current_ai_ = next; - result = Connect(read_callback_); + scoped_refptr<LoadLog> load_log; + load_log.swap(load_log_); + TRACE_EVENT_END("socket.connect", this, ""); + LoadLog::EndEvent(load_log, LoadLog::TYPE_TCP_CONNECT); + result = Connect(read_callback_, load_log); } else { result = MapConnectError(error_code); + TRACE_EVENT_END("socket.connect", this, ""); + LoadLog::EndEvent(load_log_, LoadLog::TYPE_TCP_CONNECT); + load_log_ = NULL; } } else { NOTREACHED(); result = ERR_UNEXPECTED; + TRACE_EVENT_END("socket.connect", this, ""); + LoadLog::EndEvent(load_log_, LoadLog::TYPE_TCP_CONNECT); + load_log_ = NULL; } if (result != ERR_IO_PENDING) diff --git a/net/socket/tcp_client_socket_win.h b/net/socket/tcp_client_socket_win.h index 6bc63fc..032f1a6 100644 --- a/net/socket/tcp_client_socket_win.h +++ b/net/socket/tcp_client_socket_win.h @@ -14,6 +14,8 @@ namespace net { +class LoadLog; + class TCPClientSocketWin : public ClientSocket { public: // The IP address(es) and port number to connect to. The TCP socket will try @@ -24,7 +26,7 @@ class TCPClientSocketWin : public ClientSocket { ~TCPClientSocketWin(); // ClientSocket methods: - virtual int Connect(CompletionCallback* callback); + virtual int Connect(CompletionCallback* callback, LoadLog* load_log); virtual void Disconnect(); virtual bool IsConnected() const; virtual bool IsConnectedAndIdle() const; @@ -41,6 +43,9 @@ class TCPClientSocketWin : public ClientSocket { private: class Core; + // Performs the actual connect(). Returns a net error code. + int DoConnect(); + int CreateSocket(const struct addrinfo* ai); void DoReadCallback(int rv); void DoWriteCallback(int rv); @@ -72,6 +77,8 @@ class TCPClientSocketWin : public ClientSocket { // External callback; called when write is complete. CompletionCallback* write_callback_; + scoped_refptr<LoadLog> load_log_; + DISALLOW_COPY_AND_ASSIGN(TCPClientSocketWin); }; diff --git a/net/socket/tcp_pinger.h b/net/socket/tcp_pinger.h index 0b0bd9b..af9dc84 100644 --- a/net/socket/tcp_pinger.h +++ b/net/socket/tcp_pinger.h @@ -86,7 +86,7 @@ class TCPPinger { void DoConnect() { sock_.reset(new TCPClientSocket(addr_)); - int rv = sock_->Connect(&connect_callback_); + int rv = sock_->Connect(&connect_callback_, NULL); // Regardless of success or failure, if we're done now, // signal the customer. if (rv != ERR_IO_PENDING) |