diff options
-rw-r--r-- | net/base/net_log_event_type_list.h | 14 | ||||
-rw-r--r-- | net/http/http_proxy_client_socket_pool.cc | 11 | ||||
-rw-r--r-- | net/http/http_proxy_client_socket_pool.h | 5 | ||||
-rw-r--r-- | net/socket/client_socket_pool.h | 15 | ||||
-rw-r--r-- | net/socket/client_socket_pool_base.cc | 107 | ||||
-rw-r--r-- | net/socket/client_socket_pool_base.h | 108 | ||||
-rw-r--r-- | net/socket/client_socket_pool_base_unittest.cc | 366 | ||||
-rw-r--r-- | net/socket/socks_client_socket_pool.cc | 11 | ||||
-rw-r--r-- | net/socket/socks_client_socket_pool.h | 5 | ||||
-rw-r--r-- | net/socket/ssl_client_socket_pool.cc | 11 | ||||
-rw-r--r-- | net/socket/ssl_client_socket_pool.h | 5 | ||||
-rw-r--r-- | net/socket/tcp_client_socket_pool.cc | 20 | ||||
-rw-r--r-- | net/socket/tcp_client_socket_pool.h | 5 |
13 files changed, 646 insertions, 37 deletions
diff --git a/net/base/net_log_event_type_list.h b/net/base/net_log_event_type_list.h index 9c3264f..b0b4d4b 100644 --- a/net/base/net_log_event_type_list.h +++ b/net/base/net_log_event_type_list.h @@ -412,6 +412,13 @@ EVENT_TYPE(SOCKET_POOL_REUSED_AN_EXISTING_SOCKET) // } EVENT_TYPE(TCP_CLIENT_SOCKET_POOL_REQUESTED_SOCKET) +// This event simply describes the host:port that were requested from the +// socket pool. Its parameters are: +// { +// "host_and_port": <String encoding the host and port> +// } +EVENT_TYPE(TCP_CLIENT_SOCKET_POOL_REQUESTED_SOCKETS) + // A backup socket is created due to slow connect EVENT_TYPE(SOCKET_BACKUP_CREATED) @@ -434,6 +441,13 @@ EVENT_TYPE(SOCKET_POOL_BOUND_TO_CONNECT_JOB) // } EVENT_TYPE(SOCKET_POOL_BOUND_TO_SOCKET) +// The start/end of a client socket pool request for multiple sockets. +// The event parameters are: +// { +// "num_sockets": <Number of sockets we're trying to ensure are connected> +// } +EVENT_TYPE(SOCKET_POOL_CONNECTING_N_SOCKETS) + // ------------------------------------------------------------------------ // URLRequest // ------------------------------------------------------------------------ diff --git a/net/http/http_proxy_client_socket_pool.cc b/net/http/http_proxy_client_socket_pool.cc index 0f55e14..4a5495b 100644 --- a/net/http/http_proxy_client_socket_pool.cc +++ b/net/http/http_proxy_client_socket_pool.cc @@ -299,6 +299,17 @@ int HttpProxyClientSocketPool::RequestSocket(const std::string& group_name, handle, callback, net_log); } +void HttpProxyClientSocketPool::RequestSockets( + const std::string& group_name, + const void* params, + int num_sockets, + const BoundNetLog& net_log) { + const scoped_refptr<HttpProxySocketParams>* casted_params = + static_cast<const scoped_refptr<HttpProxySocketParams>*>(params); + + base_.RequestSockets(group_name, *casted_params, num_sockets, net_log); +} + void HttpProxyClientSocketPool::CancelRequest( const std::string& group_name, ClientSocketHandle* handle) { diff --git a/net/http/http_proxy_client_socket_pool.h b/net/http/http_proxy_client_socket_pool.h index 3ee215a..f95a054 100644 --- a/net/http/http_proxy_client_socket_pool.h +++ b/net/http/http_proxy_client_socket_pool.h @@ -162,6 +162,11 @@ class HttpProxyClientSocketPool : 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/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", ¶ms_, 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", ¶ms_, 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", ¶ms_, 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", ¶ms_, kDefaultMaxSockets, + BoundNetLog()); + + ASSERT_TRUE(pool_->HasGroup("a")); + EXPECT_EQ(kDefaultMaxSockets, pool_->NumConnectJobsInGroup("a")); + + ASSERT_FALSE(pool_->HasGroup("b")); + + pool_->RequestSockets("b", ¶ms_, 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", ¶ms_, kDefaultMaxSockets - 1, + BoundNetLog()); + + ASSERT_TRUE(pool_->HasGroup("a")); + EXPECT_EQ(kDefaultMaxSockets - 1, pool_->NumConnectJobsInGroup("a")); + + ASSERT_FALSE(pool_->HasGroup("b")); + + pool_->RequestSockets("b", ¶ms_, 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", ¶ms_, 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", ¶ms_, 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", ¶ms_, kDefaultMaxSocketsPerGroup, + BoundNetLog()); + + ASSERT_TRUE(pool_->HasGroup("a")); + EXPECT_EQ(0, pool_->NumConnectJobsInGroup("a")); + EXPECT_EQ(kDefaultMaxSocketsPerGroup, pool_->IdleSocketCountInGroup("a")); + + pool_->RequestSockets("b", ¶ms_, 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", ¶ms_, 2, BoundNetLog()); + + ASSERT_TRUE(pool_->HasGroup("a")); + EXPECT_EQ(2, pool_->NumConnectJobsInGroup("a")); + EXPECT_EQ(0, pool_->IdleSocketCountInGroup("a")); + + pool_->RequestSockets("a", ¶ms_, 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", ¶ms_, 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", ¶ms_, 1, BoundNetLog()); + + ASSERT_TRUE(pool_->HasGroup("a")); + EXPECT_EQ(1, pool_->NumConnectJobsInGroup("a")); + EXPECT_EQ(0, pool_->IdleSocketCountInGroup("a")); + + pool_->RequestSockets("a", ¶ms_, 2, BoundNetLog()); + EXPECT_EQ(2, pool_->NumConnectJobsInGroup("a")); + EXPECT_EQ(0, pool_->IdleSocketCountInGroup("a")); + + pool_->RequestSockets("a", ¶ms_, 3, BoundNetLog()); + EXPECT_EQ(3, pool_->NumConnectJobsInGroup("a")); + EXPECT_EQ(0, pool_->IdleSocketCountInGroup("a")); + + pool_->RequestSockets("a", ¶ms_, 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", ¶ms_, 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); |