blob: 4c1600eeb52ebbf2a361008804680bf27d8927b7 [file] [log] [blame]
[email protected]5acdce12011-03-30 13:00:201// Copyright (c) 2011 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
[email protected]5e6efa52011-06-27 17:26:417#include <math.h>
[email protected]ff579d42009-06-24 15:47:028#include "base/compiler_specific.h"
[email protected]fd4fe0b2010-02-08 23:02:159#include "base/format_macros.h"
[email protected]5e6efa52011-06-27 17:26:4110#include "base/logging.h"
[email protected]ff579d42009-06-24 15:47:0211#include "base/message_loop.h"
[email protected]835d7c82010-10-14 04:38:3812#include "base/metrics/stats_counters.h"
[email protected]7286e3fc2011-07-19 22:13:2413#include "base/stl_util.h"
[email protected]5e6efa52011-06-27 17:26:4114#include "base/string_number_conversions.h"
[email protected]fd4fe0b2010-02-08 23:02:1515#include "base/string_util.h"
[email protected]ff579d42009-06-24 15:47:0216#include "base/time.h"
[email protected]9349cfb2010-08-31 18:00:5317#include "base/values.h"
[email protected]9e743cd2010-03-16 07:03:5318#include "net/base/net_log.h"
[email protected]ff579d42009-06-24 15:47:0219#include "net/base/net_errors.h"
20#include "net/socket/client_socket_handle.h"
21
22using base::TimeDelta;
23
24namespace {
25
[email protected]64770b7d2011-11-16 04:30:4126// Indicate whether we should enable idle socket cleanup timer. When timer is
27// disabled, sockets are closed next time a socket request is made.
28bool g_cleanup_timer_enabled = true;
29
[email protected]ff579d42009-06-24 15:47:0230// The timeout value, in seconds, used to clean up idle sockets that can't be
31// reused.
32//
33// Note: It's important to close idle sockets that have received data as soon
34// as possible because the received data may cause BSOD on Windows XP under
35// some conditions. See http://crbug.com/4606.
36const int kCleanupInterval = 10; // DO NOT INCREASE THIS TIMEOUT.
37
[email protected]c847c2a2011-04-08 13:56:1438// Indicate whether or not we should establish a new transport layer connection
39// after a certain timeout has passed without receiving an ACK.
[email protected]06d94042010-08-25 01:45:2240bool g_connect_backup_jobs_enabled = true;
41
[email protected]5e6efa52011-06-27 17:26:4142double g_socket_reuse_policy_penalty_exponent = -1;
43int g_socket_reuse_policy = -1;
44
[email protected]ff579d42009-06-24 15:47:0245} // namespace
46
47namespace net {
48
[email protected]5e6efa52011-06-27 17:26:4149int GetSocketReusePolicy() {
50 return g_socket_reuse_policy;
51}
52
53void SetSocketReusePolicy(int policy) {
54 DCHECK_GE(policy, 0);
55 DCHECK_LE(policy, 2);
56 if (policy > 2 || policy < 0) {
57 LOG(ERROR) << "Invalid socket reuse policy";
58 return;
59 }
60
61 double exponents[] = { 0, 0.25, -1 };
62 g_socket_reuse_policy_penalty_exponent = exponents[policy];
63 g_socket_reuse_policy = policy;
64
65 VLOG(1) << "Setting g_socket_reuse_policy_penalty_exponent = "
66 << g_socket_reuse_policy_penalty_exponent;
67}
68
[email protected]2ab05b52009-07-01 23:57:5869ConnectJob::ConnectJob(const std::string& group_name,
[email protected]974ebd62009-08-03 23:14:3470 base::TimeDelta timeout_duration,
[email protected]fd7b7c92009-08-20 19:38:3071 Delegate* delegate,
[email protected]9e743cd2010-03-16 07:03:5372 const BoundNetLog& net_log)
[email protected]2ab05b52009-07-01 23:57:5873 : group_name_(group_name),
[email protected]974ebd62009-08-03 23:14:3474 timeout_duration_(timeout_duration),
[email protected]2ab05b52009-07-01 23:57:5875 delegate_(delegate),
[email protected]a2006ece2010-04-23 16:44:0276 net_log_(net_log),
[email protected]2c2bef152010-10-13 00:55:0377 idle_(true),
78 preconnect_state_(NOT_PRECONNECT) {
[email protected]2ab05b52009-07-01 23:57:5879 DCHECK(!group_name.empty());
[email protected]2ab05b52009-07-01 23:57:5880 DCHECK(delegate);
[email protected]06650c52010-06-03 00:49:1781 net_log.BeginEvent(NetLog::TYPE_SOCKET_POOL_CONNECT_JOB, NULL);
[email protected]2ab05b52009-07-01 23:57:5882}
83
[email protected]fd7b7c92009-08-20 19:38:3084ConnectJob::~ConnectJob() {
[email protected]06650c52010-06-03 00:49:1785 net_log().EndEvent(NetLog::TYPE_SOCKET_POOL_CONNECT_JOB, NULL);
[email protected]fd7b7c92009-08-20 19:38:3086}
[email protected]2ab05b52009-07-01 23:57:5887
[email protected]2c2bef152010-10-13 00:55:0388void ConnectJob::Initialize(bool is_preconnect) {
89 if (is_preconnect)
90 preconnect_state_ = UNUSED_PRECONNECT;
91 else
92 preconnect_state_ = NOT_PRECONNECT;
93}
94
[email protected]974ebd62009-08-03 23:14:3495int ConnectJob::Connect() {
96 if (timeout_duration_ != base::TimeDelta())
[email protected]d323a172011-09-02 18:23:0297 timer_.Start(FROM_HERE, timeout_duration_, this, &ConnectJob::OnTimeout);
[email protected]fd7b7c92009-08-20 19:38:3098
[email protected]a2006ece2010-04-23 16:44:0299 idle_ = false;
[email protected]fd7b7c92009-08-20 19:38:30100
[email protected]06650c52010-06-03 00:49:17101 LogConnectStart();
102
[email protected]fd7b7c92009-08-20 19:38:30103 int rv = ConnectInternal();
104
105 if (rv != ERR_IO_PENDING) {
[email protected]06650c52010-06-03 00:49:17106 LogConnectCompletion(rv);
[email protected]fd7b7c92009-08-20 19:38:30107 delegate_ = NULL;
[email protected]fd7b7c92009-08-20 19:38:30108 }
109
110 return rv;
111}
112
[email protected]2c2bef152010-10-13 00:55:03113void ConnectJob::UseForNormalRequest() {
114 DCHECK_EQ(UNUSED_PRECONNECT, preconnect_state_);
115 preconnect_state_ = USED_PRECONNECT;
116}
117
[email protected]3268023f2011-05-05 00:08:10118void ConnectJob::set_socket(StreamSocket* socket) {
[email protected]06650c52010-06-03 00:49:17119 if (socket) {
[email protected]00cd9c42010-11-02 20:15:57120 net_log().AddEvent(NetLog::TYPE_CONNECT_JOB_SET_SOCKET, make_scoped_refptr(
121 new NetLogSourceParameter("source_dependency",
122 socket->NetLog().source())));
[email protected]06650c52010-06-03 00:49:17123 }
124 socket_.reset(socket);
125}
126
[email protected]fd7b7c92009-08-20 19:38:30127void ConnectJob::NotifyDelegateOfCompletion(int rv) {
128 // The delegate will delete |this|.
129 Delegate *delegate = delegate_;
130 delegate_ = NULL;
131
[email protected]06650c52010-06-03 00:49:17132 LogConnectCompletion(rv);
[email protected]fd7b7c92009-08-20 19:38:30133 delegate->OnConnectJobComplete(rv, this);
[email protected]974ebd62009-08-03 23:14:34134}
135
[email protected]a796bcec2010-03-22 17:17:26136void ConnectJob::ResetTimer(base::TimeDelta remaining_time) {
137 timer_.Stop();
[email protected]d323a172011-09-02 18:23:02138 timer_.Start(FROM_HERE, remaining_time, this, &ConnectJob::OnTimeout);
[email protected]a796bcec2010-03-22 17:17:26139}
140
[email protected]06650c52010-06-03 00:49:17141void ConnectJob::LogConnectStart() {
142 net_log().BeginEvent(NetLog::TYPE_SOCKET_POOL_CONNECT_JOB_CONNECT,
[email protected]00cd9c42010-11-02 20:15:57143 make_scoped_refptr(new NetLogStringParameter("group_name", group_name_)));
[email protected]06650c52010-06-03 00:49:17144}
145
146void ConnectJob::LogConnectCompletion(int net_error) {
[email protected]d7fd1782011-02-08 19:16:43147 net_log().EndEventWithNetErrorCode(
148 NetLog::TYPE_SOCKET_POOL_CONNECT_JOB_CONNECT, net_error);
[email protected]06650c52010-06-03 00:49:17149}
150
[email protected]974ebd62009-08-03 23:14:34151void ConnectJob::OnTimeout() {
[email protected]6e713f02009-08-06 02:56:40152 // Make sure the socket is NULL before calling into |delegate|.
153 set_socket(NULL);
[email protected]fd7b7c92009-08-20 19:38:30154
[email protected]ec11be62010-04-28 19:28:09155 net_log_.AddEvent(NetLog::TYPE_SOCKET_POOL_CONNECT_JOB_TIMED_OUT, NULL);
[email protected]fd7b7c92009-08-20 19:38:30156
157 NotifyDelegateOfCompletion(ERR_TIMED_OUT);
[email protected]974ebd62009-08-03 23:14:34158}
159
[email protected]d80a4322009-08-14 07:07:49160namespace internal {
161
[email protected]fd4fe0b2010-02-08 23:02:15162ClientSocketPoolBaseHelper::Request::Request(
163 ClientSocketHandle* handle,
[email protected]f1f3f0f82011-10-01 20:38:10164 OldCompletionCallback* callback,
[email protected]fd4fe0b2010-02-08 23:02:15165 RequestPriority priority,
[email protected]5acdce12011-03-30 13:00:20166 bool ignore_limits,
[email protected]2c2bef152010-10-13 00:55:03167 Flags flags,
[email protected]9e743cd2010-03-16 07:03:53168 const BoundNetLog& net_log)
[email protected]2431756e2010-09-29 20:26:13169 : handle_(handle),
170 callback_(callback),
171 priority_(priority),
[email protected]5acdce12011-03-30 13:00:20172 ignore_limits_(ignore_limits),
[email protected]2c2bef152010-10-13 00:55:03173 flags_(flags),
[email protected]9e743cd2010-03-16 07:03:53174 net_log_(net_log) {}
[email protected]fd4fe0b2010-02-08 23:02:15175
176ClientSocketPoolBaseHelper::Request::~Request() {}
177
[email protected]d80a4322009-08-14 07:07:49178ClientSocketPoolBaseHelper::ClientSocketPoolBaseHelper(
[email protected]211d2172009-07-22 15:48:53179 int max_sockets,
[email protected]ff579d42009-06-24 15:47:02180 int max_sockets_per_group,
[email protected]9bf28db2009-08-29 01:35:16181 base::TimeDelta unused_idle_socket_timeout,
182 base::TimeDelta used_idle_socket_timeout,
[email protected]66761b952010-06-25 21:30:38183 ConnectJobFactory* connect_job_factory)
[email protected]ff579d42009-06-24 15:47:02184 : idle_socket_count_(0),
[email protected]211d2172009-07-22 15:48:53185 connecting_socket_count_(0),
186 handed_out_socket_count_(0),
187 max_sockets_(max_sockets),
[email protected]ff579d42009-06-24 15:47:02188 max_sockets_per_group_(max_sockets_per_group),
[email protected]64770b7d2011-11-16 04:30:41189 use_cleanup_timer_(g_cleanup_timer_enabled),
[email protected]9bf28db2009-08-29 01:35:16190 unused_idle_socket_timeout_(unused_idle_socket_timeout),
191 used_idle_socket_timeout_(used_idle_socket_timeout),
[email protected]100d5fb92009-12-21 21:08:35192 connect_job_factory_(connect_job_factory),
[email protected]06d94042010-08-25 01:45:22193 connect_backup_jobs_enabled_(false),
[email protected]2431756e2010-09-29 20:26:13194 pool_generation_number_(0),
195 method_factory_(ALLOW_THIS_IN_INITIALIZER_LIST(this)) {
[email protected]211d2172009-07-22 15:48:53196 DCHECK_LE(0, max_sockets_per_group);
197 DCHECK_LE(max_sockets_per_group, max_sockets);
[email protected]a554a8262010-05-20 00:13:52198
[email protected]232a5812011-03-04 22:42:08199 NetworkChangeNotifier::AddIPAddressObserver(this);
[email protected]211d2172009-07-22 15:48:53200}
[email protected]ff579d42009-06-24 15:47:02201
[email protected]d80a4322009-08-14 07:07:49202ClientSocketPoolBaseHelper::~ClientSocketPoolBaseHelper() {
[email protected]2431756e2010-09-29 20:26:13203 // Clean up any idle sockets and pending connect jobs. Assert that we have no
204 // remaining active sockets or pending requests. They should have all been
205 // cleaned up prior to |this| being destroyed.
206 Flush();
207 DCHECK(group_map_.empty());
[email protected]05ea9ff2010-07-15 19:08:21208 DCHECK(pending_callback_map_.empty());
[email protected]4d3b05d2010-01-27 21:27:29209 DCHECK_EQ(0, connecting_socket_count_);
[email protected]a554a8262010-05-20 00:13:52210
[email protected]232a5812011-03-04 22:42:08211 NetworkChangeNotifier::RemoveIPAddressObserver(this);
[email protected]ff579d42009-06-24 15:47:02212}
213
214// InsertRequestIntoQueue inserts the request into the queue based on
215// priority. Highest priorities are closest to the front. Older requests are
216// prioritized over requests of equal priority.
217//
218// static
[email protected]d80a4322009-08-14 07:07:49219void ClientSocketPoolBaseHelper::InsertRequestIntoQueue(
220 const Request* r, RequestQueue* pending_requests) {
[email protected]ff579d42009-06-24 15:47:02221 RequestQueue::iterator it = pending_requests->begin();
[email protected]ac790b42009-12-02 04:31:31222 while (it != pending_requests->end() && r->priority() >= (*it)->priority())
[email protected]ff579d42009-06-24 15:47:02223 ++it;
224 pending_requests->insert(it, r);
225}
226
[email protected]fd7b7c92009-08-20 19:38:30227// static
228const ClientSocketPoolBaseHelper::Request*
229ClientSocketPoolBaseHelper::RemoveRequestFromQueue(
[email protected]417da102011-03-11 17:45:05230 const RequestQueue::iterator& it, Group* group) {
[email protected]fd7b7c92009-08-20 19:38:30231 const Request* req = *it;
[email protected]3f00be82010-09-27 19:50:02232 group->mutable_pending_requests()->erase(it);
233 // If there are no more requests, we kill the backup timer.
234 if (group->pending_requests().empty())
[email protected]e4d9a9722011-05-12 00:16:00235 group->CleanupBackupJob();
[email protected]fd7b7c92009-08-20 19:38:30236 return req;
237}
238
[email protected]d80a4322009-08-14 07:07:49239int ClientSocketPoolBaseHelper::RequestSocket(
[email protected]ff579d42009-06-24 15:47:02240 const std::string& group_name,
[email protected]d80a4322009-08-14 07:07:49241 const Request* request) {
[email protected]2c2bef152010-10-13 00:55:03242 CHECK(request->callback());
243 CHECK(request->handle());
244
[email protected]64770b7d2011-11-16 04:30:41245 // Cleanup any timed-out idle sockets if no timer is used.
246 if (!use_cleanup_timer_)
247 CleanupIdleSockets(false);
248
[email protected]ec11be62010-04-28 19:28:09249 request->net_log().BeginEvent(NetLog::TYPE_SOCKET_POOL, NULL);
[email protected]aed99ef02010-08-26 14:04:32250 Group* group = GetOrCreateGroup(group_name);
[email protected]eb5a99382010-07-11 03:18:26251
[email protected]fd4fe0b2010-02-08 23:02:15252 int rv = RequestSocketInternal(group_name, request);
[email protected]e7e99322010-05-04 23:30:17253 if (rv != ERR_IO_PENDING) {
[email protected]d7fd1782011-02-08 19:16:43254 request->net_log().EndEventWithNetErrorCode(NetLog::TYPE_SOCKET_POOL, rv);
[email protected]05ea9ff2010-07-15 19:08:21255 CHECK(!request->handle()->is_initialized());
[email protected]e7e99322010-05-04 23:30:17256 delete request;
257 } else {
[email protected]aed99ef02010-08-26 14:04:32258 InsertRequestIntoQueue(request, group->mutable_pending_requests());
[email protected]e7e99322010-05-04 23:30:17259 }
[email protected]fd4fe0b2010-02-08 23:02:15260 return rv;
261}
262
[email protected]2c2bef152010-10-13 00:55:03263void ClientSocketPoolBaseHelper::RequestSockets(
264 const std::string& group_name,
265 const Request& request,
266 int num_sockets) {
267 DCHECK(!request.callback());
268 DCHECK(!request.handle());
269
[email protected]64770b7d2011-11-16 04:30:41270 // Cleanup any timed out idle sockets if no timer is used.
271 if (!use_cleanup_timer_)
272 CleanupIdleSockets(false);
273
[email protected]2c2bef152010-10-13 00:55:03274 if (num_sockets > max_sockets_per_group_) {
[email protected]2c2bef152010-10-13 00:55:03275 num_sockets = max_sockets_per_group_;
276 }
277
278 request.net_log().BeginEvent(
279 NetLog::TYPE_SOCKET_POOL_CONNECTING_N_SOCKETS,
[email protected]00cd9c42010-11-02 20:15:57280 make_scoped_refptr(new NetLogIntegerParameter(
281 "num_sockets", num_sockets)));
[email protected]2c2bef152010-10-13 00:55:03282
283 Group* group = GetOrCreateGroup(group_name);
284
[email protected]3c819f522010-12-02 02:03:12285 // RequestSocketsInternal() may delete the group.
286 bool deleted_group = false;
287
[email protected]d7fd1782011-02-08 19:16:43288 int rv = OK;
[email protected]2c2bef152010-10-13 00:55:03289 for (int num_iterations_left = num_sockets;
290 group->NumActiveSocketSlots() < num_sockets &&
291 num_iterations_left > 0 ; num_iterations_left--) {
[email protected]d7fd1782011-02-08 19:16:43292 rv = RequestSocketInternal(group_name, &request);
[email protected]2c2bef152010-10-13 00:55:03293 if (rv < 0 && rv != ERR_IO_PENDING) {
294 // We're encountering a synchronous error. Give up.
[email protected]3c819f522010-12-02 02:03:12295 if (!ContainsKey(group_map_, group_name))
296 deleted_group = true;
297 break;
298 }
299 if (!ContainsKey(group_map_, group_name)) {
300 // Unexpected. The group should only be getting deleted on synchronous
301 // error.
302 NOTREACHED();
303 deleted_group = true;
[email protected]2c2bef152010-10-13 00:55:03304 break;
305 }
306 }
307
[email protected]3c819f522010-12-02 02:03:12308 if (!deleted_group && group->IsEmpty())
[email protected]2c2bef152010-10-13 00:55:03309 RemoveGroup(group_name);
310
[email protected]d7fd1782011-02-08 19:16:43311 if (rv == ERR_IO_PENDING)
312 rv = OK;
313 request.net_log().EndEventWithNetErrorCode(
314 NetLog::TYPE_SOCKET_POOL_CONNECTING_N_SOCKETS, rv);
[email protected]2c2bef152010-10-13 00:55:03315}
316
[email protected]fd4fe0b2010-02-08 23:02:15317int ClientSocketPoolBaseHelper::RequestSocketInternal(
318 const std::string& group_name,
319 const Request* request) {
[email protected]d80a4322009-08-14 07:07:49320 DCHECK_GE(request->priority(), 0);
[email protected]d80a4322009-08-14 07:07:49321 ClientSocketHandle* const handle = request->handle();
[email protected]2c2bef152010-10-13 00:55:03322 const bool preconnecting = !handle;
[email protected]aed99ef02010-08-26 14:04:32323 Group* group = GetOrCreateGroup(group_name);
[email protected]ff579d42009-06-24 15:47:02324
[email protected]2c2bef152010-10-13 00:55:03325 if (!(request->flags() & NO_IDLE_SOCKETS)) {
326 // Try to reuse a socket.
327 if (AssignIdleSocketToGroup(request, group))
328 return OK;
329 }
330
331 if (!preconnecting && group->TryToUsePreconnectConnectJob())
332 return ERR_IO_PENDING;
[email protected]65552102010-04-09 22:58:10333
[email protected]43a21b82010-06-10 21:30:54334 // Can we make another active socket now?
[email protected]5acdce12011-03-30 13:00:20335 if (!group->HasAvailableSocketSlot(max_sockets_per_group_) &&
336 !request->ignore_limits()) {
[email protected]43a21b82010-06-10 21:30:54337 request->net_log().AddEvent(
338 NetLog::TYPE_SOCKET_POOL_STALLED_MAX_SOCKETS_PER_GROUP, NULL);
339 return ERR_IO_PENDING;
340 }
341
[email protected]5acdce12011-03-30 13:00:20342 if (ReachedMaxSocketsLimit() && !request->ignore_limits()) {
[email protected]43a21b82010-06-10 21:30:54343 if (idle_socket_count() > 0) {
[email protected]dcbe168a2010-12-02 03:14:46344 bool closed = CloseOneIdleSocketExceptInGroup(group);
345 if (preconnecting && !closed)
346 return ERR_PRECONNECT_MAX_SOCKET_LIMIT;
[email protected]43a21b82010-06-10 21:30:54347 } else {
348 // We could check if we really have a stalled group here, but it requires
349 // a scan of all groups, so just flip a flag here, and do the check later.
[email protected]43a21b82010-06-10 21:30:54350 request->net_log().AddEvent(
351 NetLog::TYPE_SOCKET_POOL_STALLED_MAX_SOCKETS, NULL);
352 return ERR_IO_PENDING;
353 }
354 }
355
[email protected]ff579d42009-06-24 15:47:02356 // We couldn't find a socket to reuse, so allocate and connect a new one.
[email protected]2ab05b52009-07-01 23:57:58357 scoped_ptr<ConnectJob> connect_job(
[email protected]06650c52010-06-03 00:49:17358 connect_job_factory_->NewConnectJob(group_name, *request, this));
[email protected]ff579d42009-06-24 15:47:02359
[email protected]2c2bef152010-10-13 00:55:03360 connect_job->Initialize(preconnecting);
[email protected]2ab05b52009-07-01 23:57:58361 int rv = connect_job->Connect();
362 if (rv == OK) {
[email protected]06650c52010-06-03 00:49:17363 LogBoundConnectJobToRequest(connect_job->net_log().source(), request);
[email protected]2c2bef152010-10-13 00:55:03364 if (!preconnecting) {
365 HandOutSocket(connect_job->ReleaseSocket(), false /* not reused */,
366 handle, base::TimeDelta(), group, request->net_log());
367 } else {
368 AddIdleSocket(connect_job->ReleaseSocket(), group);
369 }
[email protected]2ab05b52009-07-01 23:57:58370 } else if (rv == ERR_IO_PENDING) {
[email protected]6b624c62010-03-14 08:37:32371 // If we don't have any sockets in this group, set a timer for potentially
372 // creating a new one. If the SYN is lost, this backup socket may complete
373 // before the slow socket, improving end user latency.
[email protected]2c2bef152010-10-13 00:55:03374 if (connect_backup_jobs_enabled_ &&
[email protected]e4d9a9722011-05-12 00:16:00375 group->IsEmpty() && !group->HasBackupJob()) {
[email protected]aed99ef02010-08-26 14:04:32376 group->StartBackupSocketTimer(group_name, this);
[email protected]2c2bef152010-10-13 00:55:03377 }
[email protected]6b624c62010-03-14 08:37:32378
[email protected]211d2172009-07-22 15:48:53379 connecting_socket_count_++;
380
[email protected]aed99ef02010-08-26 14:04:32381 group->AddJob(connect_job.release());
[email protected]a2006ece2010-04-23 16:44:02382 } else {
[email protected]06650c52010-06-03 00:49:17383 LogBoundConnectJobToRequest(connect_job->net_log().source(), request);
[email protected]3268023f2011-05-05 00:08:10384 StreamSocket* error_socket = NULL;
[email protected]fd2e53e2011-01-14 20:40:52385 if (!preconnecting) {
386 DCHECK(handle);
387 connect_job->GetAdditionalErrorState(handle);
388 error_socket = connect_job->ReleaseSocket();
389 }
[email protected]e772db3f2010-07-12 18:11:13390 if (error_socket) {
391 HandOutSocket(error_socket, false /* not reused */, handle,
[email protected]aed99ef02010-08-26 14:04:32392 base::TimeDelta(), group, request->net_log());
393 } else if (group->IsEmpty()) {
394 RemoveGroup(group_name);
[email protected]05ea9ff2010-07-15 19:08:21395 }
[email protected]2ab05b52009-07-01 23:57:58396 }
[email protected]ff579d42009-06-24 15:47:02397
[email protected]2ab05b52009-07-01 23:57:58398 return rv;
[email protected]ff579d42009-06-24 15:47:02399}
400
[email protected]05ea9ff2010-07-15 19:08:21401bool ClientSocketPoolBaseHelper::AssignIdleSocketToGroup(
[email protected]aed99ef02010-08-26 14:04:32402 const Request* request, Group* group) {
[email protected]e1b54dc2010-10-06 21:27:22403 std::list<IdleSocket>* idle_sockets = group->mutable_idle_sockets();
404 std::list<IdleSocket>::iterator idle_socket_it = idle_sockets->end();
[email protected]5e6efa52011-06-27 17:26:41405 double max_score = -1;
[email protected]e1b54dc2010-10-06 21:27:22406
407 // Iterate through the idle sockets forwards (oldest to newest)
408 // * Delete any disconnected ones.
409 // * If we find a used idle socket, assign to |idle_socket|. At the end,
410 // the |idle_socket_it| will be set to the newest used idle socket.
411 for (std::list<IdleSocket>::iterator it = idle_sockets->begin();
412 it != idle_sockets->end();) {
413 if (!it->socket->IsConnectedAndIdle()) {
414 DecrementIdleCount();
415 delete it->socket;
416 it = idle_sockets->erase(it);
417 continue;
[email protected]eb5a99382010-07-11 03:18:26418 }
[email protected]e1b54dc2010-10-06 21:27:22419
420 if (it->socket->WasEverUsed()) {
421 // We found one we can reuse!
[email protected]5e6efa52011-06-27 17:26:41422 double score = 0;
423 int64 bytes_read = it->socket->NumBytesRead();
424 double num_kb = static_cast<double>(bytes_read) / 1024.0;
425 int idle_time_sec = (base::TimeTicks::Now() - it->start_time).InSeconds();
426 idle_time_sec = std::max(1, idle_time_sec);
427
428 if (g_socket_reuse_policy_penalty_exponent >= 0 && num_kb >= 0) {
429 score = num_kb / pow(idle_time_sec,
430 g_socket_reuse_policy_penalty_exponent);
431 }
432
433 // Equality to prefer recently used connection.
434 if (score >= max_score) {
435 idle_socket_it = it;
436 max_score = score;
437 }
[email protected]e1b54dc2010-10-06 21:27:22438 }
439
440 ++it;
[email protected]eb5a99382010-07-11 03:18:26441 }
[email protected]e1b54dc2010-10-06 21:27:22442
443 // If we haven't found an idle socket, that means there are no used idle
444 // sockets. Pick the oldest (first) idle socket (FIFO).
445
446 if (idle_socket_it == idle_sockets->end() && !idle_sockets->empty())
447 idle_socket_it = idle_sockets->begin();
448
449 if (idle_socket_it != idle_sockets->end()) {
450 DecrementIdleCount();
451 base::TimeDelta idle_time =
452 base::TimeTicks::Now() - idle_socket_it->start_time;
453 IdleSocket idle_socket = *idle_socket_it;
454 idle_sockets->erase(idle_socket_it);
455 HandOutSocket(
456 idle_socket.socket,
457 idle_socket.socket->WasEverUsed(),
458 request->handle(),
459 idle_time,
460 group,
461 request->net_log());
462 return true;
463 }
464
[email protected]eb5a99382010-07-11 03:18:26465 return false;
466}
467
[email protected]06650c52010-06-03 00:49:17468// static
469void ClientSocketPoolBaseHelper::LogBoundConnectJobToRequest(
470 const NetLog::Source& connect_job_source, const Request* request) {
471 request->net_log().AddEvent(
472 NetLog::TYPE_SOCKET_POOL_BOUND_TO_CONNECT_JOB,
[email protected]00cd9c42010-11-02 20:15:57473 make_scoped_refptr(new NetLogSourceParameter(
474 "source_dependency", connect_job_source)));
[email protected]06650c52010-06-03 00:49:17475}
476
[email protected]d80a4322009-08-14 07:07:49477void ClientSocketPoolBaseHelper::CancelRequest(
[email protected]05ea9ff2010-07-15 19:08:21478 const std::string& group_name, ClientSocketHandle* handle) {
479 PendingCallbackMap::iterator callback_it = pending_callback_map_.find(handle);
480 if (callback_it != pending_callback_map_.end()) {
481 int result = callback_it->second.result;
482 pending_callback_map_.erase(callback_it);
[email protected]3268023f2011-05-05 00:08:10483 StreamSocket* socket = handle->release_socket();
[email protected]05ea9ff2010-07-15 19:08:21484 if (socket) {
485 if (result != OK)
486 socket->Disconnect();
487 ReleaseSocket(handle->group_name(), socket, handle->id());
488 }
489 return;
490 }
[email protected]b6501d3d2010-06-03 23:53:34491
[email protected]ff579d42009-06-24 15:47:02492 CHECK(ContainsKey(group_map_, group_name));
493
[email protected]aed99ef02010-08-26 14:04:32494 Group* group = GetOrCreateGroup(group_name);
[email protected]ff579d42009-06-24 15:47:02495
[email protected]ff579d42009-06-24 15:47:02496 // Search pending_requests for matching handle.
[email protected]aed99ef02010-08-26 14:04:32497 RequestQueue::iterator it = group->mutable_pending_requests()->begin();
498 for (; it != group->pending_requests().end(); ++it) {
[email protected]d80a4322009-08-14 07:07:49499 if ((*it)->handle() == handle) {
[email protected]2c2bef152010-10-13 00:55:03500 scoped_ptr<const Request> req(RemoveRequestFromQueue(it, group));
[email protected]ec11be62010-04-28 19:28:09501 req->net_log().AddEvent(NetLog::TYPE_CANCELLED, NULL);
502 req->net_log().EndEvent(NetLog::TYPE_SOCKET_POOL, NULL);
[email protected]eb5a99382010-07-11 03:18:26503
504 // We let the job run, unless we're at the socket limit.
[email protected]aed99ef02010-08-26 14:04:32505 if (group->jobs().size() && ReachedMaxSocketsLimit()) {
506 RemoveConnectJob(*group->jobs().begin(), group);
[email protected]eb5a99382010-07-11 03:18:26507 CheckForStalledSocketGroups();
[email protected]974ebd62009-08-03 23:14:34508 }
[email protected]eb5a99382010-07-11 03:18:26509 break;
[email protected]ff579d42009-06-24 15:47:02510 }
511 }
[email protected]ff579d42009-06-24 15:47:02512}
513
[email protected]2abfe90a2010-08-25 17:49:51514bool ClientSocketPoolBaseHelper::HasGroup(const std::string& group_name) const {
515 return ContainsKey(group_map_, group_name);
516}
517
[email protected]d80a4322009-08-14 07:07:49518void ClientSocketPoolBaseHelper::CloseIdleSockets() {
[email protected]ff579d42009-06-24 15:47:02519 CleanupIdleSockets(true);
[email protected]06f92462010-08-31 19:24:14520 DCHECK_EQ(0, idle_socket_count_);
[email protected]ff579d42009-06-24 15:47:02521}
522
[email protected]d80a4322009-08-14 07:07:49523int ClientSocketPoolBaseHelper::IdleSocketCountInGroup(
[email protected]ff579d42009-06-24 15:47:02524 const std::string& group_name) const {
525 GroupMap::const_iterator i = group_map_.find(group_name);
526 CHECK(i != group_map_.end());
527
[email protected]aed99ef02010-08-26 14:04:32528 return i->second->idle_sockets().size();
[email protected]ff579d42009-06-24 15:47:02529}
530
[email protected]d80a4322009-08-14 07:07:49531LoadState ClientSocketPoolBaseHelper::GetLoadState(
[email protected]ff579d42009-06-24 15:47:02532 const std::string& group_name,
533 const ClientSocketHandle* handle) const {
[email protected]05ea9ff2010-07-15 19:08:21534 if (ContainsKey(pending_callback_map_, handle))
535 return LOAD_STATE_CONNECTING;
536
[email protected]ff579d42009-06-24 15:47:02537 if (!ContainsKey(group_map_, group_name)) {
538 NOTREACHED() << "ClientSocketPool does not contain group: " << group_name
539 << " for handle: " << handle;
540 return LOAD_STATE_IDLE;
541 }
542
543 // Can't use operator[] since it is non-const.
[email protected]aed99ef02010-08-26 14:04:32544 const Group& group = *group_map_.find(group_name)->second;
[email protected]ff579d42009-06-24 15:47:02545
[email protected]ff579d42009-06-24 15:47:02546 // Search pending_requests for matching handle.
[email protected]aed99ef02010-08-26 14:04:32547 RequestQueue::const_iterator it = group.pending_requests().begin();
548 for (size_t i = 0; it != group.pending_requests().end(); ++it, ++i) {
[email protected]d80a4322009-08-14 07:07:49549 if ((*it)->handle() == handle) {
[email protected]aed99ef02010-08-26 14:04:32550 if (i < group.jobs().size()) {
[email protected]5fc08e32009-07-15 17:09:57551 LoadState max_state = LOAD_STATE_IDLE;
[email protected]aed99ef02010-08-26 14:04:32552 for (ConnectJobSet::const_iterator job_it = group.jobs().begin();
553 job_it != group.jobs().end(); ++job_it) {
[email protected]46451352009-09-01 14:54:21554 max_state = std::max(max_state, (*job_it)->GetLoadState());
[email protected]5fc08e32009-07-15 17:09:57555 }
556 return max_state;
557 } else {
558 // TODO(wtc): Add a state for being on the wait list.
559 // See http://www.crbug.com/5077.
560 return LOAD_STATE_IDLE;
561 }
[email protected]ff579d42009-06-24 15:47:02562 }
563 }
564
565 NOTREACHED();
566 return LOAD_STATE_IDLE;
567}
568
[email protected]ba00b492010-09-08 14:53:38569DictionaryValue* ClientSocketPoolBaseHelper::GetInfoAsValue(
[email protected]59d7a5a2010-08-30 16:44:27570 const std::string& name, const std::string& type) const {
571 DictionaryValue* dict = new DictionaryValue();
572 dict->SetString("name", name);
573 dict->SetString("type", type);
574 dict->SetInteger("handed_out_socket_count", handed_out_socket_count_);
575 dict->SetInteger("connecting_socket_count", connecting_socket_count_);
576 dict->SetInteger("idle_socket_count", idle_socket_count_);
577 dict->SetInteger("max_socket_count", max_sockets_);
578 dict->SetInteger("max_sockets_per_group", max_sockets_per_group_);
579 dict->SetInteger("pool_generation_number", pool_generation_number_);
580
581 if (group_map_.empty())
582 return dict;
583
584 DictionaryValue* all_groups_dict = new DictionaryValue();
585 for (GroupMap::const_iterator it = group_map_.begin();
586 it != group_map_.end(); it++) {
587 const Group* group = it->second;
588 DictionaryValue* group_dict = new DictionaryValue();
589
590 group_dict->SetInteger("pending_request_count",
591 group->pending_requests().size());
592 if (!group->pending_requests().empty()) {
593 group_dict->SetInteger("top_pending_priority",
594 group->TopPendingPriority());
595 }
596
597 group_dict->SetInteger("active_socket_count", group->active_socket_count());
[email protected]0496f9a32010-09-30 16:08:07598
599 ListValue* idle_socket_list = new ListValue();
[email protected]e1b54dc2010-10-06 21:27:22600 std::list<IdleSocket>::const_iterator idle_socket;
[email protected]0496f9a32010-09-30 16:08:07601 for (idle_socket = group->idle_sockets().begin();
602 idle_socket != group->idle_sockets().end();
603 idle_socket++) {
604 int source_id = idle_socket->socket->NetLog().source().id;
605 idle_socket_list->Append(Value::CreateIntegerValue(source_id));
606 }
607 group_dict->Set("idle_sockets", idle_socket_list);
608
609 ListValue* connect_jobs_list = new ListValue();
[email protected]2c2bef152010-10-13 00:55:03610 std::set<ConnectJob*>::const_iterator job = group->jobs().begin();
[email protected]0496f9a32010-09-30 16:08:07611 for (job = group->jobs().begin(); job != group->jobs().end(); job++) {
612 int source_id = (*job)->net_log().source().id;
613 connect_jobs_list->Append(Value::CreateIntegerValue(source_id));
614 }
615 group_dict->Set("connect_jobs", connect_jobs_list);
[email protected]59d7a5a2010-08-30 16:44:27616
617 group_dict->SetBoolean("is_stalled",
618 group->IsStalled(max_sockets_per_group_));
[email protected]e4d9a9722011-05-12 00:16:00619 group_dict->SetBoolean("has_backup_job", group->HasBackupJob());
[email protected]59d7a5a2010-08-30 16:44:27620
621 all_groups_dict->SetWithoutPathExpansion(it->first, group_dict);
622 }
623 dict->Set("groups", all_groups_dict);
624 return dict;
625}
626
[email protected]d80a4322009-08-14 07:07:49627bool ClientSocketPoolBaseHelper::IdleSocket::ShouldCleanup(
[email protected]9bf28db2009-08-29 01:35:16628 base::TimeTicks now,
629 base::TimeDelta timeout) const {
630 bool timed_out = (now - start_time) >= timeout;
[email protected]0f873e82010-09-02 16:09:01631 if (timed_out)
632 return true;
633 if (socket->WasEverUsed())
634 return !socket->IsConnectedAndIdle();
635 return !socket->IsConnected();
[email protected]ff579d42009-06-24 15:47:02636}
637
[email protected]d80a4322009-08-14 07:07:49638void ClientSocketPoolBaseHelper::CleanupIdleSockets(bool force) {
[email protected]ff579d42009-06-24 15:47:02639 if (idle_socket_count_ == 0)
640 return;
641
642 // Current time value. Retrieving it once at the function start rather than
643 // inside the inner loop, since it shouldn't change by any meaningful amount.
644 base::TimeTicks now = base::TimeTicks::Now();
645
646 GroupMap::iterator i = group_map_.begin();
647 while (i != group_map_.end()) {
[email protected]aed99ef02010-08-26 14:04:32648 Group* group = i->second;
[email protected]ff579d42009-06-24 15:47:02649
[email protected]e1b54dc2010-10-06 21:27:22650 std::list<IdleSocket>::iterator j = group->mutable_idle_sockets()->begin();
[email protected]aed99ef02010-08-26 14:04:32651 while (j != group->idle_sockets().end()) {
[email protected]9bf28db2009-08-29 01:35:16652 base::TimeDelta timeout =
[email protected]0f873e82010-09-02 16:09:01653 j->socket->WasEverUsed() ?
654 used_idle_socket_timeout_ : unused_idle_socket_timeout_;
[email protected]9bf28db2009-08-29 01:35:16655 if (force || j->ShouldCleanup(now, timeout)) {
[email protected]ff579d42009-06-24 15:47:02656 delete j->socket;
[email protected]aed99ef02010-08-26 14:04:32657 j = group->mutable_idle_sockets()->erase(j);
[email protected]ff579d42009-06-24 15:47:02658 DecrementIdleCount();
659 } else {
660 ++j;
661 }
662 }
663
664 // Delete group if no longer needed.
[email protected]aed99ef02010-08-26 14:04:32665 if (group->IsEmpty()) {
666 RemoveGroup(i++);
[email protected]ff579d42009-06-24 15:47:02667 } else {
668 ++i;
669 }
670 }
671}
672
[email protected]aed99ef02010-08-26 14:04:32673ClientSocketPoolBaseHelper::Group* ClientSocketPoolBaseHelper::GetOrCreateGroup(
674 const std::string& group_name) {
675 GroupMap::iterator it = group_map_.find(group_name);
676 if (it != group_map_.end())
677 return it->second;
678 Group* group = new Group;
679 group_map_[group_name] = group;
680 return group;
681}
682
683void ClientSocketPoolBaseHelper::RemoveGroup(const std::string& group_name) {
684 GroupMap::iterator it = group_map_.find(group_name);
685 CHECK(it != group_map_.end());
686
687 RemoveGroup(it);
688}
689
690void ClientSocketPoolBaseHelper::RemoveGroup(GroupMap::iterator it) {
691 delete it->second;
692 group_map_.erase(it);
693}
694
[email protected]06d94042010-08-25 01:45:22695// static
[email protected]2d6728692011-03-12 01:39:55696bool ClientSocketPoolBaseHelper::connect_backup_jobs_enabled() {
697 return g_connect_backup_jobs_enabled;
698}
699
700// static
[email protected]636b8252011-04-08 19:56:54701bool ClientSocketPoolBaseHelper::set_connect_backup_jobs_enabled(bool enabled) {
702 bool old_value = g_connect_backup_jobs_enabled;
[email protected]06d94042010-08-25 01:45:22703 g_connect_backup_jobs_enabled = enabled;
[email protected]636b8252011-04-08 19:56:54704 return old_value;
[email protected]06d94042010-08-25 01:45:22705}
706
707void ClientSocketPoolBaseHelper::EnableConnectBackupJobs() {
708 connect_backup_jobs_enabled_ = g_connect_backup_jobs_enabled;
709}
710
[email protected]d80a4322009-08-14 07:07:49711void ClientSocketPoolBaseHelper::IncrementIdleCount() {
[email protected]64770b7d2011-11-16 04:30:41712 if (++idle_socket_count_ == 1 && use_cleanup_timer_)
713 StartIdleSocketTimer();
[email protected]ff579d42009-06-24 15:47:02714}
715
[email protected]d80a4322009-08-14 07:07:49716void ClientSocketPoolBaseHelper::DecrementIdleCount() {
[email protected]ff579d42009-06-24 15:47:02717 if (--idle_socket_count_ == 0)
718 timer_.Stop();
719}
720
[email protected]64770b7d2011-11-16 04:30:41721// static
722bool ClientSocketPoolBaseHelper::cleanup_timer_enabled() {
723 return g_cleanup_timer_enabled;
724}
725
726// static
727bool ClientSocketPoolBaseHelper::set_cleanup_timer_enabled(bool enabled) {
728 bool old_value = g_cleanup_timer_enabled;
729 g_cleanup_timer_enabled = enabled;
730 return old_value;
731}
732
733void ClientSocketPoolBaseHelper::StartIdleSocketTimer() {
734 timer_.Start(FROM_HERE, TimeDelta::FromSeconds(kCleanupInterval), this,
735 &ClientSocketPoolBaseHelper::OnCleanupTimerFired);
736}
737
[email protected]eb5a99382010-07-11 03:18:26738void ClientSocketPoolBaseHelper::ReleaseSocket(const std::string& group_name,
[email protected]3268023f2011-05-05 00:08:10739 StreamSocket* socket,
[email protected]eb5a99382010-07-11 03:18:26740 int id) {
[email protected]ff579d42009-06-24 15:47:02741 GroupMap::iterator i = group_map_.find(group_name);
742 CHECK(i != group_map_.end());
743
[email protected]aed99ef02010-08-26 14:04:32744 Group* group = i->second;
[email protected]ff579d42009-06-24 15:47:02745
[email protected]b1f031dd2010-03-02 23:19:33746 CHECK_GT(handed_out_socket_count_, 0);
[email protected]211d2172009-07-22 15:48:53747 handed_out_socket_count_--;
748
[email protected]aed99ef02010-08-26 14:04:32749 CHECK_GT(group->active_socket_count(), 0);
750 group->DecrementActiveSocketCount();
[email protected]ff579d42009-06-24 15:47:02751
[email protected]a7e38572010-06-07 18:22:24752 const bool can_reuse = socket->IsConnectedAndIdle() &&
753 id == pool_generation_number_;
[email protected]ff579d42009-06-24 15:47:02754 if (can_reuse) {
[email protected]eb5a99382010-07-11 03:18:26755 // Add it to the idle list.
[email protected]0f873e82010-09-02 16:09:01756 AddIdleSocket(socket, group);
[email protected]aed99ef02010-08-26 14:04:32757 OnAvailableSocketSlot(group_name, group);
[email protected]ff579d42009-06-24 15:47:02758 } else {
759 delete socket;
760 }
[email protected]05ea9ff2010-07-15 19:08:21761
[email protected]eb5a99382010-07-11 03:18:26762 CheckForStalledSocketGroups();
763}
[email protected]ff579d42009-06-24 15:47:02764
[email protected]eb5a99382010-07-11 03:18:26765void ClientSocketPoolBaseHelper::CheckForStalledSocketGroups() {
766 // If we have idle sockets, see if we can give one to the top-stalled group.
767 std::string top_group_name;
768 Group* top_group = NULL;
[email protected]05ea9ff2010-07-15 19:08:21769 if (!FindTopStalledGroup(&top_group, &top_group_name))
[email protected]eb5a99382010-07-11 03:18:26770 return;
[email protected]4f2abec2010-02-03 18:10:16771
[email protected]eb5a99382010-07-11 03:18:26772 if (ReachedMaxSocketsLimit()) {
773 if (idle_socket_count() > 0) {
774 CloseOneIdleSocket();
[email protected]d7027bb2010-05-10 18:58:54775 } else {
[email protected]eb5a99382010-07-11 03:18:26776 // We can't activate more sockets since we're already at our global
777 // limit.
[email protected]4f2abec2010-02-03 18:10:16778 return;
[email protected]d7027bb2010-05-10 18:58:54779 }
[email protected]4f2abec2010-02-03 18:10:16780 }
[email protected]eb5a99382010-07-11 03:18:26781
782 // Note: we don't loop on waking stalled groups. If the stalled group is at
783 // its limit, may be left with other stalled groups that could be
[email protected]05ea9ff2010-07-15 19:08:21784 // woken. This isn't optimal, but there is no starvation, so to avoid
[email protected]eb5a99382010-07-11 03:18:26785 // the looping we leave it at this.
[email protected]05ea9ff2010-07-15 19:08:21786 OnAvailableSocketSlot(top_group_name, top_group);
[email protected]ff579d42009-06-24 15:47:02787}
788
[email protected]211d2172009-07-22 15:48:53789// Search for the highest priority pending request, amongst the groups that
790// are not at the |max_sockets_per_group_| limit. Note: for requests with
791// the same priority, the winner is based on group hash ordering (and not
792// insertion order).
[email protected]05ea9ff2010-07-15 19:08:21793bool ClientSocketPoolBaseHelper::FindTopStalledGroup(Group** group,
794 std::string* group_name) {
[email protected]211d2172009-07-22 15:48:53795 Group* top_group = NULL;
796 const std::string* top_group_name = NULL;
[email protected]05ea9ff2010-07-15 19:08:21797 bool has_stalled_group = false;
[email protected]211d2172009-07-22 15:48:53798 for (GroupMap::iterator i = group_map_.begin();
799 i != group_map_.end(); ++i) {
[email protected]aed99ef02010-08-26 14:04:32800 Group* curr_group = i->second;
801 const RequestQueue& queue = curr_group->pending_requests();
[email protected]211d2172009-07-22 15:48:53802 if (queue.empty())
803 continue;
[email protected]aed99ef02010-08-26 14:04:32804 if (curr_group->IsStalled(max_sockets_per_group_)) {
[email protected]05ea9ff2010-07-15 19:08:21805 has_stalled_group = true;
[email protected]6427fe22010-04-16 22:27:41806 bool has_higher_priority = !top_group ||
[email protected]aed99ef02010-08-26 14:04:32807 curr_group->TopPendingPriority() < top_group->TopPendingPriority();
[email protected]6427fe22010-04-16 22:27:41808 if (has_higher_priority) {
[email protected]aed99ef02010-08-26 14:04:32809 top_group = curr_group;
[email protected]6427fe22010-04-16 22:27:41810 top_group_name = &i->first;
811 }
[email protected]211d2172009-07-22 15:48:53812 }
813 }
[email protected]05ea9ff2010-07-15 19:08:21814
[email protected]211d2172009-07-22 15:48:53815 if (top_group) {
816 *group = top_group;
817 *group_name = *top_group_name;
818 }
[email protected]05ea9ff2010-07-15 19:08:21819 return has_stalled_group;
[email protected]211d2172009-07-22 15:48:53820}
821
[email protected]d80a4322009-08-14 07:07:49822void ClientSocketPoolBaseHelper::OnConnectJobComplete(
823 int result, ConnectJob* job) {
[email protected]2ab05b52009-07-01 23:57:58824 DCHECK_NE(ERR_IO_PENDING, result);
825 const std::string group_name = job->group_name();
[email protected]ff579d42009-06-24 15:47:02826 GroupMap::iterator group_it = group_map_.find(group_name);
827 CHECK(group_it != group_map_.end());
[email protected]aed99ef02010-08-26 14:04:32828 Group* group = group_it->second;
[email protected]ff579d42009-06-24 15:47:02829
[email protected]3268023f2011-05-05 00:08:10830 scoped_ptr<StreamSocket> socket(job->ReleaseSocket());
[email protected]ff579d42009-06-24 15:47:02831
[email protected]9e743cd2010-03-16 07:03:53832 BoundNetLog job_log = job->net_log();
[email protected]5fc08e32009-07-15 17:09:57833
[email protected]4d3b05d2010-01-27 21:27:29834 if (result == OK) {
835 DCHECK(socket.get());
[email protected]aed99ef02010-08-26 14:04:32836 RemoveConnectJob(job, group);
837 if (!group->pending_requests().empty()) {
[email protected]4d3b05d2010-01-27 21:27:29838 scoped_ptr<const Request> r(RemoveRequestFromQueue(
[email protected]3f00be82010-09-27 19:50:02839 group->mutable_pending_requests()->begin(), group));
[email protected]06650c52010-06-03 00:49:17840 LogBoundConnectJobToRequest(job_log.source(), r.get());
[email protected]4d3b05d2010-01-27 21:27:29841 HandOutSocket(
842 socket.release(), false /* unused socket */, r->handle(),
[email protected]aed99ef02010-08-26 14:04:32843 base::TimeDelta(), group, r->net_log());
[email protected]06650c52010-06-03 00:49:17844 r->net_log().EndEvent(NetLog::TYPE_SOCKET_POOL, NULL);
[email protected]05ea9ff2010-07-15 19:08:21845 InvokeUserCallbackLater(r->handle(), r->callback(), result);
[email protected]5fc08e32009-07-15 17:09:57846 } else {
[email protected]0f873e82010-09-02 16:09:01847 AddIdleSocket(socket.release(), group);
[email protected]aed99ef02010-08-26 14:04:32848 OnAvailableSocketSlot(group_name, group);
[email protected]05ea9ff2010-07-15 19:08:21849 CheckForStalledSocketGroups();
[email protected]5fc08e32009-07-15 17:09:57850 }
[email protected]94c20472010-01-14 08:14:36851 } else {
[email protected]e772db3f2010-07-12 18:11:13852 // If we got a socket, it must contain error information so pass that
853 // up so that the caller can retrieve it.
854 bool handed_out_socket = false;
[email protected]aed99ef02010-08-26 14:04:32855 if (!group->pending_requests().empty()) {
[email protected]4d3b05d2010-01-27 21:27:29856 scoped_ptr<const Request> r(RemoveRequestFromQueue(
[email protected]3f00be82010-09-27 19:50:02857 group->mutable_pending_requests()->begin(), group));
[email protected]06650c52010-06-03 00:49:17858 LogBoundConnectJobToRequest(job_log.source(), r.get());
[email protected]e60e47a2010-07-14 03:37:18859 job->GetAdditionalErrorState(r->handle());
[email protected]aed99ef02010-08-26 14:04:32860 RemoveConnectJob(job, group);
[email protected]e772db3f2010-07-12 18:11:13861 if (socket.get()) {
862 handed_out_socket = true;
863 HandOutSocket(socket.release(), false /* unused socket */, r->handle(),
[email protected]aed99ef02010-08-26 14:04:32864 base::TimeDelta(), group, r->net_log());
[email protected]e772db3f2010-07-12 18:11:13865 }
[email protected]d7fd1782011-02-08 19:16:43866 r->net_log().EndEventWithNetErrorCode(NetLog::TYPE_SOCKET_POOL,
867 result);
[email protected]05ea9ff2010-07-15 19:08:21868 InvokeUserCallbackLater(r->handle(), r->callback(), result);
[email protected]e60e47a2010-07-14 03:37:18869 } else {
[email protected]aed99ef02010-08-26 14:04:32870 RemoveConnectJob(job, group);
[email protected]4d3b05d2010-01-27 21:27:29871 }
[email protected]05ea9ff2010-07-15 19:08:21872 if (!handed_out_socket) {
[email protected]aed99ef02010-08-26 14:04:32873 OnAvailableSocketSlot(group_name, group);
[email protected]05ea9ff2010-07-15 19:08:21874 CheckForStalledSocketGroups();
875 }
[email protected]ff579d42009-06-24 15:47:02876 }
[email protected]ff579d42009-06-24 15:47:02877}
878
[email protected]66761b952010-06-25 21:30:38879void ClientSocketPoolBaseHelper::OnIPAddressChanged() {
880 Flush();
881}
882
[email protected]a7e38572010-06-07 18:22:24883void ClientSocketPoolBaseHelper::Flush() {
884 pool_generation_number_++;
[email protected]06f92462010-08-31 19:24:14885 CancelAllConnectJobs();
[email protected]a554a8262010-05-20 00:13:52886 CloseIdleSockets();
[email protected]06f92462010-08-31 19:24:14887 AbortAllRequests();
[email protected]a554a8262010-05-20 00:13:52888}
889
[email protected]2c2bef152010-10-13 00:55:03890void ClientSocketPoolBaseHelper::RemoveConnectJob(ConnectJob* job,
[email protected]4d3b05d2010-01-27 21:27:29891 Group* group) {
[email protected]b1f031dd2010-03-02 23:19:33892 CHECK_GT(connecting_socket_count_, 0);
[email protected]211d2172009-07-22 15:48:53893 connecting_socket_count_--;
894
[email protected]25eea382010-07-10 23:55:26895 DCHECK(group);
[email protected]aed99ef02010-08-26 14:04:32896 DCHECK(ContainsKey(group->jobs(), job));
897 group->RemoveJob(job);
[email protected]25eea382010-07-10 23:55:26898
899 // If we've got no more jobs for this group, then we no longer need a
900 // backup job either.
[email protected]aed99ef02010-08-26 14:04:32901 if (group->jobs().empty())
[email protected]e4d9a9722011-05-12 00:16:00902 group->CleanupBackupJob();
[email protected]25eea382010-07-10 23:55:26903
[email protected]8ae03f42010-07-07 19:08:10904 DCHECK(job);
905 delete job;
[email protected]2ab05b52009-07-01 23:57:58906}
[email protected]ff579d42009-06-24 15:47:02907
[email protected]8ae03f42010-07-07 19:08:10908void ClientSocketPoolBaseHelper::OnAvailableSocketSlot(
[email protected]05ea9ff2010-07-15 19:08:21909 const std::string& group_name, Group* group) {
[email protected]2abfe90a2010-08-25 17:49:51910 DCHECK(ContainsKey(group_map_, group_name));
[email protected]05ea9ff2010-07-15 19:08:21911 if (group->IsEmpty())
[email protected]aed99ef02010-08-26 14:04:32912 RemoveGroup(group_name);
913 else if (!group->pending_requests().empty())
[email protected]2abfe90a2010-08-25 17:49:51914 ProcessPendingRequest(group_name, group);
[email protected]8ae03f42010-07-07 19:08:10915}
[email protected]06650c52010-06-03 00:49:17916
[email protected]8ae03f42010-07-07 19:08:10917void ClientSocketPoolBaseHelper::ProcessPendingRequest(
[email protected]05ea9ff2010-07-15 19:08:21918 const std::string& group_name, Group* group) {
919 int rv = RequestSocketInternal(group_name,
[email protected]aed99ef02010-08-26 14:04:32920 *group->pending_requests().begin());
[email protected]05ea9ff2010-07-15 19:08:21921 if (rv != ERR_IO_PENDING) {
922 scoped_ptr<const Request> request(RemoveRequestFromQueue(
[email protected]3f00be82010-09-27 19:50:02923 group->mutable_pending_requests()->begin(), group));
[email protected]2abfe90a2010-08-25 17:49:51924 if (group->IsEmpty())
[email protected]aed99ef02010-08-26 14:04:32925 RemoveGroup(group_name);
[email protected]8ae03f42010-07-07 19:08:10926
[email protected]d7fd1782011-02-08 19:16:43927 request->net_log().EndEventWithNetErrorCode(NetLog::TYPE_SOCKET_POOL, rv);
[email protected]64770b7d2011-11-16 04:30:41928 InvokeUserCallbackLater(request->handle(), request->callback(), rv);
[email protected]2ab05b52009-07-01 23:57:58929 }
930}
931
[email protected]d80a4322009-08-14 07:07:49932void ClientSocketPoolBaseHelper::HandOutSocket(
[email protected]3268023f2011-05-05 00:08:10933 StreamSocket* socket,
[email protected]2ab05b52009-07-01 23:57:58934 bool reused,
935 ClientSocketHandle* handle,
[email protected]f9d285c2009-08-17 19:54:29936 base::TimeDelta idle_time,
[email protected]fd4fe0b2010-02-08 23:02:15937 Group* group,
[email protected]9e743cd2010-03-16 07:03:53938 const BoundNetLog& net_log) {
[email protected]2ab05b52009-07-01 23:57:58939 DCHECK(socket);
940 handle->set_socket(socket);
941 handle->set_is_reused(reused);
[email protected]f9d285c2009-08-17 19:54:29942 handle->set_idle_time(idle_time);
[email protected]a7e38572010-06-07 18:22:24943 handle->set_pool_id(pool_generation_number_);
[email protected]211d2172009-07-22 15:48:53944
[email protected]d13f51b2010-04-27 23:20:45945 if (reused) {
[email protected]ec11be62010-04-28 19:28:09946 net_log.AddEvent(
[email protected]d13f51b2010-04-27 23:20:45947 NetLog::TYPE_SOCKET_POOL_REUSED_AN_EXISTING_SOCKET,
[email protected]00cd9c42010-11-02 20:15:57948 make_scoped_refptr(new NetLogIntegerParameter(
949 "idle_ms", static_cast<int>(idle_time.InMilliseconds()))));
[email protected]fd4fe0b2010-02-08 23:02:15950 }
[email protected]d13f51b2010-04-27 23:20:45951
[email protected]06650c52010-06-03 00:49:17952 net_log.AddEvent(NetLog::TYPE_SOCKET_POOL_BOUND_TO_SOCKET,
[email protected]00cd9c42010-11-02 20:15:57953 make_scoped_refptr(new NetLogSourceParameter(
954 "source_dependency", socket->NetLog().source())));
[email protected]fd4fe0b2010-02-08 23:02:15955
[email protected]211d2172009-07-22 15:48:53956 handed_out_socket_count_++;
[email protected]aed99ef02010-08-26 14:04:32957 group->IncrementActiveSocketCount();
[email protected]ff579d42009-06-24 15:47:02958}
959
[email protected]d80a4322009-08-14 07:07:49960void ClientSocketPoolBaseHelper::AddIdleSocket(
[email protected]3268023f2011-05-05 00:08:10961 StreamSocket* socket, Group* group) {
[email protected]5fc08e32009-07-15 17:09:57962 DCHECK(socket);
963 IdleSocket idle_socket;
964 idle_socket.socket = socket;
965 idle_socket.start_time = base::TimeTicks::Now();
[email protected]5fc08e32009-07-15 17:09:57966
[email protected]aed99ef02010-08-26 14:04:32967 group->mutable_idle_sockets()->push_back(idle_socket);
[email protected]5fc08e32009-07-15 17:09:57968 IncrementIdleCount();
969}
970
[email protected]d80a4322009-08-14 07:07:49971void ClientSocketPoolBaseHelper::CancelAllConnectJobs() {
[email protected]74d75e0b2010-08-23 20:39:54972 for (GroupMap::iterator i = group_map_.begin(); i != group_map_.end();) {
[email protected]aed99ef02010-08-26 14:04:32973 Group* group = i->second;
974 connecting_socket_count_ -= group->jobs().size();
975 group->RemoveAllJobs();
[email protected]6b624c62010-03-14 08:37:32976
[email protected]5fc08e32009-07-15 17:09:57977 // Delete group if no longer needed.
[email protected]aed99ef02010-08-26 14:04:32978 if (group->IsEmpty()) {
[email protected]06f92462010-08-31 19:24:14979 // RemoveGroup() will call .erase() which will invalidate the iterator,
980 // but i will already have been incremented to a valid iterator before
981 // RemoveGroup() is called.
982 RemoveGroup(i++);
983 } else {
984 ++i;
985 }
986 }
987 DCHECK_EQ(0, connecting_socket_count_);
988}
989
990void ClientSocketPoolBaseHelper::AbortAllRequests() {
991 for (GroupMap::iterator i = group_map_.begin(); i != group_map_.end();) {
992 Group* group = i->second;
993
994 RequestQueue pending_requests;
995 pending_requests.swap(*group->mutable_pending_requests());
996 for (RequestQueue::iterator it2 = pending_requests.begin();
997 it2 != pending_requests.end(); ++it2) {
[email protected]2c2bef152010-10-13 00:55:03998 scoped_ptr<const Request> request(*it2);
[email protected]06f92462010-08-31 19:24:14999 InvokeUserCallbackLater(
1000 request->handle(), request->callback(), ERR_ABORTED);
1001 }
1002
1003 // Delete group if no longer needed.
1004 if (group->IsEmpty()) {
1005 // RemoveGroup() will call .erase() which will invalidate the iterator,
1006 // but i will already have been incremented to a valid iterator before
1007 // RemoveGroup() is called.
[email protected]aed99ef02010-08-26 14:04:321008 RemoveGroup(i++);
[email protected]74d75e0b2010-08-23 20:39:541009 } else {
1010 ++i;
[email protected]5fc08e32009-07-15 17:09:571011 }
1012 }
1013}
1014
[email protected]d80a4322009-08-14 07:07:491015bool ClientSocketPoolBaseHelper::ReachedMaxSocketsLimit() const {
[email protected]211d2172009-07-22 15:48:531016 // Each connecting socket will eventually connect and be handed out.
[email protected]43a21b82010-06-10 21:30:541017 int total = handed_out_socket_count_ + connecting_socket_count_ +
1018 idle_socket_count();
[email protected]5acdce12011-03-30 13:00:201019 // There can be more sockets than the limit since some requests can ignore
1020 // the limit
[email protected]c901f6d2010-04-27 17:48:281021 if (total < max_sockets_)
1022 return false;
[email protected]c901f6d2010-04-27 17:48:281023 return true;
[email protected]211d2172009-07-22 15:48:531024}
1025
[email protected]43a21b82010-06-10 21:30:541026void ClientSocketPoolBaseHelper::CloseOneIdleSocket() {
[email protected]dcbe168a2010-12-02 03:14:461027 CloseOneIdleSocketExceptInGroup(NULL);
1028}
1029
1030bool ClientSocketPoolBaseHelper::CloseOneIdleSocketExceptInGroup(
1031 const Group* exception_group) {
[email protected]43a21b82010-06-10 21:30:541032 CHECK_GT(idle_socket_count(), 0);
1033
1034 for (GroupMap::iterator i = group_map_.begin(); i != group_map_.end(); ++i) {
[email protected]aed99ef02010-08-26 14:04:321035 Group* group = i->second;
[email protected]dcbe168a2010-12-02 03:14:461036 if (exception_group == group)
1037 continue;
[email protected]e1b54dc2010-10-06 21:27:221038 std::list<IdleSocket>* idle_sockets = group->mutable_idle_sockets();
[email protected]43a21b82010-06-10 21:30:541039
[email protected]e1b54dc2010-10-06 21:27:221040 if (!idle_sockets->empty()) {
1041 delete idle_sockets->front().socket;
1042 idle_sockets->pop_front();
[email protected]43a21b82010-06-10 21:30:541043 DecrementIdleCount();
[email protected]aed99ef02010-08-26 14:04:321044 if (group->IsEmpty())
1045 RemoveGroup(i);
[email protected]43a21b82010-06-10 21:30:541046
[email protected]dcbe168a2010-12-02 03:14:461047 return true;
[email protected]43a21b82010-06-10 21:30:541048 }
1049 }
1050
[email protected]dcbe168a2010-12-02 03:14:461051 if (!exception_group)
1052 LOG(DFATAL) << "No idle socket found to close!.";
1053
1054 return false;
[email protected]43a21b82010-06-10 21:30:541055}
1056
[email protected]05ea9ff2010-07-15 19:08:211057void ClientSocketPoolBaseHelper::InvokeUserCallbackLater(
[email protected]f1f3f0f82011-10-01 20:38:101058 ClientSocketHandle* handle, OldCompletionCallback* callback, int rv) {
[email protected]05ea9ff2010-07-15 19:08:211059 CHECK(!ContainsKey(pending_callback_map_, handle));
1060 pending_callback_map_[handle] = CallbackResultPair(callback, rv);
1061 MessageLoop::current()->PostTask(
1062 FROM_HERE,
[email protected]2431756e2010-09-29 20:26:131063 method_factory_.NewRunnableMethod(
[email protected]05ea9ff2010-07-15 19:08:211064 &ClientSocketPoolBaseHelper::InvokeUserCallback,
1065 handle));
1066}
1067
1068void ClientSocketPoolBaseHelper::InvokeUserCallback(
1069 ClientSocketHandle* handle) {
1070 PendingCallbackMap::iterator it = pending_callback_map_.find(handle);
1071
1072 // Exit if the request has already been cancelled.
1073 if (it == pending_callback_map_.end())
1074 return;
1075
1076 CHECK(!handle->is_initialized());
[email protected]f1f3f0f82011-10-01 20:38:101077 OldCompletionCallback* callback = it->second.callback;
[email protected]05ea9ff2010-07-15 19:08:211078 int result = it->second.result;
1079 pending_callback_map_.erase(it);
1080 callback->Run(result);
1081}
1082
[email protected]aed99ef02010-08-26 14:04:321083ClientSocketPoolBaseHelper::Group::Group()
1084 : active_socket_count_(0),
1085 ALLOW_THIS_IN_INITIALIZER_LIST(method_factory_(this)) {}
1086
[email protected]e4d9a9722011-05-12 00:16:001087ClientSocketPoolBaseHelper::Group::~Group() {
1088 CleanupBackupJob();
[email protected]aed99ef02010-08-26 14:04:321089}
1090
1091void ClientSocketPoolBaseHelper::Group::StartBackupSocketTimer(
1092 const std::string& group_name,
1093 ClientSocketPoolBaseHelper* pool) {
1094 // Only allow one timer pending to create a backup socket.
1095 if (!method_factory_.empty())
1096 return;
1097
1098 MessageLoop::current()->PostDelayedTask(
1099 FROM_HERE,
1100 method_factory_.NewRunnableMethod(
1101 &Group::OnBackupSocketTimerFired, group_name, pool),
1102 pool->ConnectRetryIntervalMs());
1103}
1104
[email protected]2c2bef152010-10-13 00:55:031105bool ClientSocketPoolBaseHelper::Group::TryToUsePreconnectConnectJob() {
1106 for (std::set<ConnectJob*>::iterator it = jobs_.begin();
1107 it != jobs_.end(); ++it) {
1108 ConnectJob* job = *it;
1109 if (job->is_unused_preconnect()) {
1110 job->UseForNormalRequest();
1111 return true;
1112 }
1113 }
1114 return false;
1115}
1116
[email protected]aed99ef02010-08-26 14:04:321117void ClientSocketPoolBaseHelper::Group::OnBackupSocketTimerFired(
1118 std::string group_name,
1119 ClientSocketPoolBaseHelper* pool) {
1120 // If there are no more jobs pending, there is no work to do.
1121 // If we've done our cleanups correctly, this should not happen.
1122 if (jobs_.empty()) {
1123 NOTREACHED();
1124 return;
1125 }
1126
1127 // If our backup job is waiting on DNS, or if we can't create any sockets
1128 // right now due to limits, just reset the timer.
1129 if (pool->ReachedMaxSocketsLimit() ||
1130 !HasAvailableSocketSlot(pool->max_sockets_per_group_) ||
1131 (*jobs_.begin())->GetLoadState() == LOAD_STATE_RESOLVING_HOST) {
1132 StartBackupSocketTimer(group_name, pool);
1133 return;
1134 }
1135
[email protected]a9fc8fc2011-05-10 02:41:071136 if (pending_requests_.empty())
[email protected]4baaf9d2010-08-31 15:15:441137 return;
[email protected]4baaf9d2010-08-31 15:15:441138
[email protected]aed99ef02010-08-26 14:04:321139 ConnectJob* backup_job = pool->connect_job_factory_->NewConnectJob(
1140 group_name, **pending_requests_.begin(), pool);
1141 backup_job->net_log().AddEvent(NetLog::TYPE_SOCKET_BACKUP_CREATED, NULL);
1142 SIMPLE_STATS_COUNTER("socket.backup_created");
1143 int rv = backup_job->Connect();
1144 pool->connecting_socket_count_++;
1145 AddJob(backup_job);
1146 if (rv != ERR_IO_PENDING)
1147 pool->OnConnectJobComplete(rv, backup_job);
1148}
1149
1150void ClientSocketPoolBaseHelper::Group::RemoveAllJobs() {
1151 // Delete active jobs.
1152 STLDeleteElements(&jobs_);
1153
1154 // Cancel pending backup job.
1155 method_factory_.RevokeAll();
1156}
1157
[email protected]d80a4322009-08-14 07:07:491158} // namespace internal
1159
[email protected]ff579d42009-06-24 15:47:021160} // namespace net