summaryrefslogtreecommitdiffstats
path: root/net/socket
diff options
context:
space:
mode:
authorgagansingh@google.com <gagansingh@google.com@0039d316-1c4b-4281-b951-d872f2087c98>2011-06-24 16:47:06 +0000
committergagansingh@google.com <gagansingh@google.com@0039d316-1c4b-4281-b951-d872f2087c98>2011-06-24 16:47:06 +0000
commit0ca76cb6e3d1ca12d55bab9900a8f0a650c6db09 (patch)
treef03dd8bc67014c738f70a1c1bb20f62af72902e6 /net/socket
parent591805d2915ce33ccd61eb624924f14f95b5c15d (diff)
downloadchromium_src-0ca76cb6e3d1ca12d55bab9900a8f0a650c6db09.zip
chromium_src-0ca76cb6e3d1ca12d55bab9900a8f0a650c6db09.tar.gz
chromium_src-0ca76cb6e3d1ca12d55bab9900a8f0a650c6db09.tar.bz2
Warmth of a connection (cwnd) is estimated by the amount of data written to the socket.
Choosing the warmest connection would mean faster resource load times. idle time is the time a socket has remained idle (no http requests being served on it). Probability of server resetting a connection increases with idle time duration. Using a cost function that takes into account bytes transferred and idle time to pick best connection to schedule http requests on. CODEREVIEW done in http://codereview.chromium.org/6990036/ Contributed by gagansingh@google.com Review URL: http://codereview.chromium.org/7189055 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@90373 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'net/socket')
-rw-r--r--net/socket/client_socket_pool_base.cc44
-rw-r--r--net/socket/client_socket_pool_base.h18
-rw-r--r--net/socket/client_socket_pool_base_unittest.cc84
-rw-r--r--net/socket/socket_test_util.cc29
-rw-r--r--net/socket/socket_test_util.h7
-rw-r--r--net/socket/socks5_client_socket.cc18
-rw-r--r--net/socket/socks5_client_socket.h2
-rw-r--r--net/socket/socks_client_socket.cc16
-rw-r--r--net/socket/socks_client_socket.h2
-rw-r--r--net/socket/ssl_client_socket_mac.cc16
-rw-r--r--net/socket/ssl_client_socket_mac.h2
-rw-r--r--net/socket/ssl_client_socket_nss.cc16
-rw-r--r--net/socket/ssl_client_socket_nss.h2
-rw-r--r--net/socket/ssl_client_socket_win.cc16
-rw-r--r--net/socket/ssl_client_socket_win.h2
-rw-r--r--net/socket/ssl_server_socket_nss.cc8
-rw-r--r--net/socket/ssl_server_socket_nss.h2
-rw-r--r--net/socket/ssl_server_socket_unittest.cc8
-rw-r--r--net/socket/stream_socket.h7
-rw-r--r--net/socket/tcp_client_socket_libevent.cc15
-rw-r--r--net/socket/tcp_client_socket_libevent.h6
-rw-r--r--net/socket/tcp_client_socket_win.cc15
-rw-r--r--net/socket/tcp_client_socket_win.h6
-rw-r--r--net/socket/transport_client_socket_pool_unittest.cc12
-rw-r--r--net/socket/transport_client_socket_unittest.cc9
25 files changed, 353 insertions, 9 deletions
diff --git a/net/socket/client_socket_pool_base.cc b/net/socket/client_socket_pool_base.cc
index ddcbba6..d39890b 100644
--- a/net/socket/client_socket_pool_base.cc
+++ b/net/socket/client_socket_pool_base.cc
@@ -4,11 +4,14 @@
#include "net/socket/client_socket_pool_base.h"
+#include <math.h>
#include "base/compiler_specific.h"
#include "base/format_macros.h"
+#include "base/logging.h"
#include "base/message_loop.h"
#include "base/metrics/stats_counters.h"
#include "base/stl_util-inl.h"
+#include "base/string_number_conversions.h"
#include "base/string_util.h"
#include "base/time.h"
#include "base/values.h"
@@ -32,10 +35,33 @@ const int kCleanupInterval = 10; // DO NOT INCREASE THIS TIMEOUT.
// after a certain timeout has passed without receiving an ACK.
bool g_connect_backup_jobs_enabled = true;
+double g_socket_reuse_policy_penalty_exponent = -1;
+int g_socket_reuse_policy = -1;
+
} // namespace
namespace net {
+int GetSocketReusePolicy() {
+ return g_socket_reuse_policy;
+}
+
+void SetSocketReusePolicy(int policy) {
+ DCHECK_GE(policy, 0);
+ DCHECK_LE(policy, 2);
+ if (policy > 2 || policy < 0) {
+ LOG(ERROR) << "Invalid socket reuse policy";
+ return;
+ }
+
+ double exponents[] = { 0, 0.25, -1 };
+ g_socket_reuse_policy_penalty_exponent = exponents[policy];
+ g_socket_reuse_policy = policy;
+
+ VLOG(1) << "Setting g_socket_reuse_policy_penalty_exponent = "
+ << g_socket_reuse_policy_penalty_exponent;
+}
+
ConnectJob::ConnectJob(const std::string& group_name,
base::TimeDelta timeout_duration,
Delegate* delegate,
@@ -363,6 +389,7 @@ bool ClientSocketPoolBaseHelper::AssignIdleSocketToGroup(
const Request* request, Group* group) {
std::list<IdleSocket>* idle_sockets = group->mutable_idle_sockets();
std::list<IdleSocket>::iterator idle_socket_it = idle_sockets->end();
+ double max_score = -1;
// Iterate through the idle sockets forwards (oldest to newest)
// * Delete any disconnected ones.
@@ -379,7 +406,22 @@ bool ClientSocketPoolBaseHelper::AssignIdleSocketToGroup(
if (it->socket->WasEverUsed()) {
// We found one we can reuse!
- idle_socket_it = it;
+ double score = 0;
+ int64 bytes_read = it->socket->NumBytesRead();
+ double num_kb = static_cast<double>(bytes_read) / 1024.0;
+ int idle_time_sec = (base::TimeTicks::Now() - it->start_time).InSeconds();
+ idle_time_sec = std::max(1, idle_time_sec);
+
+ if (g_socket_reuse_policy_penalty_exponent >= 0 && num_kb >= 0) {
+ score = num_kb / pow(idle_time_sec,
+ g_socket_reuse_policy_penalty_exponent);
+ }
+
+ // Equality to prefer recently used connection.
+ if (score >= max_score) {
+ idle_socket_it = it;
+ max_score = score;
+ }
}
++it;
diff --git a/net/socket/client_socket_pool_base.h b/net/socket/client_socket_pool_base.h
index a5defdf..2490c02 100644
--- a/net/socket/client_socket_pool_base.h
+++ b/net/socket/client_socket_pool_base.h
@@ -50,6 +50,13 @@ namespace net {
class ClientSocketHandle;
+// Returns the client socket reuse policy.
+int GetSocketReusePolicy();
+
+// Sets the client socket reuse policy.
+// NOTE: 'policy' should be a valid ClientSocketReusePolicy enum value.
+NET_API void SetSocketReusePolicy(int policy);
+
// ConnectJob provides an abstract interface for "connecting" a socket.
// The connection may involve host resolution, tcp connection, ssl connection,
// etc.
@@ -167,6 +174,17 @@ class NET_TEST ClientSocketPoolBaseHelper
NO_IDLE_SOCKETS = 0x1, // Do not return an idle socket. Create a new one.
};
+ enum ClientSocketReusePolicy {
+ // Socket with largest amount of bytes transferred.
+ USE_WARMEST_SOCKET = 0,
+
+ // Socket which scores highest on large bytes transferred and low idle time.
+ USE_WARM_SOCKET = 1,
+
+ // Socket which was most recently used.
+ USE_LAST_ACCESSED_SOCKET = 2,
+ };
+
class NET_TEST Request {
public:
Request(ClientSocketHandle* handle,
diff --git a/net/socket/client_socket_pool_base_unittest.cc b/net/socket/client_socket_pool_base_unittest.cc
index 4864001..6cdbdd3 100644
--- a/net/socket/client_socket_pool_base_unittest.cc
+++ b/net/socket/client_socket_pool_base_unittest.cc
@@ -45,12 +45,14 @@ typedef ClientSocketPoolBase<TestSocketParams> TestClientSocketPoolBase;
class MockClientSocket : public StreamSocket {
public:
- MockClientSocket() : connected_(false), was_used_to_convey_data_(false) {}
+ MockClientSocket() : connected_(false), was_used_to_convey_data_(false),
+ num_bytes_read_(0) {}
// Socket methods:
virtual int Read(
- IOBuffer* /* buf */, int /* len */, CompletionCallback* /* callback */) {
- return ERR_UNEXPECTED;
+ IOBuffer* /* buf */, int len, CompletionCallback* /* callback */) {
+ num_bytes_read_ += len;
+ return len;
}
virtual int Write(
@@ -86,13 +88,22 @@ class MockClientSocket : public StreamSocket {
virtual void SetSubresourceSpeculation() {}
virtual void SetOmniboxSpeculation() {}
- virtual bool WasEverUsed() const { return was_used_to_convey_data_; }
+ virtual bool WasEverUsed() const {
+ return was_used_to_convey_data_ || num_bytes_read_ > 0;
+ }
virtual bool UsingTCPFastOpen() const { return false; }
+ virtual int64 NumBytesRead() const { return num_bytes_read_; }
+ virtual base::TimeDelta GetConnectTimeMicros() const {
+ static const base::TimeDelta kDummyConnectTimeMicros =
+ base::TimeDelta::FromMicroseconds(10);
+ return kDummyConnectTimeMicros; // Dummy value.
+ }
private:
bool connected_;
BoundNetLog net_log_;
bool was_used_to_convey_data_;
+ int num_bytes_read_;
DISALLOW_COPY_AND_ASSIGN(MockClientSocket);
};
@@ -604,6 +615,71 @@ class ClientSocketPoolBaseTest : public testing::Test {
ClientSocketPoolTest test_base_;
};
+TEST_F(ClientSocketPoolBaseTest, AssignIdleSocketToGroup_WarmestSocket) {
+ CreatePool(4, 4);
+ net::SetSocketReusePolicy(0);
+
+ EXPECT_EQ(OK, StartRequest("a", kDefaultPriority));
+ EXPECT_EQ(OK, StartRequest("a", kDefaultPriority));
+ EXPECT_EQ(OK, StartRequest("a", kDefaultPriority));
+ EXPECT_EQ(OK, StartRequest("a", kDefaultPriority));
+
+ std::map<int, StreamSocket*> sockets_;
+ for (size_t i = 0; i < test_base_.requests_size(); i++) {
+ TestSocketRequest* req = test_base_.request(i);
+ StreamSocket* s = req->handle()->socket();
+ MockClientSocket* sock = static_cast<MockClientSocket*>(s);
+ CHECK(sock);
+ sockets_[i] = sock;
+ sock->Read(NULL, 1024 - i, NULL);
+ }
+
+ ReleaseAllConnections(ClientSocketPoolTest::KEEP_ALIVE);
+
+ EXPECT_EQ(OK, StartRequest("a", kDefaultPriority));
+ TestSocketRequest* req = test_base_.request(test_base_.requests_size() - 1);
+
+ // First socket is warmest.
+ EXPECT_EQ(sockets_[0], req->handle()->socket());
+
+ // Test that NumBytes are as expected.
+ EXPECT_EQ(1024, sockets_[0]->NumBytesRead());
+ EXPECT_EQ(1023, sockets_[1]->NumBytesRead());
+ EXPECT_EQ(1022, sockets_[2]->NumBytesRead());
+ EXPECT_EQ(1021, sockets_[3]->NumBytesRead());
+
+ ReleaseAllConnections(ClientSocketPoolTest::NO_KEEP_ALIVE);
+}
+
+TEST_F(ClientSocketPoolBaseTest, AssignIdleSocketToGroup_LastAccessedSocket) {
+ CreatePool(4, 4);
+ net::SetSocketReusePolicy(2);
+
+ EXPECT_EQ(OK, StartRequest("a", kDefaultPriority));
+ EXPECT_EQ(OK, StartRequest("a", kDefaultPriority));
+ EXPECT_EQ(OK, StartRequest("a", kDefaultPriority));
+ EXPECT_EQ(OK, StartRequest("a", kDefaultPriority));
+
+ std::map<int, StreamSocket*> sockets_;
+ for (size_t i = 0; i < test_base_.requests_size(); i++) {
+ TestSocketRequest* req = test_base_.request(i);
+ StreamSocket* s = req->handle()->socket();
+ MockClientSocket* sock = static_cast<MockClientSocket*>(s);
+ CHECK(sock);
+ sockets_[i] = sock;
+ sock->Read(NULL, 1024 - i, NULL);
+ }
+
+ ReleaseAllConnections(ClientSocketPoolTest::KEEP_ALIVE);
+
+ EXPECT_EQ(OK, StartRequest("a", kDefaultPriority));
+ TestSocketRequest* req = test_base_.request(test_base_.requests_size() - 1);
+
+ // Last socket is most recently accessed.
+ EXPECT_EQ(sockets_[3], req->handle()->socket());
+ ReleaseAllConnections(ClientSocketPoolTest::NO_KEEP_ALIVE);
+}
+
// Even though a timeout is specified, it doesn't time out on a synchronous
// completion.
TEST_F(ClientSocketPoolBaseTest, ConnectJob_NoTimeoutOnSynchronousCompletion) {
diff --git a/net/socket/socket_test_util.cc b/net/socket/socket_test_util.cc
index 4e4e8fe..0573f73 100644
--- a/net/socket/socket_test_util.cc
+++ b/net/socket/socket_test_util.cc
@@ -707,6 +707,7 @@ MockTCPClientSocket::MockTCPClientSocket(const net::AddressList& addresses,
addresses_(addresses),
data_(data),
read_offset_(0),
+ num_bytes_read_(0),
read_data_(false, net::ERR_UNEXPECTED),
need_read_data_(true),
peer_closed_connection_(false),
@@ -811,6 +812,17 @@ bool MockTCPClientSocket::UsingTCPFastOpen() const {
return false;
}
+int64 MockTCPClientSocket::NumBytesRead() const {
+ return num_bytes_read_;
+}
+
+base::TimeDelta MockTCPClientSocket::GetConnectTimeMicros() const {
+ // Dummy value.
+ static const base::TimeDelta kTestingConnectTimeMicros =
+ base::TimeDelta::FromMicroseconds(20);
+ return kTestingConnectTimeMicros;
+}
+
void MockTCPClientSocket::OnReadComplete(const MockRead& data) {
// There must be a read pending.
DCHECK(pending_buf_);
@@ -853,6 +865,7 @@ int MockTCPClientSocket::CompleteRead() {
result = std::min(buf_len, read_data_.data_len - read_offset_);
memcpy(buf->data(), read_data_.data + read_offset_, result);
read_offset_ += result;
+ num_bytes_read_ += result;
if (read_offset_ == read_data_.data_len) {
need_read_data_ = true;
read_offset_ = 0;
@@ -1001,6 +1014,14 @@ bool DeterministicMockTCPClientSocket::UsingTCPFastOpen() const {
return false;
}
+int64 DeterministicMockTCPClientSocket::NumBytesRead() const {
+ return -1;
+}
+
+base::TimeDelta DeterministicMockTCPClientSocket::GetConnectTimeMicros() const {
+ return base::TimeDelta::FromMicroseconds(-1);
+}
+
void DeterministicMockTCPClientSocket::OnReadComplete(const MockRead& data) {}
class MockSSLClientSocket::ConnectCallback
@@ -1094,6 +1115,14 @@ bool MockSSLClientSocket::UsingTCPFastOpen() const {
return transport_->socket()->UsingTCPFastOpen();
}
+int64 MockSSLClientSocket::NumBytesRead() const {
+ return -1;
+}
+
+base::TimeDelta MockSSLClientSocket::GetConnectTimeMicros() const {
+ return base::TimeDelta::FromMicroseconds(-1);
+}
+
void MockSSLClientSocket::GetSSLInfo(net::SSLInfo* ssl_info) {
ssl_info->Reset();
ssl_info->cert = data_->cert_;
diff --git a/net/socket/socket_test_util.h b/net/socket/socket_test_util.h
index 9a31288..d1f4816 100644
--- a/net/socket/socket_test_util.h
+++ b/net/socket/socket_test_util.h
@@ -631,6 +631,8 @@ class MockTCPClientSocket : public MockClientSocket {
virtual int GetPeerAddress(AddressList* address) const;
virtual bool WasEverUsed() const;
virtual bool UsingTCPFastOpen() const;
+ virtual int64 NumBytesRead() const;
+ virtual base::TimeDelta GetConnectTimeMicros() const;
// MockClientSocket:
virtual void OnReadComplete(const MockRead& data);
@@ -642,6 +644,7 @@ class MockTCPClientSocket : public MockClientSocket {
net::SocketDataProvider* data_;
int read_offset_;
+ int num_bytes_read_;
net::MockRead read_data_;
bool need_read_data_;
@@ -683,6 +686,8 @@ class DeterministicMockTCPClientSocket : public MockClientSocket,
virtual bool IsConnectedAndIdle() const;
virtual bool WasEverUsed() const;
virtual bool UsingTCPFastOpen() const;
+ virtual int64 NumBytesRead() const;
+ virtual base::TimeDelta GetConnectTimeMicros() const;
// MockClientSocket:
virtual void OnReadComplete(const MockRead& data);
@@ -724,6 +729,8 @@ class MockSSLClientSocket : public MockClientSocket {
virtual bool IsConnected() const;
virtual bool WasEverUsed() const;
virtual bool UsingTCPFastOpen() const;
+ virtual int64 NumBytesRead() const;
+ virtual base::TimeDelta GetConnectTimeMicros() const;
// SSLClientSocket methods:
virtual void GetSSLInfo(net::SSLInfo* ssl_info);
diff --git a/net/socket/socks5_client_socket.cc b/net/socket/socks5_client_socket.cc
index 7a1c10d..2f5cee4 100644
--- a/net/socket/socks5_client_socket.cc
+++ b/net/socket/socks5_client_socket.cc
@@ -1,4 +1,4 @@
-// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -142,6 +142,22 @@ bool SOCKS5ClientSocket::UsingTCPFastOpen() const {
return false;
}
+int64 SOCKS5ClientSocket::NumBytesRead() const {
+ if (transport_.get() && transport_->socket()) {
+ return transport_->socket()->NumBytesRead();
+ }
+ NOTREACHED();
+ return -1;
+}
+
+base::TimeDelta SOCKS5ClientSocket::GetConnectTimeMicros() const {
+ if (transport_.get() && transport_->socket()) {
+ return transport_->socket()->GetConnectTimeMicros();
+ }
+ NOTREACHED();
+ return base::TimeDelta::FromMicroseconds(-1);
+}
+
// Read is called by the transport layer above to read. This can only be done
// if the SOCKS handshake is complete.
int SOCKS5ClientSocket::Read(IOBuffer* buf, int buf_len,
diff --git a/net/socket/socks5_client_socket.h b/net/socket/socks5_client_socket.h
index 955ad90..a9d30df 100644
--- a/net/socket/socks5_client_socket.h
+++ b/net/socket/socks5_client_socket.h
@@ -60,6 +60,8 @@ class NET_TEST SOCKS5ClientSocket : public StreamSocket {
virtual void SetOmniboxSpeculation();
virtual bool WasEverUsed() const;
virtual bool UsingTCPFastOpen() const;
+ virtual int64 NumBytesRead() const;
+ virtual base::TimeDelta GetConnectTimeMicros() const;
// Socket methods:
virtual int Read(IOBuffer* buf, int buf_len, CompletionCallback* callback);
diff --git a/net/socket/socks_client_socket.cc b/net/socket/socks_client_socket.cc
index d885f15..4a45b01 100644
--- a/net/socket/socks_client_socket.cc
+++ b/net/socket/socks_client_socket.cc
@@ -169,6 +169,22 @@ bool SOCKSClientSocket::UsingTCPFastOpen() const {
return false;
}
+int64 SOCKSClientSocket::NumBytesRead() const {
+ if (transport_.get() && transport_->socket()) {
+ return transport_->socket()->NumBytesRead();
+ }
+ NOTREACHED();
+ return -1;
+}
+
+base::TimeDelta SOCKSClientSocket::GetConnectTimeMicros() const {
+ if (transport_.get() && transport_->socket()) {
+ return transport_->socket()->GetConnectTimeMicros();
+ }
+ NOTREACHED();
+ return base::TimeDelta::FromMicroseconds(-1);
+}
+
// Read is called by the transport layer above to read. This can only be done
// if the SOCKS handshake is complete.
diff --git a/net/socket/socks_client_socket.h b/net/socket/socks_client_socket.h
index 7c4ba35..286538f 100644
--- a/net/socket/socks_client_socket.h
+++ b/net/socket/socks_client_socket.h
@@ -58,6 +58,8 @@ class NET_TEST SOCKSClientSocket : public StreamSocket {
virtual void SetOmniboxSpeculation();
virtual bool WasEverUsed() const;
virtual bool UsingTCPFastOpen() const;
+ virtual int64 NumBytesRead() const;
+ virtual base::TimeDelta GetConnectTimeMicros() const;
// Socket methods:
virtual int Read(IOBuffer* buf, int buf_len, CompletionCallback* callback);
diff --git a/net/socket/ssl_client_socket_mac.cc b/net/socket/ssl_client_socket_mac.cc
index 2fc11ec..c38b78a 100644
--- a/net/socket/ssl_client_socket_mac.cc
+++ b/net/socket/ssl_client_socket_mac.cc
@@ -658,6 +658,22 @@ bool SSLClientSocketMac::UsingTCPFastOpen() const {
return false;
}
+int64 SSLClientSocketMac::NumBytesRead() const {
+ if (transport_.get() && transport_->socket()) {
+ return transport_->socket()->NumBytesRead();
+ }
+ NOTREACHED();
+ return -1;
+}
+
+base::TimeDelta SSLClientSocketMac::GetConnectTimeMicros() const {
+ if (transport_.get() && transport_->socket()) {
+ return transport_->socket()->GetConnectTimeMicros();
+ }
+ NOTREACHED();
+ return base::TimeDelta::FromMicroseconds(-1);
+}
+
int SSLClientSocketMac::Read(IOBuffer* buf, int buf_len,
CompletionCallback* callback) {
DCHECK(completed_handshake());
diff --git a/net/socket/ssl_client_socket_mac.h b/net/socket/ssl_client_socket_mac.h
index 4dbffe6..8ef33e9 100644
--- a/net/socket/ssl_client_socket_mac.h
+++ b/net/socket/ssl_client_socket_mac.h
@@ -57,6 +57,8 @@ class SSLClientSocketMac : public SSLClientSocket {
virtual void SetOmniboxSpeculation();
virtual bool WasEverUsed() const;
virtual bool UsingTCPFastOpen() const;
+ virtual int64 NumBytesRead() const;
+ virtual base::TimeDelta GetConnectTimeMicros() const;
// Socket methods:
virtual int Read(IOBuffer* buf, int buf_len, CompletionCallback* callback);
diff --git a/net/socket/ssl_client_socket_nss.cc b/net/socket/ssl_client_socket_nss.cc
index 18b4e58..9657026 100644
--- a/net/socket/ssl_client_socket_nss.cc
+++ b/net/socket/ssl_client_socket_nss.cc
@@ -714,6 +714,22 @@ bool SSLClientSocketNSS::UsingTCPFastOpen() const {
return false;
}
+int64 SSLClientSocketNSS::NumBytesRead() const {
+ if (transport_.get() && transport_->socket()) {
+ return transport_->socket()->NumBytesRead();
+ }
+ NOTREACHED();
+ return -1;
+}
+
+base::TimeDelta SSLClientSocketNSS::GetConnectTimeMicros() const {
+ if (transport_.get() && transport_->socket()) {
+ return transport_->socket()->GetConnectTimeMicros();
+ }
+ NOTREACHED();
+ return base::TimeDelta::FromMicroseconds(-1);
+}
+
int SSLClientSocketNSS::Read(IOBuffer* buf, int buf_len,
CompletionCallback* callback) {
EnterFunction(buf_len);
diff --git a/net/socket/ssl_client_socket_nss.h b/net/socket/ssl_client_socket_nss.h
index 1c5d80e..7d2f7cf 100644
--- a/net/socket/ssl_client_socket_nss.h
+++ b/net/socket/ssl_client_socket_nss.h
@@ -75,6 +75,8 @@ class SSLClientSocketNSS : public SSLClientSocket {
virtual void SetOmniboxSpeculation();
virtual bool WasEverUsed() const;
virtual bool UsingTCPFastOpen() const;
+ virtual int64 NumBytesRead() const;
+ virtual base::TimeDelta GetConnectTimeMicros() const;
// Socket methods:
virtual int Read(IOBuffer* buf, int buf_len, CompletionCallback* callback);
diff --git a/net/socket/ssl_client_socket_win.cc b/net/socket/ssl_client_socket_win.cc
index 1392e1d..4cc3103 100644
--- a/net/socket/ssl_client_socket_win.cc
+++ b/net/socket/ssl_client_socket_win.cc
@@ -731,6 +731,22 @@ bool SSLClientSocketWin::UsingTCPFastOpen() const {
return false;
}
+int64 SSLClientSocketWin::NumBytesRead() const {
+ if (transport_.get() && transport_->socket()) {
+ return transport_->socket()->NumBytesRead();
+ }
+ NOTREACHED();
+ return -1;
+}
+
+base::TimeDelta SSLClientSocketWin::GetConnectTimeMicros() const {
+ if (transport_.get() && transport_->socket()) {
+ return transport_->socket()->GetConnectTimeMicros();
+ }
+ NOTREACHED();
+ return base::TimeDelta::FromMicroseconds(-1);
+}
+
int SSLClientSocketWin::Read(IOBuffer* buf, int buf_len,
CompletionCallback* callback) {
DCHECK(completed_handshake());
diff --git a/net/socket/ssl_client_socket_win.h b/net/socket/ssl_client_socket_win.h
index fb54c43..59f403a 100644
--- a/net/socket/ssl_client_socket_win.h
+++ b/net/socket/ssl_client_socket_win.h
@@ -62,6 +62,8 @@ class SSLClientSocketWin : public SSLClientSocket {
virtual void SetOmniboxSpeculation();
virtual bool WasEverUsed() const;
virtual bool UsingTCPFastOpen() const;
+ virtual int64 NumBytesRead() const;
+ virtual base::TimeDelta GetConnectTimeMicros() const;
// Socket methods:
virtual int Read(IOBuffer* buf, int buf_len, CompletionCallback* callback);
diff --git a/net/socket/ssl_server_socket_nss.cc b/net/socket/ssl_server_socket_nss.cc
index 0f35ce9c..b272f8e 100644
--- a/net/socket/ssl_server_socket_nss.cc
+++ b/net/socket/ssl_server_socket_nss.cc
@@ -226,6 +226,14 @@ bool SSLServerSocketNSS::UsingTCPFastOpen() const {
return transport_socket_->UsingTCPFastOpen();
}
+int64 SSLServerSocketNSS::NumBytesRead() const {
+ return transport_socket_->NumBytesRead();
+}
+
+base::TimeDelta SSLServerSocketNSS::GetConnectTimeMicros() const {
+ return transport_socket_->GetConnectTimeMicros();
+}
+
int SSLServerSocketNSS::InitializeSSLOptions() {
// Transport connected, now hook it up to nss
// TODO(port): specify rx and tx buffer sizes separately
diff --git a/net/socket/ssl_server_socket_nss.h b/net/socket/ssl_server_socket_nss.h
index 366a915..5903c17 100644
--- a/net/socket/ssl_server_socket_nss.h
+++ b/net/socket/ssl_server_socket_nss.h
@@ -54,6 +54,8 @@ class SSLServerSocketNSS : public SSLServerSocket {
virtual void SetOmniboxSpeculation();
virtual bool WasEverUsed() const;
virtual bool UsingTCPFastOpen() const;
+ virtual int64 NumBytesRead() const;
+ virtual base::TimeDelta GetConnectTimeMicros() const;
private:
enum State {
diff --git a/net/socket/ssl_server_socket_unittest.cc b/net/socket/ssl_server_socket_unittest.cc
index 02f333b..de89c20 100644
--- a/net/socket/ssl_server_socket_unittest.cc
+++ b/net/socket/ssl_server_socket_unittest.cc
@@ -171,6 +171,14 @@ class FakeSocket : public StreamSocket {
return false;
}
+ virtual int64 NumBytesRead() const {
+ return -1;
+ }
+
+ virtual base::TimeDelta GetConnectTimeMicros() const {
+ return base::TimeDelta::FromMicroseconds(-1);
+ }
+
private:
net::BoundNetLog net_log_;
FakeDataChannel* incoming_;
diff --git a/net/socket/stream_socket.h b/net/socket/stream_socket.h
index 544fbcd..ef2f698 100644
--- a/net/socket/stream_socket.h
+++ b/net/socket/stream_socket.h
@@ -6,6 +6,7 @@
#define NET_SOCKET_STREAM_SOCKET_H_
#pragma once
+#include "base/time.h"
#include "net/base/net_log.h"
#include "net/socket/socket.h"
@@ -79,6 +80,12 @@ class NET_TEST StreamSocket : public Socket {
// TCP FastOpen is an experiment with sending data in the TCP SYN packet.
virtual bool UsingTCPFastOpen() const = 0;
+ // Returns the number of bytes successfully read from this socket.
+ virtual int64 NumBytesRead() const = 0;
+
+ // Returns the connection setup time of this socket.
+ virtual base::TimeDelta GetConnectTimeMicros() const = 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_libevent.cc b/net/socket/tcp_client_socket_libevent.cc
index 38c3446..27c106c 100644
--- a/net/socket/tcp_client_socket_libevent.cc
+++ b/net/socket/tcp_client_socket_libevent.cc
@@ -137,7 +137,8 @@ TCPClientSocketLibevent::TCPClientSocketLibevent(
net_log_(BoundNetLog::Make(net_log, NetLog::SOURCE_SOCKET)),
previously_disconnected_(false),
use_tcp_fastopen_(false),
- tcp_fastopen_connected_(false) {
+ tcp_fastopen_connected_(false),
+ num_bytes_read_(0) {
scoped_refptr<NetLog::EventParameters> params;
if (source.is_valid())
params = new NetLogSourceParameter("source_dependency", source);
@@ -298,6 +299,7 @@ int TCPClientSocketLibevent::DoConnect() {
// Connect the socket.
if (!use_tcp_fastopen_) {
+ connect_start_time_ = base::TimeTicks::Now();
if (!HANDLE_EINTR(connect(socket_, current_ai_->ai_addr,
static_cast<int>(current_ai_->ai_addrlen)))) {
// Connected without waiting!
@@ -339,6 +341,7 @@ int TCPClientSocketLibevent::DoConnectComplete(int result) {
write_socket_watcher_.StopWatchingFileDescriptor();
if (result == OK) {
+ connect_time_micros_ = base::TimeTicks::Now() - connect_start_time_;
use_history_.set_was_ever_connected();
return OK; // Done!
}
@@ -440,6 +443,7 @@ int TCPClientSocketLibevent::Read(IOBuffer* buf,
if (nread >= 0) {
base::StatsCounter read_bytes("tcp.read_bytes");
read_bytes.Add(nread);
+ num_bytes_read_ += static_cast<int64>(nread);
if (nread > 0)
use_history_.set_was_used_to_convey_data();
net_log_.AddByteTransferEvent(NetLog::TYPE_SOCKET_BYTES_RECEIVED, nread,
@@ -634,6 +638,7 @@ void TCPClientSocketLibevent::DidCompleteRead() {
result = bytes_transferred;
base::StatsCounter read_bytes("tcp.read_bytes");
read_bytes.Add(bytes_transferred);
+ num_bytes_read_ += static_cast<int64>(bytes_transferred);
if (bytes_transferred > 0)
use_history_.set_was_used_to_convey_data();
net_log_.AddByteTransferEvent(NetLog::TYPE_SOCKET_BYTES_RECEIVED, result,
@@ -723,4 +728,12 @@ bool TCPClientSocketLibevent::UsingTCPFastOpen() const {
return use_tcp_fastopen_;
}
+int64 TCPClientSocketLibevent::NumBytesRead() const {
+ return num_bytes_read_;
+}
+
+base::TimeDelta TCPClientSocketLibevent::GetConnectTimeMicros() const {
+ return connect_time_micros_;
+}
+
} // namespace net
diff --git a/net/socket/tcp_client_socket_libevent.h b/net/socket/tcp_client_socket_libevent.h
index 607b9ee..f5e4a28 100644
--- a/net/socket/tcp_client_socket_libevent.h
+++ b/net/socket/tcp_client_socket_libevent.h
@@ -53,6 +53,8 @@ class TCPClientSocketLibevent : public StreamSocket, base::NonThreadSafe {
virtual void SetOmniboxSpeculation();
virtual bool WasEverUsed() const;
virtual bool UsingTCPFastOpen() const;
+ virtual int64 NumBytesRead() const;
+ virtual base::TimeDelta GetConnectTimeMicros() const;
// Socket methods:
// Multiple outstanding requests are not supported.
@@ -195,6 +197,10 @@ class TCPClientSocketLibevent : public StreamSocket, base::NonThreadSafe {
// True when TCP FastOpen is in use and we have done the connect.
bool tcp_fastopen_connected_;
+ base::TimeTicks connect_start_time_;
+ base::TimeDelta connect_time_micros_;
+ int64 num_bytes_read_;
+
DISALLOW_COPY_AND_ASSIGN(TCPClientSocketLibevent);
};
diff --git a/net/socket/tcp_client_socket_win.cc b/net/socket/tcp_client_socket_win.cc
index 71187a1..f4026b7 100644
--- a/net/socket/tcp_client_socket_win.cc
+++ b/net/socket/tcp_client_socket_win.cc
@@ -323,7 +323,8 @@ TCPClientSocketWin::TCPClientSocketWin(const AddressList& addresses,
next_connect_state_(CONNECT_STATE_NONE),
connect_os_error_(0),
net_log_(BoundNetLog::Make(net_log, NetLog::SOURCE_SOCKET)),
- previously_disconnected_(false) {
+ previously_disconnected_(false),
+ num_bytes_read_(0) {
scoped_refptr<NetLog::EventParameters> params;
if (source.is_valid())
params = new NetLogSourceParameter("source_dependency", source);
@@ -484,6 +485,7 @@ int TCPClientSocketWin::DoConnect() {
core_->write_overlapped_.hEvent = WSACreateEvent();
+ connect_start_time_ = base::TimeTicks::Now();
if (!connect(socket_, ai->ai_addr, static_cast<int>(ai->ai_addrlen))) {
// Connected without waiting!
//
@@ -522,6 +524,7 @@ int TCPClientSocketWin::DoConnectComplete(int result) {
net_log_.EndEvent(NetLog::TYPE_TCP_CONNECT_ATTEMPT, params);
if (result == OK) {
+ connect_time_micros_ = base::TimeTicks::Now() - connect_start_time_;
use_history_.set_was_ever_connected();
return OK; // Done!
}
@@ -658,6 +661,14 @@ bool TCPClientSocketWin::UsingTCPFastOpen() const {
return false;
}
+int64 TCPClientSocketWin::NumBytesRead() const {
+ return num_bytes_read_;
+}
+
+base::TimeDelta TCPClientSocketWin::GetConnectTimeMicros() const {
+ return connect_time_micros_;
+}
+
int TCPClientSocketWin::Read(IOBuffer* buf,
int buf_len,
CompletionCallback* callback) {
@@ -688,6 +699,7 @@ int TCPClientSocketWin::Read(IOBuffer* buf,
base::MemoryDebug::MarkAsInitialized(core_->read_buffer_.buf, num);
base::StatsCounter read_bytes("tcp.read_bytes");
read_bytes.Add(num);
+ num_bytes_read_ += num;
if (num > 0)
use_history_.set_was_used_to_convey_data();
net_log_.AddByteTransferEvent(NetLog::TYPE_SOCKET_BYTES_RECEIVED, num,
@@ -858,6 +870,7 @@ void TCPClientSocketWin::DidCompleteRead() {
if (ok) {
base::StatsCounter read_bytes("tcp.read_bytes");
read_bytes.Add(num_bytes);
+ num_bytes_read_ += num_bytes;
if (num_bytes > 0)
use_history_.set_was_used_to_convey_data();
net_log_.AddByteTransferEvent(NetLog::TYPE_SOCKET_BYTES_RECEIVED,
diff --git a/net/socket/tcp_client_socket_win.h b/net/socket/tcp_client_socket_win.h
index 3282772..b1f9f3b 100644
--- a/net/socket/tcp_client_socket_win.h
+++ b/net/socket/tcp_client_socket_win.h
@@ -53,6 +53,8 @@ class NET_API TCPClientSocketWin : public StreamSocket,
virtual void SetOmniboxSpeculation();
virtual bool WasEverUsed() const;
virtual bool UsingTCPFastOpen() const;
+ virtual int64 NumBytesRead() const;
+ virtual base::TimeDelta GetConnectTimeMicros() const;
// Socket methods:
// Multiple outstanding requests are not supported.
@@ -141,6 +143,10 @@ class NET_API TCPClientSocketWin : public StreamSocket,
// histograms.
UseHistory use_history_;
+ base::TimeTicks connect_start_time_;
+ base::TimeDelta connect_time_micros_;
+ int64 num_bytes_read_;
+
DISALLOW_COPY_AND_ASSIGN(TCPClientSocketWin);
};
diff --git a/net/socket/transport_client_socket_pool_unittest.cc b/net/socket/transport_client_socket_pool_unittest.cc
index 5716a4d..d12cd9d 100644
--- a/net/socket/transport_client_socket_pool_unittest.cc
+++ b/net/socket/transport_client_socket_pool_unittest.cc
@@ -85,6 +85,10 @@ class MockClientSocket : public StreamSocket {
virtual void SetOmniboxSpeculation() {}
virtual bool WasEverUsed() const { return false; }
virtual bool UsingTCPFastOpen() const { return false; }
+ virtual int64 NumBytesRead() const { return -1; }
+ virtual base::TimeDelta GetConnectTimeMicros() const {
+ return base::TimeDelta::FromMicroseconds(-1);
+ }
// Socket methods:
virtual int Read(IOBuffer* buf, int buf_len,
@@ -135,6 +139,10 @@ class MockFailingClientSocket : public StreamSocket {
virtual void SetOmniboxSpeculation() {}
virtual bool WasEverUsed() const { return false; }
virtual bool UsingTCPFastOpen() const { return false; }
+ virtual int64 NumBytesRead() const { return -1; }
+ virtual base::TimeDelta GetConnectTimeMicros() const {
+ return base::TimeDelta::FromMicroseconds(-1);
+ }
// Socket methods:
virtual int Read(IOBuffer* buf, int buf_len,
@@ -209,6 +217,10 @@ class MockPendingClientSocket : public StreamSocket {
virtual void SetOmniboxSpeculation() {}
virtual bool WasEverUsed() const { return false; }
virtual bool UsingTCPFastOpen() const { return false; }
+ virtual int64 NumBytesRead() const { return -1; }
+ virtual base::TimeDelta GetConnectTimeMicros() const {
+ return base::TimeDelta::FromMicroseconds(-1);
+ }
// Socket methods:
virtual int Read(IOBuffer* buf, int buf_len,
diff --git a/net/socket/transport_client_socket_unittest.cc b/net/socket/transport_client_socket_unittest.cc
index bb0be35..8f377e5 100644
--- a/net/socket/transport_client_socket_unittest.cc
+++ b/net/socket/transport_client_socket_unittest.cc
@@ -277,6 +277,8 @@ TEST_P(TransportClientSocketTest, Read) {
rv = sock_->Read(buf, 4096, &callback);
ASSERT_EQ(ERR_IO_PENDING, rv);
+ EXPECT_EQ(static_cast<int64>(std::string(kServerReply).size()),
+ sock_->NumBytesRead());
CloseServerSocket();
EXPECT_EQ(0, callback.WaitForResult());
}
@@ -309,6 +311,8 @@ TEST_P(TransportClientSocketTest, Read_SmallChunks) {
// then close the server socket, and note the close.
rv = sock_->Read(buf, 1, &callback);
+ EXPECT_EQ(static_cast<int64>(std::string(kServerReply).size()),
+ sock_->NumBytesRead());
ASSERT_EQ(ERR_IO_PENDING, rv);
CloseServerSocket();
EXPECT_EQ(0, callback.WaitForResult());
@@ -329,9 +333,12 @@ TEST_P(TransportClientSocketTest, Read_Interrupted) {
scoped_refptr<IOBuffer> buf(new IOBuffer(16));
rv = sock_->Read(buf, 16, &callback);
EXPECT_TRUE(rv >= 0 || rv == ERR_IO_PENDING);
+ EXPECT_EQ(0, sock_->NumBytesRead());
- if (rv == ERR_IO_PENDING)
+ if (rv == ERR_IO_PENDING) {
rv = callback.WaitForResult();
+ EXPECT_EQ(16, sock_->NumBytesRead());
+ }
EXPECT_NE(0, rv);
}