blob: 2e8534e016d49967929cb82e8258bfc1241be235 [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]9e743cd2010-03-16 07:03:5314#include "net/base/net_log.h"
[email protected]ff579d42009-06-24 15:47:0215#include "net/base/net_errors.h"
16#include "net/socket/client_socket_handle.h"
17
18using base::TimeDelta;
19
20namespace {
21
22// The timeout value, in seconds, used to clean up idle sockets that can't be
23// reused.
24//
25// Note: It's important to close idle sockets that have received data as soon
26// as possible because the received data may cause BSOD on Windows XP under
27// some conditions. See http://crbug.com/4606.
28const int kCleanupInterval = 10; // DO NOT INCREASE THIS TIMEOUT.
29
[email protected]06d94042010-08-25 01:45:2230// Indicate whether or not we should establish a new TCP connection after a
31// certain timeout has passed without receiving an ACK.
32bool g_connect_backup_jobs_enabled = true;
33
[email protected]ff579d42009-06-24 15:47:0234} // namespace
35
36namespace net {
37
[email protected]2ab05b52009-07-01 23:57:5838ConnectJob::ConnectJob(const std::string& group_name,
[email protected]974ebd62009-08-03 23:14:3439 base::TimeDelta timeout_duration,
[email protected]fd7b7c92009-08-20 19:38:3040 Delegate* delegate,
[email protected]9e743cd2010-03-16 07:03:5341 const BoundNetLog& net_log)
[email protected]2ab05b52009-07-01 23:57:5842 : group_name_(group_name),
[email protected]974ebd62009-08-03 23:14:3443 timeout_duration_(timeout_duration),
[email protected]2ab05b52009-07-01 23:57:5844 delegate_(delegate),
[email protected]a2006ece2010-04-23 16:44:0245 net_log_(net_log),
46 idle_(true) {
[email protected]2ab05b52009-07-01 23:57:5847 DCHECK(!group_name.empty());
[email protected]2ab05b52009-07-01 23:57:5848 DCHECK(delegate);
[email protected]06650c52010-06-03 00:49:1749 net_log.BeginEvent(NetLog::TYPE_SOCKET_POOL_CONNECT_JOB, NULL);
[email protected]2ab05b52009-07-01 23:57:5850}
51
[email protected]fd7b7c92009-08-20 19:38:3052ConnectJob::~ConnectJob() {
[email protected]06650c52010-06-03 00:49:1753 net_log().EndEvent(NetLog::TYPE_SOCKET_POOL_CONNECT_JOB, NULL);
[email protected]fd7b7c92009-08-20 19:38:3054}
[email protected]2ab05b52009-07-01 23:57:5855
[email protected]974ebd62009-08-03 23:14:3456int ConnectJob::Connect() {
57 if (timeout_duration_ != base::TimeDelta())
58 timer_.Start(timeout_duration_, this, &ConnectJob::OnTimeout);
[email protected]fd7b7c92009-08-20 19:38:3059
[email protected]a2006ece2010-04-23 16:44:0260 idle_ = false;
[email protected]fd7b7c92009-08-20 19:38:3061
[email protected]06650c52010-06-03 00:49:1762 LogConnectStart();
63
[email protected]fd7b7c92009-08-20 19:38:3064 int rv = ConnectInternal();
65
66 if (rv != ERR_IO_PENDING) {
[email protected]06650c52010-06-03 00:49:1767 LogConnectCompletion(rv);
[email protected]fd7b7c92009-08-20 19:38:3068 delegate_ = NULL;
[email protected]fd7b7c92009-08-20 19:38:3069 }
70
71 return rv;
72}
73
[email protected]06650c52010-06-03 00:49:1774void ConnectJob::set_socket(ClientSocket* socket) {
75 if (socket) {
76 net_log().AddEvent(NetLog::TYPE_CONNECT_JOB_SET_SOCKET,
77 new NetLogSourceParameter("source_dependency",
78 socket->NetLog().source()));
79 }
80 socket_.reset(socket);
81}
82
[email protected]fd7b7c92009-08-20 19:38:3083void ConnectJob::NotifyDelegateOfCompletion(int rv) {
84 // The delegate will delete |this|.
85 Delegate *delegate = delegate_;
86 delegate_ = NULL;
87
[email protected]06650c52010-06-03 00:49:1788 LogConnectCompletion(rv);
[email protected]fd7b7c92009-08-20 19:38:3089 delegate->OnConnectJobComplete(rv, this);
[email protected]974ebd62009-08-03 23:14:3490}
91
[email protected]a796bcec2010-03-22 17:17:2692void ConnectJob::ResetTimer(base::TimeDelta remaining_time) {
93 timer_.Stop();
94 timer_.Start(remaining_time, this, &ConnectJob::OnTimeout);
95}
96
[email protected]06650c52010-06-03 00:49:1797void ConnectJob::LogConnectStart() {
98 net_log().BeginEvent(NetLog::TYPE_SOCKET_POOL_CONNECT_JOB_CONNECT,
99 new NetLogStringParameter("group_name", group_name_));
100}
101
102void ConnectJob::LogConnectCompletion(int net_error) {
103 scoped_refptr<NetLog::EventParameters> params;
104 if (net_error != OK)
105 params = new NetLogIntegerParameter("net_error", net_error);
106 net_log().EndEvent(NetLog::TYPE_SOCKET_POOL_CONNECT_JOB_CONNECT, params);
107}
108
[email protected]974ebd62009-08-03 23:14:34109void ConnectJob::OnTimeout() {
[email protected]6e713f02009-08-06 02:56:40110 // Make sure the socket is NULL before calling into |delegate|.
111 set_socket(NULL);
[email protected]fd7b7c92009-08-20 19:38:30112
[email protected]ec11be62010-04-28 19:28:09113 net_log_.AddEvent(NetLog::TYPE_SOCKET_POOL_CONNECT_JOB_TIMED_OUT, NULL);
[email protected]fd7b7c92009-08-20 19:38:30114
115 NotifyDelegateOfCompletion(ERR_TIMED_OUT);
[email protected]974ebd62009-08-03 23:14:34116}
117
[email protected]d80a4322009-08-14 07:07:49118namespace internal {
119
[email protected]fd4fe0b2010-02-08 23:02:15120ClientSocketPoolBaseHelper::Request::Request(
121 ClientSocketHandle* handle,
122 CompletionCallback* callback,
123 RequestPriority priority,
[email protected]9e743cd2010-03-16 07:03:53124 const BoundNetLog& net_log)
[email protected]fd4fe0b2010-02-08 23:02:15125 : handle_(handle), callback_(callback), priority_(priority),
[email protected]9e743cd2010-03-16 07:03:53126 net_log_(net_log) {}
[email protected]fd4fe0b2010-02-08 23:02:15127
128ClientSocketPoolBaseHelper::Request::~Request() {}
129
[email protected]d80a4322009-08-14 07:07:49130ClientSocketPoolBaseHelper::ClientSocketPoolBaseHelper(
[email protected]211d2172009-07-22 15:48:53131 int max_sockets,
[email protected]ff579d42009-06-24 15:47:02132 int max_sockets_per_group,
[email protected]9bf28db2009-08-29 01:35:16133 base::TimeDelta unused_idle_socket_timeout,
134 base::TimeDelta used_idle_socket_timeout,
[email protected]66761b952010-06-25 21:30:38135 ConnectJobFactory* connect_job_factory)
[email protected]ff579d42009-06-24 15:47:02136 : idle_socket_count_(0),
[email protected]211d2172009-07-22 15:48:53137 connecting_socket_count_(0),
138 handed_out_socket_count_(0),
139 max_sockets_(max_sockets),
[email protected]ff579d42009-06-24 15:47:02140 max_sockets_per_group_(max_sockets_per_group),
[email protected]9bf28db2009-08-29 01:35:16141 unused_idle_socket_timeout_(unused_idle_socket_timeout),
142 used_idle_socket_timeout_(used_idle_socket_timeout),
[email protected]100d5fb92009-12-21 21:08:35143 connect_job_factory_(connect_job_factory),
[email protected]06d94042010-08-25 01:45:22144 connect_backup_jobs_enabled_(false),
[email protected]74d75e0b2010-08-23 20:39:54145 ALLOW_THIS_IN_INITIALIZER_LIST(method_factory_(this)),
[email protected]09d6ecb02010-07-22 20:10:45146 pool_generation_number_(0),
147 in_destructor_(false) {
[email protected]211d2172009-07-22 15:48:53148 DCHECK_LE(0, max_sockets_per_group);
149 DCHECK_LE(max_sockets_per_group, max_sockets);
[email protected]a554a8262010-05-20 00:13:52150
[email protected]66761b952010-06-25 21:30:38151 NetworkChangeNotifier::AddObserver(this);
[email protected]211d2172009-07-22 15:48:53152}
[email protected]ff579d42009-06-24 15:47:02153
[email protected]d80a4322009-08-14 07:07:49154ClientSocketPoolBaseHelper::~ClientSocketPoolBaseHelper() {
[email protected]09d6ecb02010-07-22 20:10:45155 in_destructor_ = true;
[email protected]4d3b05d2010-01-27 21:27:29156 CancelAllConnectJobs();
157
[email protected]ff579d42009-06-24 15:47:02158 // Clean up any idle sockets. Assert that we have no remaining active
159 // sockets or pending requests. They should have all been cleaned up prior
160 // to the manager being destroyed.
161 CloseIdleSockets();
[email protected]6b624c62010-03-14 08:37:32162 CHECK(group_map_.empty());
[email protected]05ea9ff2010-07-15 19:08:21163 DCHECK(pending_callback_map_.empty());
[email protected]4d3b05d2010-01-27 21:27:29164 DCHECK_EQ(0, connecting_socket_count_);
[email protected]a554a8262010-05-20 00:13:52165
[email protected]66761b952010-06-25 21:30:38166 NetworkChangeNotifier::RemoveObserver(this);
[email protected]ff579d42009-06-24 15:47:02167}
168
169// InsertRequestIntoQueue inserts the request into the queue based on
170// priority. Highest priorities are closest to the front. Older requests are
171// prioritized over requests of equal priority.
172//
173// static
[email protected]d80a4322009-08-14 07:07:49174void ClientSocketPoolBaseHelper::InsertRequestIntoQueue(
175 const Request* r, RequestQueue* pending_requests) {
[email protected]ff579d42009-06-24 15:47:02176 RequestQueue::iterator it = pending_requests->begin();
[email protected]ac790b42009-12-02 04:31:31177 while (it != pending_requests->end() && r->priority() >= (*it)->priority())
[email protected]ff579d42009-06-24 15:47:02178 ++it;
179 pending_requests->insert(it, r);
180}
181
[email protected]fd7b7c92009-08-20 19:38:30182// static
183const ClientSocketPoolBaseHelper::Request*
184ClientSocketPoolBaseHelper::RemoveRequestFromQueue(
185 RequestQueue::iterator it, RequestQueue* pending_requests) {
186 const Request* req = *it;
[email protected]fd7b7c92009-08-20 19:38:30187 pending_requests->erase(it);
188 return req;
189}
190
[email protected]d80a4322009-08-14 07:07:49191int ClientSocketPoolBaseHelper::RequestSocket(
[email protected]ff579d42009-06-24 15:47:02192 const std::string& group_name,
[email protected]d80a4322009-08-14 07:07:49193 const Request* request) {
[email protected]ec11be62010-04-28 19:28:09194 request->net_log().BeginEvent(NetLog::TYPE_SOCKET_POOL, NULL);
[email protected]74d75e0b2010-08-23 20:39:54195 Group& group = group_map_[group_name];
[email protected]eb5a99382010-07-11 03:18:26196
[email protected]fd4fe0b2010-02-08 23:02:15197 int rv = RequestSocketInternal(group_name, request);
[email protected]e7e99322010-05-04 23:30:17198 if (rv != ERR_IO_PENDING) {
[email protected]ec11be62010-04-28 19:28:09199 request->net_log().EndEvent(NetLog::TYPE_SOCKET_POOL, NULL);
[email protected]05ea9ff2010-07-15 19:08:21200 CHECK(!request->handle()->is_initialized());
[email protected]e7e99322010-05-04 23:30:17201 delete request;
202 } else {
[email protected]74d75e0b2010-08-23 20:39:54203 InsertRequestIntoQueue(request, &group.pending_requests);
[email protected]e7e99322010-05-04 23:30:17204 }
[email protected]fd4fe0b2010-02-08 23:02:15205 return rv;
206}
207
208int ClientSocketPoolBaseHelper::RequestSocketInternal(
209 const std::string& group_name,
210 const Request* request) {
[email protected]d80a4322009-08-14 07:07:49211 DCHECK_GE(request->priority(), 0);
212 CompletionCallback* const callback = request->callback();
213 CHECK(callback);
214 ClientSocketHandle* const handle = request->handle();
215 CHECK(handle);
[email protected]74d75e0b2010-08-23 20:39:54216 Group& group = group_map_[group_name];
[email protected]ff579d42009-06-24 15:47:02217
[email protected]65552102010-04-09 22:58:10218 // Try to reuse a socket.
[email protected]74d75e0b2010-08-23 20:39:54219 if (AssignIdleSocketToGroup(&group, request))
[email protected]eb5a99382010-07-11 03:18:26220 return OK;
[email protected]65552102010-04-09 22:58:10221
[email protected]43a21b82010-06-10 21:30:54222 // Can we make another active socket now?
[email protected]74d75e0b2010-08-23 20:39:54223 if (!group.HasAvailableSocketSlot(max_sockets_per_group_)) {
[email protected]43a21b82010-06-10 21:30:54224 request->net_log().AddEvent(
225 NetLog::TYPE_SOCKET_POOL_STALLED_MAX_SOCKETS_PER_GROUP, NULL);
226 return ERR_IO_PENDING;
227 }
228
229 if (ReachedMaxSocketsLimit()) {
230 if (idle_socket_count() > 0) {
231 CloseOneIdleSocket();
232 } else {
233 // We could check if we really have a stalled group here, but it requires
234 // a scan of all groups, so just flip a flag here, and do the check later.
[email protected]43a21b82010-06-10 21:30:54235 request->net_log().AddEvent(
236 NetLog::TYPE_SOCKET_POOL_STALLED_MAX_SOCKETS, NULL);
237 return ERR_IO_PENDING;
238 }
239 }
240
[email protected]ff579d42009-06-24 15:47:02241 // We couldn't find a socket to reuse, so allocate and connect a new one.
[email protected]2ab05b52009-07-01 23:57:58242 scoped_ptr<ConnectJob> connect_job(
[email protected]06650c52010-06-03 00:49:17243 connect_job_factory_->NewConnectJob(group_name, *request, this));
[email protected]ff579d42009-06-24 15:47:02244
[email protected]2ab05b52009-07-01 23:57:58245 int rv = connect_job->Connect();
246 if (rv == OK) {
[email protected]06650c52010-06-03 00:49:17247 LogBoundConnectJobToRequest(connect_job->net_log().source(), request);
[email protected]2ab05b52009-07-01 23:57:58248 HandOutSocket(connect_job->ReleaseSocket(), false /* not reused */,
[email protected]74d75e0b2010-08-23 20:39:54249 handle, base::TimeDelta(), &group, request->net_log());
[email protected]2ab05b52009-07-01 23:57:58250 } else if (rv == ERR_IO_PENDING) {
[email protected]6b624c62010-03-14 08:37:32251 // If we don't have any sockets in this group, set a timer for potentially
252 // creating a new one. If the SYN is lost, this backup socket may complete
253 // before the slow socket, improving end user latency.
[email protected]06d94042010-08-25 01:45:22254 if (group.IsEmpty() && !group.connect_backup_job &&
255 connect_backup_jobs_enabled_) {
256 group.connect_backup_job = connect_job_factory_->NewConnectJob(group_name,
257 *request,
258 this);
[email protected]74d75e0b2010-08-23 20:39:54259 StartBackupSocketTimer(group_name);
260 }
[email protected]6b624c62010-03-14 08:37:32261
[email protected]211d2172009-07-22 15:48:53262 connecting_socket_count_++;
263
[email protected]74d75e0b2010-08-23 20:39:54264 ConnectJob* job = connect_job.release();
265 group.jobs.insert(job);
[email protected]a2006ece2010-04-23 16:44:02266 } else {
[email protected]06650c52010-06-03 00:49:17267 LogBoundConnectJobToRequest(connect_job->net_log().source(), request);
[email protected]e60e47a2010-07-14 03:37:18268 connect_job->GetAdditionalErrorState(handle);
[email protected]e772db3f2010-07-12 18:11:13269 ClientSocket* error_socket = connect_job->ReleaseSocket();
270 if (error_socket) {
271 HandOutSocket(error_socket, false /* not reused */, handle,
[email protected]74d75e0b2010-08-23 20:39:54272 base::TimeDelta(), &group, request->net_log());
273 } else if (group.IsEmpty()) {
274 group_map_.erase(group_name);
[email protected]05ea9ff2010-07-15 19:08:21275 }
[email protected]2ab05b52009-07-01 23:57:58276 }
[email protected]ff579d42009-06-24 15:47:02277
[email protected]2ab05b52009-07-01 23:57:58278 return rv;
[email protected]ff579d42009-06-24 15:47:02279}
280
[email protected]05ea9ff2010-07-15 19:08:21281bool ClientSocketPoolBaseHelper::AssignIdleSocketToGroup(
[email protected]74d75e0b2010-08-23 20:39:54282 Group* group, const Request* request) {
[email protected]eb5a99382010-07-11 03:18:26283 // Iterate through the list of idle sockets until we find one or exhaust
284 // the list.
[email protected]74d75e0b2010-08-23 20:39:54285 while (!group->idle_sockets.empty()) {
286 IdleSocket idle_socket = group->idle_sockets.back();
287 group->idle_sockets.pop_back();
[email protected]eb5a99382010-07-11 03:18:26288 DecrementIdleCount();
289 if (idle_socket.socket->IsConnectedAndIdle()) {
290 // We found one we can reuse!
291 base::TimeDelta idle_time =
292 base::TimeTicks::Now() - idle_socket.start_time;
293 HandOutSocket(
294 idle_socket.socket, idle_socket.used, request->handle(), idle_time,
295 group, request->net_log());
296 return true;
297 }
298 delete idle_socket.socket;
299 }
300 return false;
301}
302
[email protected]06650c52010-06-03 00:49:17303// static
304void ClientSocketPoolBaseHelper::LogBoundConnectJobToRequest(
305 const NetLog::Source& connect_job_source, const Request* request) {
306 request->net_log().AddEvent(
307 NetLog::TYPE_SOCKET_POOL_BOUND_TO_CONNECT_JOB,
308 new NetLogSourceParameter("source_dependency", connect_job_source));
309}
310
[email protected]74d75e0b2010-08-23 20:39:54311void ClientSocketPoolBaseHelper::StartBackupSocketTimer(
312 const std::string& group_name) {
313 CHECK(ContainsKey(group_map_, group_name));
314 Group& group = group_map_[group_name];
315
316 // Only allow one timer pending to create a backup socket.
317 if (group.backup_task)
318 return;
319
320 group.backup_task = method_factory_.NewRunnableMethod(
321 &ClientSocketPoolBaseHelper::OnBackupSocketTimerFired, group_name);
322 MessageLoop::current()->PostDelayedTask(FROM_HERE, group.backup_task,
323 ConnectRetryIntervalMs());
324}
325
326void ClientSocketPoolBaseHelper::OnBackupSocketTimerFired(
327 const std::string& group_name) {
328 CHECK(ContainsKey(group_map_, group_name));
329
330 Group& group = group_map_[group_name];
331
332 CHECK(group.backup_task);
333 group.backup_task = NULL;
334
[email protected]06d94042010-08-25 01:45:22335 CHECK(group.connect_backup_job);
[email protected]74d75e0b2010-08-23 20:39:54336
337 // If there are no more jobs pending, there is no work to do.
338 // If we've done our cleanups correctly, this should not happen.
339 if (group.jobs.empty()) {
340 NOTREACHED();
341 return;
342 }
343
344 // If our backup job is waiting on DNS, or if we can't create any sockets
345 // right now due to limits, just reset the timer.
346 if (ReachedMaxSocketsLimit() ||
347 !group.HasAvailableSocketSlot(max_sockets_per_group_) ||
348 (*group.jobs.begin())->GetLoadState() == LOAD_STATE_RESOLVING_HOST) {
349 StartBackupSocketTimer(group_name);
350 return;
351 }
352
[email protected]06d94042010-08-25 01:45:22353 group.connect_backup_job->net_log().AddEvent(
354 NetLog::TYPE_SOCKET_BACKUP_CREATED,
355 NULL);
[email protected]74d75e0b2010-08-23 20:39:54356 SIMPLE_STATS_COUNTER("socket.backup_created");
[email protected]06d94042010-08-25 01:45:22357 int rv = group.connect_backup_job->Connect();
[email protected]74d75e0b2010-08-23 20:39:54358 connecting_socket_count_++;
[email protected]06d94042010-08-25 01:45:22359 group.jobs.insert(group.connect_backup_job);
360 ConnectJob* job = group.connect_backup_job;
361 group.connect_backup_job = NULL;
[email protected]74d75e0b2010-08-23 20:39:54362 if (rv != ERR_IO_PENDING)
363 OnConnectJobComplete(rv, job);
364}
365
[email protected]d80a4322009-08-14 07:07:49366void ClientSocketPoolBaseHelper::CancelRequest(
[email protected]05ea9ff2010-07-15 19:08:21367 const std::string& group_name, ClientSocketHandle* handle) {
368 PendingCallbackMap::iterator callback_it = pending_callback_map_.find(handle);
369 if (callback_it != pending_callback_map_.end()) {
370 int result = callback_it->second.result;
371 pending_callback_map_.erase(callback_it);
372 ClientSocket* socket = handle->release_socket();
373 if (socket) {
374 if (result != OK)
375 socket->Disconnect();
376 ReleaseSocket(handle->group_name(), socket, handle->id());
377 }
378 return;
379 }
[email protected]b6501d3d2010-06-03 23:53:34380
[email protected]ff579d42009-06-24 15:47:02381 CHECK(ContainsKey(group_map_, group_name));
382
[email protected]74d75e0b2010-08-23 20:39:54383 Group& group = group_map_[group_name];
[email protected]ff579d42009-06-24 15:47:02384
[email protected]ff579d42009-06-24 15:47:02385 // Search pending_requests for matching handle.
[email protected]74d75e0b2010-08-23 20:39:54386 RequestQueue::iterator it = group.pending_requests.begin();
387 for (; it != group.pending_requests.end(); ++it) {
[email protected]d80a4322009-08-14 07:07:49388 if ((*it)->handle() == handle) {
[email protected]74d75e0b2010-08-23 20:39:54389 const Request* req = RemoveRequestFromQueue(it, &group.pending_requests);
[email protected]ec11be62010-04-28 19:28:09390 req->net_log().AddEvent(NetLog::TYPE_CANCELLED, NULL);
391 req->net_log().EndEvent(NetLog::TYPE_SOCKET_POOL, NULL);
[email protected]fd7b7c92009-08-20 19:38:30392 delete req;
[email protected]eb5a99382010-07-11 03:18:26393
394 // We let the job run, unless we're at the socket limit.
[email protected]74d75e0b2010-08-23 20:39:54395 if (group.jobs.size() && ReachedMaxSocketsLimit()) {
396 RemoveConnectJob(*group.jobs.begin(), &group);
[email protected]eb5a99382010-07-11 03:18:26397 CheckForStalledSocketGroups();
[email protected]974ebd62009-08-03 23:14:34398 }
[email protected]eb5a99382010-07-11 03:18:26399 break;
[email protected]ff579d42009-06-24 15:47:02400 }
401 }
[email protected]ff579d42009-06-24 15:47:02402}
403
[email protected]d80a4322009-08-14 07:07:49404void ClientSocketPoolBaseHelper::CloseIdleSockets() {
[email protected]ff579d42009-06-24 15:47:02405 CleanupIdleSockets(true);
406}
407
[email protected]d80a4322009-08-14 07:07:49408int ClientSocketPoolBaseHelper::IdleSocketCountInGroup(
[email protected]ff579d42009-06-24 15:47:02409 const std::string& group_name) const {
410 GroupMap::const_iterator i = group_map_.find(group_name);
411 CHECK(i != group_map_.end());
412
[email protected]74d75e0b2010-08-23 20:39:54413 return i->second.idle_sockets.size();
[email protected]ff579d42009-06-24 15:47:02414}
415
[email protected]d80a4322009-08-14 07:07:49416LoadState ClientSocketPoolBaseHelper::GetLoadState(
[email protected]ff579d42009-06-24 15:47:02417 const std::string& group_name,
418 const ClientSocketHandle* handle) const {
[email protected]05ea9ff2010-07-15 19:08:21419 if (ContainsKey(pending_callback_map_, handle))
420 return LOAD_STATE_CONNECTING;
421
[email protected]ff579d42009-06-24 15:47:02422 if (!ContainsKey(group_map_, group_name)) {
423 NOTREACHED() << "ClientSocketPool does not contain group: " << group_name
424 << " for handle: " << handle;
425 return LOAD_STATE_IDLE;
426 }
427
428 // Can't use operator[] since it is non-const.
[email protected]74d75e0b2010-08-23 20:39:54429 const Group& group = group_map_.find(group_name)->second;
[email protected]ff579d42009-06-24 15:47:02430
[email protected]ff579d42009-06-24 15:47:02431 // Search pending_requests for matching handle.
[email protected]74d75e0b2010-08-23 20:39:54432 RequestQueue::const_iterator it = group.pending_requests.begin();
433 for (size_t i = 0; it != group.pending_requests.end(); ++it, ++i) {
[email protected]d80a4322009-08-14 07:07:49434 if ((*it)->handle() == handle) {
[email protected]74d75e0b2010-08-23 20:39:54435 if (i < group.jobs.size()) {
[email protected]5fc08e32009-07-15 17:09:57436 LoadState max_state = LOAD_STATE_IDLE;
[email protected]74d75e0b2010-08-23 20:39:54437 for (ConnectJobSet::const_iterator job_it = group.jobs.begin();
438 job_it != group.jobs.end(); ++job_it) {
[email protected]46451352009-09-01 14:54:21439 max_state = std::max(max_state, (*job_it)->GetLoadState());
[email protected]5fc08e32009-07-15 17:09:57440 }
441 return max_state;
442 } else {
443 // TODO(wtc): Add a state for being on the wait list.
444 // See http://www.crbug.com/5077.
445 return LOAD_STATE_IDLE;
446 }
[email protected]ff579d42009-06-24 15:47:02447 }
448 }
449
450 NOTREACHED();
451 return LOAD_STATE_IDLE;
452}
453
[email protected]d80a4322009-08-14 07:07:49454bool ClientSocketPoolBaseHelper::IdleSocket::ShouldCleanup(
[email protected]9bf28db2009-08-29 01:35:16455 base::TimeTicks now,
456 base::TimeDelta timeout) const {
457 bool timed_out = (now - start_time) >= timeout;
[email protected]5fc08e32009-07-15 17:09:57458 return timed_out ||
459 !(used ? socket->IsConnectedAndIdle() : socket->IsConnected());
[email protected]ff579d42009-06-24 15:47:02460}
461
[email protected]d80a4322009-08-14 07:07:49462void ClientSocketPoolBaseHelper::CleanupIdleSockets(bool force) {
[email protected]ff579d42009-06-24 15:47:02463 if (idle_socket_count_ == 0)
464 return;
465
[email protected]09d6ecb02010-07-22 20:10:45466 // Deleting an SSL socket may remove the last reference to an
467 // HttpNetworkSession (in an incognito session), triggering the destruction
468 // of pools, potentially causing a recursive call to this function. Hold a
469 // reference to |this| to prevent that.
470 scoped_refptr<ClientSocketPoolBaseHelper> protect_this;
471 if (!in_destructor_)
472 protect_this = this;
473
[email protected]ff579d42009-06-24 15:47:02474 // Current time value. Retrieving it once at the function start rather than
475 // inside the inner loop, since it shouldn't change by any meaningful amount.
476 base::TimeTicks now = base::TimeTicks::Now();
477
478 GroupMap::iterator i = group_map_.begin();
479 while (i != group_map_.end()) {
[email protected]74d75e0b2010-08-23 20:39:54480 Group& group = i->second;
[email protected]ff579d42009-06-24 15:47:02481
[email protected]74d75e0b2010-08-23 20:39:54482 std::deque<IdleSocket>::iterator j = group.idle_sockets.begin();
483 while (j != group.idle_sockets.end()) {
[email protected]9bf28db2009-08-29 01:35:16484 base::TimeDelta timeout =
485 j->used ? used_idle_socket_timeout_ : unused_idle_socket_timeout_;
486 if (force || j->ShouldCleanup(now, timeout)) {
[email protected]ff579d42009-06-24 15:47:02487 delete j->socket;
[email protected]74d75e0b2010-08-23 20:39:54488 j = group.idle_sockets.erase(j);
[email protected]ff579d42009-06-24 15:47:02489 DecrementIdleCount();
490 } else {
491 ++j;
492 }
493 }
494
495 // Delete group if no longer needed.
[email protected]74d75e0b2010-08-23 20:39:54496 if (group.IsEmpty()) {
497 group_map_.erase(i++);
[email protected]ff579d42009-06-24 15:47:02498 } else {
499 ++i;
500 }
501 }
502}
503
[email protected]06d94042010-08-25 01:45:22504// static
505void ClientSocketPoolBaseHelper::set_connect_backup_jobs_enabled(bool enabled) {
506 g_connect_backup_jobs_enabled = enabled;
507}
508
509void ClientSocketPoolBaseHelper::EnableConnectBackupJobs() {
510 connect_backup_jobs_enabled_ = g_connect_backup_jobs_enabled;
511}
512
[email protected]d80a4322009-08-14 07:07:49513void ClientSocketPoolBaseHelper::IncrementIdleCount() {
[email protected]ff579d42009-06-24 15:47:02514 if (++idle_socket_count_ == 1)
515 timer_.Start(TimeDelta::FromSeconds(kCleanupInterval), this,
[email protected]d80a4322009-08-14 07:07:49516 &ClientSocketPoolBaseHelper::OnCleanupTimerFired);
[email protected]ff579d42009-06-24 15:47:02517}
518
[email protected]d80a4322009-08-14 07:07:49519void ClientSocketPoolBaseHelper::DecrementIdleCount() {
[email protected]ff579d42009-06-24 15:47:02520 if (--idle_socket_count_ == 0)
521 timer_.Stop();
522}
523
[email protected]eb5a99382010-07-11 03:18:26524void ClientSocketPoolBaseHelper::ReleaseSocket(const std::string& group_name,
525 ClientSocket* socket,
526 int id) {
[email protected]ff579d42009-06-24 15:47:02527 GroupMap::iterator i = group_map_.find(group_name);
528 CHECK(i != group_map_.end());
529
[email protected]74d75e0b2010-08-23 20:39:54530 Group& group = i->second;
[email protected]ff579d42009-06-24 15:47:02531
[email protected]b1f031dd2010-03-02 23:19:33532 CHECK_GT(handed_out_socket_count_, 0);
[email protected]211d2172009-07-22 15:48:53533 handed_out_socket_count_--;
534
[email protected]74d75e0b2010-08-23 20:39:54535 CHECK_GT(group.active_socket_count, 0);
536 group.active_socket_count--;
[email protected]ff579d42009-06-24 15:47:02537
[email protected]a7e38572010-06-07 18:22:24538 const bool can_reuse = socket->IsConnectedAndIdle() &&
539 id == pool_generation_number_;
[email protected]ff579d42009-06-24 15:47:02540 if (can_reuse) {
[email protected]eb5a99382010-07-11 03:18:26541 // Add it to the idle list.
[email protected]74d75e0b2010-08-23 20:39:54542 AddIdleSocket(socket, true /* used socket */, &group);
543 OnAvailableSocketSlot(group_name, &group);
[email protected]ff579d42009-06-24 15:47:02544 } else {
545 delete socket;
546 }
[email protected]05ea9ff2010-07-15 19:08:21547
[email protected]eb5a99382010-07-11 03:18:26548 CheckForStalledSocketGroups();
549}
[email protected]ff579d42009-06-24 15:47:02550
[email protected]eb5a99382010-07-11 03:18:26551void ClientSocketPoolBaseHelper::CheckForStalledSocketGroups() {
552 // If we have idle sockets, see if we can give one to the top-stalled group.
553 std::string top_group_name;
554 Group* top_group = NULL;
[email protected]05ea9ff2010-07-15 19:08:21555 if (!FindTopStalledGroup(&top_group, &top_group_name))
[email protected]eb5a99382010-07-11 03:18:26556 return;
[email protected]4f2abec2010-02-03 18:10:16557
[email protected]eb5a99382010-07-11 03:18:26558 if (ReachedMaxSocketsLimit()) {
559 if (idle_socket_count() > 0) {
560 CloseOneIdleSocket();
[email protected]d7027bb2010-05-10 18:58:54561 } else {
[email protected]eb5a99382010-07-11 03:18:26562 // We can't activate more sockets since we're already at our global
563 // limit.
[email protected]4f2abec2010-02-03 18:10:16564 return;
[email protected]d7027bb2010-05-10 18:58:54565 }
[email protected]4f2abec2010-02-03 18:10:16566 }
[email protected]eb5a99382010-07-11 03:18:26567
568 // Note: we don't loop on waking stalled groups. If the stalled group is at
569 // its limit, may be left with other stalled groups that could be
[email protected]05ea9ff2010-07-15 19:08:21570 // woken. This isn't optimal, but there is no starvation, so to avoid
[email protected]eb5a99382010-07-11 03:18:26571 // the looping we leave it at this.
[email protected]05ea9ff2010-07-15 19:08:21572 OnAvailableSocketSlot(top_group_name, top_group);
[email protected]ff579d42009-06-24 15:47:02573}
574
[email protected]211d2172009-07-22 15:48:53575// Search for the highest priority pending request, amongst the groups that
576// are not at the |max_sockets_per_group_| limit. Note: for requests with
577// the same priority, the winner is based on group hash ordering (and not
578// insertion order).
[email protected]05ea9ff2010-07-15 19:08:21579bool ClientSocketPoolBaseHelper::FindTopStalledGroup(Group** group,
580 std::string* group_name) {
[email protected]211d2172009-07-22 15:48:53581 Group* top_group = NULL;
582 const std::string* top_group_name = NULL;
[email protected]05ea9ff2010-07-15 19:08:21583 bool has_stalled_group = false;
[email protected]211d2172009-07-22 15:48:53584 for (GroupMap::iterator i = group_map_.begin();
585 i != group_map_.end(); ++i) {
[email protected]74d75e0b2010-08-23 20:39:54586 Group& group = i->second;
587 const RequestQueue& queue = group.pending_requests;
[email protected]211d2172009-07-22 15:48:53588 if (queue.empty())
589 continue;
[email protected]74d75e0b2010-08-23 20:39:54590 if (group.IsStalled(max_sockets_per_group_)) {
[email protected]05ea9ff2010-07-15 19:08:21591 has_stalled_group = true;
[email protected]6427fe22010-04-16 22:27:41592 bool has_higher_priority = !top_group ||
[email protected]74d75e0b2010-08-23 20:39:54593 group.TopPendingPriority() < top_group->TopPendingPriority();
[email protected]6427fe22010-04-16 22:27:41594 if (has_higher_priority) {
[email protected]74d75e0b2010-08-23 20:39:54595 top_group = &group;
[email protected]6427fe22010-04-16 22:27:41596 top_group_name = &i->first;
597 }
[email protected]211d2172009-07-22 15:48:53598 }
599 }
[email protected]05ea9ff2010-07-15 19:08:21600
[email protected]211d2172009-07-22 15:48:53601 if (top_group) {
602 *group = top_group;
603 *group_name = *top_group_name;
604 }
[email protected]05ea9ff2010-07-15 19:08:21605 return has_stalled_group;
[email protected]211d2172009-07-22 15:48:53606}
607
[email protected]d80a4322009-08-14 07:07:49608void ClientSocketPoolBaseHelper::OnConnectJobComplete(
609 int result, ConnectJob* job) {
[email protected]2ab05b52009-07-01 23:57:58610 DCHECK_NE(ERR_IO_PENDING, result);
611 const std::string group_name = job->group_name();
[email protected]ff579d42009-06-24 15:47:02612 GroupMap::iterator group_it = group_map_.find(group_name);
613 CHECK(group_it != group_map_.end());
[email protected]74d75e0b2010-08-23 20:39:54614 Group& group = group_it->second;
[email protected]ff579d42009-06-24 15:47:02615
[email protected]5fc08e32009-07-15 17:09:57616 scoped_ptr<ClientSocket> socket(job->ReleaseSocket());
[email protected]ff579d42009-06-24 15:47:02617
[email protected]9e743cd2010-03-16 07:03:53618 BoundNetLog job_log = job->net_log();
[email protected]5fc08e32009-07-15 17:09:57619
[email protected]4d3b05d2010-01-27 21:27:29620 if (result == OK) {
621 DCHECK(socket.get());
[email protected]74d75e0b2010-08-23 20:39:54622 RemoveConnectJob(job, &group);
623 if (!group.pending_requests.empty()) {
[email protected]4d3b05d2010-01-27 21:27:29624 scoped_ptr<const Request> r(RemoveRequestFromQueue(
[email protected]74d75e0b2010-08-23 20:39:54625 group.pending_requests.begin(), &group.pending_requests));
[email protected]06650c52010-06-03 00:49:17626 LogBoundConnectJobToRequest(job_log.source(), r.get());
[email protected]4d3b05d2010-01-27 21:27:29627 HandOutSocket(
628 socket.release(), false /* unused socket */, r->handle(),
[email protected]74d75e0b2010-08-23 20:39:54629 base::TimeDelta(), &group, r->net_log());
[email protected]06650c52010-06-03 00:49:17630 r->net_log().EndEvent(NetLog::TYPE_SOCKET_POOL, NULL);
[email protected]05ea9ff2010-07-15 19:08:21631 InvokeUserCallbackLater(r->handle(), r->callback(), result);
[email protected]5fc08e32009-07-15 17:09:57632 } else {
[email protected]74d75e0b2010-08-23 20:39:54633 AddIdleSocket(socket.release(), false /* unused socket */, &group);
634 OnAvailableSocketSlot(group_name, &group);
[email protected]05ea9ff2010-07-15 19:08:21635 CheckForStalledSocketGroups();
[email protected]5fc08e32009-07-15 17:09:57636 }
[email protected]94c20472010-01-14 08:14:36637 } else {
[email protected]e772db3f2010-07-12 18:11:13638 // If we got a socket, it must contain error information so pass that
639 // up so that the caller can retrieve it.
640 bool handed_out_socket = false;
[email protected]74d75e0b2010-08-23 20:39:54641 if (!group.pending_requests.empty()) {
[email protected]4d3b05d2010-01-27 21:27:29642 scoped_ptr<const Request> r(RemoveRequestFromQueue(
[email protected]74d75e0b2010-08-23 20:39:54643 group.pending_requests.begin(), &group.pending_requests));
[email protected]06650c52010-06-03 00:49:17644 LogBoundConnectJobToRequest(job_log.source(), r.get());
[email protected]e60e47a2010-07-14 03:37:18645 job->GetAdditionalErrorState(r->handle());
[email protected]74d75e0b2010-08-23 20:39:54646 RemoveConnectJob(job, &group);
[email protected]e772db3f2010-07-12 18:11:13647 if (socket.get()) {
648 handed_out_socket = true;
649 HandOutSocket(socket.release(), false /* unused socket */, r->handle(),
[email protected]74d75e0b2010-08-23 20:39:54650 base::TimeDelta(), &group, r->net_log());
[email protected]e772db3f2010-07-12 18:11:13651 }
[email protected]06650c52010-06-03 00:49:17652 r->net_log().EndEvent(NetLog::TYPE_SOCKET_POOL,
653 new NetLogIntegerParameter("net_error", result));
[email protected]05ea9ff2010-07-15 19:08:21654 InvokeUserCallbackLater(r->handle(), r->callback(), result);
[email protected]e60e47a2010-07-14 03:37:18655 } else {
[email protected]74d75e0b2010-08-23 20:39:54656 RemoveConnectJob(job, &group);
[email protected]4d3b05d2010-01-27 21:27:29657 }
[email protected]05ea9ff2010-07-15 19:08:21658 if (!handed_out_socket) {
[email protected]74d75e0b2010-08-23 20:39:54659 OnAvailableSocketSlot(group_name, &group);
[email protected]05ea9ff2010-07-15 19:08:21660 CheckForStalledSocketGroups();
661 }
[email protected]ff579d42009-06-24 15:47:02662 }
[email protected]ff579d42009-06-24 15:47:02663}
664
[email protected]66761b952010-06-25 21:30:38665void ClientSocketPoolBaseHelper::OnIPAddressChanged() {
666 Flush();
667}
668
[email protected]a7e38572010-06-07 18:22:24669void ClientSocketPoolBaseHelper::Flush() {
670 pool_generation_number_++;
[email protected]a554a8262010-05-20 00:13:52671 CloseIdleSockets();
672}
673
[email protected]25eea382010-07-10 23:55:26674void ClientSocketPoolBaseHelper::RemoveConnectJob(const ConnectJob* job,
[email protected]4d3b05d2010-01-27 21:27:29675 Group* group) {
[email protected]b1f031dd2010-03-02 23:19:33676 CHECK_GT(connecting_socket_count_, 0);
[email protected]211d2172009-07-22 15:48:53677 connecting_socket_count_--;
678
[email protected]25eea382010-07-10 23:55:26679 DCHECK(group);
[email protected]74d75e0b2010-08-23 20:39:54680 DCHECK(ContainsKey(group->jobs, job));
681 group->jobs.erase(job);
[email protected]25eea382010-07-10 23:55:26682
683 // If we've got no more jobs for this group, then we no longer need a
684 // backup job either.
[email protected]74d75e0b2010-08-23 20:39:54685 if (group->jobs.empty())
[email protected]25eea382010-07-10 23:55:26686 group->CleanupBackupJob();
687
[email protected]8ae03f42010-07-07 19:08:10688 DCHECK(job);
689 delete job;
[email protected]2ab05b52009-07-01 23:57:58690}
[email protected]ff579d42009-06-24 15:47:02691
[email protected]8ae03f42010-07-07 19:08:10692void ClientSocketPoolBaseHelper::OnAvailableSocketSlot(
[email protected]05ea9ff2010-07-15 19:08:21693 const std::string& group_name, Group* group) {
[email protected]74d75e0b2010-08-23 20:39:54694 if (!group->pending_requests.empty())
[email protected]05ea9ff2010-07-15 19:08:21695 ProcessPendingRequest(group_name, group);
696
697 if (group->IsEmpty())
[email protected]74d75e0b2010-08-23 20:39:54698 group_map_.erase(group_name);
[email protected]8ae03f42010-07-07 19:08:10699}
[email protected]06650c52010-06-03 00:49:17700
[email protected]8ae03f42010-07-07 19:08:10701void ClientSocketPoolBaseHelper::ProcessPendingRequest(
[email protected]05ea9ff2010-07-15 19:08:21702 const std::string& group_name, Group* group) {
703 int rv = RequestSocketInternal(group_name,
[email protected]74d75e0b2010-08-23 20:39:54704 *group->pending_requests.begin());
[email protected]05ea9ff2010-07-15 19:08:21705 if (rv != ERR_IO_PENDING) {
706 scoped_ptr<const Request> request(RemoveRequestFromQueue(
[email protected]74d75e0b2010-08-23 20:39:54707 group->pending_requests.begin(), &group->pending_requests));
[email protected]8ae03f42010-07-07 19:08:10708
[email protected]05ea9ff2010-07-15 19:08:21709 scoped_refptr<NetLog::EventParameters> params;
710 if (rv != OK)
711 params = new NetLogIntegerParameter("net_error", rv);
712 request->net_log().EndEvent(NetLog::TYPE_SOCKET_POOL, params);
713 InvokeUserCallbackLater(
714 request->handle(), request->callback(), rv);
[email protected]2ab05b52009-07-01 23:57:58715 }
716}
717
[email protected]d80a4322009-08-14 07:07:49718void ClientSocketPoolBaseHelper::HandOutSocket(
[email protected]2ab05b52009-07-01 23:57:58719 ClientSocket* socket,
720 bool reused,
721 ClientSocketHandle* handle,
[email protected]f9d285c2009-08-17 19:54:29722 base::TimeDelta idle_time,
[email protected]fd4fe0b2010-02-08 23:02:15723 Group* group,
[email protected]9e743cd2010-03-16 07:03:53724 const BoundNetLog& net_log) {
[email protected]2ab05b52009-07-01 23:57:58725 DCHECK(socket);
726 handle->set_socket(socket);
727 handle->set_is_reused(reused);
[email protected]f9d285c2009-08-17 19:54:29728 handle->set_idle_time(idle_time);
[email protected]a7e38572010-06-07 18:22:24729 handle->set_pool_id(pool_generation_number_);
[email protected]211d2172009-07-22 15:48:53730
[email protected]d13f51b2010-04-27 23:20:45731 if (reused) {
[email protected]ec11be62010-04-28 19:28:09732 net_log.AddEvent(
[email protected]d13f51b2010-04-27 23:20:45733 NetLog::TYPE_SOCKET_POOL_REUSED_AN_EXISTING_SOCKET,
[email protected]ec11be62010-04-28 19:28:09734 new NetLogIntegerParameter(
735 "idle_ms", static_cast<int>(idle_time.InMilliseconds())));
[email protected]fd4fe0b2010-02-08 23:02:15736 }
[email protected]d13f51b2010-04-27 23:20:45737
[email protected]06650c52010-06-03 00:49:17738 net_log.AddEvent(NetLog::TYPE_SOCKET_POOL_BOUND_TO_SOCKET,
739 new NetLogSourceParameter(
740 "source_dependency", socket->NetLog().source()));
[email protected]fd4fe0b2010-02-08 23:02:15741
[email protected]211d2172009-07-22 15:48:53742 handed_out_socket_count_++;
[email protected]74d75e0b2010-08-23 20:39:54743 group->active_socket_count++;
[email protected]ff579d42009-06-24 15:47:02744}
745
[email protected]d80a4322009-08-14 07:07:49746void ClientSocketPoolBaseHelper::AddIdleSocket(
[email protected]5fc08e32009-07-15 17:09:57747 ClientSocket* socket, bool used, Group* group) {
748 DCHECK(socket);
749 IdleSocket idle_socket;
750 idle_socket.socket = socket;
751 idle_socket.start_time = base::TimeTicks::Now();
752 idle_socket.used = used;
753
[email protected]74d75e0b2010-08-23 20:39:54754 group->idle_sockets.push_back(idle_socket);
[email protected]5fc08e32009-07-15 17:09:57755 IncrementIdleCount();
756}
757
[email protected]d80a4322009-08-14 07:07:49758void ClientSocketPoolBaseHelper::CancelAllConnectJobs() {
[email protected]74d75e0b2010-08-23 20:39:54759 for (GroupMap::iterator i = group_map_.begin(); i != group_map_.end();) {
760 Group& group = i->second;
761 connecting_socket_count_ -= group.jobs.size();
762 STLDeleteElements(&group.jobs);
763
764 if (group.backup_task) {
765 group.backup_task->Cancel();
766 group.backup_task = NULL;
767 }
[email protected]6b624c62010-03-14 08:37:32768
[email protected]5fc08e32009-07-15 17:09:57769 // Delete group if no longer needed.
[email protected]74d75e0b2010-08-23 20:39:54770 if (group.IsEmpty()) {
771 group_map_.erase(i++);
772 } else {
773 ++i;
[email protected]5fc08e32009-07-15 17:09:57774 }
775 }
776}
777
[email protected]d80a4322009-08-14 07:07:49778bool ClientSocketPoolBaseHelper::ReachedMaxSocketsLimit() const {
[email protected]211d2172009-07-22 15:48:53779 // Each connecting socket will eventually connect and be handed out.
[email protected]43a21b82010-06-10 21:30:54780 int total = handed_out_socket_count_ + connecting_socket_count_ +
781 idle_socket_count();
[email protected]211d2172009-07-22 15:48:53782 DCHECK_LE(total, max_sockets_);
[email protected]c901f6d2010-04-27 17:48:28783 if (total < max_sockets_)
784 return false;
785 LOG(WARNING) << "ReachedMaxSocketsLimit: " << total << "/" << max_sockets_;
786 return true;
[email protected]211d2172009-07-22 15:48:53787}
788
[email protected]43a21b82010-06-10 21:30:54789void ClientSocketPoolBaseHelper::CloseOneIdleSocket() {
790 CHECK_GT(idle_socket_count(), 0);
791
792 for (GroupMap::iterator i = group_map_.begin(); i != group_map_.end(); ++i) {
[email protected]74d75e0b2010-08-23 20:39:54793 Group& group = i->second;
[email protected]43a21b82010-06-10 21:30:54794
[email protected]74d75e0b2010-08-23 20:39:54795 if (!group.idle_sockets.empty()) {
796 std::deque<IdleSocket>::iterator j = group.idle_sockets.begin();
[email protected]43a21b82010-06-10 21:30:54797 delete j->socket;
[email protected]74d75e0b2010-08-23 20:39:54798 group.idle_sockets.erase(j);
[email protected]43a21b82010-06-10 21:30:54799 DecrementIdleCount();
[email protected]74d75e0b2010-08-23 20:39:54800 if (group.IsEmpty())
801 group_map_.erase(i);
[email protected]43a21b82010-06-10 21:30:54802
803 return;
804 }
805 }
806
807 LOG(DFATAL) << "No idle socket found to close!.";
808}
809
[email protected]05ea9ff2010-07-15 19:08:21810void ClientSocketPoolBaseHelper::InvokeUserCallbackLater(
811 ClientSocketHandle* handle, CompletionCallback* callback, int rv) {
812 CHECK(!ContainsKey(pending_callback_map_, handle));
813 pending_callback_map_[handle] = CallbackResultPair(callback, rv);
814 MessageLoop::current()->PostTask(
815 FROM_HERE,
816 NewRunnableMethod(
817 this,
818 &ClientSocketPoolBaseHelper::InvokeUserCallback,
819 handle));
820}
821
822void ClientSocketPoolBaseHelper::InvokeUserCallback(
823 ClientSocketHandle* handle) {
824 PendingCallbackMap::iterator it = pending_callback_map_.find(handle);
825
826 // Exit if the request has already been cancelled.
827 if (it == pending_callback_map_.end())
828 return;
829
830 CHECK(!handle->is_initialized());
831 CompletionCallback* callback = it->second.callback;
832 int result = it->second.result;
833 pending_callback_map_.erase(it);
834 callback->Run(result);
835}
836
[email protected]d80a4322009-08-14 07:07:49837} // namespace internal
838
[email protected]ff579d42009-06-24 15:47:02839} // namespace net