Commit 23fdb7b4 authored by ttuttle's avatar ttuttle Committed by Commit bot

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}
parent c0c82849
......@@ -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;
......
......@@ -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);
......
......@@ -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,
......
......@@ -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);
......
......@@ -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,
......
......@@ -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
......@@ -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 {
......
......@@ -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
......
......@@ -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();
......
......@@ -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.
......
......@@ -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);
......
......@@ -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);
......
......@@ -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());
......
......@@ -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,
......
......@@ -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
......@@ -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);
......
......@@ -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,
......
......@@ -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_;
}
......
......@@ -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,
......
......@@ -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_;
......
......@@ -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
......
......@@ -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;
......
......@@ -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;
......
......@@ -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
......
......@@ -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,
......
......@@ -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
......
......@@ -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,
......
......@@ -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("");
......
......@@ -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,
......
......@@ -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) {
......
......@@ -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,
......
......@@ -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,
......
......@@ -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);
......
......@@ -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 {
......
......@@ -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.
......
......@@ -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 {
......
......@@ -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_;
......
......@@ -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
......
......@@ -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);
......
......@@ -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);
};
......
......@@ -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