summaryrefslogtreecommitdiffstats
path: root/net/socket
diff options
context:
space:
mode:
authorwillchan@chromium.org <willchan@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-10-13 00:55:03 +0000
committerwillchan@chromium.org <willchan@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-10-13 00:55:03 +0000
commit2c2bef15bfeea057bfd7f0c1c5ae1244ae4ed03d (patch)
tree23b324be2991afa9da65a4597cc3fb1baef5bd8c /net/socket
parentf04f73aa57b809af0e047048b88abe02b8012554 (diff)
downloadchromium_src-2c2bef15bfeea057bfd7f0c1c5ae1244ae4ed03d.zip
chromium_src-2c2bef15bfeea057bfd7f0c1c5ae1244ae4ed03d.tar.gz
chromium_src-2c2bef15bfeea057bfd7f0c1c5ae1244ae4ed03d.tar.bz2
Add ClientSocketPoolBaseHelper support for preconnect.
Adds a RequestSockets() API to ClientSocketPool interface. - no RequestPriority param, all requests default to LOWEST. - adds a |num_sockets| param to control how many sockets to try to ensure are connected. Adds an implementation for said function in ClientSocketPoolBaseHelper. Adds a new ClientSocketPoolBaseHelper::Flag type to modify socket request behavior. In this case, we bypass idle sockets. Adds a preconnect concept to ConnectJob. This lets normal requests hijack preconnect jobs. Modifies all ClientSocketPool subclasses to support new RequestSockets API(). Adds new tests. No client actually uses this API yet. We need to plumb it up to the preconnect system. BUG=54450 TEST=new tests in ClientSocketPoolBaseTest Review URL: http://codereview.chromium.org/3689004 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@62365 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'net/socket')
-rw-r--r--net/socket/client_socket_pool.h15
-rw-r--r--net/socket/client_socket_pool_base.cc107
-rw-r--r--net/socket/client_socket_pool_base.h108
-rw-r--r--net/socket/client_socket_pool_base_unittest.cc366
-rw-r--r--net/socket/socks_client_socket_pool.cc11
-rw-r--r--net/socket/socks_client_socket_pool.h5
-rw-r--r--net/socket/ssl_client_socket_pool.cc11
-rw-r--r--net/socket/ssl_client_socket_pool.h5
-rw-r--r--net/socket/tcp_client_socket_pool.cc20
-rw-r--r--net/socket/tcp_client_socket_pool.h5
10 files changed, 616 insertions, 37 deletions
diff --git a/net/socket/client_socket_pool.h b/net/socket/client_socket_pool.h
index ad5f1ae..d097c0f 100644
--- a/net/socket/client_socket_pool.h
+++ b/net/socket/client_socket_pool.h
@@ -67,6 +67,21 @@ class ClientSocketPool {
CompletionCallback* callback,
const BoundNetLog& net_log) = 0;
+ // RequestSockets is used to request that |num_sockets| be connected in the
+ // connection group for |group_name|. If the connection group already has
+ // |num_sockets| idle sockets / active sockets / currently connecting sockets,
+ // then this function doesn't do anything. Otherwise, it will start up as
+ // many connections as necessary to reach |num_sockets| total sockets for the
+ // group. It uses |params| to control how to connect the sockets. The
+ // ClientSocketPool will assign a priority to the new connections, if any.
+ // This priority will probably be lower than all others, since this method
+ // is intended to make sure ahead of time that |num_sockets| sockets are
+ // available to talk to a host.
+ virtual void RequestSockets(const std::string& group_name,
+ const void* params,
+ int num_sockets,
+ const BoundNetLog& net_log) = 0;
+
// Called to cancel a RequestSocket call that returned ERR_IO_PENDING. The
// same handle parameter must be passed to this method as was passed to the
// RequestSocket call being cancelled. The associated CompletionCallback is
diff --git a/net/socket/client_socket_pool_base.cc b/net/socket/client_socket_pool_base.cc
index 994e1d2..13d8b68 100644
--- a/net/socket/client_socket_pool_base.cc
+++ b/net/socket/client_socket_pool_base.cc
@@ -44,7 +44,8 @@ ConnectJob::ConnectJob(const std::string& group_name,
timeout_duration_(timeout_duration),
delegate_(delegate),
net_log_(net_log),
- idle_(true) {
+ idle_(true),
+ preconnect_state_(NOT_PRECONNECT) {
DCHECK(!group_name.empty());
DCHECK(delegate);
net_log.BeginEvent(NetLog::TYPE_SOCKET_POOL_CONNECT_JOB, NULL);
@@ -54,6 +55,13 @@ ConnectJob::~ConnectJob() {
net_log().EndEvent(NetLog::TYPE_SOCKET_POOL_CONNECT_JOB, NULL);
}
+void ConnectJob::Initialize(bool is_preconnect) {
+ if (is_preconnect)
+ preconnect_state_ = UNUSED_PRECONNECT;
+ else
+ preconnect_state_ = NOT_PRECONNECT;
+}
+
int ConnectJob::Connect() {
if (timeout_duration_ != base::TimeDelta())
timer_.Start(timeout_duration_, this, &ConnectJob::OnTimeout);
@@ -72,6 +80,11 @@ int ConnectJob::Connect() {
return rv;
}
+void ConnectJob::UseForNormalRequest() {
+ DCHECK_EQ(UNUSED_PRECONNECT, preconnect_state_);
+ preconnect_state_ = USED_PRECONNECT;
+}
+
void ConnectJob::set_socket(ClientSocket* socket) {
if (socket) {
net_log().AddEvent(NetLog::TYPE_CONNECT_JOB_SET_SOCKET,
@@ -122,10 +135,12 @@ ClientSocketPoolBaseHelper::Request::Request(
ClientSocketHandle* handle,
CompletionCallback* callback,
RequestPriority priority,
+ Flags flags,
const BoundNetLog& net_log)
: handle_(handle),
callback_(callback),
priority_(priority),
+ flags_(flags),
net_log_(net_log) {}
ClientSocketPoolBaseHelper::Request::~Request() {}
@@ -193,6 +208,9 @@ ClientSocketPoolBaseHelper::RemoveRequestFromQueue(
int ClientSocketPoolBaseHelper::RequestSocket(
const std::string& group_name,
const Request* request) {
+ CHECK(request->callback());
+ CHECK(request->handle());
+
request->net_log().BeginEvent(NetLog::TYPE_SOCKET_POOL, NULL);
Group* group = GetOrCreateGroup(group_name);
@@ -207,19 +225,57 @@ int ClientSocketPoolBaseHelper::RequestSocket(
return rv;
}
+void ClientSocketPoolBaseHelper::RequestSockets(
+ const std::string& group_name,
+ const Request& request,
+ int num_sockets) {
+ DCHECK(!request.callback());
+ DCHECK(!request.handle());
+
+ if (num_sockets > max_sockets_per_group_) {
+ NOTREACHED();
+ num_sockets = max_sockets_per_group_;
+ }
+
+ request.net_log().BeginEvent(
+ NetLog::TYPE_SOCKET_POOL_CONNECTING_N_SOCKETS,
+ new NetLogIntegerParameter("num_sockets", num_sockets));
+
+ Group* group = GetOrCreateGroup(group_name);
+
+ for (int num_iterations_left = num_sockets;
+ group->NumActiveSocketSlots() < num_sockets &&
+ num_iterations_left > 0 ; num_iterations_left--) {
+ int rv = RequestSocketInternal(group_name, &request);
+ if (rv < 0 && rv != ERR_IO_PENDING) {
+ // We're encountering a synchronous error. Give up.
+ break;
+ }
+ }
+
+ if (group->IsEmpty())
+ RemoveGroup(group_name);
+
+ request.net_log().EndEvent(
+ NetLog::TYPE_SOCKET_POOL_CONNECTING_N_SOCKETS, NULL);
+}
+
int ClientSocketPoolBaseHelper::RequestSocketInternal(
const std::string& group_name,
const Request* request) {
DCHECK_GE(request->priority(), 0);
- CompletionCallback* const callback = request->callback();
- CHECK(callback);
ClientSocketHandle* const handle = request->handle();
- CHECK(handle);
+ const bool preconnecting = !handle;
Group* group = GetOrCreateGroup(group_name);
- // Try to reuse a socket.
- if (AssignIdleSocketToGroup(request, group))
- return OK;
+ if (!(request->flags() & NO_IDLE_SOCKETS)) {
+ // Try to reuse a socket.
+ if (AssignIdleSocketToGroup(request, group))
+ return OK;
+ }
+
+ if (!preconnecting && group->TryToUsePreconnectConnectJob())
+ return ERR_IO_PENDING;
// Can we make another active socket now?
if (!group->HasAvailableSocketSlot(max_sockets_per_group_)) {
@@ -244,18 +300,25 @@ int ClientSocketPoolBaseHelper::RequestSocketInternal(
scoped_ptr<ConnectJob> connect_job(
connect_job_factory_->NewConnectJob(group_name, *request, this));
+ connect_job->Initialize(preconnecting);
int rv = connect_job->Connect();
if (rv == OK) {
LogBoundConnectJobToRequest(connect_job->net_log().source(), request);
- HandOutSocket(connect_job->ReleaseSocket(), false /* not reused */,
- handle, base::TimeDelta(), group, request->net_log());
+ if (!preconnecting) {
+ HandOutSocket(connect_job->ReleaseSocket(), false /* not reused */,
+ handle, base::TimeDelta(), group, request->net_log());
+ } else {
+ AddIdleSocket(connect_job->ReleaseSocket(), group);
+ }
} else if (rv == ERR_IO_PENDING) {
// If we don't have any sockets in this group, set a timer for potentially
// creating a new one. If the SYN is lost, this backup socket may complete
// before the slow socket, improving end user latency.
- if (group->IsEmpty() && !group->HasBackupJob() &&
- connect_backup_jobs_enabled_)
+ if (connect_backup_jobs_enabled_ &&
+ group->IsEmpty() && !group->HasBackupJob() &&
+ handle) {
group->StartBackupSocketTimer(group_name, this);
+ }
connecting_socket_count_++;
@@ -357,10 +420,9 @@ void ClientSocketPoolBaseHelper::CancelRequest(
RequestQueue::iterator it = group->mutable_pending_requests()->begin();
for (; it != group->pending_requests().end(); ++it) {
if ((*it)->handle() == handle) {
- const Request* req = RemoveRequestFromQueue(it, group);
+ scoped_ptr<const Request> req(RemoveRequestFromQueue(it, group));
req->net_log().AddEvent(NetLog::TYPE_CANCELLED, NULL);
req->net_log().EndEvent(NetLog::TYPE_SOCKET_POOL, NULL);
- delete req;
// We let the job run, unless we're at the socket limit.
if (group->jobs().size() && ReachedMaxSocketsLimit()) {
@@ -468,7 +530,7 @@ DictionaryValue* ClientSocketPoolBaseHelper::GetInfoAsValue(
group_dict->Set("idle_sockets", idle_socket_list);
ListValue* connect_jobs_list = new ListValue();
- std::set<const ConnectJob*>::const_iterator job = group->jobs().begin();
+ std::set<ConnectJob*>::const_iterator job = group->jobs().begin();
for (job = group->jobs().begin(); job != group->jobs().end(); job++) {
int source_id = (*job)->net_log().source().id;
connect_jobs_list->Append(Value::CreateIntegerValue(source_id));
@@ -725,7 +787,7 @@ void ClientSocketPoolBaseHelper::Flush() {
AbortAllRequests();
}
-void ClientSocketPoolBaseHelper::RemoveConnectJob(const ConnectJob* job,
+void ClientSocketPoolBaseHelper::RemoveConnectJob(ConnectJob* job,
Group* group) {
CHECK_GT(connecting_socket_count_, 0);
connecting_socket_count_--;
@@ -837,10 +899,9 @@ void ClientSocketPoolBaseHelper::AbortAllRequests() {
pending_requests.swap(*group->mutable_pending_requests());
for (RequestQueue::iterator it2 = pending_requests.begin();
it2 != pending_requests.end(); ++it2) {
- const Request* request = *it2;
+ scoped_ptr<const Request> request(*it2);
InvokeUserCallbackLater(
request->handle(), request->callback(), ERR_ABORTED);
- delete request;
}
// Delete group if no longer needed.
@@ -934,6 +995,18 @@ void ClientSocketPoolBaseHelper::Group::StartBackupSocketTimer(
pool->ConnectRetryIntervalMs());
}
+bool ClientSocketPoolBaseHelper::Group::TryToUsePreconnectConnectJob() {
+ for (std::set<ConnectJob*>::iterator it = jobs_.begin();
+ it != jobs_.end(); ++it) {
+ ConnectJob* job = *it;
+ if (job->is_unused_preconnect()) {
+ job->UseForNormalRequest();
+ return true;
+ }
+ }
+ return false;
+}
+
void ClientSocketPoolBaseHelper::Group::OnBackupSocketTimerFired(
std::string group_name,
ClientSocketPoolBaseHelper* pool) {
diff --git a/net/socket/client_socket_pool_base.h b/net/socket/client_socket_pool_base.h
index a39eeaa..6c626f7 100644
--- a/net/socket/client_socket_pool_base.h
+++ b/net/socket/client_socket_pool_base.h
@@ -76,6 +76,16 @@ class ConnectJob {
// Accessors
const std::string& group_name() const { return group_name_; }
const BoundNetLog& net_log() { return net_log_; }
+ bool is_preconnect() const { return preconnect_state_ != NOT_PRECONNECT; }
+ bool is_unused_preconnect() const {
+ return preconnect_state_ == UNUSED_PRECONNECT;
+ }
+
+ // Initialized by the ClientSocketPoolBaseHelper.
+ // TODO(willchan): Move most of the constructor arguments over here. We
+ // shouldn't give the ConnectJobFactory (subclasses) the ability to screw up
+ // the initialization.
+ void Initialize(bool is_preconnect);
// Releases |socket_| to the client. On connection error, this should return
// NULL.
@@ -89,6 +99,10 @@ class ConnectJob {
// if it succeeded.
int Connect();
+ // Precondition: is_unused_preconnect() must be true. Marks the job as a
+ // used preconnect job.
+ void UseForNormalRequest();
+
virtual LoadState GetLoadState() const = 0;
// If Connect returns an error (or OnConnectJobComplete reports an error
@@ -105,6 +119,12 @@ class ConnectJob {
void ResetTimer(base::TimeDelta remainingTime);
private:
+ enum PreconnectState {
+ NOT_PRECONNECT,
+ UNUSED_PRECONNECT,
+ USED_PRECONNECT,
+ };
+
virtual int ConnectInternal() = 0;
void LogConnectStart();
@@ -122,6 +142,7 @@ class ConnectJob {
BoundNetLog net_log_;
// A ConnectJob is idle until Connect() has been called.
bool idle_;
+ PreconnectState preconnect_state_;
DISALLOW_COPY_AND_ASSIGN(ConnectJob);
};
@@ -137,11 +158,20 @@ class ClientSocketPoolBaseHelper
: public ConnectJob::Delegate,
public NetworkChangeNotifier::Observer {
public:
+ // Used to specify specific behavior for the ClientSocketPool.
+ enum Flag {
+ NORMAL = 0, // Normal behavior.
+ NO_IDLE_SOCKETS = 0x1, // Do not return an idle socket. Create a new one.
+ };
+
+ typedef uint32 Flags;
+
class Request {
public:
Request(ClientSocketHandle* handle,
CompletionCallback* callback,
RequestPriority priority,
+ Flags flags,
const BoundNetLog& net_log);
virtual ~Request();
@@ -149,12 +179,14 @@ class ClientSocketPoolBaseHelper
ClientSocketHandle* handle() const { return handle_; }
CompletionCallback* callback() const { return callback_; }
RequestPriority priority() const { return priority_; }
+ const Flags flags() const { return flags_; }
const BoundNetLog& net_log() const { return net_log_; }
private:
ClientSocketHandle* const handle_;
CompletionCallback* const callback_;
const RequestPriority priority_;
+ const Flags flags_;
BoundNetLog net_log_;
DISALLOW_COPY_AND_ASSIGN(Request);
@@ -190,6 +222,11 @@ class ClientSocketPoolBaseHelper
// heap allocated.
int RequestSocket(const std::string& group_name, const Request* request);
+ // See ClientSocketPool::RequestSocket for documentation on this function.
+ void RequestSockets(const std::string& group_name,
+ const Request& request,
+ int num_sockets);
+
// See ClientSocketPool::CancelRequest for documentation on this function.
void CancelRequest(const std::string& group_name,
ClientSocketHandle* handle);
@@ -234,6 +271,10 @@ class ClientSocketPoolBaseHelper
return group_map_.find(group_name)->second->jobs().size();
}
+ int NumActiveSocketsInGroup(const std::string& group_name) const {
+ return group_map_.find(group_name)->second->active_socket_count();
+ }
+
bool HasGroup(const std::string& group_name) const;
// Closes all idle sockets if |force| is true. Else, only closes idle
@@ -271,7 +312,7 @@ class ClientSocketPoolBaseHelper
bool ShouldCleanup(base::TimeTicks now, base::TimeDelta timeout) const;
};
- typedef std::deque<const Request*> RequestQueue;
+ typedef std::deque<const Request* > RequestQueue;
typedef std::map<const ClientSocketHandle*, const Request*> RequestMap;
// A Group is allocated per group_name when there are idle sockets or pending
@@ -288,8 +329,12 @@ class ClientSocketPoolBaseHelper
}
bool HasAvailableSocketSlot(int max_sockets_per_group) const {
- return active_socket_count_ + static_cast<int>(jobs_.size()) <
- max_sockets_per_group;
+ return NumActiveSocketSlots() < max_sockets_per_group;
+ }
+
+ int NumActiveSocketSlots() const {
+ return active_socket_count_ + static_cast<int>(jobs_.size()) +
+ static_cast<int>(idle_sockets_.size());
}
bool IsStalled(int max_sockets_per_group) const {
@@ -311,19 +356,18 @@ class ClientSocketPoolBaseHelper
void StartBackupSocketTimer(const std::string& group_name,
ClientSocketPoolBaseHelper* pool);
- // Called when the backup socket timer fires.
- void OnBackupSocketTimerFired(
- std::string group_name,
- ClientSocketPoolBaseHelper* pool);
+ // Searches |jobs_| to see if there's a preconnect ConnectJob, and if so,
+ // uses it. Returns true on success. Otherwise, returns false.
+ bool TryToUsePreconnectConnectJob();
- void AddJob(const ConnectJob* job) { jobs_.insert(job); }
- void RemoveJob(const ConnectJob* job) { jobs_.erase(job); }
+ void AddJob(ConnectJob* job) { jobs_.insert(job); }
+ void RemoveJob(ConnectJob* job) { jobs_.erase(job); }
void RemoveAllJobs();
void IncrementActiveSocketCount() { active_socket_count_++; }
void DecrementActiveSocketCount() { active_socket_count_--; }
- const std::set<const ConnectJob*>& jobs() const { return jobs_; }
+ const std::set<ConnectJob*>& jobs() const { return jobs_; }
const std::list<IdleSocket>& idle_sockets() const { return idle_sockets_; }
const RequestQueue& pending_requests() const { return pending_requests_; }
int active_socket_count() const { return active_socket_count_; }
@@ -331,8 +375,13 @@ class ClientSocketPoolBaseHelper
std::list<IdleSocket>* mutable_idle_sockets() { return &idle_sockets_; }
private:
+ // Called when the backup socket timer fires.
+ void OnBackupSocketTimerFired(
+ std::string group_name,
+ ClientSocketPoolBaseHelper* pool);
+
std::list<IdleSocket> idle_sockets_;
- std::set<const ConnectJob*> jobs_;
+ std::set<ConnectJob*> jobs_;
RequestQueue pending_requests_;
int active_socket_count_; // number of active sockets used by clients
// A factory to pin the backup_job tasks.
@@ -341,7 +390,7 @@ class ClientSocketPoolBaseHelper
typedef std::map<std::string, Group*> GroupMap;
- typedef std::set<const ConnectJob*> ConnectJobSet;
+ typedef std::set<ConnectJob*> ConnectJobSet;
struct CallbackResultPair {
CallbackResultPair() : callback(NULL), result(OK) {}
@@ -381,7 +430,7 @@ class ClientSocketPoolBaseHelper
}
// Removes |job| from |connect_job_set_|. Also updates |group| if non-NULL.
- void RemoveConnectJob(const ConnectJob* job, Group* group);
+ void RemoveConnectJob(ConnectJob* job, Group* group);
// Tries to see if we can handle any more requests for |group|.
void OnAvailableSocketSlot(const std::string& group_name, Group* group);
@@ -505,16 +554,17 @@ class ClientSocketPoolBase {
Request(ClientSocketHandle* handle,
CompletionCallback* callback,
RequestPriority priority,
+ internal::ClientSocketPoolBaseHelper::Flags flags,
const scoped_refptr<SocketParams>& params,
const BoundNetLog& net_log)
: internal::ClientSocketPoolBaseHelper::Request(
- handle, callback, priority, net_log),
+ handle, callback, priority, flags, net_log),
params_(params) {}
const scoped_refptr<SocketParams>& params() const { return params_; }
private:
- scoped_refptr<SocketParams> params_;
+ const scoped_refptr<SocketParams> params_;
};
class ConnectJobFactory {
@@ -556,18 +606,36 @@ class ClientSocketPoolBase {
// These member functions simply forward to ClientSocketPoolBaseHelper.
// RequestSocket bundles up the parameters into a Request and then forwards to
- // ClientSocketPoolBaseHelper::RequestSocket(). Note that the memory
- // ownership is transferred in the asynchronous (ERR_IO_PENDING) case.
+ // ClientSocketPoolBaseHelper::RequestSocket().
int RequestSocket(const std::string& group_name,
const scoped_refptr<SocketParams>& params,
RequestPriority priority,
ClientSocketHandle* handle,
CompletionCallback* callback,
const BoundNetLog& net_log) {
- Request* request = new Request(handle, callback, priority, params, net_log);
+ Request* request =
+ new Request(handle, callback, priority,
+ internal::ClientSocketPoolBaseHelper::NORMAL,
+ params, net_log);
return helper_.RequestSocket(group_name, request);
}
+ // RequestSockets bundles up the parameters into a Request and then forwards
+ // to ClientSocketPoolBaseHelper::RequestSockets(). Note that it assigns the
+ // priority to LOWEST and specifies the NO_IDLE_SOCKETS flag.
+ void RequestSockets(const std::string& group_name,
+ const scoped_refptr<SocketParams>& params,
+ int num_sockets,
+ const BoundNetLog& net_log) {
+ const Request request(NULL /* no handle */,
+ NULL /* no callback */,
+ LOWEST,
+ internal::ClientSocketPoolBaseHelper::NO_IDLE_SOCKETS,
+ params,
+ net_log);
+ helper_.RequestSockets(group_name, request, num_sockets);
+ }
+
void CancelRequest(const std::string& group_name,
ClientSocketHandle* handle) {
return helper_.CancelRequest(group_name, handle);
@@ -599,6 +667,10 @@ class ClientSocketPoolBase {
return helper_.NumConnectJobsInGroup(group_name);
}
+ int NumActiveSocketsInGroup(const std::string& group_name) const {
+ return helper_.NumActiveSocketsInGroup(group_name);
+ }
+
bool HasGroup(const std::string& group_name) const {
return helper_.HasGroup(group_name);
}
diff --git a/net/socket/client_socket_pool_base_unittest.cc b/net/socket/client_socket_pool_base_unittest.cc
index 87f2ae4..0f06160 100644
--- a/net/socket/client_socket_pool_base_unittest.cc
+++ b/net/socket/client_socket_pool_base_unittest.cc
@@ -382,6 +382,16 @@ class TestClientSocketPool : public ClientSocketPool {
handle, callback, net_log);
}
+ virtual void RequestSockets(const std::string& group_name,
+ const void* params,
+ int num_sockets,
+ const BoundNetLog& net_log) {
+ const scoped_refptr<TestSocketParams>* casted_params =
+ static_cast<const scoped_refptr<TestSocketParams>*>(params);
+
+ base_.RequestSockets(group_name, *casted_params, num_sockets, net_log);
+ }
+
virtual void CancelRequest(
const std::string& group_name,
ClientSocketHandle* handle) {
@@ -434,6 +444,10 @@ class TestClientSocketPool : public ClientSocketPool {
return base_.NumConnectJobsInGroup(group_name);
}
+ int NumActiveSocketsInGroup(const std::string& group_name) const {
+ return base_.NumActiveSocketsInGroup(group_name);
+ }
+
bool HasGroup(const std::string& group_name) const {
return base_.HasGroup(group_name);
}
@@ -565,7 +579,9 @@ TEST_F(ClientSocketPoolBaseTest, ConnectJob_NoTimeoutOnSynchronousCompletion) {
TestConnectJobDelegate delegate;
ClientSocketHandle ignored;
TestClientSocketPoolBase::Request request(
- &ignored, NULL, kDefaultPriority, params_, BoundNetLog());
+ &ignored, NULL, kDefaultPriority,
+ internal::ClientSocketPoolBaseHelper::NORMAL,
+ params_, BoundNetLog());
scoped_ptr<TestConnectJob> job(
new TestConnectJob(TestConnectJob::kMockJob,
"a",
@@ -583,7 +599,9 @@ TEST_F(ClientSocketPoolBaseTest, ConnectJob_TimedOut) {
CapturingNetLog log(CapturingNetLog::kUnbounded);
TestClientSocketPoolBase::Request request(
- &ignored, NULL, kDefaultPriority, params_, BoundNetLog());
+ &ignored, NULL, kDefaultPriority,
+ internal::ClientSocketPoolBaseHelper::NORMAL,
+ params_, BoundNetLog());
// Deleted by TestConnectJobDelegate.
TestConnectJob* job =
new TestConnectJob(TestConnectJob::kMockPendingJob,
@@ -2630,6 +2648,350 @@ TEST_F(ClientSocketPoolBaseTest, PreferUsedSocketToUnusedSocket) {
EXPECT_FALSE(handle3.socket()->WasEverUsed());
}
+TEST_F(ClientSocketPoolBaseTest, RequestSockets) {
+ CreatePool(kDefaultMaxSockets, kDefaultMaxSocketsPerGroup);
+ connect_job_factory_->set_job_type(TestConnectJob::kMockPendingJob);
+
+ pool_->RequestSockets("a", &params_, 2, BoundNetLog());
+
+ ASSERT_TRUE(pool_->HasGroup("a"));
+ EXPECT_EQ(2, pool_->NumConnectJobsInGroup("a"));
+ EXPECT_EQ(0, pool_->IdleSocketCountInGroup("a"));
+
+ ClientSocketHandle handle1;
+ TestCompletionCallback callback1;
+ EXPECT_EQ(ERR_IO_PENDING, handle1.Init("a",
+ params_,
+ kDefaultPriority,
+ &callback1,
+ pool_.get(),
+ BoundNetLog()));
+
+ ClientSocketHandle handle2;
+ TestCompletionCallback callback2;
+ EXPECT_EQ(ERR_IO_PENDING, handle2.Init("a",
+ params_,
+ kDefaultPriority,
+ &callback2,
+ pool_.get(),
+ BoundNetLog()));
+
+ EXPECT_EQ(2, pool_->NumConnectJobsInGroup("a"));
+ EXPECT_EQ(0, pool_->IdleSocketCountInGroup("a"));
+
+ EXPECT_EQ(OK, callback1.WaitForResult());
+ EXPECT_EQ(OK, callback2.WaitForResult());
+ handle1.Reset();
+ handle2.Reset();
+
+ EXPECT_EQ(0, pool_->NumConnectJobsInGroup("a"));
+ EXPECT_EQ(2, pool_->IdleSocketCountInGroup("a"));
+}
+
+TEST_F(ClientSocketPoolBaseTest, RequestSocketsWhenAlreadyHaveAConnectJob) {
+ CreatePool(kDefaultMaxSockets, kDefaultMaxSocketsPerGroup);
+ connect_job_factory_->set_job_type(TestConnectJob::kMockPendingJob);
+
+ ClientSocketHandle handle1;
+ TestCompletionCallback callback1;
+ EXPECT_EQ(ERR_IO_PENDING, handle1.Init("a",
+ params_,
+ kDefaultPriority,
+ &callback1,
+ pool_.get(),
+ BoundNetLog()));
+
+ ASSERT_TRUE(pool_->HasGroup("a"));
+ EXPECT_EQ(1, pool_->NumConnectJobsInGroup("a"));
+ EXPECT_EQ(0, pool_->IdleSocketCountInGroup("a"));
+
+ pool_->RequestSockets("a", &params_, 2, BoundNetLog());
+
+ EXPECT_EQ(2, pool_->NumConnectJobsInGroup("a"));
+ EXPECT_EQ(0, pool_->IdleSocketCountInGroup("a"));
+
+ ClientSocketHandle handle2;
+ TestCompletionCallback callback2;
+ EXPECT_EQ(ERR_IO_PENDING, handle2.Init("a",
+ params_,
+ kDefaultPriority,
+ &callback2,
+ pool_.get(),
+ BoundNetLog()));
+
+ EXPECT_EQ(2, pool_->NumConnectJobsInGroup("a"));
+ EXPECT_EQ(0, pool_->IdleSocketCountInGroup("a"));
+
+ EXPECT_EQ(OK, callback1.WaitForResult());
+ EXPECT_EQ(OK, callback2.WaitForResult());
+ handle1.Reset();
+ handle2.Reset();
+
+ EXPECT_EQ(0, pool_->NumConnectJobsInGroup("a"));
+ EXPECT_EQ(2, pool_->IdleSocketCountInGroup("a"));
+}
+
+TEST_F(ClientSocketPoolBaseTest,
+ RequestSocketsWhenAlreadyHaveMultipleConnectJob) {
+ CreatePool(4, 4);
+ connect_job_factory_->set_job_type(TestConnectJob::kMockPendingJob);
+
+ ClientSocketHandle handle1;
+ TestCompletionCallback callback1;
+ EXPECT_EQ(ERR_IO_PENDING, handle1.Init("a",
+ params_,
+ kDefaultPriority,
+ &callback1,
+ pool_.get(),
+ BoundNetLog()));
+
+ ClientSocketHandle handle2;
+ TestCompletionCallback callback2;
+ EXPECT_EQ(ERR_IO_PENDING, handle2.Init("a",
+ params_,
+ kDefaultPriority,
+ &callback2,
+ pool_.get(),
+ BoundNetLog()));
+
+ ClientSocketHandle handle3;
+ TestCompletionCallback callback3;
+ EXPECT_EQ(ERR_IO_PENDING, handle3.Init("a",
+ params_,
+ kDefaultPriority,
+ &callback3,
+ pool_.get(),
+ BoundNetLog()));
+
+ ASSERT_TRUE(pool_->HasGroup("a"));
+ EXPECT_EQ(3, pool_->NumConnectJobsInGroup("a"));
+ EXPECT_EQ(0, pool_->IdleSocketCountInGroup("a"));
+
+ pool_->RequestSockets("a", &params_, 2, BoundNetLog());
+
+ EXPECT_EQ(3, pool_->NumConnectJobsInGroup("a"));
+ EXPECT_EQ(0, pool_->IdleSocketCountInGroup("a"));
+
+ EXPECT_EQ(OK, callback1.WaitForResult());
+ EXPECT_EQ(OK, callback2.WaitForResult());
+ EXPECT_EQ(OK, callback3.WaitForResult());
+ handle1.Reset();
+ handle2.Reset();
+ handle3.Reset();
+
+ EXPECT_EQ(0, pool_->NumConnectJobsInGroup("a"));
+ EXPECT_EQ(3, pool_->IdleSocketCountInGroup("a"));
+}
+
+TEST_F(ClientSocketPoolBaseTest, RequestSocketsAtMaxSocketLimit) {
+ CreatePool(kDefaultMaxSockets, kDefaultMaxSockets);
+ connect_job_factory_->set_job_type(TestConnectJob::kMockPendingJob);
+
+ ASSERT_FALSE(pool_->HasGroup("a"));
+
+ pool_->RequestSockets("a", &params_, kDefaultMaxSockets,
+ BoundNetLog());
+
+ ASSERT_TRUE(pool_->HasGroup("a"));
+ EXPECT_EQ(kDefaultMaxSockets, pool_->NumConnectJobsInGroup("a"));
+
+ ASSERT_FALSE(pool_->HasGroup("b"));
+
+ pool_->RequestSockets("b", &params_, kDefaultMaxSockets,
+ BoundNetLog());
+
+ ASSERT_FALSE(pool_->HasGroup("b"));
+}
+
+TEST_F(ClientSocketPoolBaseTest, RequestSocketsHitMaxSocketLimit) {
+ CreatePool(kDefaultMaxSockets, kDefaultMaxSockets);
+ connect_job_factory_->set_job_type(TestConnectJob::kMockPendingJob);
+
+ ASSERT_FALSE(pool_->HasGroup("a"));
+
+ pool_->RequestSockets("a", &params_, kDefaultMaxSockets - 1,
+ BoundNetLog());
+
+ ASSERT_TRUE(pool_->HasGroup("a"));
+ EXPECT_EQ(kDefaultMaxSockets - 1, pool_->NumConnectJobsInGroup("a"));
+
+ ASSERT_FALSE(pool_->HasGroup("b"));
+
+ pool_->RequestSockets("b", &params_, kDefaultMaxSockets,
+ BoundNetLog());
+
+ ASSERT_TRUE(pool_->HasGroup("b"));
+ EXPECT_EQ(1, pool_->NumConnectJobsInGroup("b"));
+}
+
+TEST_F(ClientSocketPoolBaseTest, RequestSocketsCountIdleSockets) {
+ CreatePool(4, 4);
+ connect_job_factory_->set_job_type(TestConnectJob::kMockPendingJob);
+
+ ClientSocketHandle handle1;
+ TestCompletionCallback callback1;
+ EXPECT_EQ(ERR_IO_PENDING, handle1.Init("a",
+ params_,
+ kDefaultPriority,
+ &callback1,
+ pool_.get(),
+ BoundNetLog()));
+ ASSERT_EQ(OK, callback1.WaitForResult());
+ handle1.Reset();
+
+ ASSERT_TRUE(pool_->HasGroup("a"));
+ EXPECT_EQ(0, pool_->NumConnectJobsInGroup("a"));
+ EXPECT_EQ(1, pool_->IdleSocketCountInGroup("a"));
+
+ pool_->RequestSockets("a", &params_, 2, BoundNetLog());
+
+ EXPECT_EQ(1, pool_->NumConnectJobsInGroup("a"));
+ EXPECT_EQ(1, pool_->IdleSocketCountInGroup("a"));
+}
+
+TEST_F(ClientSocketPoolBaseTest, RequestSocketsCountActiveSockets) {
+ CreatePool(4, 4);
+ connect_job_factory_->set_job_type(TestConnectJob::kMockPendingJob);
+
+ ClientSocketHandle handle1;
+ TestCompletionCallback callback1;
+ EXPECT_EQ(ERR_IO_PENDING, handle1.Init("a",
+ params_,
+ kDefaultPriority,
+ &callback1,
+ pool_.get(),
+ BoundNetLog()));
+ ASSERT_EQ(OK, callback1.WaitForResult());
+
+ ASSERT_TRUE(pool_->HasGroup("a"));
+ EXPECT_EQ(0, pool_->NumConnectJobsInGroup("a"));
+ EXPECT_EQ(0, pool_->IdleSocketCountInGroup("a"));
+ EXPECT_EQ(1, pool_->NumActiveSocketsInGroup("a"));
+
+ pool_->RequestSockets("a", &params_, 2, BoundNetLog());
+
+ EXPECT_EQ(1, pool_->NumConnectJobsInGroup("a"));
+ EXPECT_EQ(0, pool_->IdleSocketCountInGroup("a"));
+ EXPECT_EQ(1, pool_->NumActiveSocketsInGroup("a"));
+}
+
+TEST_F(ClientSocketPoolBaseTest, RequestSocketsSynchronous) {
+ CreatePool(kDefaultMaxSockets, kDefaultMaxSocketsPerGroup);
+ connect_job_factory_->set_job_type(TestConnectJob::kMockJob);
+
+ pool_->RequestSockets("a", &params_, kDefaultMaxSocketsPerGroup,
+ BoundNetLog());
+
+ ASSERT_TRUE(pool_->HasGroup("a"));
+ EXPECT_EQ(0, pool_->NumConnectJobsInGroup("a"));
+ EXPECT_EQ(kDefaultMaxSocketsPerGroup, pool_->IdleSocketCountInGroup("a"));
+
+ pool_->RequestSockets("b", &params_, kDefaultMaxSocketsPerGroup,
+ BoundNetLog());
+
+ EXPECT_EQ(0, pool_->NumConnectJobsInGroup("b"));
+ EXPECT_EQ(kDefaultMaxSocketsPerGroup, pool_->IdleSocketCountInGroup("b"));
+}
+
+TEST_F(ClientSocketPoolBaseTest, RequestSocketsMultipleTimesDoesNothing) {
+ CreatePool(4, 4);
+ connect_job_factory_->set_job_type(TestConnectJob::kMockPendingJob);
+
+ pool_->RequestSockets("a", &params_, 2, BoundNetLog());
+
+ ASSERT_TRUE(pool_->HasGroup("a"));
+ EXPECT_EQ(2, pool_->NumConnectJobsInGroup("a"));
+ EXPECT_EQ(0, pool_->IdleSocketCountInGroup("a"));
+
+ pool_->RequestSockets("a", &params_, 2, BoundNetLog());
+ EXPECT_EQ(2, pool_->NumConnectJobsInGroup("a"));
+ EXPECT_EQ(0, pool_->IdleSocketCountInGroup("a"));
+
+ ClientSocketHandle handle1;
+ TestCompletionCallback callback1;
+ EXPECT_EQ(ERR_IO_PENDING, handle1.Init("a",
+ params_,
+ kDefaultPriority,
+ &callback1,
+ pool_.get(),
+ BoundNetLog()));
+ ASSERT_EQ(OK, callback1.WaitForResult());
+
+ ClientSocketHandle handle2;
+ TestCompletionCallback callback2;
+ int rv = handle2.Init("a",
+ params_,
+ kDefaultPriority,
+ &callback2,
+ pool_.get(),
+ BoundNetLog());
+ if (rv != OK) {
+ EXPECT_EQ(ERR_IO_PENDING, rv);
+ EXPECT_EQ(OK, callback2.WaitForResult());
+ }
+
+ handle1.Reset();
+ handle2.Reset();
+
+ EXPECT_EQ(2, pool_->IdleSocketCountInGroup("a"));
+
+ pool_->RequestSockets("a", &params_, 2, BoundNetLog());
+ EXPECT_EQ(0, pool_->NumConnectJobsInGroup("a"));
+ EXPECT_EQ(2, pool_->IdleSocketCountInGroup("a"));
+}
+
+TEST_F(ClientSocketPoolBaseTest, RequestSocketsDifferentNumSockets) {
+ CreatePool(4, 4);
+ connect_job_factory_->set_job_type(TestConnectJob::kMockPendingJob);
+
+ pool_->RequestSockets("a", &params_, 1, BoundNetLog());
+
+ ASSERT_TRUE(pool_->HasGroup("a"));
+ EXPECT_EQ(1, pool_->NumConnectJobsInGroup("a"));
+ EXPECT_EQ(0, pool_->IdleSocketCountInGroup("a"));
+
+ pool_->RequestSockets("a", &params_, 2, BoundNetLog());
+ EXPECT_EQ(2, pool_->NumConnectJobsInGroup("a"));
+ EXPECT_EQ(0, pool_->IdleSocketCountInGroup("a"));
+
+ pool_->RequestSockets("a", &params_, 3, BoundNetLog());
+ EXPECT_EQ(3, pool_->NumConnectJobsInGroup("a"));
+ EXPECT_EQ(0, pool_->IdleSocketCountInGroup("a"));
+
+ pool_->RequestSockets("a", &params_, 1, BoundNetLog());
+ EXPECT_EQ(3, pool_->NumConnectJobsInGroup("a"));
+ EXPECT_EQ(0, pool_->IdleSocketCountInGroup("a"));
+}
+
+TEST_F(ClientSocketPoolBaseTest, PreconnectJobsTakenByNormalRequests) {
+ CreatePool(kDefaultMaxSockets, kDefaultMaxSocketsPerGroup);
+ connect_job_factory_->set_job_type(TestConnectJob::kMockPendingJob);
+
+ pool_->RequestSockets("a", &params_, 1, BoundNetLog());
+
+ ASSERT_TRUE(pool_->HasGroup("a"));
+ EXPECT_EQ(1, pool_->NumConnectJobsInGroup("a"));
+ EXPECT_EQ(0, pool_->IdleSocketCountInGroup("a"));
+
+ ClientSocketHandle handle1;
+ TestCompletionCallback callback1;
+ EXPECT_EQ(ERR_IO_PENDING, handle1.Init("a",
+ params_,
+ kDefaultPriority,
+ &callback1,
+ pool_.get(),
+ BoundNetLog()));
+
+ EXPECT_EQ(1, pool_->NumConnectJobsInGroup("a"));
+ EXPECT_EQ(0, pool_->IdleSocketCountInGroup("a"));
+
+ ASSERT_EQ(OK, callback1.WaitForResult());
+
+ handle1.Reset();
+
+ EXPECT_EQ(1, pool_->IdleSocketCountInGroup("a"));
+}
+
} // namespace
} // namespace net
diff --git a/net/socket/socks_client_socket_pool.cc b/net/socket/socks_client_socket_pool.cc
index cae333a..6d9e814c 100644
--- a/net/socket/socks_client_socket_pool.cc
+++ b/net/socket/socks_client_socket_pool.cc
@@ -207,6 +207,17 @@ int SOCKSClientSocketPool::RequestSocket(const std::string& group_name,
handle, callback, net_log);
}
+void SOCKSClientSocketPool::RequestSockets(
+ const std::string& group_name,
+ const void* params,
+ int num_sockets,
+ const BoundNetLog& net_log) {
+ const scoped_refptr<SOCKSSocketParams>* casted_params =
+ static_cast<const scoped_refptr<SOCKSSocketParams>*>(params);
+
+ base_.RequestSockets(group_name, *casted_params, num_sockets, net_log);
+}
+
void SOCKSClientSocketPool::CancelRequest(const std::string& group_name,
ClientSocketHandle* handle) {
base_.CancelRequest(group_name, handle);
diff --git a/net/socket/socks_client_socket_pool.h b/net/socket/socks_client_socket_pool.h
index a257d0f..96eb4cf 100644
--- a/net/socket/socks_client_socket_pool.h
+++ b/net/socket/socks_client_socket_pool.h
@@ -122,6 +122,11 @@ class SOCKSClientSocketPool : public ClientSocketPool {
CompletionCallback* callback,
const BoundNetLog& net_log);
+ virtual void RequestSockets(const std::string& group_name,
+ const void* params,
+ int num_sockets,
+ const BoundNetLog& net_log);
+
virtual void CancelRequest(const std::string& group_name,
ClientSocketHandle* handle);
diff --git a/net/socket/ssl_client_socket_pool.cc b/net/socket/ssl_client_socket_pool.cc
index ea0a177..22d921a 100644
--- a/net/socket/ssl_client_socket_pool.cc
+++ b/net/socket/ssl_client_socket_pool.cc
@@ -428,6 +428,17 @@ int SSLClientSocketPool::RequestSocket(const std::string& group_name,
handle, callback, net_log);
}
+void SSLClientSocketPool::RequestSockets(
+ const std::string& group_name,
+ const void* params,
+ int num_sockets,
+ const BoundNetLog& net_log) {
+ const scoped_refptr<SSLSocketParams>* casted_params =
+ static_cast<const scoped_refptr<SSLSocketParams>*>(params);
+
+ base_.RequestSockets(group_name, *casted_params, num_sockets, net_log);
+}
+
void SSLClientSocketPool::CancelRequest(const std::string& group_name,
ClientSocketHandle* handle) {
base_.CancelRequest(group_name, handle);
diff --git a/net/socket/ssl_client_socket_pool.h b/net/socket/ssl_client_socket_pool.h
index 2c75e03..935a0d7 100644
--- a/net/socket/ssl_client_socket_pool.h
+++ b/net/socket/ssl_client_socket_pool.h
@@ -183,6 +183,11 @@ class SSLClientSocketPool : public ClientSocketPool,
CompletionCallback* callback,
const BoundNetLog& net_log);
+ virtual void RequestSockets(const std::string& group_name,
+ const void* params,
+ int num_sockets,
+ const BoundNetLog& net_log);
+
virtual void CancelRequest(const std::string& group_name,
ClientSocketHandle* handle);
diff --git a/net/socket/tcp_client_socket_pool.cc b/net/socket/tcp_client_socket_pool.cc
index bea4dff..f11ae25 100644
--- a/net/socket/tcp_client_socket_pool.cc
+++ b/net/socket/tcp_client_socket_pool.cc
@@ -231,6 +231,26 @@ int TCPClientSocketPool::RequestSocket(
callback, net_log);
}
+void TCPClientSocketPool::RequestSockets(
+ const std::string& group_name,
+ const void* params,
+ int num_sockets,
+ const BoundNetLog& net_log) {
+ const scoped_refptr<TCPSocketParams>* casted_params =
+ static_cast<const scoped_refptr<TCPSocketParams>*>(params);
+
+ if (net_log.IsLoggingAll()) {
+ // TODO(eroman): Split out the host and port parameters.
+ net_log.AddEvent(
+ NetLog::TYPE_TCP_CLIENT_SOCKET_POOL_REQUESTED_SOCKETS,
+ new NetLogStringParameter(
+ "host_and_port",
+ casted_params->get()->destination().host_port_pair().ToString()));
+ }
+
+ base_.RequestSockets(group_name, *casted_params, num_sockets, net_log);
+}
+
void TCPClientSocketPool::CancelRequest(
const std::string& group_name,
ClientSocketHandle* handle) {
diff --git a/net/socket/tcp_client_socket_pool.h b/net/socket/tcp_client_socket_pool.h
index 4837468..08f0634f 100644
--- a/net/socket/tcp_client_socket_pool.h
+++ b/net/socket/tcp_client_socket_pool.h
@@ -131,6 +131,11 @@ class TCPClientSocketPool : public ClientSocketPool {
CompletionCallback* callback,
const BoundNetLog& net_log);
+ virtual void RequestSockets(const std::string& group_name,
+ const void* params,
+ int num_sockets,
+ const BoundNetLog& net_log);
+
virtual void CancelRequest(const std::string& group_name,
ClientSocketHandle* handle);