blob: 13d8b684311a86497480f54d170f9d53dfd4d971 [file] [log] [blame]
[email protected]a796bcec2010-03-22 17:17:261// Copyright (c) 2010 The Chromium Authors. All rights reserved.
[email protected]ff579d42009-06-24 15:47:022// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "net/socket/client_socket_pool_base.h"
6
7#include "base/compiler_specific.h"
[email protected]fd4fe0b2010-02-08 23:02:158#include "base/format_macros.h"
[email protected]ff579d42009-06-24 15:47:029#include "base/message_loop.h"
[email protected]6b624c62010-03-14 08:37:3210#include "base/stats_counters.h"
[email protected]ff579d42009-06-24 15:47:0211#include "base/stl_util-inl.h"
[email protected]fd4fe0b2010-02-08 23:02:1512#include "base/string_util.h"
[email protected]ff579d42009-06-24 15:47:0213#include "base/time.h"
[email protected]9349cfb2010-08-31 18:00:5314#include "base/values.h"
[email protected]9e743cd2010-03-16 07:03:5315#include "net/base/net_log.h"
[email protected]ff579d42009-06-24 15:47:0216#include "net/base/net_errors.h"
17#include "net/socket/client_socket_handle.h"
18
19using base::TimeDelta;
20
21namespace {
22
23// The timeout value, in seconds, used to clean up idle sockets that can't be
24// reused.
25//
26// Note: It's important to close idle sockets that have received data as soon
27// as possible because the received data may cause BSOD on Windows XP under
28// some conditions. See http://crbug.com/4606.
29const int kCleanupInterval = 10; // DO NOT INCREASE THIS TIMEOUT.
30
[email protected]06d94042010-08-25 01:45:2231// Indicate whether or not we should establish a new TCP connection after a
32// certain timeout has passed without receiving an ACK.
33bool g_connect_backup_jobs_enabled = true;
34
[email protected]ff579d42009-06-24 15:47:0235} // namespace
36
37namespace net {
38
[email protected]2ab05b52009-07-01 23:57:5839ConnectJob::ConnectJob(const std::string& group_name,
[email protected]974ebd62009-08-03 23:14:3440 base::TimeDelta timeout_duration,
[email protected]fd7b7c92009-08-20 19:38:3041 Delegate* delegate,
[email protected]9e743cd2010-03-16 07:03:5342 const BoundNetLog& net_log)
[email protected]2ab05b52009-07-01 23:57:5843 : group_name_(group_name),
[email protected]974ebd62009-08-03 23:14:3444 timeout_duration_(timeout_duration),
[email protected]2ab05b52009-07-01 23:57:5845 delegate_(delegate),
[email protected]a2006ece2010-04-23 16:44:0246 net_log_(net_log),
[email protected]2c2bef152010-10-13 00:55:0347 idle_(true),
48 preconnect_state_(NOT_PRECONNECT) {
[email protected]2ab05b52009-07-01 23:57:5849 DCHECK(!group_name.empty());
[email protected]2ab05b52009-07-01 23:57:5850 DCHECK(delegate);
[email protected]06650c52010-06-03 00:49:1751 net_log.BeginEvent(NetLog::TYPE_SOCKET_POOL_CONNECT_JOB, NULL);
[email protected]2ab05b52009-07-01 23:57:5852}
53
[email protected]fd7b7c92009-08-20 19:38:3054ConnectJob::~ConnectJob() {
[email protected]06650c52010-06-03 00:49:1755 net_log().EndEvent(NetLog::TYPE_SOCKET_POOL_CONNECT_JOB, NULL);
[email protected]fd7b7c92009-08-20 19:38:3056}
[email protected]2ab05b52009-07-01 23:57:5857
[email protected]2c2bef152010-10-13 00:55:0358void ConnectJob::Initialize(bool is_preconnect) {
59 if (is_preconnect)
60 preconnect_state_ = UNUSED_PRECONNECT;
61 else
62 preconnect_state_ = NOT_PRECONNECT;
63}
64
[email protected]974ebd62009-08-03 23:14:3465int ConnectJob::Connect() {
66 if (timeout_duration_ != base::TimeDelta())
67 timer_.Start(timeout_duration_, this, &ConnectJob::OnTimeout);
[email protected]fd7b7c92009-08-20 19:38:3068
[email protected]a2006ece2010-04-23 16:44:0269 idle_ = false;
[email protected]fd7b7c92009-08-20 19:38:3070
[email protected]06650c52010-06-03 00:49:1771 LogConnectStart();
72
[email protected]fd7b7c92009-08-20 19:38:3073 int rv = ConnectInternal();
74
75 if (rv != ERR_IO_PENDING) {
[email protected]06650c52010-06-03 00:49:1776 LogConnectCompletion(rv);
[email protected]fd7b7c92009-08-20 19:38:3077 delegate_ = NULL;
[email protected]fd7b7c92009-08-20 19:38:3078 }
79
80 return rv;
81}
82
[email protected]2c2bef152010-10-13 00:55:0383void ConnectJob::UseForNormalRequest() {
84 DCHECK_EQ(UNUSED_PRECONNECT, preconnect_state_);
85 preconnect_state_ = USED_PRECONNECT;
86}
87
[email protected]06650c52010-06-03 00:49:1788void ConnectJob::set_socket(ClientSocket* socket) {
89 if (socket) {
90 net_log().AddEvent(NetLog::TYPE_CONNECT_JOB_SET_SOCKET,
91 new NetLogSourceParameter("source_dependency",
92 socket->NetLog().source()));
93 }
94 socket_.reset(socket);
95}
96
[email protected]fd7b7c92009-08-20 19:38:3097void ConnectJob::NotifyDelegateOfCompletion(int rv) {
98 // The delegate will delete |this|.
99 Delegate *delegate = delegate_;
100 delegate_ = NULL;
101
[email protected]06650c52010-06-03 00:49:17102 LogConnectCompletion(rv);
[email protected]fd7b7c92009-08-20 19:38:30103 delegate->OnConnectJobComplete(rv, this);
[email protected]974ebd62009-08-03 23:14:34104}
105
[email protected]a796bcec2010-03-22 17:17:26106void ConnectJob::ResetTimer(base::TimeDelta remaining_time) {
107 timer_.Stop();
108 timer_.Start(remaining_time, this, &ConnectJob::OnTimeout);
109}
110
[email protected]06650c52010-06-03 00:49:17111void ConnectJob::LogConnectStart() {
112 net_log().BeginEvent(NetLog::TYPE_SOCKET_POOL_CONNECT_JOB_CONNECT,
113 new NetLogStringParameter("group_name", group_name_));
114}
115
116void ConnectJob::LogConnectCompletion(int net_error) {
117 scoped_refptr<NetLog::EventParameters> params;
118 if (net_error != OK)
119 params = new NetLogIntegerParameter("net_error", net_error);
120 net_log().EndEvent(NetLog::TYPE_SOCKET_POOL_CONNECT_JOB_CONNECT, params);
121}
122
[email protected]974ebd62009-08-03 23:14:34123void ConnectJob::OnTimeout() {
[email protected]6e713f02009-08-06 02:56:40124 // Make sure the socket is NULL before calling into |delegate|.
125 set_socket(NULL);
[email protected]fd7b7c92009-08-20 19:38:30126
[email protected]ec11be62010-04-28 19:28:09127 net_log_.AddEvent(NetLog::TYPE_SOCKET_POOL_CONNECT_JOB_TIMED_OUT, NULL);
[email protected]fd7b7c92009-08-20 19:38:30128
129 NotifyDelegateOfCompletion(ERR_TIMED_OUT);
[email protected]974ebd62009-08-03 23:14:34130}
131
[email protected]d80a4322009-08-14 07:07:49132namespace internal {
133
[email protected]fd4fe0b2010-02-08 23:02:15134ClientSocketPoolBaseHelper::Request::Request(
135 ClientSocketHandle* handle,
136 CompletionCallback* callback,
137 RequestPriority priority,
[email protected]2c2bef152010-10-13 00:55:03138 Flags flags,
[email protected]9e743cd2010-03-16 07:03:53139 const BoundNetLog& net_log)
[email protected]2431756e2010-09-29 20:26:13140 : handle_(handle),
141 callback_(callback),
142 priority_(priority),
[email protected]2c2bef152010-10-13 00:55:03143 flags_(flags),
[email protected]9e743cd2010-03-16 07:03:53144 net_log_(net_log) {}
[email protected]fd4fe0b2010-02-08 23:02:15145
146ClientSocketPoolBaseHelper::Request::~Request() {}
147
[email protected]d80a4322009-08-14 07:07:49148ClientSocketPoolBaseHelper::ClientSocketPoolBaseHelper(
[email protected]211d2172009-07-22 15:48:53149 int max_sockets,
[email protected]ff579d42009-06-24 15:47:02150 int max_sockets_per_group,
[email protected]9bf28db2009-08-29 01:35:16151 base::TimeDelta unused_idle_socket_timeout,
152 base::TimeDelta used_idle_socket_timeout,
[email protected]66761b952010-06-25 21:30:38153 ConnectJobFactory* connect_job_factory)
[email protected]ff579d42009-06-24 15:47:02154 : idle_socket_count_(0),
[email protected]211d2172009-07-22 15:48:53155 connecting_socket_count_(0),
156 handed_out_socket_count_(0),
157 max_sockets_(max_sockets),
[email protected]ff579d42009-06-24 15:47:02158 max_sockets_per_group_(max_sockets_per_group),
[email protected]9bf28db2009-08-29 01:35:16159 unused_idle_socket_timeout_(unused_idle_socket_timeout),
160 used_idle_socket_timeout_(used_idle_socket_timeout),
[email protected]100d5fb92009-12-21 21:08:35161 connect_job_factory_(connect_job_factory),
[email protected]06d94042010-08-25 01:45:22162 connect_backup_jobs_enabled_(false),
[email protected]2431756e2010-09-29 20:26:13163 pool_generation_number_(0),
164 method_factory_(ALLOW_THIS_IN_INITIALIZER_LIST(this)) {
[email protected]211d2172009-07-22 15:48:53165 DCHECK_LE(0, max_sockets_per_group);
166 DCHECK_LE(max_sockets_per_group, max_sockets);
[email protected]a554a8262010-05-20 00:13:52167
[email protected]66761b952010-06-25 21:30:38168 NetworkChangeNotifier::AddObserver(this);
[email protected]211d2172009-07-22 15:48:53169}
[email protected]ff579d42009-06-24 15:47:02170
[email protected]d80a4322009-08-14 07:07:49171ClientSocketPoolBaseHelper::~ClientSocketPoolBaseHelper() {
[email protected]2431756e2010-09-29 20:26:13172 // Clean up any idle sockets and pending connect jobs. Assert that we have no
173 // remaining active sockets or pending requests. They should have all been
174 // cleaned up prior to |this| being destroyed.
175 Flush();
176 DCHECK(group_map_.empty());
[email protected]05ea9ff2010-07-15 19:08:21177 DCHECK(pending_callback_map_.empty());
[email protected]4d3b05d2010-01-27 21:27:29178 DCHECK_EQ(0, connecting_socket_count_);
[email protected]a554a8262010-05-20 00:13:52179
[email protected]66761b952010-06-25 21:30:38180 NetworkChangeNotifier::RemoveObserver(this);
[email protected]ff579d42009-06-24 15:47:02181}
182
183// InsertRequestIntoQueue inserts the request into the queue based on
184// priority. Highest priorities are closest to the front. Older requests are
185// prioritized over requests of equal priority.
186//
187// static
[email protected]d80a4322009-08-14 07:07:49188void ClientSocketPoolBaseHelper::InsertRequestIntoQueue(
189 const Request* r, RequestQueue* pending_requests) {
[email protected]ff579d42009-06-24 15:47:02190 RequestQueue::iterator it = pending_requests->begin();
[email protected]ac790b42009-12-02 04:31:31191 while (it != pending_requests->end() && r->priority() >= (*it)->priority())
[email protected]ff579d42009-06-24 15:47:02192 ++it;
193 pending_requests->insert(it, r);
194}
195
[email protected]fd7b7c92009-08-20 19:38:30196// static
197const ClientSocketPoolBaseHelper::Request*
198ClientSocketPoolBaseHelper::RemoveRequestFromQueue(
[email protected]3f00be82010-09-27 19:50:02199 RequestQueue::iterator it, Group* group) {
[email protected]fd7b7c92009-08-20 19:38:30200 const Request* req = *it;
[email protected]3f00be82010-09-27 19:50:02201 group->mutable_pending_requests()->erase(it);
202 // If there are no more requests, we kill the backup timer.
203 if (group->pending_requests().empty())
204 group->CleanupBackupJob();
[email protected]fd7b7c92009-08-20 19:38:30205 return req;
206}
207
[email protected]d80a4322009-08-14 07:07:49208int ClientSocketPoolBaseHelper::RequestSocket(
[email protected]ff579d42009-06-24 15:47:02209 const std::string& group_name,
[email protected]d80a4322009-08-14 07:07:49210 const Request* request) {
[email protected]2c2bef152010-10-13 00:55:03211 CHECK(request->callback());
212 CHECK(request->handle());
213
[email protected]ec11be62010-04-28 19:28:09214 request->net_log().BeginEvent(NetLog::TYPE_SOCKET_POOL, NULL);
[email protected]aed99ef02010-08-26 14:04:32215 Group* group = GetOrCreateGroup(group_name);
[email protected]eb5a99382010-07-11 03:18:26216
[email protected]fd4fe0b2010-02-08 23:02:15217 int rv = RequestSocketInternal(group_name, request);
[email protected]e7e99322010-05-04 23:30:17218 if (rv != ERR_IO_PENDING) {
[email protected]ec11be62010-04-28 19:28:09219 request->net_log().EndEvent(NetLog::TYPE_SOCKET_POOL, NULL);
[email protected]05ea9ff2010-07-15 19:08:21220 CHECK(!request->handle()->is_initialized());
[email protected]e7e99322010-05-04 23:30:17221 delete request;
222 } else {
[email protected]aed99ef02010-08-26 14:04:32223 InsertRequestIntoQueue(request, group->mutable_pending_requests());
[email protected]e7e99322010-05-04 23:30:17224 }
[email protected]fd4fe0b2010-02-08 23:02:15225 return rv;
226}
227
[email protected]2c2bef152010-10-13 00:55:03228void ClientSocketPoolBaseHelper::RequestSockets(
229 const std::string& group_name,
230 const Request& request,
231 int num_sockets) {
232 DCHECK(!request.callback());
233 DCHECK(!request.handle());
234
235 if (num_sockets > max_sockets_per_group_) {
236 NOTREACHED();
237 num_sockets = max_sockets_per_group_;
238 }
239
240 request.net_log().BeginEvent(
241 NetLog::TYPE_SOCKET_POOL_CONNECTING_N_SOCKETS,
242 new NetLogIntegerParameter("num_sockets", num_sockets));
243
244 Group* group = GetOrCreateGroup(group_name);
245
246 for (int num_iterations_left = num_sockets;
247 group->NumActiveSocketSlots() < num_sockets &&
248 num_iterations_left > 0 ; num_iterations_left--) {
249 int rv = RequestSocketInternal(group_name, &request);
250 if (rv < 0 && rv != ERR_IO_PENDING) {
251 // We're encountering a synchronous error. Give up.
252 break;
253 }
254 }
255
256 if (group->IsEmpty())
257 RemoveGroup(group_name);
258
259 request.net_log().EndEvent(
260 NetLog::TYPE_SOCKET_POOL_CONNECTING_N_SOCKETS, NULL);
261}
262
[email protected]fd4fe0b2010-02-08 23:02:15263int ClientSocketPoolBaseHelper::RequestSocketInternal(
264 const std::string& group_name,
265 const Request* request) {
[email protected]d80a4322009-08-14 07:07:49266 DCHECK_GE(request->priority(), 0);
[email protected]d80a4322009-08-14 07:07:49267 ClientSocketHandle* const handle = request->handle();
[email protected]2c2bef152010-10-13 00:55:03268 const bool preconnecting = !handle;
[email protected]aed99ef02010-08-26 14:04:32269 Group* group = GetOrCreateGroup(group_name);
[email protected]ff579d42009-06-24 15:47:02270
[email protected]2c2bef152010-10-13 00:55:03271 if (!(request->flags() & NO_IDLE_SOCKETS)) {
272 // Try to reuse a socket.
273 if (AssignIdleSocketToGroup(request, group))
274 return OK;
275 }
276
277 if (!preconnecting && group->TryToUsePreconnectConnectJob())
278 return ERR_IO_PENDING;
[email protected]65552102010-04-09 22:58:10279
[email protected]43a21b82010-06-10 21:30:54280 // Can we make another active socket now?
[email protected]aed99ef02010-08-26 14:04:32281 if (!group->HasAvailableSocketSlot(max_sockets_per_group_)) {
[email protected]43a21b82010-06-10 21:30:54282 request->net_log().AddEvent(
283 NetLog::TYPE_SOCKET_POOL_STALLED_MAX_SOCKETS_PER_GROUP, NULL);
284 return ERR_IO_PENDING;
285 }
286
287 if (ReachedMaxSocketsLimit()) {
288 if (idle_socket_count() > 0) {
289 CloseOneIdleSocket();
290 } else {
291 // We could check if we really have a stalled group here, but it requires
292 // a scan of all groups, so just flip a flag here, and do the check later.
[email protected]43a21b82010-06-10 21:30:54293 request->net_log().AddEvent(
294 NetLog::TYPE_SOCKET_POOL_STALLED_MAX_SOCKETS, NULL);
295 return ERR_IO_PENDING;
296 }
297 }
298
[email protected]ff579d42009-06-24 15:47:02299 // We couldn't find a socket to reuse, so allocate and connect a new one.
[email protected]2ab05b52009-07-01 23:57:58300 scoped_ptr<ConnectJob> connect_job(
[email protected]06650c52010-06-03 00:49:17301 connect_job_factory_->NewConnectJob(group_name, *request, this));
[email protected]ff579d42009-06-24 15:47:02302
[email protected]2c2bef152010-10-13 00:55:03303 connect_job->Initialize(preconnecting);
[email protected]2ab05b52009-07-01 23:57:58304 int rv = connect_job->Connect();
305 if (rv == OK) {
[email protected]06650c52010-06-03 00:49:17306 LogBoundConnectJobToRequest(connect_job->net_log().source(), request);
[email protected]2c2bef152010-10-13 00:55:03307 if (!preconnecting) {
308 HandOutSocket(connect_job->ReleaseSocket(), false /* not reused */,
309 handle, base::TimeDelta(), group, request->net_log());
310 } else {
311 AddIdleSocket(connect_job->ReleaseSocket(), group);
312 }
[email protected]2ab05b52009-07-01 23:57:58313 } else if (rv == ERR_IO_PENDING) {
[email protected]6b624c62010-03-14 08:37:32314 // If we don't have any sockets in this group, set a timer for potentially
315 // creating a new one. If the SYN is lost, this backup socket may complete
316 // before the slow socket, improving end user latency.
[email protected]2c2bef152010-10-13 00:55:03317 if (connect_backup_jobs_enabled_ &&
318 group->IsEmpty() && !group->HasBackupJob() &&
319 handle) {
[email protected]aed99ef02010-08-26 14:04:32320 group->StartBackupSocketTimer(group_name, this);
[email protected]2c2bef152010-10-13 00:55:03321 }
[email protected]6b624c62010-03-14 08:37:32322
[email protected]211d2172009-07-22 15:48:53323 connecting_socket_count_++;
324
[email protected]aed99ef02010-08-26 14:04:32325 group->AddJob(connect_job.release());
[email protected]a2006ece2010-04-23 16:44:02326 } else {
[email protected]06650c52010-06-03 00:49:17327 LogBoundConnectJobToRequest(connect_job->net_log().source(), request);
[email protected]e60e47a2010-07-14 03:37:18328 connect_job->GetAdditionalErrorState(handle);
[email protected]e772db3f2010-07-12 18:11:13329 ClientSocket* error_socket = connect_job->ReleaseSocket();
330 if (error_socket) {
331 HandOutSocket(error_socket, false /* not reused */, handle,
[email protected]aed99ef02010-08-26 14:04:32332 base::TimeDelta(), group, request->net_log());
333 } else if (group->IsEmpty()) {
334 RemoveGroup(group_name);
[email protected]05ea9ff2010-07-15 19:08:21335 }
[email protected]2ab05b52009-07-01 23:57:58336 }
[email protected]ff579d42009-06-24 15:47:02337
[email protected]2ab05b52009-07-01 23:57:58338 return rv;
[email protected]ff579d42009-06-24 15:47:02339}
340
[email protected]05ea9ff2010-07-15 19:08:21341bool ClientSocketPoolBaseHelper::AssignIdleSocketToGroup(
[email protected]aed99ef02010-08-26 14:04:32342 const Request* request, Group* group) {
[email protected]e1b54dc2010-10-06 21:27:22343 std::list<IdleSocket>* idle_sockets = group->mutable_idle_sockets();
344 std::list<IdleSocket>::iterator idle_socket_it = idle_sockets->end();
345
346 // Iterate through the idle sockets forwards (oldest to newest)
347 // * Delete any disconnected ones.
348 // * If we find a used idle socket, assign to |idle_socket|. At the end,
349 // the |idle_socket_it| will be set to the newest used idle socket.
350 for (std::list<IdleSocket>::iterator it = idle_sockets->begin();
351 it != idle_sockets->end();) {
352 if (!it->socket->IsConnectedAndIdle()) {
353 DecrementIdleCount();
354 delete it->socket;
355 it = idle_sockets->erase(it);
356 continue;
[email protected]eb5a99382010-07-11 03:18:26357 }
[email protected]e1b54dc2010-10-06 21:27:22358
359 if (it->socket->WasEverUsed()) {
360 // We found one we can reuse!
361 idle_socket_it = it;
362 }
363
364 ++it;
[email protected]eb5a99382010-07-11 03:18:26365 }
[email protected]e1b54dc2010-10-06 21:27:22366
367 // If we haven't found an idle socket, that means there are no used idle
368 // sockets. Pick the oldest (first) idle socket (FIFO).
369
370 if (idle_socket_it == idle_sockets->end() && !idle_sockets->empty())
371 idle_socket_it = idle_sockets->begin();
372
373 if (idle_socket_it != idle_sockets->end()) {
374 DecrementIdleCount();
375 base::TimeDelta idle_time =
376 base::TimeTicks::Now() - idle_socket_it->start_time;
377 IdleSocket idle_socket = *idle_socket_it;
378 idle_sockets->erase(idle_socket_it);
379 HandOutSocket(
380 idle_socket.socket,
381 idle_socket.socket->WasEverUsed(),
382 request->handle(),
383 idle_time,
384 group,
385 request->net_log());
386 return true;
387 }
388
[email protected]eb5a99382010-07-11 03:18:26389 return false;
390}
391
[email protected]06650c52010-06-03 00:49:17392// static
393void ClientSocketPoolBaseHelper::LogBoundConnectJobToRequest(
394 const NetLog::Source& connect_job_source, const Request* request) {
395 request->net_log().AddEvent(
396 NetLog::TYPE_SOCKET_POOL_BOUND_TO_CONNECT_JOB,
397 new NetLogSourceParameter("source_dependency", connect_job_source));
398}
399
[email protected]d80a4322009-08-14 07:07:49400void ClientSocketPoolBaseHelper::CancelRequest(
[email protected]05ea9ff2010-07-15 19:08:21401 const std::string& group_name, ClientSocketHandle* handle) {
402 PendingCallbackMap::iterator callback_it = pending_callback_map_.find(handle);
403 if (callback_it != pending_callback_map_.end()) {
404 int result = callback_it->second.result;
405 pending_callback_map_.erase(callback_it);
406 ClientSocket* socket = handle->release_socket();
407 if (socket) {
408 if (result != OK)
409 socket->Disconnect();
410 ReleaseSocket(handle->group_name(), socket, handle->id());
411 }
412 return;
413 }
[email protected]b6501d3d2010-06-03 23:53:34414
[email protected]ff579d42009-06-24 15:47:02415 CHECK(ContainsKey(group_map_, group_name));
416
[email protected]aed99ef02010-08-26 14:04:32417 Group* group = GetOrCreateGroup(group_name);
[email protected]ff579d42009-06-24 15:47:02418
[email protected]ff579d42009-06-24 15:47:02419 // Search pending_requests for matching handle.
[email protected]aed99ef02010-08-26 14:04:32420 RequestQueue::iterator it = group->mutable_pending_requests()->begin();
421 for (; it != group->pending_requests().end(); ++it) {
[email protected]d80a4322009-08-14 07:07:49422 if ((*it)->handle() == handle) {
[email protected]2c2bef152010-10-13 00:55:03423 scoped_ptr<const Request> req(RemoveRequestFromQueue(it, group));
[email protected]ec11be62010-04-28 19:28:09424 req->net_log().AddEvent(NetLog::TYPE_CANCELLED, NULL);
425 req->net_log().EndEvent(NetLog::TYPE_SOCKET_POOL, NULL);
[email protected]eb5a99382010-07-11 03:18:26426
427 // We let the job run, unless we're at the socket limit.
[email protected]aed99ef02010-08-26 14:04:32428 if (group->jobs().size() && ReachedMaxSocketsLimit()) {
429 RemoveConnectJob(*group->jobs().begin(), group);
[email protected]eb5a99382010-07-11 03:18:26430 CheckForStalledSocketGroups();
[email protected]974ebd62009-08-03 23:14:34431 }
[email protected]eb5a99382010-07-11 03:18:26432 break;
[email protected]ff579d42009-06-24 15:47:02433 }
434 }
[email protected]ff579d42009-06-24 15:47:02435}
436
[email protected]2abfe90a2010-08-25 17:49:51437bool ClientSocketPoolBaseHelper::HasGroup(const std::string& group_name) const {
438 return ContainsKey(group_map_, group_name);
439}
440
[email protected]d80a4322009-08-14 07:07:49441void ClientSocketPoolBaseHelper::CloseIdleSockets() {
[email protected]ff579d42009-06-24 15:47:02442 CleanupIdleSockets(true);
[email protected]06f92462010-08-31 19:24:14443 DCHECK_EQ(0, idle_socket_count_);
[email protected]ff579d42009-06-24 15:47:02444}
445
[email protected]d80a4322009-08-14 07:07:49446int ClientSocketPoolBaseHelper::IdleSocketCountInGroup(
[email protected]ff579d42009-06-24 15:47:02447 const std::string& group_name) const {
448 GroupMap::const_iterator i = group_map_.find(group_name);
449 CHECK(i != group_map_.end());
450
[email protected]aed99ef02010-08-26 14:04:32451 return i->second->idle_sockets().size();
[email protected]ff579d42009-06-24 15:47:02452}
453
[email protected]d80a4322009-08-14 07:07:49454LoadState ClientSocketPoolBaseHelper::GetLoadState(
[email protected]ff579d42009-06-24 15:47:02455 const std::string& group_name,
456 const ClientSocketHandle* handle) const {
[email protected]05ea9ff2010-07-15 19:08:21457 if (ContainsKey(pending_callback_map_, handle))
458 return LOAD_STATE_CONNECTING;
459
[email protected]ff579d42009-06-24 15:47:02460 if (!ContainsKey(group_map_, group_name)) {
461 NOTREACHED() << "ClientSocketPool does not contain group: " << group_name
462 << " for handle: " << handle;
463 return LOAD_STATE_IDLE;
464 }
465
466 // Can't use operator[] since it is non-const.
[email protected]aed99ef02010-08-26 14:04:32467 const Group& group = *group_map_.find(group_name)->second;
[email protected]ff579d42009-06-24 15:47:02468
[email protected]ff579d42009-06-24 15:47:02469 // Search pending_requests for matching handle.
[email protected]aed99ef02010-08-26 14:04:32470 RequestQueue::const_iterator it = group.pending_requests().begin();
471 for (size_t i = 0; it != group.pending_requests().end(); ++it, ++i) {
[email protected]d80a4322009-08-14 07:07:49472 if ((*it)->handle() == handle) {
[email protected]aed99ef02010-08-26 14:04:32473 if (i < group.jobs().size()) {
[email protected]5fc08e32009-07-15 17:09:57474 LoadState max_state = LOAD_STATE_IDLE;
[email protected]aed99ef02010-08-26 14:04:32475 for (ConnectJobSet::const_iterator job_it = group.jobs().begin();
476 job_it != group.jobs().end(); ++job_it) {
[email protected]46451352009-09-01 14:54:21477 max_state = std::max(max_state, (*job_it)->GetLoadState());
[email protected]5fc08e32009-07-15 17:09:57478 }
479 return max_state;
480 } else {
481 // TODO(wtc): Add a state for being on the wait list.
482 // See http://www.crbug.com/5077.
483 return LOAD_STATE_IDLE;
484 }
[email protected]ff579d42009-06-24 15:47:02485 }
486 }
487
488 NOTREACHED();
489 return LOAD_STATE_IDLE;
490}
491
[email protected]ba00b492010-09-08 14:53:38492DictionaryValue* ClientSocketPoolBaseHelper::GetInfoAsValue(
[email protected]59d7a5a2010-08-30 16:44:27493 const std::string& name, const std::string& type) const {
494 DictionaryValue* dict = new DictionaryValue();
495 dict->SetString("name", name);
496 dict->SetString("type", type);
497 dict->SetInteger("handed_out_socket_count", handed_out_socket_count_);
498 dict->SetInteger("connecting_socket_count", connecting_socket_count_);
499 dict->SetInteger("idle_socket_count", idle_socket_count_);
500 dict->SetInteger("max_socket_count", max_sockets_);
501 dict->SetInteger("max_sockets_per_group", max_sockets_per_group_);
502 dict->SetInteger("pool_generation_number", pool_generation_number_);
503
504 if (group_map_.empty())
505 return dict;
506
507 DictionaryValue* all_groups_dict = new DictionaryValue();
508 for (GroupMap::const_iterator it = group_map_.begin();
509 it != group_map_.end(); it++) {
510 const Group* group = it->second;
511 DictionaryValue* group_dict = new DictionaryValue();
512
513 group_dict->SetInteger("pending_request_count",
514 group->pending_requests().size());
515 if (!group->pending_requests().empty()) {
516 group_dict->SetInteger("top_pending_priority",
517 group->TopPendingPriority());
518 }
519
520 group_dict->SetInteger("active_socket_count", group->active_socket_count());
[email protected]0496f9a32010-09-30 16:08:07521
522 ListValue* idle_socket_list = new ListValue();
[email protected]e1b54dc2010-10-06 21:27:22523 std::list<IdleSocket>::const_iterator idle_socket;
[email protected]0496f9a32010-09-30 16:08:07524 for (idle_socket = group->idle_sockets().begin();
525 idle_socket != group->idle_sockets().end();
526 idle_socket++) {
527 int source_id = idle_socket->socket->NetLog().source().id;
528 idle_socket_list->Append(Value::CreateIntegerValue(source_id));
529 }
530 group_dict->Set("idle_sockets", idle_socket_list);
531
532 ListValue* connect_jobs_list = new ListValue();
[email protected]2c2bef152010-10-13 00:55:03533 std::set<ConnectJob*>::const_iterator job = group->jobs().begin();
[email protected]0496f9a32010-09-30 16:08:07534 for (job = group->jobs().begin(); job != group->jobs().end(); job++) {
535 int source_id = (*job)->net_log().source().id;
536 connect_jobs_list->Append(Value::CreateIntegerValue(source_id));
537 }
538 group_dict->Set("connect_jobs", connect_jobs_list);
[email protected]59d7a5a2010-08-30 16:44:27539
540 group_dict->SetBoolean("is_stalled",
541 group->IsStalled(max_sockets_per_group_));
542 group_dict->SetBoolean("has_backup_job", group->HasBackupJob());
543
544 all_groups_dict->SetWithoutPathExpansion(it->first, group_dict);
545 }
546 dict->Set("groups", all_groups_dict);
547 return dict;
548}
549
[email protected]d80a4322009-08-14 07:07:49550bool ClientSocketPoolBaseHelper::IdleSocket::ShouldCleanup(
[email protected]9bf28db2009-08-29 01:35:16551 base::TimeTicks now,
552 base::TimeDelta timeout) const {
553 bool timed_out = (now - start_time) >= timeout;
[email protected]0f873e82010-09-02 16:09:01554 if (timed_out)
555 return true;
556 if (socket->WasEverUsed())
557 return !socket->IsConnectedAndIdle();
558 return !socket->IsConnected();
[email protected]ff579d42009-06-24 15:47:02559}
560
[email protected]d80a4322009-08-14 07:07:49561void ClientSocketPoolBaseHelper::CleanupIdleSockets(bool force) {
[email protected]ff579d42009-06-24 15:47:02562 if (idle_socket_count_ == 0)
563 return;
564
565 // Current time value. Retrieving it once at the function start rather than
566 // inside the inner loop, since it shouldn't change by any meaningful amount.
567 base::TimeTicks now = base::TimeTicks::Now();
568
569 GroupMap::iterator i = group_map_.begin();
570 while (i != group_map_.end()) {
[email protected]aed99ef02010-08-26 14:04:32571 Group* group = i->second;
[email protected]ff579d42009-06-24 15:47:02572
[email protected]e1b54dc2010-10-06 21:27:22573 std::list<IdleSocket>::iterator j = group->mutable_idle_sockets()->begin();
[email protected]aed99ef02010-08-26 14:04:32574 while (j != group->idle_sockets().end()) {
[email protected]9bf28db2009-08-29 01:35:16575 base::TimeDelta timeout =
[email protected]0f873e82010-09-02 16:09:01576 j->socket->WasEverUsed() ?
577 used_idle_socket_timeout_ : unused_idle_socket_timeout_;
[email protected]9bf28db2009-08-29 01:35:16578 if (force || j->ShouldCleanup(now, timeout)) {
[email protected]ff579d42009-06-24 15:47:02579 delete j->socket;
[email protected]aed99ef02010-08-26 14:04:32580 j = group->mutable_idle_sockets()->erase(j);
[email protected]ff579d42009-06-24 15:47:02581 DecrementIdleCount();
582 } else {
583 ++j;
584 }
585 }
586
587 // Delete group if no longer needed.
[email protected]aed99ef02010-08-26 14:04:32588 if (group->IsEmpty()) {
589 RemoveGroup(i++);
[email protected]ff579d42009-06-24 15:47:02590 } else {
591 ++i;
592 }
593 }
594}
595
[email protected]aed99ef02010-08-26 14:04:32596ClientSocketPoolBaseHelper::Group* ClientSocketPoolBaseHelper::GetOrCreateGroup(
597 const std::string& group_name) {
598 GroupMap::iterator it = group_map_.find(group_name);
599 if (it != group_map_.end())
600 return it->second;
601 Group* group = new Group;
602 group_map_[group_name] = group;
603 return group;
604}
605
606void ClientSocketPoolBaseHelper::RemoveGroup(const std::string& group_name) {
607 GroupMap::iterator it = group_map_.find(group_name);
608 CHECK(it != group_map_.end());
609
610 RemoveGroup(it);
611}
612
613void ClientSocketPoolBaseHelper::RemoveGroup(GroupMap::iterator it) {
614 delete it->second;
615 group_map_.erase(it);
616}
617
[email protected]06d94042010-08-25 01:45:22618// static
619void ClientSocketPoolBaseHelper::set_connect_backup_jobs_enabled(bool enabled) {
620 g_connect_backup_jobs_enabled = enabled;
621}
622
623void ClientSocketPoolBaseHelper::EnableConnectBackupJobs() {
624 connect_backup_jobs_enabled_ = g_connect_backup_jobs_enabled;
625}
626
[email protected]d80a4322009-08-14 07:07:49627void ClientSocketPoolBaseHelper::IncrementIdleCount() {
[email protected]ff579d42009-06-24 15:47:02628 if (++idle_socket_count_ == 1)
629 timer_.Start(TimeDelta::FromSeconds(kCleanupInterval), this,
[email protected]d80a4322009-08-14 07:07:49630 &ClientSocketPoolBaseHelper::OnCleanupTimerFired);
[email protected]ff579d42009-06-24 15:47:02631}
632
[email protected]d80a4322009-08-14 07:07:49633void ClientSocketPoolBaseHelper::DecrementIdleCount() {
[email protected]ff579d42009-06-24 15:47:02634 if (--idle_socket_count_ == 0)
635 timer_.Stop();
636}
637
[email protected]eb5a99382010-07-11 03:18:26638void ClientSocketPoolBaseHelper::ReleaseSocket(const std::string& group_name,
639 ClientSocket* socket,
640 int id) {
[email protected]ff579d42009-06-24 15:47:02641 GroupMap::iterator i = group_map_.find(group_name);
642 CHECK(i != group_map_.end());
643
[email protected]aed99ef02010-08-26 14:04:32644 Group* group = i->second;
[email protected]ff579d42009-06-24 15:47:02645
[email protected]b1f031dd2010-03-02 23:19:33646 CHECK_GT(handed_out_socket_count_, 0);
[email protected]211d2172009-07-22 15:48:53647 handed_out_socket_count_--;
648
[email protected]aed99ef02010-08-26 14:04:32649 CHECK_GT(group->active_socket_count(), 0);
650 group->DecrementActiveSocketCount();
[email protected]ff579d42009-06-24 15:47:02651
[email protected]a7e38572010-06-07 18:22:24652 const bool can_reuse = socket->IsConnectedAndIdle() &&
653 id == pool_generation_number_;
[email protected]ff579d42009-06-24 15:47:02654 if (can_reuse) {
[email protected]eb5a99382010-07-11 03:18:26655 // Add it to the idle list.
[email protected]0f873e82010-09-02 16:09:01656 AddIdleSocket(socket, group);
[email protected]aed99ef02010-08-26 14:04:32657 OnAvailableSocketSlot(group_name, group);
[email protected]ff579d42009-06-24 15:47:02658 } else {
659 delete socket;
660 }
[email protected]05ea9ff2010-07-15 19:08:21661
[email protected]eb5a99382010-07-11 03:18:26662 CheckForStalledSocketGroups();
663}
[email protected]ff579d42009-06-24 15:47:02664
[email protected]eb5a99382010-07-11 03:18:26665void ClientSocketPoolBaseHelper::CheckForStalledSocketGroups() {
666 // If we have idle sockets, see if we can give one to the top-stalled group.
667 std::string top_group_name;
668 Group* top_group = NULL;
[email protected]05ea9ff2010-07-15 19:08:21669 if (!FindTopStalledGroup(&top_group, &top_group_name))
[email protected]eb5a99382010-07-11 03:18:26670 return;
[email protected]4f2abec2010-02-03 18:10:16671
[email protected]eb5a99382010-07-11 03:18:26672 if (ReachedMaxSocketsLimit()) {
673 if (idle_socket_count() > 0) {
674 CloseOneIdleSocket();
[email protected]d7027bb2010-05-10 18:58:54675 } else {
[email protected]eb5a99382010-07-11 03:18:26676 // We can't activate more sockets since we're already at our global
677 // limit.
[email protected]4f2abec2010-02-03 18:10:16678 return;
[email protected]d7027bb2010-05-10 18:58:54679 }
[email protected]4f2abec2010-02-03 18:10:16680 }
[email protected]eb5a99382010-07-11 03:18:26681
682 // Note: we don't loop on waking stalled groups. If the stalled group is at
683 // its limit, may be left with other stalled groups that could be
[email protected]05ea9ff2010-07-15 19:08:21684 // woken. This isn't optimal, but there is no starvation, so to avoid
[email protected]eb5a99382010-07-11 03:18:26685 // the looping we leave it at this.
[email protected]05ea9ff2010-07-15 19:08:21686 OnAvailableSocketSlot(top_group_name, top_group);
[email protected]ff579d42009-06-24 15:47:02687}
688
[email protected]211d2172009-07-22 15:48:53689// Search for the highest priority pending request, amongst the groups that
690// are not at the |max_sockets_per_group_| limit. Note: for requests with
691// the same priority, the winner is based on group hash ordering (and not
692// insertion order).
[email protected]05ea9ff2010-07-15 19:08:21693bool ClientSocketPoolBaseHelper::FindTopStalledGroup(Group** group,
694 std::string* group_name) {
[email protected]211d2172009-07-22 15:48:53695 Group* top_group = NULL;
696 const std::string* top_group_name = NULL;
[email protected]05ea9ff2010-07-15 19:08:21697 bool has_stalled_group = false;
[email protected]211d2172009-07-22 15:48:53698 for (GroupMap::iterator i = group_map_.begin();
699 i != group_map_.end(); ++i) {
[email protected]aed99ef02010-08-26 14:04:32700 Group* curr_group = i->second;
701 const RequestQueue& queue = curr_group->pending_requests();
[email protected]211d2172009-07-22 15:48:53702 if (queue.empty())
703 continue;
[email protected]aed99ef02010-08-26 14:04:32704 if (curr_group->IsStalled(max_sockets_per_group_)) {
[email protected]05ea9ff2010-07-15 19:08:21705 has_stalled_group = true;
[email protected]6427fe22010-04-16 22:27:41706 bool has_higher_priority = !top_group ||
[email protected]aed99ef02010-08-26 14:04:32707 curr_group->TopPendingPriority() < top_group->TopPendingPriority();
[email protected]6427fe22010-04-16 22:27:41708 if (has_higher_priority) {
[email protected]aed99ef02010-08-26 14:04:32709 top_group = curr_group;
[email protected]6427fe22010-04-16 22:27:41710 top_group_name = &i->first;
711 }
[email protected]211d2172009-07-22 15:48:53712 }
713 }
[email protected]05ea9ff2010-07-15 19:08:21714
[email protected]211d2172009-07-22 15:48:53715 if (top_group) {
716 *group = top_group;
717 *group_name = *top_group_name;
718 }
[email protected]05ea9ff2010-07-15 19:08:21719 return has_stalled_group;
[email protected]211d2172009-07-22 15:48:53720}
721
[email protected]d80a4322009-08-14 07:07:49722void ClientSocketPoolBaseHelper::OnConnectJobComplete(
723 int result, ConnectJob* job) {
[email protected]2ab05b52009-07-01 23:57:58724 DCHECK_NE(ERR_IO_PENDING, result);
725 const std::string group_name = job->group_name();
[email protected]ff579d42009-06-24 15:47:02726 GroupMap::iterator group_it = group_map_.find(group_name);
727 CHECK(group_it != group_map_.end());
[email protected]aed99ef02010-08-26 14:04:32728 Group* group = group_it->second;
[email protected]ff579d42009-06-24 15:47:02729
[email protected]5fc08e32009-07-15 17:09:57730 scoped_ptr<ClientSocket> socket(job->ReleaseSocket());
[email protected]ff579d42009-06-24 15:47:02731
[email protected]9e743cd2010-03-16 07:03:53732 BoundNetLog job_log = job->net_log();
[email protected]5fc08e32009-07-15 17:09:57733
[email protected]4d3b05d2010-01-27 21:27:29734 if (result == OK) {
735 DCHECK(socket.get());
[email protected]aed99ef02010-08-26 14:04:32736 RemoveConnectJob(job, group);
737 if (!group->pending_requests().empty()) {
[email protected]4d3b05d2010-01-27 21:27:29738 scoped_ptr<const Request> r(RemoveRequestFromQueue(
[email protected]3f00be82010-09-27 19:50:02739 group->mutable_pending_requests()->begin(), group));
[email protected]06650c52010-06-03 00:49:17740 LogBoundConnectJobToRequest(job_log.source(), r.get());
[email protected]4d3b05d2010-01-27 21:27:29741 HandOutSocket(
742 socket.release(), false /* unused socket */, r->handle(),
[email protected]aed99ef02010-08-26 14:04:32743 base::TimeDelta(), group, r->net_log());
[email protected]06650c52010-06-03 00:49:17744 r->net_log().EndEvent(NetLog::TYPE_SOCKET_POOL, NULL);
[email protected]05ea9ff2010-07-15 19:08:21745 InvokeUserCallbackLater(r->handle(), r->callback(), result);
[email protected]5fc08e32009-07-15 17:09:57746 } else {
[email protected]0f873e82010-09-02 16:09:01747 AddIdleSocket(socket.release(), group);
[email protected]aed99ef02010-08-26 14:04:32748 OnAvailableSocketSlot(group_name, group);
[email protected]05ea9ff2010-07-15 19:08:21749 CheckForStalledSocketGroups();
[email protected]5fc08e32009-07-15 17:09:57750 }
[email protected]94c20472010-01-14 08:14:36751 } else {
[email protected]e772db3f2010-07-12 18:11:13752 // If we got a socket, it must contain error information so pass that
753 // up so that the caller can retrieve it.
754 bool handed_out_socket = false;
[email protected]aed99ef02010-08-26 14:04:32755 if (!group->pending_requests().empty()) {
[email protected]4d3b05d2010-01-27 21:27:29756 scoped_ptr<const Request> r(RemoveRequestFromQueue(
[email protected]3f00be82010-09-27 19:50:02757 group->mutable_pending_requests()->begin(), group));
[email protected]06650c52010-06-03 00:49:17758 LogBoundConnectJobToRequest(job_log.source(), r.get());
[email protected]e60e47a2010-07-14 03:37:18759 job->GetAdditionalErrorState(r->handle());
[email protected]aed99ef02010-08-26 14:04:32760 RemoveConnectJob(job, group);
[email protected]e772db3f2010-07-12 18:11:13761 if (socket.get()) {
762 handed_out_socket = true;
763 HandOutSocket(socket.release(), false /* unused socket */, r->handle(),
[email protected]aed99ef02010-08-26 14:04:32764 base::TimeDelta(), group, r->net_log());
[email protected]e772db3f2010-07-12 18:11:13765 }
[email protected]06650c52010-06-03 00:49:17766 r->net_log().EndEvent(NetLog::TYPE_SOCKET_POOL,
767 new NetLogIntegerParameter("net_error", result));
[email protected]05ea9ff2010-07-15 19:08:21768 InvokeUserCallbackLater(r->handle(), r->callback(), result);
[email protected]e60e47a2010-07-14 03:37:18769 } else {
[email protected]aed99ef02010-08-26 14:04:32770 RemoveConnectJob(job, group);
[email protected]4d3b05d2010-01-27 21:27:29771 }
[email protected]05ea9ff2010-07-15 19:08:21772 if (!handed_out_socket) {
[email protected]aed99ef02010-08-26 14:04:32773 OnAvailableSocketSlot(group_name, group);
[email protected]05ea9ff2010-07-15 19:08:21774 CheckForStalledSocketGroups();
775 }
[email protected]ff579d42009-06-24 15:47:02776 }
[email protected]ff579d42009-06-24 15:47:02777}
778
[email protected]66761b952010-06-25 21:30:38779void ClientSocketPoolBaseHelper::OnIPAddressChanged() {
780 Flush();
781}
782
[email protected]a7e38572010-06-07 18:22:24783void ClientSocketPoolBaseHelper::Flush() {
784 pool_generation_number_++;
[email protected]06f92462010-08-31 19:24:14785 CancelAllConnectJobs();
[email protected]a554a8262010-05-20 00:13:52786 CloseIdleSockets();
[email protected]06f92462010-08-31 19:24:14787 AbortAllRequests();
[email protected]a554a8262010-05-20 00:13:52788}
789
[email protected]2c2bef152010-10-13 00:55:03790void ClientSocketPoolBaseHelper::RemoveConnectJob(ConnectJob* job,
[email protected]4d3b05d2010-01-27 21:27:29791 Group* group) {
[email protected]b1f031dd2010-03-02 23:19:33792 CHECK_GT(connecting_socket_count_, 0);
[email protected]211d2172009-07-22 15:48:53793 connecting_socket_count_--;
794
[email protected]25eea382010-07-10 23:55:26795 DCHECK(group);
[email protected]aed99ef02010-08-26 14:04:32796 DCHECK(ContainsKey(group->jobs(), job));
797 group->RemoveJob(job);
[email protected]25eea382010-07-10 23:55:26798
799 // If we've got no more jobs for this group, then we no longer need a
800 // backup job either.
[email protected]aed99ef02010-08-26 14:04:32801 if (group->jobs().empty())
[email protected]25eea382010-07-10 23:55:26802 group->CleanupBackupJob();
803
[email protected]8ae03f42010-07-07 19:08:10804 DCHECK(job);
805 delete job;
[email protected]2ab05b52009-07-01 23:57:58806}
[email protected]ff579d42009-06-24 15:47:02807
[email protected]8ae03f42010-07-07 19:08:10808void ClientSocketPoolBaseHelper::OnAvailableSocketSlot(
[email protected]05ea9ff2010-07-15 19:08:21809 const std::string& group_name, Group* group) {
[email protected]2abfe90a2010-08-25 17:49:51810 DCHECK(ContainsKey(group_map_, group_name));
[email protected]05ea9ff2010-07-15 19:08:21811 if (group->IsEmpty())
[email protected]aed99ef02010-08-26 14:04:32812 RemoveGroup(group_name);
813 else if (!group->pending_requests().empty())
[email protected]2abfe90a2010-08-25 17:49:51814 ProcessPendingRequest(group_name, group);
[email protected]8ae03f42010-07-07 19:08:10815}
[email protected]06650c52010-06-03 00:49:17816
[email protected]8ae03f42010-07-07 19:08:10817void ClientSocketPoolBaseHelper::ProcessPendingRequest(
[email protected]05ea9ff2010-07-15 19:08:21818 const std::string& group_name, Group* group) {
819 int rv = RequestSocketInternal(group_name,
[email protected]aed99ef02010-08-26 14:04:32820 *group->pending_requests().begin());
[email protected]05ea9ff2010-07-15 19:08:21821 if (rv != ERR_IO_PENDING) {
822 scoped_ptr<const Request> request(RemoveRequestFromQueue(
[email protected]3f00be82010-09-27 19:50:02823 group->mutable_pending_requests()->begin(), group));
[email protected]2abfe90a2010-08-25 17:49:51824 if (group->IsEmpty())
[email protected]aed99ef02010-08-26 14:04:32825 RemoveGroup(group_name);
[email protected]8ae03f42010-07-07 19:08:10826
[email protected]05ea9ff2010-07-15 19:08:21827 scoped_refptr<NetLog::EventParameters> params;
828 if (rv != OK)
829 params = new NetLogIntegerParameter("net_error", rv);
830 request->net_log().EndEvent(NetLog::TYPE_SOCKET_POOL, params);
831 InvokeUserCallbackLater(
832 request->handle(), request->callback(), rv);
[email protected]2ab05b52009-07-01 23:57:58833 }
834}
835
[email protected]d80a4322009-08-14 07:07:49836void ClientSocketPoolBaseHelper::HandOutSocket(
[email protected]2ab05b52009-07-01 23:57:58837 ClientSocket* socket,
838 bool reused,
839 ClientSocketHandle* handle,
[email protected]f9d285c2009-08-17 19:54:29840 base::TimeDelta idle_time,
[email protected]fd4fe0b2010-02-08 23:02:15841 Group* group,
[email protected]9e743cd2010-03-16 07:03:53842 const BoundNetLog& net_log) {
[email protected]2ab05b52009-07-01 23:57:58843 DCHECK(socket);
844 handle->set_socket(socket);
845 handle->set_is_reused(reused);
[email protected]f9d285c2009-08-17 19:54:29846 handle->set_idle_time(idle_time);
[email protected]a7e38572010-06-07 18:22:24847 handle->set_pool_id(pool_generation_number_);
[email protected]211d2172009-07-22 15:48:53848
[email protected]d13f51b2010-04-27 23:20:45849 if (reused) {
[email protected]ec11be62010-04-28 19:28:09850 net_log.AddEvent(
[email protected]d13f51b2010-04-27 23:20:45851 NetLog::TYPE_SOCKET_POOL_REUSED_AN_EXISTING_SOCKET,
[email protected]ec11be62010-04-28 19:28:09852 new NetLogIntegerParameter(
853 "idle_ms", static_cast<int>(idle_time.InMilliseconds())));
[email protected]fd4fe0b2010-02-08 23:02:15854 }
[email protected]d13f51b2010-04-27 23:20:45855
[email protected]06650c52010-06-03 00:49:17856 net_log.AddEvent(NetLog::TYPE_SOCKET_POOL_BOUND_TO_SOCKET,
857 new NetLogSourceParameter(
858 "source_dependency", socket->NetLog().source()));
[email protected]fd4fe0b2010-02-08 23:02:15859
[email protected]211d2172009-07-22 15:48:53860 handed_out_socket_count_++;
[email protected]aed99ef02010-08-26 14:04:32861 group->IncrementActiveSocketCount();
[email protected]ff579d42009-06-24 15:47:02862}
863
[email protected]d80a4322009-08-14 07:07:49864void ClientSocketPoolBaseHelper::AddIdleSocket(
[email protected]0f873e82010-09-02 16:09:01865 ClientSocket* socket, Group* group) {
[email protected]5fc08e32009-07-15 17:09:57866 DCHECK(socket);
867 IdleSocket idle_socket;
868 idle_socket.socket = socket;
869 idle_socket.start_time = base::TimeTicks::Now();
[email protected]5fc08e32009-07-15 17:09:57870
[email protected]aed99ef02010-08-26 14:04:32871 group->mutable_idle_sockets()->push_back(idle_socket);
[email protected]5fc08e32009-07-15 17:09:57872 IncrementIdleCount();
873}
874
[email protected]d80a4322009-08-14 07:07:49875void ClientSocketPoolBaseHelper::CancelAllConnectJobs() {
[email protected]74d75e0b2010-08-23 20:39:54876 for (GroupMap::iterator i = group_map_.begin(); i != group_map_.end();) {
[email protected]aed99ef02010-08-26 14:04:32877 Group* group = i->second;
878 connecting_socket_count_ -= group->jobs().size();
879 group->RemoveAllJobs();
[email protected]6b624c62010-03-14 08:37:32880
[email protected]5fc08e32009-07-15 17:09:57881 // Delete group if no longer needed.
[email protected]aed99ef02010-08-26 14:04:32882 if (group->IsEmpty()) {
[email protected]06f92462010-08-31 19:24:14883 // RemoveGroup() will call .erase() which will invalidate the iterator,
884 // but i will already have been incremented to a valid iterator before
885 // RemoveGroup() is called.
886 RemoveGroup(i++);
887 } else {
888 ++i;
889 }
890 }
891 DCHECK_EQ(0, connecting_socket_count_);
892}
893
894void ClientSocketPoolBaseHelper::AbortAllRequests() {
895 for (GroupMap::iterator i = group_map_.begin(); i != group_map_.end();) {
896 Group* group = i->second;
897
898 RequestQueue pending_requests;
899 pending_requests.swap(*group->mutable_pending_requests());
900 for (RequestQueue::iterator it2 = pending_requests.begin();
901 it2 != pending_requests.end(); ++it2) {
[email protected]2c2bef152010-10-13 00:55:03902 scoped_ptr<const Request> request(*it2);
[email protected]06f92462010-08-31 19:24:14903 InvokeUserCallbackLater(
904 request->handle(), request->callback(), ERR_ABORTED);
905 }
906
907 // Delete group if no longer needed.
908 if (group->IsEmpty()) {
909 // RemoveGroup() will call .erase() which will invalidate the iterator,
910 // but i will already have been incremented to a valid iterator before
911 // RemoveGroup() is called.
[email protected]aed99ef02010-08-26 14:04:32912 RemoveGroup(i++);
[email protected]74d75e0b2010-08-23 20:39:54913 } else {
914 ++i;
[email protected]5fc08e32009-07-15 17:09:57915 }
916 }
917}
918
[email protected]d80a4322009-08-14 07:07:49919bool ClientSocketPoolBaseHelper::ReachedMaxSocketsLimit() const {
[email protected]211d2172009-07-22 15:48:53920 // Each connecting socket will eventually connect and be handed out.
[email protected]43a21b82010-06-10 21:30:54921 int total = handed_out_socket_count_ + connecting_socket_count_ +
922 idle_socket_count();
[email protected]211d2172009-07-22 15:48:53923 DCHECK_LE(total, max_sockets_);
[email protected]c901f6d2010-04-27 17:48:28924 if (total < max_sockets_)
925 return false;
[email protected]c901f6d2010-04-27 17:48:28926 return true;
[email protected]211d2172009-07-22 15:48:53927}
928
[email protected]43a21b82010-06-10 21:30:54929void ClientSocketPoolBaseHelper::CloseOneIdleSocket() {
930 CHECK_GT(idle_socket_count(), 0);
931
932 for (GroupMap::iterator i = group_map_.begin(); i != group_map_.end(); ++i) {
[email protected]aed99ef02010-08-26 14:04:32933 Group* group = i->second;
[email protected]e1b54dc2010-10-06 21:27:22934 std::list<IdleSocket>* idle_sockets = group->mutable_idle_sockets();
[email protected]43a21b82010-06-10 21:30:54935
[email protected]e1b54dc2010-10-06 21:27:22936 if (!idle_sockets->empty()) {
937 delete idle_sockets->front().socket;
938 idle_sockets->pop_front();
[email protected]43a21b82010-06-10 21:30:54939 DecrementIdleCount();
[email protected]aed99ef02010-08-26 14:04:32940 if (group->IsEmpty())
941 RemoveGroup(i);
[email protected]43a21b82010-06-10 21:30:54942
943 return;
944 }
945 }
946
947 LOG(DFATAL) << "No idle socket found to close!.";
948}
949
[email protected]05ea9ff2010-07-15 19:08:21950void ClientSocketPoolBaseHelper::InvokeUserCallbackLater(
951 ClientSocketHandle* handle, CompletionCallback* callback, int rv) {
952 CHECK(!ContainsKey(pending_callback_map_, handle));
953 pending_callback_map_[handle] = CallbackResultPair(callback, rv);
954 MessageLoop::current()->PostTask(
955 FROM_HERE,
[email protected]2431756e2010-09-29 20:26:13956 method_factory_.NewRunnableMethod(
[email protected]05ea9ff2010-07-15 19:08:21957 &ClientSocketPoolBaseHelper::InvokeUserCallback,
958 handle));
959}
960
961void ClientSocketPoolBaseHelper::InvokeUserCallback(
962 ClientSocketHandle* handle) {
963 PendingCallbackMap::iterator it = pending_callback_map_.find(handle);
964
965 // Exit if the request has already been cancelled.
966 if (it == pending_callback_map_.end())
967 return;
968
969 CHECK(!handle->is_initialized());
970 CompletionCallback* callback = it->second.callback;
971 int result = it->second.result;
972 pending_callback_map_.erase(it);
973 callback->Run(result);
974}
975
[email protected]aed99ef02010-08-26 14:04:32976ClientSocketPoolBaseHelper::Group::Group()
977 : active_socket_count_(0),
978 ALLOW_THIS_IN_INITIALIZER_LIST(method_factory_(this)) {}
979
980ClientSocketPoolBaseHelper::Group::~Group() {
981 CleanupBackupJob();
982}
983
984void ClientSocketPoolBaseHelper::Group::StartBackupSocketTimer(
985 const std::string& group_name,
986 ClientSocketPoolBaseHelper* pool) {
987 // Only allow one timer pending to create a backup socket.
988 if (!method_factory_.empty())
989 return;
990
991 MessageLoop::current()->PostDelayedTask(
992 FROM_HERE,
993 method_factory_.NewRunnableMethod(
994 &Group::OnBackupSocketTimerFired, group_name, pool),
995 pool->ConnectRetryIntervalMs());
996}
997
[email protected]2c2bef152010-10-13 00:55:03998bool ClientSocketPoolBaseHelper::Group::TryToUsePreconnectConnectJob() {
999 for (std::set<ConnectJob*>::iterator it = jobs_.begin();
1000 it != jobs_.end(); ++it) {
1001 ConnectJob* job = *it;
1002 if (job->is_unused_preconnect()) {
1003 job->UseForNormalRequest();
1004 return true;
1005 }
1006 }
1007 return false;
1008}
1009
[email protected]aed99ef02010-08-26 14:04:321010void ClientSocketPoolBaseHelper::Group::OnBackupSocketTimerFired(
1011 std::string group_name,
1012 ClientSocketPoolBaseHelper* pool) {
1013 // If there are no more jobs pending, there is no work to do.
1014 // If we've done our cleanups correctly, this should not happen.
1015 if (jobs_.empty()) {
1016 NOTREACHED();
1017 return;
1018 }
1019
1020 // If our backup job is waiting on DNS, or if we can't create any sockets
1021 // right now due to limits, just reset the timer.
1022 if (pool->ReachedMaxSocketsLimit() ||
1023 !HasAvailableSocketSlot(pool->max_sockets_per_group_) ||
1024 (*jobs_.begin())->GetLoadState() == LOAD_STATE_RESOLVING_HOST) {
1025 StartBackupSocketTimer(group_name, pool);
1026 return;
1027 }
1028
[email protected]4baaf9d2010-08-31 15:15:441029 if (pending_requests_.empty()) {
1030 LOG(DFATAL) << "No pending request for backup job.";
1031 return;
1032 }
1033
[email protected]aed99ef02010-08-26 14:04:321034 ConnectJob* backup_job = pool->connect_job_factory_->NewConnectJob(
1035 group_name, **pending_requests_.begin(), pool);
1036 backup_job->net_log().AddEvent(NetLog::TYPE_SOCKET_BACKUP_CREATED, NULL);
1037 SIMPLE_STATS_COUNTER("socket.backup_created");
1038 int rv = backup_job->Connect();
1039 pool->connecting_socket_count_++;
1040 AddJob(backup_job);
1041 if (rv != ERR_IO_PENDING)
1042 pool->OnConnectJobComplete(rv, backup_job);
1043}
1044
1045void ClientSocketPoolBaseHelper::Group::RemoveAllJobs() {
1046 // Delete active jobs.
1047 STLDeleteElements(&jobs_);
1048
1049 // Cancel pending backup job.
1050 method_factory_.RevokeAll();
1051}
1052
[email protected]d80a4322009-08-14 07:07:491053} // namespace internal
1054
[email protected]ff579d42009-06-24 15:47:021055} // namespace net