summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorttuttle <ttuttle@chromium.org>2015-05-14 18:28:03 -0700
committerCommit bot <commit-bot@chromium.org>2015-05-15 01:28:20 +0000
commit23fdb7b4ed86ee9f63b16a3b432fa2c721432bd2 (patch)
treec588b5338738541f02cfab69a8b213670127c744
parentc0c828496a25acd34b85985b412799933a36f1ff (diff)
downloadchromium_src-23fdb7b4ed86ee9f63b16a3b432fa2c721432bd2.zip
chromium_src-23fdb7b4ed86ee9f63b16a3b432fa2c721432bd2.tar.gz
chromium_src-23fdb7b4ed86ee9f63b16a3b432fa2c721432bd2.tar.bz2
Collect all ConnectionAttempts from both sockets in TransportConnectJob.
Before, the TransportConnectJob simply inferred that, if the main socket failed to connect, the address it was using was the last address in the list. With this change, the TCPClientSocket actually tracks all of the connection attempts made (as it tries each address in the list), and the TransportConnectJob copies the attempts from both the main and fallback sockets and records all of them in the ClientSocketHandle in GetAdditionalErrorState. BUG=480565 TBR=jam Review URL: https://codereview.chromium.org/1096203006 Cr-Commit-Position: refs/heads/master@{#330012}
-rw-r--r--chrome/browser/devtools/device/usb/android_usb_socket.cc5
-rw-r--r--chrome/browser/devtools/device/usb/android_usb_socket.h4
-rw-r--r--chrome/browser/extensions/api/socket/tls_socket_unittest.cc3
-rw-r--r--content/browser/renderer_host/p2p/socket_host_test_utils.cc4
-rw-r--r--content/browser/renderer_host/p2p/socket_host_test_utils.h4
-rw-r--r--jingle/glue/fake_ssl_client_socket.cc5
-rw-r--r--jingle/glue/fake_ssl_client_socket.h4
-rw-r--r--jingle/glue/fake_ssl_client_socket_unittest.cc3
-rw-r--r--jingle/glue/proxy_resolving_client_socket.cc5
-rw-r--r--jingle/glue/proxy_resolving_client_socket.h4
-rw-r--r--jingle/glue/pseudotcp_adapter.cc6
-rw-r--r--jingle/glue/pseudotcp_adapter.h4
-rw-r--r--net/http/http_proxy_client_socket.cc5
-rw-r--r--net/http/http_proxy_client_socket.h3
-rw-r--r--net/http/http_stream_factory_impl_job.cc25
-rw-r--r--net/http/http_stream_factory_impl_job.h2
-rw-r--r--net/server/http_server_unittest.cc5
-rw-r--r--net/socket/client_socket_handle.h3
-rw-r--r--net/socket/client_socket_pool_base.cc6
-rw-r--r--net/socket/client_socket_pool_base_unittest.cc5
-rw-r--r--net/socket/connection_attempts.h2
-rw-r--r--net/socket/socket_test_util.cc20
-rw-r--r--net/socket/socket_test_util.h6
-rw-r--r--net/socket/socks5_client_socket.cc3
-rw-r--r--net/socket/socks5_client_socket.h3
-rw-r--r--net/socket/socks_client_socket.cc3
-rw-r--r--net/socket/socks_client_socket.h3
-rw-r--r--net/socket/ssl_client_socket_nss.cc4
-rw-r--r--net/socket/ssl_client_socket_nss.h3
-rw-r--r--net/socket/ssl_client_socket_openssl.cc5
-rw-r--r--net/socket/ssl_client_socket_openssl.h3
-rw-r--r--net/socket/ssl_client_socket_unittest.cc9
-rw-r--r--net/socket/ssl_server_socket_nss.cc4
-rw-r--r--net/socket/ssl_server_socket_nss.h3
-rw-r--r--net/socket/ssl_server_socket_openssl.cc5
-rw-r--r--net/socket/ssl_server_socket_openssl.h3
-rw-r--r--net/socket/ssl_server_socket_unittest.cc8
-rw-r--r--net/socket/stream_socket.h11
-rw-r--r--net/socket/tcp_client_socket.cc18
-rw-r--r--net/socket/tcp_client_socket.h8
-rw-r--r--net/socket/transport_client_socket_pool.cc60
-rw-r--r--net/socket/transport_client_socket_pool.h12
-rw-r--r--net/socket/transport_client_socket_pool_test_util.cc37
-rw-r--r--net/socket/transport_client_socket_pool_test_util.h3
-rw-r--r--net/socket/transport_client_socket_pool_unittest.cc43
-rw-r--r--net/socket/unix_domain_client_socket_posix.cc5
-rw-r--r--net/socket/unix_domain_client_socket_posix.h3
-rw-r--r--net/socket/websocket_endpoint_lock_manager_unittest.cc8
-rw-r--r--net/spdy/spdy_proxy_client_socket.cc5
-rw-r--r--net/spdy/spdy_proxy_client_socket.h3
-rw-r--r--remoting/protocol/channel_multiplexer.cc6
-rw-r--r--remoting/protocol/fake_stream_socket.cc6
-rw-r--r--remoting/protocol/fake_stream_socket.h4
53 files changed, 392 insertions, 32 deletions
diff --git a/chrome/browser/devtools/device/usb/android_usb_socket.cc b/chrome/browser/devtools/device/usb/android_usb_socket.cc
index fde3230..1310f6e 100644
--- a/chrome/browser/devtools/device/usb/android_usb_socket.cc
+++ b/chrome/browser/devtools/device/usb/android_usb_socket.cc
@@ -234,6 +234,11 @@ bool AndroidUsbSocket::GetSSLInfo(net::SSLInfo* ssl_info) {
return false;
}
+void AndroidUsbSocket::GetConnectionAttempts(
+ net::ConnectionAttempts* out) const {
+ out->clear();
+}
+
void AndroidUsbSocket::RespondToReader(bool disconnect) {
if (read_callback_.is_null() || (read_buffer_.empty() && !disconnect))
return;
diff --git a/chrome/browser/devtools/device/usb/android_usb_socket.h b/chrome/browser/devtools/device/usb/android_usb_socket.h
index 85ef112..fa22deb 100644
--- a/chrome/browser/devtools/device/usb/android_usb_socket.h
+++ b/chrome/browser/devtools/device/usb/android_usb_socket.h
@@ -52,6 +52,10 @@ class AndroidUsbSocket : public net::StreamSocket,
bool WasNpnNegotiated() const override;
net::NextProto GetNegotiatedProtocol() const override;
bool GetSSLInfo(net::SSLInfo* ssl_info) override;
+ void GetConnectionAttempts(net::ConnectionAttempts* out) const override;
+ void ClearConnectionAttempts() override {}
+ void AddConnectionAttempts(const net::ConnectionAttempts& attempts) override {
+ }
private:
void RespondToReader(bool disconnect);
diff --git a/chrome/browser/extensions/api/socket/tls_socket_unittest.cc b/chrome/browser/extensions/api/socket/tls_socket_unittest.cc
index adebfbf..49edd64 100644
--- a/chrome/browser/extensions/api/socket/tls_socket_unittest.cc
+++ b/chrome/browser/extensions/api/socket/tls_socket_unittest.cc
@@ -53,6 +53,9 @@ class MockSSLClientSocket : public net::SSLClientSocket {
MOCK_CONST_METHOD0(WasEverUsed, bool());
MOCK_CONST_METHOD0(UsingTCPFastOpen, bool());
MOCK_METHOD1(GetSSLInfo, bool(net::SSLInfo*));
+ MOCK_CONST_METHOD1(GetConnectionAttempts, void(net::ConnectionAttempts*));
+ MOCK_METHOD0(ClearConnectionAttempts, void());
+ MOCK_METHOD1(AddConnectionAttempts, void(const net::ConnectionAttempts&));
MOCK_METHOD5(ExportKeyingMaterial,
int(const StringPiece&,
bool,
diff --git a/content/browser/renderer_host/p2p/socket_host_test_utils.cc b/content/browser/renderer_host/p2p/socket_host_test_utils.cc
index 12257b9..ed07966 100644
--- a/content/browser/renderer_host/p2p/socket_host_test_utils.cc
+++ b/content/browser/renderer_host/p2p/socket_host_test_utils.cc
@@ -172,6 +172,10 @@ bool FakeSocket::GetSSLInfo(net::SSLInfo* ssl_info) {
return false;
}
+void FakeSocket::GetConnectionAttempts(net::ConnectionAttempts* out) const {
+ out->clear();
+}
+
void CreateRandomPacket(std::vector<char>* packet) {
size_t size = kStunHeaderSize + rand() % 1000;
packet->resize(size);
diff --git a/content/browser/renderer_host/p2p/socket_host_test_utils.h b/content/browser/renderer_host/p2p/socket_host_test_utils.h
index b008f9f..9ab4634 100644
--- a/content/browser/renderer_host/p2p/socket_host_test_utils.h
+++ b/content/browser/renderer_host/p2p/socket_host_test_utils.h
@@ -63,6 +63,10 @@ class FakeSocket : public net::StreamSocket {
bool WasNpnNegotiated() const override;
net::NextProto GetNegotiatedProtocol() const override;
bool GetSSLInfo(net::SSLInfo* ssl_info) override;
+ void GetConnectionAttempts(net::ConnectionAttempts* out) const override;
+ void ClearConnectionAttempts() override {}
+ void AddConnectionAttempts(const net::ConnectionAttempts& attempts) override {
+ }
private:
void DoAsyncWrite(scoped_refptr<net::IOBuffer> buf, int buf_len,
diff --git a/jingle/glue/fake_ssl_client_socket.cc b/jingle/glue/fake_ssl_client_socket.cc
index 4cc6867..657bd76 100644
--- a/jingle/glue/fake_ssl_client_socket.cc
+++ b/jingle/glue/fake_ssl_client_socket.cc
@@ -344,4 +344,9 @@ bool FakeSSLClientSocket::GetSSLInfo(net::SSLInfo* ssl_info) {
return transport_socket_->GetSSLInfo(ssl_info);
}
+void FakeSSLClientSocket::GetConnectionAttempts(
+ net::ConnectionAttempts* out) const {
+ out->clear();
+}
+
} // namespace jingle_glue
diff --git a/jingle/glue/fake_ssl_client_socket.h b/jingle/glue/fake_ssl_client_socket.h
index bf951d6..8f90429 100644
--- a/jingle/glue/fake_ssl_client_socket.h
+++ b/jingle/glue/fake_ssl_client_socket.h
@@ -67,6 +67,10 @@ class FakeSSLClientSocket : public net::StreamSocket {
bool WasNpnNegotiated() const override;
net::NextProto GetNegotiatedProtocol() const override;
bool GetSSLInfo(net::SSLInfo* ssl_info) override;
+ void GetConnectionAttempts(net::ConnectionAttempts* out) const override;
+ void ClearConnectionAttempts() override {}
+ void AddConnectionAttempts(const net::ConnectionAttempts& attempts) override {
+ }
private:
enum HandshakeState {
diff --git a/jingle/glue/fake_ssl_client_socket_unittest.cc b/jingle/glue/fake_ssl_client_socket_unittest.cc
index 4df4a7d..0f81127 100644
--- a/jingle/glue/fake_ssl_client_socket_unittest.cc
+++ b/jingle/glue/fake_ssl_client_socket_unittest.cc
@@ -68,6 +68,9 @@ class MockClientSocket : public net::StreamSocket {
MOCK_CONST_METHOD0(WasNpnNegotiated, bool());
MOCK_CONST_METHOD0(GetNegotiatedProtocol, net::NextProto());
MOCK_METHOD1(GetSSLInfo, bool(net::SSLInfo*));
+ MOCK_CONST_METHOD1(GetConnectionAttempts, void(net::ConnectionAttempts*));
+ MOCK_METHOD0(ClearConnectionAttempts, void());
+ MOCK_METHOD1(AddConnectionAttempts, void(const net::ConnectionAttempts&));
};
// Break up |data| into a bunch of chunked MockReads/Writes and push
diff --git a/jingle/glue/proxy_resolving_client_socket.cc b/jingle/glue/proxy_resolving_client_socket.cc
index 5a6e068..9eb2da3 100644
--- a/jingle/glue/proxy_resolving_client_socket.cc
+++ b/jingle/glue/proxy_resolving_client_socket.cc
@@ -420,6 +420,11 @@ bool ProxyResolvingClientSocket::GetSSLInfo(net::SSLInfo* ssl_info) {
return false;
}
+void ProxyResolvingClientSocket::GetConnectionAttempts(
+ net::ConnectionAttempts* out) const {
+ out->clear();
+}
+
void ProxyResolvingClientSocket::CloseTransportSocket() {
if (transport_.get() && transport_->socket())
transport_->socket()->Disconnect();
diff --git a/jingle/glue/proxy_resolving_client_socket.h b/jingle/glue/proxy_resolving_client_socket.h
index 696a097..e8f22ce 100644
--- a/jingle/glue/proxy_resolving_client_socket.h
+++ b/jingle/glue/proxy_resolving_client_socket.h
@@ -70,6 +70,10 @@ class ProxyResolvingClientSocket : public net::StreamSocket {
bool WasNpnNegotiated() const override;
net::NextProto GetNegotiatedProtocol() const override;
bool GetSSLInfo(net::SSLInfo* ssl_info) override;
+ void GetConnectionAttempts(net::ConnectionAttempts* out) const override;
+ void ClearConnectionAttempts() override {}
+ void AddConnectionAttempts(const net::ConnectionAttempts& attempts) override {
+ }
private:
// Proxy resolution and connection functions.
diff --git a/jingle/glue/pseudotcp_adapter.cc b/jingle/glue/pseudotcp_adapter.cc
index 5a26f7d..db27502 100644
--- a/jingle/glue/pseudotcp_adapter.cc
+++ b/jingle/glue/pseudotcp_adapter.cc
@@ -582,6 +582,12 @@ bool PseudoTcpAdapter::GetSSLInfo(net::SSLInfo* ssl_info) {
return false;
}
+void PseudoTcpAdapter::GetConnectionAttempts(
+ net::ConnectionAttempts* out) const {
+ DCHECK(CalledOnValidThread());
+ out->clear();
+}
+
void PseudoTcpAdapter::SetAckDelay(int delay_ms) {
DCHECK(CalledOnValidThread());
core_->SetAckDelay(delay_ms);
diff --git a/jingle/glue/pseudotcp_adapter.h b/jingle/glue/pseudotcp_adapter.h
index 1473000..8b11e2e 100644
--- a/jingle/glue/pseudotcp_adapter.h
+++ b/jingle/glue/pseudotcp_adapter.h
@@ -53,6 +53,10 @@ class PseudoTcpAdapter : public net::StreamSocket, base::NonThreadSafe {
bool WasNpnNegotiated() const override;
net::NextProto GetNegotiatedProtocol() const override;
bool GetSSLInfo(net::SSLInfo* ssl_info) override;
+ void GetConnectionAttempts(net::ConnectionAttempts* out) const override;
+ void ClearConnectionAttempts() override {}
+ void AddConnectionAttempts(const net::ConnectionAttempts& attempts) override {
+ }
// Set the delay for sending ACK.
void SetAckDelay(int delay_ms);
diff --git a/net/http/http_proxy_client_socket.cc b/net/http/http_proxy_client_socket.cc
index 2eec09c..2f0619b 100644
--- a/net/http/http_proxy_client_socket.cc
+++ b/net/http/http_proxy_client_socket.cc
@@ -213,6 +213,11 @@ bool HttpProxyClientSocket::GetSSLInfo(SSLInfo* ssl_info) {
return false;
}
+void HttpProxyClientSocket::GetConnectionAttempts(
+ ConnectionAttempts* out) const {
+ out->clear();
+}
+
int HttpProxyClientSocket::Read(IOBuffer* buf, int buf_len,
const CompletionCallback& callback) {
DCHECK(user_callback_.is_null());
diff --git a/net/http/http_proxy_client_socket.h b/net/http/http_proxy_client_socket.h
index cc82c57..439278a 100644
--- a/net/http/http_proxy_client_socket.h
+++ b/net/http/http_proxy_client_socket.h
@@ -72,6 +72,9 @@ class HttpProxyClientSocket : public ProxyClientSocket {
bool WasNpnNegotiated() const override;
NextProto GetNegotiatedProtocol() const override;
bool GetSSLInfo(SSLInfo* ssl_info) override;
+ void GetConnectionAttempts(ConnectionAttempts* out) const override;
+ void ClearConnectionAttempts() override {}
+ void AddConnectionAttempts(const ConnectionAttempts& attempts) override {}
// Socket implementation.
int Read(IOBuffer* buf,
diff --git a/net/http/http_stream_factory_impl_job.cc b/net/http/http_stream_factory_impl_job.cc
index 1172bf1..1d17b08 100644
--- a/net/http/http_stream_factory_impl_job.cc
+++ b/net/http/http_stream_factory_impl_job.cc
@@ -296,7 +296,7 @@ void HttpStreamFactoryImpl::Job::OnStreamReadyCallback() {
DCHECK(!IsPreconnecting());
DCHECK(!stream_factory_->for_websockets_);
- MaybeCopyConnectionAttemptsFromClientSocketHandleToRequest();
+ MaybeCopyConnectionAttemptsFromSocketOrHandle();
if (IsOrphaned()) {
stream_factory_->OnOrphanedJobComplete(this);
@@ -319,7 +319,7 @@ void HttpStreamFactoryImpl::Job::OnWebSocketHandshakeStreamReadyCallback() {
// never be ready.
DCHECK(!IsOrphaned());
- MaybeCopyConnectionAttemptsFromClientSocketHandleToRequest();
+ MaybeCopyConnectionAttemptsFromSocketOrHandle();
request_->Complete(was_npn_negotiated(),
protocol_negotiated(),
@@ -341,7 +341,7 @@ void HttpStreamFactoryImpl::Job::OnNewSpdySessionReadyCallback() {
base::WeakPtr<SpdySession> spdy_session = new_spdy_session_;
new_spdy_session_.reset();
- MaybeCopyConnectionAttemptsFromClientSocketHandleToRequest();
+ MaybeCopyConnectionAttemptsFromSocketOrHandle();
// TODO(jgraettinger): Notify the factory, and let that notify |request_|,
// rather than notifying |request_| directly.
@@ -362,7 +362,7 @@ void HttpStreamFactoryImpl::Job::OnNewSpdySessionReadyCallback() {
void HttpStreamFactoryImpl::Job::OnStreamFailedCallback(int result) {
DCHECK(!IsPreconnecting());
- MaybeCopyConnectionAttemptsFromClientSocketHandleToRequest();
+ MaybeCopyConnectionAttemptsFromSocketOrHandle();
if (IsOrphaned())
stream_factory_->OnOrphanedJobComplete(this);
@@ -375,7 +375,7 @@ void HttpStreamFactoryImpl::Job::OnCertificateErrorCallback(
int result, const SSLInfo& ssl_info) {
DCHECK(!IsPreconnecting());
- MaybeCopyConnectionAttemptsFromClientSocketHandleToRequest();
+ MaybeCopyConnectionAttemptsFromSocketOrHandle();
if (IsOrphaned())
stream_factory_->OnOrphanedJobComplete(this);
@@ -1526,12 +1526,23 @@ HttpStreamFactoryImpl::Job::GetSocketGroup() const {
return ClientSocketPoolManager::NORMAL_GROUP;
}
+// If the connection succeeds, failed connection attempts leading up to the
+// success will be returned via the successfully connected socket. If the
+// connection fails, failed connection attempts will be returned via the
+// ClientSocketHandle. Check whether a socket was returned and copy the
+// connection attempts from the proper place.
void HttpStreamFactoryImpl::Job::
- MaybeCopyConnectionAttemptsFromClientSocketHandleToRequest() {
+ MaybeCopyConnectionAttemptsFromSocketOrHandle() {
if (IsOrphaned() || !connection_)
return;
- request_->AddConnectionAttempts(connection_->connection_attempts());
+ if (connection_->socket()) {
+ ConnectionAttempts socket_attempts;
+ connection_->socket()->GetConnectionAttempts(&socket_attempts);
+ request_->AddConnectionAttempts(socket_attempts);
+ } else {
+ request_->AddConnectionAttempts(connection_->connection_attempts());
+ }
}
} // namespace net
diff --git a/net/http/http_stream_factory_impl_job.h b/net/http/http_stream_factory_impl_job.h
index a5793d1..f7285be3 100644
--- a/net/http/http_stream_factory_impl_job.h
+++ b/net/http/http_stream_factory_impl_job.h
@@ -280,7 +280,7 @@ class HttpStreamFactoryImpl::Job {
ClientSocketPoolManager::SocketGroupType GetSocketGroup() const;
- void MaybeCopyConnectionAttemptsFromClientSocketHandleToRequest();
+ void MaybeCopyConnectionAttemptsFromSocketOrHandle();
// Record histograms of latency until Connect() completes.
static void LogHttpConnectedMetrics(const ClientSocketHandle& handle);
diff --git a/net/server/http_server_unittest.cc b/net/server/http_server_unittest.cc
index a6070e8..c2426a3 100644
--- a/net/server/http_server_unittest.cc
+++ b/net/server/http_server_unittest.cc
@@ -497,6 +497,11 @@ class MockStreamSocket : public StreamSocket {
bool WasNpnNegotiated() const override { return false; }
NextProto GetNegotiatedProtocol() const override { return kProtoUnknown; }
bool GetSSLInfo(SSLInfo* ssl_info) override { return false; }
+ void GetConnectionAttempts(ConnectionAttempts* out) const override {
+ out->clear();
+ }
+ void ClearConnectionAttempts() override {}
+ void AddConnectionAttempts(const ConnectionAttempts& attempts) override {}
// Socket
int Read(IOBuffer* buf,
diff --git a/net/socket/client_socket_handle.h b/net/socket/client_socket_handle.h
index 58cf4ca..2f8bed2 100644
--- a/net/socket/client_socket_handle.h
+++ b/net/socket/client_socket_handle.h
@@ -156,6 +156,9 @@ class NET_EXPORT ClientSocketHandle {
ClientSocketHandle* release_pending_http_proxy_connection() {
return pending_http_proxy_connection_.release();
}
+ // If the connection failed, returns the connection attempts made. (If it
+ // succeeded, they will be returned through the socket instead; see
+ // |StreamSocket::GetConnectionAttempts|.)
const ConnectionAttempts& connection_attempts() {
return connection_attempts_;
}
diff --git a/net/socket/client_socket_pool_base.cc b/net/socket/client_socket_pool_base.cc
index a1080c2..c210e69 100644
--- a/net/socket/client_socket_pool_base.cc
+++ b/net/socket/client_socket_pool_base.cc
@@ -489,6 +489,12 @@ bool ClientSocketPoolBaseHelper::AssignIdleSocketToRequest(
idle_socket.socket->WasEverUsed() ?
ClientSocketHandle::REUSED_IDLE :
ClientSocketHandle::UNUSED_IDLE;
+
+ // If this socket took multiple attempts to obtain, don't report those
+ // every time it's reused, just to the first user.
+ if (idle_socket.socket->WasEverUsed())
+ idle_socket.socket->ClearConnectionAttempts();
+
HandOutSocket(
scoped_ptr<StreamSocket>(idle_socket.socket),
reuse_type,
diff --git a/net/socket/client_socket_pool_base_unittest.cc b/net/socket/client_socket_pool_base_unittest.cc
index 087db23..cfa9c6e 100644
--- a/net/socket/client_socket_pool_base_unittest.cc
+++ b/net/socket/client_socket_pool_base_unittest.cc
@@ -177,6 +177,11 @@ class MockClientSocket : public StreamSocket {
bool WasNpnNegotiated() const override { return false; }
NextProto GetNegotiatedProtocol() const override { return kProtoUnknown; }
bool GetSSLInfo(SSLInfo* ssl_info) override { return false; }
+ void GetConnectionAttempts(ConnectionAttempts* out) const override {
+ out->clear();
+ }
+ void ClearConnectionAttempts() override {}
+ void AddConnectionAttempts(const ConnectionAttempts& attempts) override {}
private:
bool connected_;
diff --git a/net/socket/connection_attempts.h b/net/socket/connection_attempts.h
index 241ffb0..185defa 100644
--- a/net/socket/connection_attempts.h
+++ b/net/socket/connection_attempts.h
@@ -22,6 +22,8 @@ struct ConnectionAttempt {
int result;
};
+// Multiple connection attempts, as might be tracked in an HttpTransaction or a
+// URLRequest. Order is insignificant.
typedef std::vector<ConnectionAttempt> ConnectionAttempts;
} // namespace net
diff --git a/net/socket/socket_test_util.cc b/net/socket/socket_test_util.cc
index cf033c2..c5861faa 100644
--- a/net/socket/socket_test_util.cc
+++ b/net/socket/socket_test_util.cc
@@ -1006,6 +1006,10 @@ const BoundNetLog& MockClientSocket::NetLog() const {
return net_log_;
}
+void MockClientSocket::GetConnectionAttempts(ConnectionAttempts* out) const {
+ out->clear();
+}
+
void MockClientSocket::GetSSLCertRequestInfo(
SSLCertRequestInfo* cert_request_info) {
}
@@ -1148,6 +1152,22 @@ int MockTCPClientSocket::Write(IOBuffer* buf, int buf_len,
return write_result.result;
}
+void MockTCPClientSocket::GetConnectionAttempts(ConnectionAttempts* out) const {
+ int connect_result = data_->connect_data().result;
+
+ out->clear();
+ if (connected_ && connect_result != OK)
+ out->push_back(ConnectionAttempt(addresses_[0], connect_result));
+}
+
+void MockTCPClientSocket::ClearConnectionAttempts() {
+ NOTIMPLEMENTED();
+}
+
+void MockTCPClientSocket::AddConnectionAttempts(const ConnectionAttempts& in) {
+ NOTIMPLEMENTED();
+}
+
int MockTCPClientSocket::Connect(const CompletionCallback& callback) {
if (connected_)
return OK;
diff --git a/net/socket/socket_test_util.h b/net/socket/socket_test_util.h
index 3bd88d2..b7d090e 100644
--- a/net/socket/socket_test_util.h
+++ b/net/socket/socket_test_util.h
@@ -779,6 +779,9 @@ class MockClientSocket : public SSLClientSocket {
const BoundNetLog& NetLog() const override;
void SetSubresourceSpeculation() override {}
void SetOmniboxSpeculation() override {}
+ void GetConnectionAttempts(ConnectionAttempts* out) const override;
+ void ClearConnectionAttempts() override {}
+ void AddConnectionAttempts(const ConnectionAttempts& attempts) override {}
// SSLClientSocket implementation.
void GetSSLCertRequestInfo(SSLCertRequestInfo* cert_request_info) override;
@@ -841,6 +844,9 @@ class MockTCPClientSocket : public MockClientSocket, public AsyncSocket {
bool UsingTCPFastOpen() const override;
bool WasNpnNegotiated() const override;
bool GetSSLInfo(SSLInfo* ssl_info) override;
+ void GetConnectionAttempts(ConnectionAttempts* out) const override;
+ void ClearConnectionAttempts() override;
+ void AddConnectionAttempts(const ConnectionAttempts& attempts) override;
// AsyncSocket:
void OnReadComplete(const MockRead& data) override;
diff --git a/net/socket/socks5_client_socket.cc b/net/socket/socks5_client_socket.cc
index e43cde6..4ac9ca5 100644
--- a/net/socket/socks5_client_socket.cc
+++ b/net/socket/socks5_client_socket.cc
@@ -144,7 +144,10 @@ bool SOCKS5ClientSocket::GetSSLInfo(SSLInfo* ssl_info) {
}
NOTREACHED();
return false;
+}
+void SOCKS5ClientSocket::GetConnectionAttempts(ConnectionAttempts* out) const {
+ out->clear();
}
// Read is called by the transport layer above to read. This can only be done
diff --git a/net/socket/socks5_client_socket.h b/net/socket/socks5_client_socket.h
index 59f481b..d54e790 100644
--- a/net/socket/socks5_client_socket.h
+++ b/net/socket/socks5_client_socket.h
@@ -55,6 +55,9 @@ class NET_EXPORT_PRIVATE SOCKS5ClientSocket : public StreamSocket {
bool WasNpnNegotiated() const override;
NextProto GetNegotiatedProtocol() const override;
bool GetSSLInfo(SSLInfo* ssl_info) override;
+ void GetConnectionAttempts(ConnectionAttempts* out) const override;
+ void ClearConnectionAttempts() override {}
+ void AddConnectionAttempts(const ConnectionAttempts& attempts) override {}
// Socket implementation.
int Read(IOBuffer* buf,
diff --git a/net/socket/socks_client_socket.cc b/net/socket/socks_client_socket.cc
index fd16f83..dbdc0251 100644
--- a/net/socket/socks_client_socket.cc
+++ b/net/socket/socks_client_socket.cc
@@ -172,7 +172,10 @@ bool SOCKSClientSocket::GetSSLInfo(SSLInfo* ssl_info) {
}
NOTREACHED();
return false;
+}
+void SOCKSClientSocket::GetConnectionAttempts(ConnectionAttempts* out) const {
+ out->clear();
}
// Read is called by the transport layer above to read. This can only be done
diff --git a/net/socket/socks_client_socket.h b/net/socket/socks_client_socket.h
index 66fab45..ee2918a 100644
--- a/net/socket/socks_client_socket.h
+++ b/net/socket/socks_client_socket.h
@@ -52,6 +52,9 @@ class NET_EXPORT_PRIVATE SOCKSClientSocket : public StreamSocket {
bool WasNpnNegotiated() const override;
NextProto GetNegotiatedProtocol() const override;
bool GetSSLInfo(SSLInfo* ssl_info) override;
+ void GetConnectionAttempts(ConnectionAttempts* out) const override;
+ void ClearConnectionAttempts() override {}
+ void AddConnectionAttempts(const ConnectionAttempts& attempts) override {}
// Socket implementation.
int Read(IOBuffer* buf,
diff --git a/net/socket/ssl_client_socket_nss.cc b/net/socket/ssl_client_socket_nss.cc
index 4d90751..229735b 100644
--- a/net/socket/ssl_client_socket_nss.cc
+++ b/net/socket/ssl_client_socket_nss.cc
@@ -2491,6 +2491,10 @@ bool SSLClientSocketNSS::GetSSLInfo(SSLInfo* ssl_info) {
return true;
}
+void SSLClientSocketNSS::GetConnectionAttempts(ConnectionAttempts* out) const {
+ out->clear();
+}
+
void SSLClientSocketNSS::GetSSLCertRequestInfo(
SSLCertRequestInfo* cert_request_info) {
EnterFunction("");
diff --git a/net/socket/ssl_client_socket_nss.h b/net/socket/ssl_client_socket_nss.h
index 97bcb032..72fa9d2 100644
--- a/net/socket/ssl_client_socket_nss.h
+++ b/net/socket/ssl_client_socket_nss.h
@@ -92,6 +92,9 @@ class SSLClientSocketNSS : public SSLClientSocket {
bool WasEverUsed() const override;
bool UsingTCPFastOpen() const override;
bool GetSSLInfo(SSLInfo* ssl_info) override;
+ void GetConnectionAttempts(ConnectionAttempts* out) const override;
+ void ClearConnectionAttempts() override {}
+ void AddConnectionAttempts(const ConnectionAttempts& attempts) override {}
// Socket implementation.
int Read(IOBuffer* buf,
diff --git a/net/socket/ssl_client_socket_openssl.cc b/net/socket/ssl_client_socket_openssl.cc
index e019b1e..9b1ce38 100644
--- a/net/socket/ssl_client_socket_openssl.cc
+++ b/net/socket/ssl_client_socket_openssl.cc
@@ -621,6 +621,11 @@ bool SSLClientSocketOpenSSL::GetSSLInfo(SSLInfo* ssl_info) {
return true;
}
+void SSLClientSocketOpenSSL::GetConnectionAttempts(
+ ConnectionAttempts* out) const {
+ out->clear();
+}
+
int SSLClientSocketOpenSSL::Read(IOBuffer* buf,
int buf_len,
const CompletionCallback& callback) {
diff --git a/net/socket/ssl_client_socket_openssl.h b/net/socket/ssl_client_socket_openssl.h
index 3f13aa6..c78a815 100644
--- a/net/socket/ssl_client_socket_openssl.h
+++ b/net/socket/ssl_client_socket_openssl.h
@@ -85,6 +85,9 @@ class SSLClientSocketOpenSSL : public SSLClientSocket {
bool WasEverUsed() const override;
bool UsingTCPFastOpen() const override;
bool GetSSLInfo(SSLInfo* ssl_info) override;
+ void GetConnectionAttempts(ConnectionAttempts* out) const override;
+ void ClearConnectionAttempts() override {}
+ void AddConnectionAttempts(const ConnectionAttempts& attempts) override {}
// Socket implementation.
int Read(IOBuffer* buf,
diff --git a/net/socket/ssl_client_socket_unittest.cc b/net/socket/ssl_client_socket_unittest.cc
index 19e5e8d..0a7b711 100644
--- a/net/socket/ssl_client_socket_unittest.cc
+++ b/net/socket/ssl_client_socket_unittest.cc
@@ -108,6 +108,15 @@ class WrappedStreamSocket : public StreamSocket {
bool GetSSLInfo(SSLInfo* ssl_info) override {
return transport_->GetSSLInfo(ssl_info);
}
+ void GetConnectionAttempts(ConnectionAttempts* out) const override {
+ transport_->GetConnectionAttempts(out);
+ }
+ void ClearConnectionAttempts() override {
+ transport_->ClearConnectionAttempts();
+ }
+ void AddConnectionAttempts(const ConnectionAttempts& attempts) override {
+ transport_->AddConnectionAttempts(attempts);
+ }
// Socket implementation:
int Read(IOBuffer* buf,
diff --git a/net/socket/ssl_server_socket_nss.cc b/net/socket/ssl_server_socket_nss.cc
index cdc0e67..6f505aff 100644
--- a/net/socket/ssl_server_socket_nss.cc
+++ b/net/socket/ssl_server_socket_nss.cc
@@ -307,6 +307,10 @@ bool SSLServerSocketNSS::GetSSLInfo(SSLInfo* ssl_info) {
return false;
}
+void SSLServerSocketNSS::GetConnectionAttempts(ConnectionAttempts* out) const {
+ out->clear();
+}
+
int SSLServerSocketNSS::InitializeSSLOptions() {
// Transport connected, now hook it up to nss
nss_fd_ = memio_CreateIOLayer(kRecvBufferSize, kSendBufferSize);
diff --git a/net/socket/ssl_server_socket_nss.h b/net/socket/ssl_server_socket_nss.h
index e91514a..d1bcec6 100644
--- a/net/socket/ssl_server_socket_nss.h
+++ b/net/socket/ssl_server_socket_nss.h
@@ -66,6 +66,9 @@ class SSLServerSocketNSS : public SSLServerSocket {
bool WasNpnNegotiated() const override;
NextProto GetNegotiatedProtocol() const override;
bool GetSSLInfo(SSLInfo* ssl_info) override;
+ void GetConnectionAttempts(ConnectionAttempts* out) const override;
+ void ClearConnectionAttempts() override {}
+ void AddConnectionAttempts(const ConnectionAttempts& attempts) override {}
private:
enum State {
diff --git a/net/socket/ssl_server_socket_openssl.cc b/net/socket/ssl_server_socket_openssl.cc
index 954e616..5a61eeb 100644
--- a/net/socket/ssl_server_socket_openssl.cc
+++ b/net/socket/ssl_server_socket_openssl.cc
@@ -248,6 +248,11 @@ bool SSLServerSocketOpenSSL::GetSSLInfo(SSLInfo* ssl_info) {
return false;
}
+void SSLServerSocketOpenSSL::GetConnectionAttempts(
+ ConnectionAttempts* out) const {
+ out->clear();
+}
+
void SSLServerSocketOpenSSL::OnSendComplete(int result) {
if (next_handshake_state_ == STATE_HANDSHAKE) {
// In handshake phase.
diff --git a/net/socket/ssl_server_socket_openssl.h b/net/socket/ssl_server_socket_openssl.h
index 5f5909b..34e8bb0 100644
--- a/net/socket/ssl_server_socket_openssl.h
+++ b/net/socket/ssl_server_socket_openssl.h
@@ -68,6 +68,9 @@ class SSLServerSocketOpenSSL : public SSLServerSocket {
bool WasNpnNegotiated() const override;
NextProto GetNegotiatedProtocol() const override;
bool GetSSLInfo(SSLInfo* ssl_info) override;
+ void GetConnectionAttempts(ConnectionAttempts* out) const override;
+ void ClearConnectionAttempts() override {}
+ void AddConnectionAttempts(const ConnectionAttempts& attempts) override {}
private:
enum State {
diff --git a/net/socket/ssl_server_socket_unittest.cc b/net/socket/ssl_server_socket_unittest.cc
index 8af2e01..84663eb 100644
--- a/net/socket/ssl_server_socket_unittest.cc
+++ b/net/socket/ssl_server_socket_unittest.cc
@@ -239,6 +239,14 @@ class FakeSocket : public StreamSocket {
bool GetSSLInfo(SSLInfo* ssl_info) override { return false; }
+ void GetConnectionAttempts(ConnectionAttempts* out) const override {
+ out->clear();
+ }
+
+ void ClearConnectionAttempts() override {}
+
+ void AddConnectionAttempts(const ConnectionAttempts& attempts) override {}
+
private:
BoundNetLog net_log_;
FakeDataChannel* incoming_;
diff --git a/net/socket/stream_socket.h b/net/socket/stream_socket.h
index 30a199e..5669ea3 100644
--- a/net/socket/stream_socket.h
+++ b/net/socket/stream_socket.h
@@ -6,6 +6,7 @@
#define NET_SOCKET_STREAM_SOCKET_H_
#include "net/log/net_log.h"
+#include "net/socket/connection_attempts.h"
#include "net/socket/next_proto.h"
#include "net/socket/socket.h"
@@ -95,6 +96,16 @@ class NET_EXPORT_PRIVATE StreamSocket : public Socket {
// SSL was not used by this socket.
virtual bool GetSSLInfo(SSLInfo* ssl_info) = 0;
+ // Overwrites |out| with the connection attempts made in the process of
+ // connecting this socket.
+ virtual void GetConnectionAttempts(ConnectionAttempts* out) const = 0;
+
+ // Clears the socket's list of connection attempts.
+ virtual void ClearConnectionAttempts() = 0;
+
+ // Adds |attempts| to the socket's list of connection attempts.
+ virtual void AddConnectionAttempts(const ConnectionAttempts& attempts) = 0;
+
protected:
// The following class is only used to gather statistics about the history of
// a socket. It is only instantiated and used in basic sockets, such as
diff --git a/net/socket/tcp_client_socket.cc b/net/socket/tcp_client_socket.cc
index 4a72bdf..a1c1fad 100644
--- a/net/socket/tcp_client_socket.cc
+++ b/net/socket/tcp_client_socket.cc
@@ -124,6 +124,7 @@ int TCPClientSocket::DoConnect() {
if (previously_disconnected_) {
use_history_.Reset();
+ connection_attempts_.clear();
previously_disconnected_ = false;
}
@@ -159,6 +160,9 @@ int TCPClientSocket::DoConnectComplete(int result) {
return OK; // Done!
}
+ connection_attempts_.push_back(
+ ConnectionAttempt(addresses_[current_address_index_], result));
+
// Close whatever partially connected socket we currently have.
DoDisconnect();
@@ -296,6 +300,20 @@ bool TCPClientSocket::SetNoDelay(bool no_delay) {
return socket_->SetNoDelay(no_delay);
}
+void TCPClientSocket::GetConnectionAttempts(ConnectionAttempts* out) const {
+ *out = connection_attempts_;
+}
+
+void TCPClientSocket::ClearConnectionAttempts() {
+ connection_attempts_.clear();
+}
+
+void TCPClientSocket::AddConnectionAttempts(
+ const ConnectionAttempts& attempts) {
+ connection_attempts_.insert(connection_attempts_.begin(), attempts.begin(),
+ attempts.end());
+}
+
void TCPClientSocket::DidCompleteConnect(int result) {
DCHECK_EQ(next_connect_state_, CONNECT_STATE_CONNECT_COMPLETE);
DCHECK_NE(result, ERR_IO_PENDING);
diff --git a/net/socket/tcp_client_socket.h b/net/socket/tcp_client_socket.h
index e1b3fa0..0b8062b 100644
--- a/net/socket/tcp_client_socket.h
+++ b/net/socket/tcp_client_socket.h
@@ -12,6 +12,7 @@
#include "net/base/completion_callback.h"
#include "net/base/net_export.h"
#include "net/log/net_log.h"
+#include "net/socket/connection_attempts.h"
#include "net/socket/stream_socket.h"
#include "net/socket/tcp_socket.h"
@@ -69,6 +70,10 @@ class NET_EXPORT TCPClientSocket : public StreamSocket {
virtual bool SetKeepAlive(bool enable, int delay);
virtual bool SetNoDelay(bool no_delay);
+ void GetConnectionAttempts(ConnectionAttempts* out) const override;
+ void ClearConnectionAttempts() override;
+ void AddConnectionAttempts(const ConnectionAttempts& attempts) override;
+
private:
// State machine for connecting the socket.
enum ConnectState {
@@ -116,6 +121,9 @@ class NET_EXPORT TCPClientSocket : public StreamSocket {
// histograms.
UseHistory use_history_;
+ // Failed connection attempts made while trying to connect this socket.
+ ConnectionAttempts connection_attempts_;
+
DISALLOW_COPY_AND_ASSIGN(TCPClientSocket);
};
diff --git a/net/socket/transport_client_socket_pool.cc b/net/socket/transport_client_socket_pool.cc
index b728cb9..a5f8adb 100644
--- a/net/socket/transport_client_socket_pool.cc
+++ b/net/socket/transport_client_socket_pool.cc
@@ -208,8 +208,7 @@ TransportConnectJob::TransportConnectJob(
BoundNetLog::Make(net_log, NetLog::SOURCE_CONNECT_JOB)),
helper_(params, client_socket_factory, host_resolver, &connect_timing_),
interval_between_connects_(CONNECT_INTERVAL_GT_20MS),
- resolve_result_(OK),
- connect_result_(OK) {
+ resolve_result_(OK) {
helper_.SetOnIOComplete(this);
}
@@ -235,18 +234,16 @@ LoadState TransportConnectJob::GetLoadState() const {
void TransportConnectJob::GetAdditionalErrorState(ClientSocketHandle* handle) {
// If hostname resolution failed, record an empty endpoint and the result.
- // If the actual socket Connect call failed, record the result and the last
- // address attempted.
- // TODO(ttuttle): Plumb into the socket layer and record *all* attempts.
+ // Also record any attempts made on either of the sockets.
ConnectionAttempts attempts;
if (resolve_result_ != OK) {
DCHECK_EQ(0u, helper_.addresses().size());
attempts.push_back(ConnectionAttempt(IPEndPoint(), resolve_result_));
- } else if (connect_result_ != OK) {
- DCHECK_LT(0u, helper_.addresses().size());
- attempts.push_back(
- ConnectionAttempt(helper_.addresses().back(), connect_result_));
}
+ attempts.insert(attempts.begin(), connection_attempts_.begin(),
+ connection_attempts_.end());
+ attempts.insert(attempts.begin(), fallback_connection_attempts_.begin(),
+ fallback_connection_attempts_.end());
handle->set_connection_attempts(attempts);
}
@@ -330,6 +327,16 @@ int TransportConnectJob::DoTransportConnect() {
int TransportConnectJob::DoTransportConnectComplete(int result) {
if (result == OK) {
+ // Success will be returned via the main socket, so also include connection
+ // attempts made on the fallback socket up to this point. (Unfortunately,
+ // the only simple way to return information in the success case is through
+ // the successfully-connected socket.)
+ if (fallback_transport_socket_) {
+ ConnectionAttempts fallback_attempts;
+ fallback_transport_socket_->GetConnectionAttempts(&fallback_attempts);
+ transport_socket_->AddConnectionAttempts(fallback_attempts);
+ }
+
bool is_ipv4 =
helper_.addresses().front().GetFamily() == ADDRESS_FAMILY_IPV4;
TransportConnectJobHelper::ConnectionLatencyHistogram race_result =
@@ -378,12 +385,17 @@ int TransportConnectJob::DoTransportConnectComplete(int result) {
SetSocket(transport_socket_.Pass());
fallback_timer_.Stop();
} else {
+ // Failure will be returned via |GetAdditionalErrorState|, so save
+ // connection attempts from both sockets for use there.
+ CopyConnectionAttemptsFromSockets();
+
// Be a bit paranoid and kill off the fallback members to prevent reuse.
fallback_transport_socket_.reset();
fallback_addresses_.reset();
}
- connect_result_ = result;
+ // N.B.: The owner of the ConnectJob will delete it after the callback is
+ // called, so the fallback socket, if any, won't stick around for long.
return result;
}
@@ -428,6 +440,17 @@ void TransportConnectJob::DoIPv6FallbackTransportConnectComplete(int result) {
if (result == OK) {
DCHECK(!fallback_connect_start_time_.is_null());
+
+ // Success will be returned via the fallback socket, so also include
+ // connection attempts made on the main socket up to this point.
+ // (Unfortunately, the only simple way to return information in the success
+ // case is through the successfully-connected socket.)
+ if (transport_socket_) {
+ ConnectionAttempts attempts;
+ transport_socket_->GetConnectionAttempts(&attempts);
+ fallback_transport_socket_->AddConnectionAttempts(attempts);
+ }
+
connect_timing_.connect_start = fallback_connect_start_time_;
helper_.HistogramDuration(
TransportConnectJobHelper::CONNECTION_LATENCY_IPV4_WINS_RACE);
@@ -435,10 +458,18 @@ void TransportConnectJob::DoIPv6FallbackTransportConnectComplete(int result) {
helper_.set_next_state(TransportConnectJobHelper::STATE_NONE);
transport_socket_.reset();
} else {
+ // Failure will be returned via |GetAdditionalErrorState|, so save
+ // connection attempts from both sockets for use there.
+ CopyConnectionAttemptsFromSockets();
+
// Be a bit paranoid and kill off the fallback members to prevent reuse.
fallback_transport_socket_.reset();
fallback_addresses_.reset();
}
+
+ // N.B.: The owner of the ConnectJob will delete it after the callback is
+ // called, so the main socket, if any, won't stick around for long.
+
NotifyDelegateOfCompletion(result); // Deletes |this|
}
@@ -446,6 +477,15 @@ int TransportConnectJob::ConnectInternal() {
return helper_.DoConnectInternal(this);
}
+void TransportConnectJob::CopyConnectionAttemptsFromSockets() {
+ if (transport_socket_)
+ transport_socket_->GetConnectionAttempts(&connection_attempts_);
+ if (fallback_transport_socket_) {
+ fallback_transport_socket_->GetConnectionAttempts(
+ &fallback_connection_attempts_);
+ }
+}
+
scoped_ptr<ConnectJob>
TransportClientSocketPool::TransportConnectJobFactory::NewConnectJob(
const std::string& group_name,
diff --git a/net/socket/transport_client_socket_pool.h b/net/socket/transport_client_socket_pool.h
index de57d18..c2c8ab2 100644
--- a/net/socket/transport_client_socket_pool.h
+++ b/net/socket/transport_client_socket_pool.h
@@ -17,6 +17,7 @@
#include "net/dns/single_request_host_resolver.h"
#include "net/socket/client_socket_pool.h"
#include "net/socket/client_socket_pool_base.h"
+#include "net/socket/connection_attempts.h"
namespace net {
@@ -196,6 +197,8 @@ class NET_EXPORT_PRIVATE TransportConnectJob : public ConnectJob {
// Otherwise, it returns a net error code.
int ConnectInternal() override;
+ void CopyConnectionAttemptsFromSockets();
+
TransportConnectJobHelper helper_;
scoped_ptr<StreamSocket> transport_socket_;
@@ -209,7 +212,14 @@ class NET_EXPORT_PRIVATE TransportConnectJob : public ConnectJob {
ConnectInterval interval_between_connects_;
int resolve_result_;
- int connect_result_;
+
+ // Used in the failure case to save connection attempts made on the main and
+ // fallback sockets and pass them on in |GetAdditionalErrorState|. (In the
+ // success case, connection attempts are passed through the returned socket;
+ // attempts are copied from the other socket, if one exists, into it before
+ // it is returned.)
+ ConnectionAttempts connection_attempts_;
+ ConnectionAttempts fallback_connection_attempts_;
DISALLOW_COPY_AND_ASSIGN(TransportConnectJob);
};
diff --git a/net/socket/transport_client_socket_pool_test_util.cc b/net/socket/transport_client_socket_pool_test_util.cc
index 82ed8e6..352fd87 100644
--- a/net/socket/transport_client_socket_pool_test_util.cc
+++ b/net/socket/transport_client_socket_pool_test_util.cc
@@ -69,6 +69,11 @@ class MockConnectClientSocket : public StreamSocket {
bool WasNpnNegotiated() const override { return false; }
NextProto GetNegotiatedProtocol() const override { return kProtoUnknown; }
bool GetSSLInfo(SSLInfo* ssl_info) override { return false; }
+ void GetConnectionAttempts(ConnectionAttempts* out) const override {
+ out->clear();
+ }
+ void ClearConnectionAttempts() override {}
+ void AddConnectionAttempts(const ConnectionAttempts& attempts) override {}
// Socket implementation.
int Read(IOBuffer* buf,
@@ -125,6 +130,13 @@ class MockFailingClientSocket : public StreamSocket {
bool WasNpnNegotiated() const override { return false; }
NextProto GetNegotiatedProtocol() const override { return kProtoUnknown; }
bool GetSSLInfo(SSLInfo* ssl_info) override { return false; }
+ void GetConnectionAttempts(ConnectionAttempts* out) const override {
+ out->clear();
+ for (const auto& addr : addrlist_)
+ out->push_back(ConnectionAttempt(addr, ERR_CONNECTION_FAILED));
+ }
+ void ClearConnectionAttempts() override {}
+ void AddConnectionAttempts(const ConnectionAttempts& attempts) override {}
// Socket implementation.
int Read(IOBuffer* buf,
@@ -196,9 +208,16 @@ class MockTriggerableClientSocket : public StreamSocket {
static scoped_ptr<StreamSocket> MakeMockStalledClientSocket(
const AddressList& addrlist,
- net::NetLog* net_log) {
+ net::NetLog* net_log,
+ bool failing) {
scoped_ptr<MockTriggerableClientSocket> socket(
new MockTriggerableClientSocket(addrlist, true, net_log));
+ if (failing) {
+ DCHECK_LE(1u, addrlist.size());
+ ConnectionAttempts attempts;
+ attempts.push_back(ConnectionAttempt(addrlist[0], ERR_CONNECTION_FAILED));
+ socket->AddConnectionAttempts(attempts);
+ }
return socket.Pass();
}
@@ -236,6 +255,14 @@ class MockTriggerableClientSocket : public StreamSocket {
bool WasNpnNegotiated() const override { return false; }
NextProto GetNegotiatedProtocol() const override { return kProtoUnknown; }
bool GetSSLInfo(SSLInfo* ssl_info) override { return false; }
+ void GetConnectionAttempts(ConnectionAttempts* out) const override {
+ *out = connection_attempts_;
+ }
+ void ClearConnectionAttempts() override { connection_attempts_.clear(); }
+ void AddConnectionAttempts(const ConnectionAttempts& attempts) override {
+ connection_attempts_.insert(connection_attempts_.begin(), attempts.begin(),
+ attempts.end());
+ }
// Socket implementation.
int Read(IOBuffer* buf,
@@ -264,6 +291,7 @@ class MockTriggerableClientSocket : public StreamSocket {
BoundNetLog net_log_;
CompletionCallback callback_;
bool use_tcp_fastopen_;
+ ConnectionAttempts connection_attempts_;
base::WeakPtrFactory<MockTriggerableClientSocket> weak_factory_;
@@ -364,8 +392,11 @@ MockTransportClientSocketFactory::CreateTransportClientSocket(
return MockTriggerableClientSocket::MakeMockDelayedClientSocket(
addresses, false, delay_, net_log_);
case MOCK_STALLED_CLIENT_SOCKET:
- return MockTriggerableClientSocket::MakeMockStalledClientSocket(addresses,
- net_log_);
+ return MockTriggerableClientSocket::MakeMockStalledClientSocket(
+ addresses, net_log_, false);
+ case MOCK_STALLED_FAILING_CLIENT_SOCKET:
+ return MockTriggerableClientSocket::MakeMockStalledClientSocket(
+ addresses, net_log_, true);
case MOCK_TRIGGERABLE_CLIENT_SOCKET: {
scoped_ptr<MockTriggerableClientSocket> rv(
new MockTriggerableClientSocket(addresses, true, net_log_));
diff --git a/net/socket/transport_client_socket_pool_test_util.h b/net/socket/transport_client_socket_pool_test_util.h
index 7b0daa3..6e38af6 100644
--- a/net/socket/transport_client_socket_pool_test_util.h
+++ b/net/socket/transport_client_socket_pool_test_util.h
@@ -62,6 +62,9 @@ class MockTransportClientSocketFactory : public ClientSocketFactory {
MOCK_DELAYED_FAILING_CLIENT_SOCKET,
// A stalled socket that never connects at all.
MOCK_STALLED_CLIENT_SOCKET,
+ // A stalled socket that never connects at all, but returns a failing
+ // ConnectionAttempt in |GetConnectionAttempts|.
+ MOCK_STALLED_FAILING_CLIENT_SOCKET,
// A socket that can be triggered to connect explicitly, asynchronously.
MOCK_TRIGGERABLE_CLIENT_SOCKET,
};
diff --git a/net/socket/transport_client_socket_pool_unittest.cc b/net/socket/transport_client_socket_pool_unittest.cc
index dbfc506..1a00d46 100644
--- a/net/socket/transport_client_socket_pool_unittest.cc
+++ b/net/socket/transport_client_socket_pool_unittest.cc
@@ -776,6 +776,8 @@ TEST_F(TransportClientSocketPoolTest, BackupSocketFailAfterStall) {
EXPECT_EQ(ERR_CONNECTION_FAILED, callback.WaitForResult());
EXPECT_FALSE(handle.is_initialized());
EXPECT_FALSE(handle.socket());
+ ASSERT_EQ(1u, handle.connection_attempts().size());
+ EXPECT_EQ(ERR_CONNECTION_FAILED, handle.connection_attempts()[0].result);
EXPECT_EQ(0, pool_.IdleSocketCount());
handle.Reset();
@@ -824,6 +826,8 @@ TEST_F(TransportClientSocketPoolTest, BackupSocketFailAfterDelay) {
EXPECT_EQ(ERR_CONNECTION_FAILED, callback.WaitForResult());
EXPECT_FALSE(handle.is_initialized());
EXPECT_FALSE(handle.socket());
+ ASSERT_EQ(1u, handle.connection_attempts().size());
+ EXPECT_EQ(ERR_CONNECTION_FAILED, handle.connection_attempts()[0].result);
handle.Reset();
// Reset for the next case.
@@ -842,11 +846,11 @@ TEST_F(TransportClientSocketPoolTest, IPv6FallbackSocketIPv4FinishesFirst) {
NULL);
MockTransportClientSocketFactory::ClientSocketType case_types[] = {
- // This is the IPv6 socket.
- MockTransportClientSocketFactory::MOCK_STALLED_CLIENT_SOCKET,
- // This is the IPv4 socket.
- MockTransportClientSocketFactory::MOCK_PENDING_CLIENT_SOCKET
- };
+ // This is the IPv6 socket. It stalls, but presents one failed connection
+ // attempt on GetConnectionAttempts.
+ MockTransportClientSocketFactory::MOCK_STALLED_FAILING_CLIENT_SOCKET,
+ // This is the IPv4 socket.
+ MockTransportClientSocketFactory::MOCK_PENDING_CLIENT_SOCKET};
client_socket_factory_.set_client_socket_types(case_types, 2);
@@ -868,6 +872,14 @@ TEST_F(TransportClientSocketPoolTest, IPv6FallbackSocketIPv4FinishesFirst) {
IPEndPoint endpoint;
handle.socket()->GetLocalAddress(&endpoint);
EXPECT_EQ(kIPv4AddressSize, endpoint.address().size());
+
+ // Check that the failed connection attempt on the main socket is collected.
+ ConnectionAttempts attempts;
+ handle.socket()->GetConnectionAttempts(&attempts);
+ ASSERT_EQ(1u, attempts.size());
+ EXPECT_EQ(ERR_CONNECTION_FAILED, attempts[0].result);
+ EXPECT_EQ(kIPv6AddressSize, attempts[0].endpoint.address().size());
+
EXPECT_EQ(2, client_socket_factory_.allocation_count());
}
@@ -884,11 +896,11 @@ TEST_F(TransportClientSocketPoolTest, IPv6FallbackSocketIPv6FinishesFirst) {
NULL);
MockTransportClientSocketFactory::ClientSocketType case_types[] = {
- // This is the IPv6 socket.
- MockTransportClientSocketFactory::MOCK_DELAYED_CLIENT_SOCKET,
- // This is the IPv4 socket.
- MockTransportClientSocketFactory::MOCK_STALLED_CLIENT_SOCKET
- };
+ // This is the IPv6 socket.
+ MockTransportClientSocketFactory::MOCK_DELAYED_CLIENT_SOCKET,
+ // This is the IPv4 socket. It stalls, but presents one failed connection
+ // attempt on GetConnectionATtempts.
+ MockTransportClientSocketFactory::MOCK_STALLED_FAILING_CLIENT_SOCKET};
client_socket_factory_.set_client_socket_types(case_types, 2);
client_socket_factory_.set_delay(base::TimeDelta::FromMilliseconds(
@@ -912,6 +924,15 @@ TEST_F(TransportClientSocketPoolTest, IPv6FallbackSocketIPv6FinishesFirst) {
IPEndPoint endpoint;
handle.socket()->GetLocalAddress(&endpoint);
EXPECT_EQ(kIPv6AddressSize, endpoint.address().size());
+
+ // Check that the failed connection attempt on the fallback socket is
+ // collected.
+ ConnectionAttempts attempts;
+ handle.socket()->GetConnectionAttempts(&attempts);
+ ASSERT_EQ(1u, attempts.size());
+ EXPECT_EQ(ERR_CONNECTION_FAILED, attempts[0].result);
+ EXPECT_EQ(kIPv4AddressSize, attempts[0].endpoint.address().size());
+
EXPECT_EQ(2, client_socket_factory_.allocation_count());
}
@@ -945,6 +966,7 @@ TEST_F(TransportClientSocketPoolTest, IPv6NoIPv4AddressesToFallbackTo) {
IPEndPoint endpoint;
handle.socket()->GetLocalAddress(&endpoint);
EXPECT_EQ(kIPv6AddressSize, endpoint.address().size());
+ EXPECT_EQ(0u, handle.connection_attempts().size());
EXPECT_EQ(1, client_socket_factory_.allocation_count());
}
@@ -977,6 +999,7 @@ TEST_F(TransportClientSocketPoolTest, IPv4HasNoFallback) {
IPEndPoint endpoint;
handle.socket()->GetLocalAddress(&endpoint);
EXPECT_EQ(kIPv4AddressSize, endpoint.address().size());
+ EXPECT_EQ(0u, handle.connection_attempts().size());
EXPECT_EQ(1, client_socket_factory_.allocation_count());
}
diff --git a/net/socket/unix_domain_client_socket_posix.cc b/net/socket/unix_domain_client_socket_posix.cc
index 70ad42b..79aa275 100644
--- a/net/socket/unix_domain_client_socket_posix.cc
+++ b/net/socket/unix_domain_client_socket_posix.cc
@@ -150,6 +150,11 @@ bool UnixDomainClientSocket::GetSSLInfo(SSLInfo* ssl_info) {
return false;
}
+void UnixDomainClientSocket::GetConnectionAttempts(
+ ConnectionAttempts* out) const {
+ out->clear();
+}
+
int UnixDomainClientSocket::Read(IOBuffer* buf, int buf_len,
const CompletionCallback& callback) {
DCHECK(socket_);
diff --git a/net/socket/unix_domain_client_socket_posix.h b/net/socket/unix_domain_client_socket_posix.h
index 0ddb9d9..77ef9d5 100644
--- a/net/socket/unix_domain_client_socket_posix.h
+++ b/net/socket/unix_domain_client_socket_posix.h
@@ -55,6 +55,9 @@ class NET_EXPORT UnixDomainClientSocket : public StreamSocket {
bool WasNpnNegotiated() const override;
NextProto GetNegotiatedProtocol() const override;
bool GetSSLInfo(SSLInfo* ssl_info) override;
+ void GetConnectionAttempts(ConnectionAttempts* out) const override;
+ void ClearConnectionAttempts() override {}
+ void AddConnectionAttempts(const ConnectionAttempts& attempts) override {}
// Socket implementation.
int Read(IOBuffer* buf,
diff --git a/net/socket/websocket_endpoint_lock_manager_unittest.cc b/net/socket/websocket_endpoint_lock_manager_unittest.cc
index dbe8494..29fc067 100644
--- a/net/socket/websocket_endpoint_lock_manager_unittest.cc
+++ b/net/socket/websocket_endpoint_lock_manager_unittest.cc
@@ -54,6 +54,14 @@ class FakeStreamSocket : public StreamSocket {
bool GetSSLInfo(SSLInfo* ssl_info) override { return false; }
+ void GetConnectionAttempts(ConnectionAttempts* out) const override {
+ out->clear();
+ }
+
+ void ClearConnectionAttempts() override {}
+
+ void AddConnectionAttempts(const ConnectionAttempts& attempts) override {}
+
// Socket implementation
int Read(IOBuffer* buf,
int buf_len,
diff --git a/net/spdy/spdy_proxy_client_socket.cc b/net/spdy/spdy_proxy_client_socket.cc
index 544b9a1..3f351b2 100644
--- a/net/spdy/spdy_proxy_client_socket.cc
+++ b/net/spdy/spdy_proxy_client_socket.cc
@@ -190,6 +190,11 @@ bool SpdyProxyClientSocket::GetSSLInfo(SSLInfo* ssl_info) {
&protocol_negotiated);
}
+void SpdyProxyClientSocket::GetConnectionAttempts(
+ ConnectionAttempts* out) const {
+ out->clear();
+}
+
int SpdyProxyClientSocket::Read(IOBuffer* buf, int buf_len,
const CompletionCallback& callback) {
DCHECK(read_callback_.is_null());
diff --git a/net/spdy/spdy_proxy_client_socket.h b/net/spdy/spdy_proxy_client_socket.h
index 371182a..30861ee 100644
--- a/net/spdy/spdy_proxy_client_socket.h
+++ b/net/spdy/spdy_proxy_client_socket.h
@@ -73,6 +73,9 @@ class NET_EXPORT_PRIVATE SpdyProxyClientSocket : public ProxyClientSocket,
bool WasNpnNegotiated() const override;
NextProto GetNegotiatedProtocol() const override;
bool GetSSLInfo(SSLInfo* ssl_info) override;
+ void GetConnectionAttempts(ConnectionAttempts* out) const override;
+ void ClearConnectionAttempts() override {}
+ void AddConnectionAttempts(const ConnectionAttempts& attempts) override {}
// Socket implementation.
int Read(IOBuffer* buf,
diff --git a/remoting/protocol/channel_multiplexer.cc b/remoting/protocol/channel_multiplexer.cc
index 832fba3..8cdbf0d 100644
--- a/remoting/protocol/channel_multiplexer.cc
+++ b/remoting/protocol/channel_multiplexer.cc
@@ -165,6 +165,12 @@ class ChannelMultiplexer::MuxSocket : public net::StreamSocket,
NOTIMPLEMENTED();
return false;
}
+ void GetConnectionAttempts(net::ConnectionAttempts* out) const override {
+ out->clear();
+ }
+ void ClearConnectionAttempts() override {}
+ void AddConnectionAttempts(const net::ConnectionAttempts& attempts) override {
+ }
private:
MuxChannel* channel_;
diff --git a/remoting/protocol/fake_stream_socket.cc b/remoting/protocol/fake_stream_socket.cc
index 7e1519a..fc7f31e 100644
--- a/remoting/protocol/fake_stream_socket.cc
+++ b/remoting/protocol/fake_stream_socket.cc
@@ -244,6 +244,12 @@ bool FakeStreamSocket::GetSSLInfo(net::SSLInfo* ssl_info) {
return false;
}
+void FakeStreamSocket::GetConnectionAttempts(
+ net::ConnectionAttempts* out) const {
+ EXPECT_TRUE(task_runner_->BelongsToCurrentThread());
+ out->clear();
+}
+
FakeStreamChannelFactory::FakeStreamChannelFactory()
: task_runner_(base::ThreadTaskRunnerHandle::Get()),
asynchronous_create_(false),
diff --git a/remoting/protocol/fake_stream_socket.h b/remoting/protocol/fake_stream_socket.h
index ac20e38..6bd1cbe 100644
--- a/remoting/protocol/fake_stream_socket.h
+++ b/remoting/protocol/fake_stream_socket.h
@@ -93,6 +93,10 @@ class FakeStreamSocket : public net::StreamSocket {
bool WasNpnNegotiated() const override;
net::NextProto GetNegotiatedProtocol() const override;
bool GetSSLInfo(net::SSLInfo* ssl_info) override;
+ void GetConnectionAttempts(net::ConnectionAttempts* out) const override;
+ void ClearConnectionAttempts() override {}
+ void AddConnectionAttempts(const net::ConnectionAttempts& attempts) override {
+ }
private:
void DoAsyncWrite(scoped_refptr<net::IOBuffer> buf, int buf_len,