blob: 30cff70939d74a3e020e8253991273eecd318abe [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.
[email protected]d80a4322009-08-14 07:07:494//
5// A ClientSocketPoolBase is used to restrict the number of sockets open at
6// a time. It also maintains a list of idle persistent sockets for reuse.
7// Subclasses of ClientSocketPool should compose ClientSocketPoolBase to handle
8// the core logic of (1) restricting the number of active (connected or
9// connecting) sockets per "group" (generally speaking, the hostname), (2)
10// maintaining a per-group list of idle, persistent sockets for reuse, and (3)
11// limiting the total number of active sockets in the system.
12//
13// ClientSocketPoolBase abstracts socket connection details behind ConnectJob,
14// ConnectJobFactory, and SocketParams. When a socket "slot" becomes available,
15// the ClientSocketPoolBase will ask the ConnectJobFactory to create a
16// ConnectJob with a SocketParams. Subclasses of ClientSocketPool should
17// implement their socket specific connection by subclassing ConnectJob and
18// implementing ConnectJob::ConnectInternal(). They can control the parameters
19// passed to each new ConnectJob instance via their ConnectJobFactory subclass
20// and templated SocketParams parameter.
21//
[email protected]ff579d42009-06-24 15:47:0222#ifndef NET_SOCKET_CLIENT_SOCKET_POOL_BASE_H_
23#define NET_SOCKET_CLIENT_SOCKET_POOL_BASE_H_
[email protected]32b76ef2010-07-26 23:08:2424#pragma once
[email protected]ff579d42009-06-24 15:47:0225
26#include <deque>
27#include <map>
[email protected]5fc08e32009-07-15 17:09:5728#include <set>
[email protected]ff579d42009-06-24 15:47:0229#include <string>
30
31#include "base/basictypes.h"
[email protected]6b624c62010-03-14 08:37:3232#include "base/compiler_specific.h"
[email protected]100d5fb92009-12-21 21:08:3533#include "base/ref_counted.h"
[email protected]ff579d42009-06-24 15:47:0234#include "base/scoped_ptr.h"
[email protected]6b624c62010-03-14 08:37:3235#include "base/task.h"
[email protected]ff579d42009-06-24 15:47:0236#include "base/time.h"
37#include "base/timer.h"
38#include "net/base/address_list.h"
39#include "net/base/completion_callback.h"
[email protected]ff579d42009-06-24 15:47:0240#include "net/base/load_states.h"
[email protected]d80a4322009-08-14 07:07:4941#include "net/base/net_errors.h"
[email protected]9e743cd2010-03-16 07:03:5342#include "net/base/net_log.h"
[email protected]a554a8262010-05-20 00:13:5243#include "net/base/network_change_notifier.h"
[email protected]ac790b42009-12-02 04:31:3144#include "net/base/request_priority.h"
[email protected]2ab05b52009-07-01 23:57:5845#include "net/socket/client_socket.h"
[email protected]ff579d42009-06-24 15:47:0246#include "net/socket/client_socket_pool.h"
47
48namespace net {
49
[email protected]ff579d42009-06-24 15:47:0250class ClientSocketHandle;
[email protected]ff579d42009-06-24 15:47:0251
52// ConnectJob provides an abstract interface for "connecting" a socket.
53// The connection may involve host resolution, tcp connection, ssl connection,
54// etc.
55class ConnectJob {
56 public:
[email protected]ab838892009-06-30 18:49:0557 class Delegate {
58 public:
59 Delegate() {}
60 virtual ~Delegate() {}
61
[email protected]2ab05b52009-07-01 23:57:5862 // Alerts the delegate that the connection completed.
63 virtual void OnConnectJobComplete(int result, ConnectJob* job) = 0;
[email protected]ab838892009-06-30 18:49:0564
65 private:
66 DISALLOW_COPY_AND_ASSIGN(Delegate);
67 };
68
[email protected]974ebd62009-08-03 23:14:3469 // A |timeout_duration| of 0 corresponds to no timeout.
[email protected]2ab05b52009-07-01 23:57:5870 ConnectJob(const std::string& group_name,
[email protected]974ebd62009-08-03 23:14:3471 base::TimeDelta timeout_duration,
[email protected]fd7b7c92009-08-20 19:38:3072 Delegate* delegate,
[email protected]9e743cd2010-03-16 07:03:5373 const BoundNetLog& net_log);
[email protected]2ab05b52009-07-01 23:57:5874 virtual ~ConnectJob();
[email protected]ff579d42009-06-24 15:47:0275
[email protected]2ab05b52009-07-01 23:57:5876 // Accessors
77 const std::string& group_name() const { return group_name_; }
[email protected]9e743cd2010-03-16 07:03:5378 const BoundNetLog& net_log() { return net_log_; }
[email protected]2ab05b52009-07-01 23:57:5879
[email protected]8e12ae02009-07-02 16:15:0480 // Releases |socket_| to the client. On connection error, this should return
81 // NULL.
[email protected]2ab05b52009-07-01 23:57:5882 ClientSocket* ReleaseSocket() { return socket_.release(); }
[email protected]ab838892009-06-30 18:49:0583
[email protected]ff579d42009-06-24 15:47:0284 // Begins connecting the socket. Returns OK on success, ERR_IO_PENDING if it
85 // cannot complete synchronously without blocking, or another net error code
[email protected]2ab05b52009-07-01 23:57:5886 // on error. In asynchronous completion, the ConnectJob will notify
87 // |delegate_| via OnConnectJobComplete. In both asynchronous and synchronous
88 // completion, ReleaseSocket() can be called to acquire the connected socket
89 // if it succeeded.
[email protected]974ebd62009-08-03 23:14:3490 int Connect();
[email protected]ff579d42009-06-24 15:47:0291
[email protected]46451352009-09-01 14:54:2192 virtual LoadState GetLoadState() const = 0;
[email protected]fd7b7c92009-08-20 19:38:3093
[email protected]e60e47a2010-07-14 03:37:1894 // If Connect returns an error (or OnConnectJobComplete reports an error
95 // result) this method will be called, allowing the pool to add
96 // additional error state to the ClientSocketHandle (post late-binding).
97 virtual void GetAdditionalErrorState(ClientSocketHandle* handle) {}
98
[email protected]ab838892009-06-30 18:49:0599 protected:
[email protected]06650c52010-06-03 00:49:17100 void set_socket(ClientSocket* socket);
[email protected]2ab05b52009-07-01 23:57:58101 ClientSocket* socket() { return socket_.get(); }
[email protected]fd7b7c92009-08-20 19:38:30102 void NotifyDelegateOfCompletion(int rv);
[email protected]a796bcec2010-03-22 17:17:26103 void ResetTimer(base::TimeDelta remainingTime);
[email protected]ab838892009-06-30 18:49:05104
[email protected]ff579d42009-06-24 15:47:02105 private:
[email protected]974ebd62009-08-03 23:14:34106 virtual int ConnectInternal() = 0;
107
[email protected]06650c52010-06-03 00:49:17108 void LogConnectStart();
109 void LogConnectCompletion(int net_error);
110
[email protected]974ebd62009-08-03 23:14:34111 // Alerts the delegate that the ConnectJob has timed out.
112 void OnTimeout();
113
[email protected]2ab05b52009-07-01 23:57:58114 const std::string group_name_;
[email protected]974ebd62009-08-03 23:14:34115 const base::TimeDelta timeout_duration_;
116 // Timer to abort jobs that take too long.
117 base::OneShotTimer<ConnectJob> timer_;
118 Delegate* delegate_;
[email protected]2ab05b52009-07-01 23:57:58119 scoped_ptr<ClientSocket> socket_;
[email protected]9e743cd2010-03-16 07:03:53120 BoundNetLog net_log_;
[email protected]a2006ece2010-04-23 16:44:02121 // A ConnectJob is idle until Connect() has been called.
122 bool idle_;
[email protected]ab838892009-06-30 18:49:05123
[email protected]ff579d42009-06-24 15:47:02124 DISALLOW_COPY_AND_ASSIGN(ConnectJob);
125};
126
[email protected]d80a4322009-08-14 07:07:49127namespace internal {
128
129// ClientSocketPoolBaseHelper is an internal class that implements almost all
130// the functionality from ClientSocketPoolBase without using templates.
131// ClientSocketPoolBase adds templated definitions built on top of
132// ClientSocketPoolBaseHelper. This class is not for external use, please use
133// ClientSocketPoolBase instead.
134class ClientSocketPoolBaseHelper
135 : public base::RefCounted<ClientSocketPoolBaseHelper>,
[email protected]a554a8262010-05-20 00:13:52136 public ConnectJob::Delegate,
137 public NetworkChangeNotifier::Observer {
[email protected]ff579d42009-06-24 15:47:02138 public:
[email protected]d80a4322009-08-14 07:07:49139 class Request {
140 public:
[email protected]684970b2009-08-14 04:54:46141 Request(ClientSocketHandle* handle,
[email protected]ff579d42009-06-24 15:47:02142 CompletionCallback* callback,
[email protected]ac790b42009-12-02 04:31:31143 RequestPriority priority,
[email protected]9e743cd2010-03-16 07:03:53144 const BoundNetLog& net_log);
[email protected]ff579d42009-06-24 15:47:02145
[email protected]fd4fe0b2010-02-08 23:02:15146 virtual ~Request();
[email protected]d80a4322009-08-14 07:07:49147
148 ClientSocketHandle* handle() const { return handle_; }
149 CompletionCallback* callback() const { return callback_; }
[email protected]ac790b42009-12-02 04:31:31150 RequestPriority priority() const { return priority_; }
[email protected]9e743cd2010-03-16 07:03:53151 const BoundNetLog& net_log() const { return net_log_; }
[email protected]d80a4322009-08-14 07:07:49152
153 private:
154 ClientSocketHandle* const handle_;
155 CompletionCallback* const callback_;
[email protected]ac790b42009-12-02 04:31:31156 const RequestPriority priority_;
[email protected]9e743cd2010-03-16 07:03:53157 BoundNetLog net_log_;
[email protected]d80a4322009-08-14 07:07:49158
159 DISALLOW_COPY_AND_ASSIGN(Request);
[email protected]ff579d42009-06-24 15:47:02160 };
161
162 class ConnectJobFactory {
163 public:
164 ConnectJobFactory() {}
165 virtual ~ConnectJobFactory() {}
166
167 virtual ConnectJob* NewConnectJob(
168 const std::string& group_name,
169 const Request& request,
[email protected]06650c52010-06-03 00:49:17170 ConnectJob::Delegate* delegate) const = 0;
[email protected]ff579d42009-06-24 15:47:02171
[email protected]a796bcec2010-03-22 17:17:26172 virtual base::TimeDelta ConnectionTimeout() const = 0;
173
[email protected]ff579d42009-06-24 15:47:02174 private:
175 DISALLOW_COPY_AND_ASSIGN(ConnectJobFactory);
176 };
177
[email protected]100d5fb92009-12-21 21:08:35178 ClientSocketPoolBaseHelper(
179 int max_sockets,
180 int max_sockets_per_group,
181 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
[email protected]d80a4322009-08-14 07:07:49185 // See ClientSocketPool::RequestSocket for documentation on this function.
[email protected]e7e99322010-05-04 23:30:17186 // ClientSocketPoolBaseHelper takes ownership of |request|, which must be
187 // heap allocated.
[email protected]d80a4322009-08-14 07:07:49188 int RequestSocket(const std::string& group_name, const Request* request);
[email protected]ff579d42009-06-24 15:47:02189
[email protected]d80a4322009-08-14 07:07:49190 // See ClientSocketPool::CancelRequest for documentation on this function.
[email protected]ff579d42009-06-24 15:47:02191 void CancelRequest(const std::string& group_name,
[email protected]05ea9ff2010-07-15 19:08:21192 ClientSocketHandle* handle);
[email protected]ff579d42009-06-24 15:47:02193
[email protected]d80a4322009-08-14 07:07:49194 // See ClientSocketPool::ReleaseSocket for documentation on this function.
[email protected]ff579d42009-06-24 15:47:02195 void ReleaseSocket(const std::string& group_name,
[email protected]a7e38572010-06-07 18:22:24196 ClientSocket* socket,
197 int id);
[email protected]ff579d42009-06-24 15:47:02198
[email protected]a7e38572010-06-07 18:22:24199 // See ClientSocketPool::Flush for documentation on this function.
200 void Flush();
[email protected]241c5c2c2010-06-21 18:46:00201
[email protected]d80a4322009-08-14 07:07:49202 // See ClientSocketPool::CloseIdleSockets for documentation on this function.
[email protected]ff579d42009-06-24 15:47:02203 void CloseIdleSockets();
204
[email protected]d80a4322009-08-14 07:07:49205 // See ClientSocketPool::IdleSocketCount() for documentation on this function.
[email protected]ff579d42009-06-24 15:47:02206 int idle_socket_count() const {
207 return idle_socket_count_;
208 }
209
[email protected]d80a4322009-08-14 07:07:49210 // See ClientSocketPool::IdleSocketCountInGroup() for documentation on this
211 // function.
[email protected]ff579d42009-06-24 15:47:02212 int IdleSocketCountInGroup(const std::string& group_name) const;
213
[email protected]d80a4322009-08-14 07:07:49214 // See ClientSocketPool::GetLoadState() for documentation on this function.
[email protected]ff579d42009-06-24 15:47:02215 LoadState GetLoadState(const std::string& group_name,
216 const ClientSocketHandle* handle) const;
217
[email protected]6b624c62010-03-14 08:37:32218 int ConnectRetryIntervalMs() const {
219 // TODO(mbelshe): Make this tuned dynamically based on measured RTT.
220 // For now, just use the max retry interval.
221 return ClientSocketPool::kMaxConnectRetryIntervalMs;
222 }
223
[email protected]d80a4322009-08-14 07:07:49224 // ConnectJob::Delegate methods:
[email protected]2ab05b52009-07-01 23:57:58225 virtual void OnConnectJobComplete(int result, ConnectJob* job);
[email protected]ff579d42009-06-24 15:47:02226
[email protected]a554a8262010-05-20 00:13:52227 // NetworkChangeNotifier::Observer methods:
[email protected]66761b952010-06-25 21:30:38228 virtual void OnIPAddressChanged();
[email protected]a554a8262010-05-20 00:13:52229
[email protected]974ebd62009-08-03 23:14:34230 int NumConnectJobsInGroup(const std::string& group_name) const {
231 return group_map_.find(group_name)->second.jobs.size();
232 }
[email protected]211d2172009-07-22 15:48:53233
[email protected]9bf28db2009-08-29 01:35:16234 // Closes all idle sockets if |force| is true. Else, only closes idle
235 // sockets that timed out or can't be reused. Made public for testing.
236 void CleanupIdleSockets(bool force);
237
[email protected]a796bcec2010-03-22 17:17:26238 base::TimeDelta ConnectionTimeout() const {
239 return connect_job_factory_->ConnectionTimeout();
240 }
241
[email protected]43a21b82010-06-10 21:30:54242 void EnableBackupJobs() { backup_jobs_enabled_ = true; }
[email protected]7c28e9a2010-03-20 01:16:13243
[email protected]ff579d42009-06-24 15:47:02244 private:
[email protected]5389bc72009-11-05 23:34:24245 friend class base::RefCounted<ClientSocketPoolBaseHelper>;
246
[email protected]ff579d42009-06-24 15:47:02247 // Entry for a persistent socket which became idle at time |start_time|.
248 struct IdleSocket {
[email protected]5fc08e32009-07-15 17:09:57249 IdleSocket() : socket(NULL), used(false) {}
[email protected]ff579d42009-06-24 15:47:02250 ClientSocket* socket;
251 base::TimeTicks start_time;
[email protected]5fc08e32009-07-15 17:09:57252 bool used; // Indicates whether or not the socket has been used yet.
[email protected]ff579d42009-06-24 15:47:02253
254 // An idle socket should be removed if it can't be reused, or has been idle
255 // for too long. |now| is the current time value (TimeTicks::Now()).
[email protected]9bf28db2009-08-29 01:35:16256 // |timeout| is the length of time to wait before timing out an idle socket.
[email protected]ff579d42009-06-24 15:47:02257 //
258 // An idle socket can't be reused if it is disconnected or has received
259 // data unexpectedly (hence no longer idle). The unread data would be
260 // mistaken for the beginning of the next response if we were to reuse the
261 // socket for a new request.
[email protected]9bf28db2009-08-29 01:35:16262 bool ShouldCleanup(base::TimeTicks now, base::TimeDelta timeout) const;
[email protected]ff579d42009-06-24 15:47:02263 };
264
[email protected]d80a4322009-08-14 07:07:49265 typedef std::deque<const Request*> RequestQueue;
266 typedef std::map<const ClientSocketHandle*, const Request*> RequestMap;
[email protected]ff579d42009-06-24 15:47:02267
268 // A Group is allocated per group_name when there are idle sockets or pending
269 // requests. Otherwise, the Group object is removed from the map.
[email protected]eb5a99382010-07-11 03:18:26270 // |active_socket_count| tracks the number of sockets held by clients.
[email protected]ff579d42009-06-24 15:47:02271 struct Group {
[email protected]6b624c62010-03-14 08:37:32272 Group()
273 : active_socket_count(0),
[email protected]6b624c62010-03-14 08:37:32274 backup_job(NULL),
275 backup_task(NULL) {
276 }
277
278 ~Group() {
279 CleanupBackupJob();
280 }
[email protected]2ab05b52009-07-01 23:57:58281
282 bool IsEmpty() const {
[email protected]2b7523d2009-07-29 20:29:23283 return active_socket_count == 0 && idle_sockets.empty() && jobs.empty() &&
[email protected]4d3b05d2010-01-27 21:27:29284 pending_requests.empty();
[email protected]2ab05b52009-07-01 23:57:58285 }
286
287 bool HasAvailableSocketSlot(int max_sockets_per_group) const {
[email protected]5fc08e32009-07-15 17:09:57288 return active_socket_count + static_cast<int>(jobs.size()) <
[email protected]2ab05b52009-07-01 23:57:58289 max_sockets_per_group;
290 }
291
[email protected]05ea9ff2010-07-15 19:08:21292 bool IsStalled(int max_sockets_per_group) const {
293 return HasAvailableSocketSlot(max_sockets_per_group) &&
294 pending_requests.size() > jobs.size();
295 }
296
[email protected]ac790b42009-12-02 04:31:31297 RequestPriority TopPendingPriority() const {
[email protected]d80a4322009-08-14 07:07:49298 return pending_requests.front()->priority();
[email protected]211d2172009-07-22 15:48:53299 }
300
[email protected]6b624c62010-03-14 08:37:32301 void CleanupBackupJob() {
302 if (backup_job) {
303 delete backup_job;
304 backup_job = NULL;
305 }
306 if (backup_task) {
307 backup_task->Cancel();
308 backup_task = NULL;
309 }
310 }
311
[email protected]ff579d42009-06-24 15:47:02312 std::deque<IdleSocket> idle_sockets;
[email protected]5fc08e32009-07-15 17:09:57313 std::set<const ConnectJob*> jobs;
[email protected]ff579d42009-06-24 15:47:02314 RequestQueue pending_requests;
[email protected]2ab05b52009-07-01 23:57:58315 int active_socket_count; // number of active sockets used by clients
[email protected]6b624c62010-03-14 08:37:32316 // A backup job in case the connect for this group takes too long.
317 ConnectJob* backup_job;
318 CancelableTask* backup_task;
[email protected]ff579d42009-06-24 15:47:02319 };
320
321 typedef std::map<std::string, Group> GroupMap;
322
[email protected]5fc08e32009-07-15 17:09:57323 typedef std::set<const ConnectJob*> ConnectJobSet;
[email protected]ff579d42009-06-24 15:47:02324
[email protected]05ea9ff2010-07-15 19:08:21325 struct CallbackResultPair {
326 CallbackResultPair() : callback(NULL), result(OK) {}
327 CallbackResultPair(CompletionCallback* callback_in, int result_in)
328 : callback(callback_in), result(result_in) {}
329
330 CompletionCallback* callback;
331 int result;
332 };
333
334 typedef std::map<const ClientSocketHandle*, CallbackResultPair>
335 PendingCallbackMap;
336
337 ~ClientSocketPoolBaseHelper();
338
[email protected]d80a4322009-08-14 07:07:49339 static void InsertRequestIntoQueue(const Request* r,
[email protected]ff579d42009-06-24 15:47:02340 RequestQueue* pending_requests);
[email protected]fd7b7c92009-08-20 19:38:30341 static const Request* RemoveRequestFromQueue(RequestQueue::iterator it,
342 RequestQueue* pending_requests);
[email protected]ff579d42009-06-24 15:47:02343
[email protected]ff579d42009-06-24 15:47:02344 // Called when the number of idle sockets changes.
345 void IncrementIdleCount();
346 void DecrementIdleCount();
347
[email protected]211d2172009-07-22 15:48:53348 // Scans the group map for groups which have an available socket slot and
[email protected]05ea9ff2010-07-15 19:08:21349 // at least one pending request. Returns true if any groups are stalled, and
350 // if so, fills |group| and |group_name| with data of the stalled group
[email protected]211d2172009-07-22 15:48:53351 // having highest priority.
[email protected]05ea9ff2010-07-15 19:08:21352 bool FindTopStalledGroup(Group** group, std::string* group_name);
[email protected]211d2172009-07-22 15:48:53353
[email protected]ff579d42009-06-24 15:47:02354 // Called when timer_ fires. This method scans the idle sockets removing
355 // sockets that timed out or can't be reused.
356 void OnCleanupTimerFired() {
357 CleanupIdleSockets(false);
358 }
359
[email protected]4d3b05d2010-01-27 21:27:29360 // Removes |job| from |connect_job_set_|. Also updates |group| if non-NULL.
361 void RemoveConnectJob(const ConnectJob* job, Group* group);
[email protected]ff579d42009-06-24 15:47:02362
[email protected]05ea9ff2010-07-15 19:08:21363 // Tries to see if we can handle any more requests for |group|.
364 void OnAvailableSocketSlot(const std::string& group_name, Group* group);
[email protected]8ae03f42010-07-07 19:08:10365
[email protected]eb5a99382010-07-11 03:18:26366 // Process a pending socket request for a group.
[email protected]05ea9ff2010-07-15 19:08:21367 void ProcessPendingRequest(const std::string& group_name, Group* group);
[email protected]ff579d42009-06-24 15:47:02368
[email protected]2ab05b52009-07-01 23:57:58369 // Assigns |socket| to |handle| and updates |group|'s counters appropriately.
370 void HandOutSocket(ClientSocket* socket,
371 bool reused,
372 ClientSocketHandle* handle,
[email protected]f9d285c2009-08-17 19:54:29373 base::TimeDelta time_idle,
[email protected]fd4fe0b2010-02-08 23:02:15374 Group* group,
[email protected]9e743cd2010-03-16 07:03:53375 const BoundNetLog& net_log);
[email protected]2ab05b52009-07-01 23:57:58376
[email protected]5fc08e32009-07-15 17:09:57377 // Adds |socket| to the list of idle sockets for |group|. |used| indicates
378 // whether or not the socket has previously been used.
379 void AddIdleSocket(ClientSocket* socket, bool used, Group* group);
380
381 // Iterates through |connect_job_map_|, canceling all ConnectJobs.
382 // Afterwards, it iterates through all groups and deletes them if they are no
383 // longer needed.
384 void CancelAllConnectJobs();
385
[email protected]211d2172009-07-22 15:48:53386 // Returns true if we can't create any more sockets due to the total limit.
[email protected]211d2172009-07-22 15:48:53387 bool ReachedMaxSocketsLimit() const;
388
[email protected]fd4fe0b2010-02-08 23:02:15389 // This is the internal implementation of RequestSocket(). It differs in that
[email protected]9e743cd2010-03-16 07:03:53390 // it does not handle logging into NetLog of the queueing status of
[email protected]fd4fe0b2010-02-08 23:02:15391 // |request|.
392 int RequestSocketInternal(const std::string& group_name,
393 const Request* request);
394
[email protected]eb5a99382010-07-11 03:18:26395 // Assigns an idle socket for the group to the request.
396 // Returns |true| if an idle socket is available, false otherwise.
397 bool AssignIdleSocketToGroup(Group* group, const Request* request);
398
[email protected]06650c52010-06-03 00:49:17399 static void LogBoundConnectJobToRequest(
400 const NetLog::Source& connect_job_source, const Request* request);
401
[email protected]6b624c62010-03-14 08:37:32402 // Set a timer to create a backup socket if it takes too long to create one.
403 void StartBackupSocketTimer(const std::string& group_name);
404
405 // Called when the backup socket timer fires.
406 void OnBackupSocketTimerFired(const std::string& group_name);
407
[email protected]43a21b82010-06-10 21:30:54408 // Closes one idle socket. Picks the first one encountered.
409 // TODO(willchan): Consider a better algorithm for doing this. Perhaps we
410 // should keep an ordered list of idle sockets, and close them in order.
411 // Requires maintaining more state. It's not clear if it's worth it since
412 // I'm not sure if we hit this situation often.
413 void CloseOneIdleSocket();
414
[email protected]eb5a99382010-07-11 03:18:26415 // Checks if there are stalled socket groups that should be notified
416 // for possible wakeup.
417 void CheckForStalledSocketGroups();
418
[email protected]05ea9ff2010-07-15 19:08:21419 // Posts a task to call InvokeUserCallback() on the next iteration through the
420 // current message loop. Inserts |callback| into |pending_callback_map_|,
421 // keyed by |handle|.
422 void InvokeUserCallbackLater(
423 ClientSocketHandle* handle, CompletionCallback* callback, int rv);
424
425 // Invokes the user callback for |handle|. By the time this task has run,
426 // it's possible that the request has been cancelled, so |handle| may not
427 // exist in |pending_callback_map_|. We look up the callback and result code
428 // in |pending_callback_map_|.
429 void InvokeUserCallback(ClientSocketHandle* handle);
[email protected]eb5a99382010-07-11 03:18:26430
[email protected]ff579d42009-06-24 15:47:02431 GroupMap group_map_;
432
[email protected]05ea9ff2010-07-15 19:08:21433 // Map of the ClientSocketHandles for which we have a pending Task to invoke a
434 // callback. This is necessary since, before we invoke said callback, it's
435 // possible that the request is cancelled.
436 PendingCallbackMap pending_callback_map_;
437
[email protected]ff579d42009-06-24 15:47:02438 // Timer used to periodically prune idle sockets that timed out or can't be
439 // reused.
[email protected]d80a4322009-08-14 07:07:49440 base::RepeatingTimer<ClientSocketPoolBaseHelper> timer_;
[email protected]ff579d42009-06-24 15:47:02441
442 // The total number of idle sockets in the system.
443 int idle_socket_count_;
444
[email protected]211d2172009-07-22 15:48:53445 // Number of connecting sockets across all groups.
446 int connecting_socket_count_;
447
448 // Number of connected sockets we handed out across all groups.
449 int handed_out_socket_count_;
450
451 // The maximum total number of sockets. See ReachedMaxSocketsLimit.
452 const int max_sockets_;
453
[email protected]ff579d42009-06-24 15:47:02454 // The maximum number of sockets kept per group.
455 const int max_sockets_per_group_;
456
[email protected]9bf28db2009-08-29 01:35:16457 // The time to wait until closing idle sockets.
458 const base::TimeDelta unused_idle_socket_timeout_;
459 const base::TimeDelta used_idle_socket_timeout_;
460
[email protected]ab838892009-06-30 18:49:05461 const scoped_ptr<ConnectJobFactory> connect_job_factory_;
[email protected]ff579d42009-06-24 15:47:02462
[email protected]7c28e9a2010-03-20 01:16:13463 // TODO(vandebo) Remove when backup jobs move to TCPClientSocketPool
464 bool backup_jobs_enabled_;
465
[email protected]6b624c62010-03-14 08:37:32466 // A factory to pin the backup_job tasks.
467 ScopedRunnableMethodFactory<ClientSocketPoolBaseHelper> method_factory_;
[email protected]a7e38572010-06-07 18:22:24468
469 // A unique id for the pool. It gets incremented every time we Flush() the
470 // pool. This is so that when sockets get released back to the pool, we can
471 // make sure that they are discarded rather than reused.
472 int pool_generation_number_;
[email protected]09d6ecb02010-07-22 20:10:45473
474 // Some parts of this class need to know if the destructor is running.
475 bool in_destructor_;
[email protected]d80a4322009-08-14 07:07:49476};
477
478} // namespace internal
479
[email protected]9bf28db2009-08-29 01:35:16480// The maximum duration, in seconds, to keep used idle persistent sockets alive.
481static const int kUsedIdleSocketTimeout = 300; // 5 minutes
482
[email protected]d80a4322009-08-14 07:07:49483template <typename SocketParams>
484class ClientSocketPoolBase {
485 public:
486 class Request : public internal::ClientSocketPoolBaseHelper::Request {
487 public:
488 Request(ClientSocketHandle* handle,
489 CompletionCallback* callback,
[email protected]ac790b42009-12-02 04:31:31490 RequestPriority priority,
[email protected]df4b4ef2010-07-12 18:25:21491 const scoped_refptr<SocketParams>& params,
[email protected]9e743cd2010-03-16 07:03:53492 const BoundNetLog& net_log)
[email protected]d80a4322009-08-14 07:07:49493 : internal::ClientSocketPoolBaseHelper::Request(
[email protected]9e743cd2010-03-16 07:03:53494 handle, callback, priority, net_log),
[email protected]d80a4322009-08-14 07:07:49495 params_(params) {}
496
[email protected]df4b4ef2010-07-12 18:25:21497 const scoped_refptr<SocketParams>& params() const { return params_; }
[email protected]d80a4322009-08-14 07:07:49498
499 private:
[email protected]df4b4ef2010-07-12 18:25:21500 scoped_refptr<SocketParams> params_;
[email protected]d80a4322009-08-14 07:07:49501 };
502
503 class ConnectJobFactory {
504 public:
505 ConnectJobFactory() {}
506 virtual ~ConnectJobFactory() {}
507
508 virtual ConnectJob* NewConnectJob(
509 const std::string& group_name,
510 const Request& request,
[email protected]06650c52010-06-03 00:49:17511 ConnectJob::Delegate* delegate) const = 0;
[email protected]d80a4322009-08-14 07:07:49512
[email protected]a796bcec2010-03-22 17:17:26513 virtual base::TimeDelta ConnectionTimeout() const = 0;
514
[email protected]d80a4322009-08-14 07:07:49515 private:
516 DISALLOW_COPY_AND_ASSIGN(ConnectJobFactory);
517 };
518
[email protected]9bf28db2009-08-29 01:35:16519 // |max_sockets| is the maximum number of sockets to be maintained by this
520 // ClientSocketPool. |max_sockets_per_group| specifies the maximum number of
521 // sockets a "group" can have. |unused_idle_socket_timeout| specifies how
522 // long to leave an unused idle socket open before closing it.
523 // |used_idle_socket_timeout| specifies how long to leave a previously used
524 // idle socket open before closing it.
[email protected]100d5fb92009-12-21 21:08:35525 ClientSocketPoolBase(
526 int max_sockets,
527 int max_sockets_per_group,
[email protected]b89f7e42010-05-20 20:37:00528 const scoped_refptr<ClientSocketPoolHistograms>& histograms,
[email protected]100d5fb92009-12-21 21:08:35529 base::TimeDelta unused_idle_socket_timeout,
530 base::TimeDelta used_idle_socket_timeout,
[email protected]66761b952010-06-25 21:30:38531 ConnectJobFactory* connect_job_factory)
[email protected]b89f7e42010-05-20 20:37:00532 : histograms_(histograms),
[email protected]a796bcec2010-03-22 17:17:26533 helper_(new internal::ClientSocketPoolBaseHelper(
[email protected]d80a4322009-08-14 07:07:49534 max_sockets, max_sockets_per_group,
[email protected]9bf28db2009-08-29 01:35:16535 unused_idle_socket_timeout, used_idle_socket_timeout,
[email protected]66761b952010-06-25 21:30:38536 new ConnectJobFactoryAdaptor(connect_job_factory))) {}
[email protected]d80a4322009-08-14 07:07:49537
[email protected]20cb5f482009-12-16 01:01:25538 virtual ~ClientSocketPoolBase() {}
[email protected]d80a4322009-08-14 07:07:49539
540 // These member functions simply forward to ClientSocketPoolBaseHelper.
541
542 // RequestSocket bundles up the parameters into a Request and then forwards to
543 // ClientSocketPoolBaseHelper::RequestSocket(). Note that the memory
544 // ownership is transferred in the asynchronous (ERR_IO_PENDING) case.
545 int RequestSocket(const std::string& group_name,
[email protected]df4b4ef2010-07-12 18:25:21546 const scoped_refptr<SocketParams>& params,
[email protected]ac790b42009-12-02 04:31:31547 RequestPriority priority,
[email protected]d80a4322009-08-14 07:07:49548 ClientSocketHandle* handle,
549 CompletionCallback* callback,
[email protected]9e743cd2010-03-16 07:03:53550 const BoundNetLog& net_log) {
[email protected]e7e99322010-05-04 23:30:17551 Request* request = new Request(handle, callback, priority, params, net_log);
552 return helper_->RequestSocket(group_name, request);
[email protected]d80a4322009-08-14 07:07:49553 }
554
555 void CancelRequest(const std::string& group_name,
[email protected]05ea9ff2010-07-15 19:08:21556 ClientSocketHandle* handle) {
[email protected]d80a4322009-08-14 07:07:49557 return helper_->CancelRequest(group_name, handle);
558 }
559
[email protected]241c5c2c2010-06-21 18:46:00560 void ReleaseSocket(const std::string& group_name, ClientSocket* socket,
561 int id) {
[email protected]a7e38572010-06-07 18:22:24562 return helper_->ReleaseSocket(group_name, socket, id);
[email protected]d80a4322009-08-14 07:07:49563 }
564
565 void CloseIdleSockets() { return helper_->CloseIdleSockets(); }
566
567 int idle_socket_count() const { return helper_->idle_socket_count(); }
568
569 int IdleSocketCountInGroup(const std::string& group_name) const {
570 return helper_->IdleSocketCountInGroup(group_name);
571 }
572
573 LoadState GetLoadState(const std::string& group_name,
574 const ClientSocketHandle* handle) const {
575 return helper_->GetLoadState(group_name, handle);
576 }
577
578 virtual void OnConnectJobComplete(int result, ConnectJob* job) {
579 return helper_->OnConnectJobComplete(result, job);
580 }
581
[email protected]d80a4322009-08-14 07:07:49582 int NumConnectJobsInGroup(const std::string& group_name) const {
583 return helper_->NumConnectJobsInGroup(group_name);
584 }
585
[email protected]9bf28db2009-08-29 01:35:16586 void CleanupIdleSockets(bool force) {
587 return helper_->CleanupIdleSockets(force);
588 }
589
[email protected]a796bcec2010-03-22 17:17:26590 base::TimeDelta ConnectionTimeout() const {
591 return helper_->ConnectionTimeout();
592 }
593
[email protected]b89f7e42010-05-20 20:37:00594 scoped_refptr<ClientSocketPoolHistograms> histograms() const {
595 return histograms_;
596 }
[email protected]a796bcec2010-03-22 17:17:26597
[email protected]43a21b82010-06-10 21:30:54598 void EnableBackupJobs() { helper_->EnableBackupJobs(); }
[email protected]7c28e9a2010-03-20 01:16:13599
[email protected]a7e38572010-06-07 18:22:24600 void Flush() { helper_->Flush(); }
601
[email protected]d80a4322009-08-14 07:07:49602 private:
603 // This adaptor class exists to bridge the
604 // internal::ClientSocketPoolBaseHelper::ConnectJobFactory and
605 // ClientSocketPoolBase::ConnectJobFactory types, allowing clients to use the
606 // typesafe ClientSocketPoolBase::ConnectJobFactory, rather than having to
607 // static_cast themselves.
608 class ConnectJobFactoryAdaptor
609 : public internal::ClientSocketPoolBaseHelper::ConnectJobFactory {
610 public:
611 typedef typename ClientSocketPoolBase<SocketParams>::ConnectJobFactory
612 ConnectJobFactory;
613
614 explicit ConnectJobFactoryAdaptor(
615 ConnectJobFactory* connect_job_factory)
616 : connect_job_factory_(connect_job_factory) {}
617 virtual ~ConnectJobFactoryAdaptor() {}
618
619 virtual ConnectJob* NewConnectJob(
620 const std::string& group_name,
621 const internal::ClientSocketPoolBaseHelper::Request& request,
[email protected]06650c52010-06-03 00:49:17622 ConnectJob::Delegate* delegate) const {
[email protected]d80a4322009-08-14 07:07:49623 const Request* casted_request = static_cast<const Request*>(&request);
624 return connect_job_factory_->NewConnectJob(
[email protected]06650c52010-06-03 00:49:17625 group_name, *casted_request, delegate);
[email protected]d80a4322009-08-14 07:07:49626 }
627
[email protected]a796bcec2010-03-22 17:17:26628 virtual base::TimeDelta ConnectionTimeout() const {
629 return connect_job_factory_->ConnectionTimeout();
630 }
631
[email protected]d80a4322009-08-14 07:07:49632 const scoped_ptr<ConnectJobFactory> connect_job_factory_;
633 };
634
[email protected]b89f7e42010-05-20 20:37:00635 // Histograms for the pool
636 const scoped_refptr<ClientSocketPoolHistograms> histograms_;
[email protected]a796bcec2010-03-22 17:17:26637
[email protected]eb5a99382010-07-11 03:18:26638 // The reason for reference counting here is because the operations on
639 // the ClientSocketPoolBaseHelper which release sockets can cause the
640 // ClientSocketPoolBase<T> reference to drop to zero. While we're deep
641 // in cleanup code, we'll often hold a reference to |self|.
[email protected]d80a4322009-08-14 07:07:49642 scoped_refptr<internal::ClientSocketPoolBaseHelper> helper_;
643
[email protected]ff579d42009-06-24 15:47:02644 DISALLOW_COPY_AND_ASSIGN(ClientSocketPoolBase);
645};
646
[email protected]ff579d42009-06-24 15:47:02647} // namespace net
648
649#endif // NET_SOCKET_CLIENT_SOCKET_POOL_BASE_H_