blob: deb405d2ffe823d94061df8daa65f7a803d9a86e [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_
24
25#include <deque>
26#include <map>
[email protected]5fc08e32009-07-15 17:09:5727#include <set>
[email protected]ff579d42009-06-24 15:47:0228#include <string>
29
30#include "base/basictypes.h"
[email protected]6b624c62010-03-14 08:37:3231#include "base/compiler_specific.h"
[email protected]100d5fb92009-12-21 21:08:3532#include "base/ref_counted.h"
[email protected]ff579d42009-06-24 15:47:0233#include "base/scoped_ptr.h"
[email protected]6b624c62010-03-14 08:37:3234#include "base/task.h"
[email protected]ff579d42009-06-24 15:47:0235#include "base/time.h"
36#include "base/timer.h"
37#include "net/base/address_list.h"
38#include "net/base/completion_callback.h"
[email protected]ff579d42009-06-24 15:47:0239#include "net/base/load_states.h"
[email protected]d80a4322009-08-14 07:07:4940#include "net/base/net_errors.h"
[email protected]9e743cd2010-03-16 07:03:5341#include "net/base/net_log.h"
[email protected]a554a8262010-05-20 00:13:5242#include "net/base/network_change_notifier.h"
[email protected]ac790b42009-12-02 04:31:3143#include "net/base/request_priority.h"
[email protected]2ab05b52009-07-01 23:57:5844#include "net/socket/client_socket.h"
[email protected]ff579d42009-06-24 15:47:0245#include "net/socket/client_socket_pool.h"
46
47namespace net {
48
[email protected]ff579d42009-06-24 15:47:0249class ClientSocketHandle;
[email protected]ff579d42009-06-24 15:47:0250
51// ConnectJob provides an abstract interface for "connecting" a socket.
52// The connection may involve host resolution, tcp connection, ssl connection,
53// etc.
54class ConnectJob {
55 public:
[email protected]ab838892009-06-30 18:49:0556 class Delegate {
57 public:
58 Delegate() {}
59 virtual ~Delegate() {}
60
[email protected]2ab05b52009-07-01 23:57:5861 // Alerts the delegate that the connection completed.
62 virtual void OnConnectJobComplete(int result, ConnectJob* job) = 0;
[email protected]ab838892009-06-30 18:49:0563
64 private:
65 DISALLOW_COPY_AND_ASSIGN(Delegate);
66 };
67
[email protected]974ebd62009-08-03 23:14:3468 // A |timeout_duration| of 0 corresponds to no timeout.
[email protected]2ab05b52009-07-01 23:57:5869 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 virtual ~ConnectJob();
[email protected]ff579d42009-06-24 15:47:0274
[email protected]2ab05b52009-07-01 23:57:5875 // Accessors
76 const std::string& group_name() const { return group_name_; }
[email protected]9e743cd2010-03-16 07:03:5377 const BoundNetLog& net_log() { return net_log_; }
[email protected]2ab05b52009-07-01 23:57:5878
[email protected]8e12ae02009-07-02 16:15:0479 // Releases |socket_| to the client. On connection error, this should return
80 // NULL.
[email protected]2ab05b52009-07-01 23:57:5881 ClientSocket* ReleaseSocket() { return socket_.release(); }
[email protected]ab838892009-06-30 18:49:0582
[email protected]ff579d42009-06-24 15:47:0283 // Begins connecting the socket. Returns OK on success, ERR_IO_PENDING if it
84 // cannot complete synchronously without blocking, or another net error code
[email protected]2ab05b52009-07-01 23:57:5885 // on error. In asynchronous completion, the ConnectJob will notify
86 // |delegate_| via OnConnectJobComplete. In both asynchronous and synchronous
87 // completion, ReleaseSocket() can be called to acquire the connected socket
88 // if it succeeded.
[email protected]974ebd62009-08-03 23:14:3489 int Connect();
[email protected]ff579d42009-06-24 15:47:0290
[email protected]46451352009-09-01 14:54:2191 virtual LoadState GetLoadState() const = 0;
[email protected]fd7b7c92009-08-20 19:38:3092
[email protected]ab838892009-06-30 18:49:0593 protected:
[email protected]06650c52010-06-03 00:49:1794 void set_socket(ClientSocket* socket);
[email protected]2ab05b52009-07-01 23:57:5895 ClientSocket* socket() { return socket_.get(); }
[email protected]fd7b7c92009-08-20 19:38:3096 void NotifyDelegateOfCompletion(int rv);
[email protected]a796bcec2010-03-22 17:17:2697 void ResetTimer(base::TimeDelta remainingTime);
[email protected]ab838892009-06-30 18:49:0598
[email protected]ff579d42009-06-24 15:47:0299 private:
[email protected]974ebd62009-08-03 23:14:34100 virtual int ConnectInternal() = 0;
101
[email protected]06650c52010-06-03 00:49:17102 void LogConnectStart();
103 void LogConnectCompletion(int net_error);
104
[email protected]974ebd62009-08-03 23:14:34105 // Alerts the delegate that the ConnectJob has timed out.
106 void OnTimeout();
107
[email protected]2ab05b52009-07-01 23:57:58108 const std::string group_name_;
[email protected]974ebd62009-08-03 23:14:34109 const base::TimeDelta timeout_duration_;
110 // Timer to abort jobs that take too long.
111 base::OneShotTimer<ConnectJob> timer_;
112 Delegate* delegate_;
[email protected]2ab05b52009-07-01 23:57:58113 scoped_ptr<ClientSocket> socket_;
[email protected]9e743cd2010-03-16 07:03:53114 BoundNetLog net_log_;
[email protected]a2006ece2010-04-23 16:44:02115 // A ConnectJob is idle until Connect() has been called.
116 bool idle_;
[email protected]ab838892009-06-30 18:49:05117
[email protected]ff579d42009-06-24 15:47:02118 DISALLOW_COPY_AND_ASSIGN(ConnectJob);
119};
120
[email protected]d80a4322009-08-14 07:07:49121namespace internal {
122
123// ClientSocketPoolBaseHelper is an internal class that implements almost all
124// the functionality from ClientSocketPoolBase without using templates.
125// ClientSocketPoolBase adds templated definitions built on top of
126// ClientSocketPoolBaseHelper. This class is not for external use, please use
127// ClientSocketPoolBase instead.
128class ClientSocketPoolBaseHelper
129 : public base::RefCounted<ClientSocketPoolBaseHelper>,
[email protected]a554a8262010-05-20 00:13:52130 public ConnectJob::Delegate,
131 public NetworkChangeNotifier::Observer {
[email protected]ff579d42009-06-24 15:47:02132 public:
[email protected]d80a4322009-08-14 07:07:49133 class Request {
134 public:
[email protected]684970b2009-08-14 04:54:46135 Request(ClientSocketHandle* handle,
[email protected]ff579d42009-06-24 15:47:02136 CompletionCallback* callback,
[email protected]ac790b42009-12-02 04:31:31137 RequestPriority priority,
[email protected]9e743cd2010-03-16 07:03:53138 const BoundNetLog& net_log);
[email protected]ff579d42009-06-24 15:47:02139
[email protected]fd4fe0b2010-02-08 23:02:15140 virtual ~Request();
[email protected]d80a4322009-08-14 07:07:49141
142 ClientSocketHandle* handle() const { return handle_; }
143 CompletionCallback* callback() const { return callback_; }
[email protected]ac790b42009-12-02 04:31:31144 RequestPriority priority() const { return priority_; }
[email protected]9e743cd2010-03-16 07:03:53145 const BoundNetLog& net_log() const { return net_log_; }
[email protected]d80a4322009-08-14 07:07:49146
147 private:
148 ClientSocketHandle* const handle_;
149 CompletionCallback* const callback_;
[email protected]ac790b42009-12-02 04:31:31150 const RequestPriority priority_;
[email protected]9e743cd2010-03-16 07:03:53151 BoundNetLog net_log_;
[email protected]d80a4322009-08-14 07:07:49152
153 DISALLOW_COPY_AND_ASSIGN(Request);
[email protected]ff579d42009-06-24 15:47:02154 };
155
156 class ConnectJobFactory {
157 public:
158 ConnectJobFactory() {}
159 virtual ~ConnectJobFactory() {}
160
161 virtual ConnectJob* NewConnectJob(
162 const std::string& group_name,
163 const Request& request,
[email protected]06650c52010-06-03 00:49:17164 ConnectJob::Delegate* delegate) const = 0;
[email protected]ff579d42009-06-24 15:47:02165
[email protected]a796bcec2010-03-22 17:17:26166 virtual base::TimeDelta ConnectionTimeout() const = 0;
167
[email protected]ff579d42009-06-24 15:47:02168 private:
169 DISALLOW_COPY_AND_ASSIGN(ConnectJobFactory);
170 };
171
[email protected]100d5fb92009-12-21 21:08:35172 ClientSocketPoolBaseHelper(
173 int max_sockets,
174 int max_sockets_per_group,
175 base::TimeDelta unused_idle_socket_timeout,
176 base::TimeDelta used_idle_socket_timeout,
[email protected]66761b952010-06-25 21:30:38177 ConnectJobFactory* connect_job_factory);
[email protected]ff579d42009-06-24 15:47:02178
[email protected]d80a4322009-08-14 07:07:49179 // See ClientSocketPool::RequestSocket for documentation on this function.
[email protected]e7e99322010-05-04 23:30:17180 // ClientSocketPoolBaseHelper takes ownership of |request|, which must be
181 // heap allocated.
[email protected]d80a4322009-08-14 07:07:49182 int RequestSocket(const std::string& group_name, const Request* request);
[email protected]ff579d42009-06-24 15:47:02183
[email protected]d80a4322009-08-14 07:07:49184 // See ClientSocketPool::CancelRequest for documentation on this function.
[email protected]ff579d42009-06-24 15:47:02185 void CancelRequest(const std::string& group_name,
186 const ClientSocketHandle* handle);
187
[email protected]d80a4322009-08-14 07:07:49188 // See ClientSocketPool::ReleaseSocket for documentation on this function.
[email protected]ff579d42009-06-24 15:47:02189 void ReleaseSocket(const std::string& group_name,
[email protected]a7e38572010-06-07 18:22:24190 ClientSocket* socket,
191 int id);
[email protected]ff579d42009-06-24 15:47:02192
[email protected]a7e38572010-06-07 18:22:24193 // See ClientSocketPool::Flush for documentation on this function.
194 void Flush();
[email protected]241c5c2c2010-06-21 18:46:00195
[email protected]d80a4322009-08-14 07:07:49196 // See ClientSocketPool::CloseIdleSockets for documentation on this function.
[email protected]ff579d42009-06-24 15:47:02197 void CloseIdleSockets();
198
[email protected]d80a4322009-08-14 07:07:49199 // See ClientSocketPool::IdleSocketCount() for documentation on this function.
[email protected]ff579d42009-06-24 15:47:02200 int idle_socket_count() const {
201 return idle_socket_count_;
202 }
203
[email protected]d80a4322009-08-14 07:07:49204 // See ClientSocketPool::IdleSocketCountInGroup() for documentation on this
205 // function.
[email protected]ff579d42009-06-24 15:47:02206 int IdleSocketCountInGroup(const std::string& group_name) const;
207
[email protected]d80a4322009-08-14 07:07:49208 // See ClientSocketPool::GetLoadState() for documentation on this function.
[email protected]ff579d42009-06-24 15:47:02209 LoadState GetLoadState(const std::string& group_name,
210 const ClientSocketHandle* handle) const;
211
[email protected]6b624c62010-03-14 08:37:32212 int ConnectRetryIntervalMs() const {
213 // TODO(mbelshe): Make this tuned dynamically based on measured RTT.
214 // For now, just use the max retry interval.
215 return ClientSocketPool::kMaxConnectRetryIntervalMs;
216 }
217
[email protected]d80a4322009-08-14 07:07:49218 // ConnectJob::Delegate methods:
[email protected]2ab05b52009-07-01 23:57:58219 virtual void OnConnectJobComplete(int result, ConnectJob* job);
[email protected]ff579d42009-06-24 15:47:02220
[email protected]a554a8262010-05-20 00:13:52221 // NetworkChangeNotifier::Observer methods:
[email protected]66761b952010-06-25 21:30:38222 virtual void OnIPAddressChanged();
[email protected]a554a8262010-05-20 00:13:52223
[email protected]8ae03f42010-07-07 19:08:10224 // For testing.
225 bool may_have_stalled_group() const { return may_have_stalled_group_; }
226
[email protected]974ebd62009-08-03 23:14:34227 int NumConnectJobsInGroup(const std::string& group_name) const {
228 return group_map_.find(group_name)->second.jobs.size();
229 }
[email protected]211d2172009-07-22 15:48:53230
[email protected]9bf28db2009-08-29 01:35:16231 // Closes all idle sockets if |force| is true. Else, only closes idle
232 // sockets that timed out or can't be reused. Made public for testing.
233 void CleanupIdleSockets(bool force);
234
[email protected]a796bcec2010-03-22 17:17:26235 base::TimeDelta ConnectionTimeout() const {
236 return connect_job_factory_->ConnectionTimeout();
237 }
238
[email protected]43a21b82010-06-10 21:30:54239 void EnableBackupJobs() { backup_jobs_enabled_ = true; }
[email protected]7c28e9a2010-03-20 01:16:13240
[email protected]ff579d42009-06-24 15:47:02241 private:
[email protected]5389bc72009-11-05 23:34:24242 friend class base::RefCounted<ClientSocketPoolBaseHelper>;
243
244 ~ClientSocketPoolBaseHelper();
245
[email protected]ff579d42009-06-24 15:47:02246 // Entry for a persistent socket which became idle at time |start_time|.
247 struct IdleSocket {
[email protected]5fc08e32009-07-15 17:09:57248 IdleSocket() : socket(NULL), used(false) {}
[email protected]ff579d42009-06-24 15:47:02249 ClientSocket* socket;
250 base::TimeTicks start_time;
[email protected]5fc08e32009-07-15 17:09:57251 bool used; // Indicates whether or not the socket has been used yet.
[email protected]ff579d42009-06-24 15:47:02252
253 // An idle socket should be removed if it can't be reused, or has been idle
254 // for too long. |now| is the current time value (TimeTicks::Now()).
[email protected]9bf28db2009-08-29 01:35:16255 // |timeout| is the length of time to wait before timing out an idle socket.
[email protected]ff579d42009-06-24 15:47:02256 //
257 // An idle socket can't be reused if it is disconnected or has received
258 // data unexpectedly (hence no longer idle). The unread data would be
259 // mistaken for the beginning of the next response if we were to reuse the
260 // socket for a new request.
[email protected]9bf28db2009-08-29 01:35:16261 bool ShouldCleanup(base::TimeTicks now, base::TimeDelta timeout) const;
[email protected]ff579d42009-06-24 15:47:02262 };
263
[email protected]d80a4322009-08-14 07:07:49264 typedef std::deque<const Request*> RequestQueue;
265 typedef std::map<const ClientSocketHandle*, const Request*> RequestMap;
[email protected]ff579d42009-06-24 15:47:02266
267 // A Group is allocated per group_name when there are idle sockets or pending
268 // requests. Otherwise, the Group object is removed from the map.
[email protected]8ae03f42010-07-07 19:08:10269 // |active_socket_count| tracks the number of sockets held by clients. Of
270 // this number of sockets held by clients, some of them may be released soon,
271 // since ReleaseSocket() was called of them, but the DoReleaseSocket() task
272 // has not run yet for them. |num_releasing_sockets| tracks these values,
273 // which is useful for not starting up new ConnectJobs when sockets may
274 // become available really soon.
[email protected]ff579d42009-06-24 15:47:02275 struct Group {
[email protected]6b624c62010-03-14 08:37:32276 Group()
277 : active_socket_count(0),
[email protected]8ae03f42010-07-07 19:08:10278 num_releasing_sockets(0),
[email protected]6b624c62010-03-14 08:37:32279 backup_job(NULL),
280 backup_task(NULL) {
281 }
282
283 ~Group() {
284 CleanupBackupJob();
285 }
[email protected]2ab05b52009-07-01 23:57:58286
287 bool IsEmpty() const {
[email protected]2b7523d2009-07-29 20:29:23288 return active_socket_count == 0 && idle_sockets.empty() && jobs.empty() &&
[email protected]4d3b05d2010-01-27 21:27:29289 pending_requests.empty();
[email protected]2ab05b52009-07-01 23:57:58290 }
291
292 bool HasAvailableSocketSlot(int max_sockets_per_group) const {
[email protected]5fc08e32009-07-15 17:09:57293 return active_socket_count + static_cast<int>(jobs.size()) <
[email protected]2ab05b52009-07-01 23:57:58294 max_sockets_per_group;
295 }
296
[email protected]8ae03f42010-07-07 19:08:10297 bool HasReleasingSockets() const {
298 return num_releasing_sockets > 0;
299 }
300
[email protected]ac790b42009-12-02 04:31:31301 RequestPriority TopPendingPriority() const {
[email protected]d80a4322009-08-14 07:07:49302 return pending_requests.front()->priority();
[email protected]211d2172009-07-22 15:48:53303 }
304
[email protected]6b624c62010-03-14 08:37:32305 void CleanupBackupJob() {
306 if (backup_job) {
307 delete backup_job;
308 backup_job = NULL;
309 }
310 if (backup_task) {
311 backup_task->Cancel();
312 backup_task = NULL;
313 }
314 }
315
[email protected]ff579d42009-06-24 15:47:02316 std::deque<IdleSocket> idle_sockets;
[email protected]5fc08e32009-07-15 17:09:57317 std::set<const ConnectJob*> jobs;
[email protected]ff579d42009-06-24 15:47:02318 RequestQueue pending_requests;
[email protected]2ab05b52009-07-01 23:57:58319 int active_socket_count; // number of active sockets used by clients
[email protected]8ae03f42010-07-07 19:08:10320 // Number of sockets being released within one loop through the MessageLoop.
321 int num_releasing_sockets;
[email protected]6b624c62010-03-14 08:37:32322 // A backup job in case the connect for this group takes too long.
323 ConnectJob* backup_job;
324 CancelableTask* backup_task;
[email protected]ff579d42009-06-24 15:47:02325 };
326
327 typedef std::map<std::string, Group> GroupMap;
328
[email protected]5fc08e32009-07-15 17:09:57329 typedef std::set<const ConnectJob*> ConnectJobSet;
[email protected]ff579d42009-06-24 15:47:02330
[email protected]d80a4322009-08-14 07:07:49331 static void InsertRequestIntoQueue(const Request* r,
[email protected]ff579d42009-06-24 15:47:02332 RequestQueue* pending_requests);
[email protected]fd7b7c92009-08-20 19:38:30333 static const Request* RemoveRequestFromQueue(RequestQueue::iterator it,
334 RequestQueue* pending_requests);
[email protected]ff579d42009-06-24 15:47:02335
[email protected]ff579d42009-06-24 15:47:02336 // Called when the number of idle sockets changes.
337 void IncrementIdleCount();
338 void DecrementIdleCount();
339
[email protected]8ae03f42010-07-07 19:08:10340 // Called via PostTask by ReleaseSocket.
341 void DoReleaseSocket(
342 const std::string& group_name, ClientSocket* socket, int id);
343
[email protected]211d2172009-07-22 15:48:53344 // Scans the group map for groups which have an available socket slot and
345 // at least one pending request. Returns number of groups found, and if found
346 // at least one, fills |group| and |group_name| with data of the stalled group
347 // having highest priority.
348 int FindTopStalledGroup(Group** group, std::string* group_name);
349
[email protected]ff579d42009-06-24 15:47:02350 // Called when timer_ fires. This method scans the idle sockets removing
351 // sockets that timed out or can't be reused.
352 void OnCleanupTimerFired() {
353 CleanupIdleSockets(false);
354 }
355
[email protected]4d3b05d2010-01-27 21:27:29356 // Removes |job| from |connect_job_set_|. Also updates |group| if non-NULL.
357 void RemoveConnectJob(const ConnectJob* job, Group* group);
[email protected]ff579d42009-06-24 15:47:02358
[email protected]8ae03f42010-07-07 19:08:10359 // Same as OnAvailableSocketSlot except it looks up the Group first to see if
360 // it's there.
361 void MaybeOnAvailableSocketSlot(const std::string& group_name);
[email protected]ff579d42009-06-24 15:47:02362
[email protected]8ae03f42010-07-07 19:08:10363 // Might delete the Group from |group_map_|.
364 void OnAvailableSocketSlot(const std::string& group_name, Group* group);
365
366 // Process a request from a group's pending_requests queue.
367 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]8ae03f42010-07-07 19:08:10387 // TODO(phajdan.jr): Also take idle sockets into account.
[email protected]211d2172009-07-22 15:48:53388 bool ReachedMaxSocketsLimit() const;
389
[email protected]fd4fe0b2010-02-08 23:02:15390 // This is the internal implementation of RequestSocket(). It differs in that
[email protected]9e743cd2010-03-16 07:03:53391 // it does not handle logging into NetLog of the queueing status of
[email protected]fd4fe0b2010-02-08 23:02:15392 // |request|.
393 int RequestSocketInternal(const std::string& group_name,
394 const Request* request);
395
[email protected]06650c52010-06-03 00:49:17396 static void LogBoundConnectJobToRequest(
397 const NetLog::Source& connect_job_source, const Request* request);
398
[email protected]6b624c62010-03-14 08:37:32399 // Set a timer to create a backup socket if it takes too long to create one.
400 void StartBackupSocketTimer(const std::string& group_name);
401
402 // Called when the backup socket timer fires.
403 void OnBackupSocketTimerFired(const std::string& group_name);
404
[email protected]43a21b82010-06-10 21:30:54405 // Closes one idle socket. Picks the first one encountered.
406 // TODO(willchan): Consider a better algorithm for doing this. Perhaps we
407 // should keep an ordered list of idle sockets, and close them in order.
408 // Requires maintaining more state. It's not clear if it's worth it since
409 // I'm not sure if we hit this situation often.
410 void CloseOneIdleSocket();
411
[email protected]ff579d42009-06-24 15:47:02412 GroupMap group_map_;
413
[email protected]ff579d42009-06-24 15:47:02414 // Timer used to periodically prune idle sockets that timed out or can't be
415 // reused.
[email protected]d80a4322009-08-14 07:07:49416 base::RepeatingTimer<ClientSocketPoolBaseHelper> timer_;
[email protected]ff579d42009-06-24 15:47:02417
418 // The total number of idle sockets in the system.
419 int idle_socket_count_;
420
[email protected]211d2172009-07-22 15:48:53421 // Number of connecting sockets across all groups.
422 int connecting_socket_count_;
423
424 // Number of connected sockets we handed out across all groups.
425 int handed_out_socket_count_;
426
[email protected]8ae03f42010-07-07 19:08:10427 // Number of sockets being released.
428 int num_releasing_sockets_;
429
[email protected]211d2172009-07-22 15:48:53430 // The maximum total number of sockets. See ReachedMaxSocketsLimit.
431 const int max_sockets_;
432
[email protected]ff579d42009-06-24 15:47:02433 // The maximum number of sockets kept per group.
434 const int max_sockets_per_group_;
435
[email protected]9bf28db2009-08-29 01:35:16436 // The time to wait until closing idle sockets.
437 const base::TimeDelta unused_idle_socket_timeout_;
438 const base::TimeDelta used_idle_socket_timeout_;
439
[email protected]8ae03f42010-07-07 19:08:10440 // Until the maximum number of sockets limit is reached, a group can only
441 // have pending requests if it exceeds the "max sockets per group" limit.
442 //
443 // This means when a socket is released, the only pending requests that can
444 // be started next belong to the same group.
445 //
446 // However once the |max_sockets_| limit is reached, this stops being true:
447 // groups can now have pending requests without having first reached the
448 // |max_sockets_per_group_| limit. So choosing the next request involves
449 // selecting the highest priority request across *all* groups.
450 //
451 // |may_have_stalled_group_| is not conclusive, since when we cancel pending
452 // requests, we may reach the situation where we have the maximum number of
453 // sockets, but no request is stalled because of the global socket limit
454 // (although some requests may be blocked on the socket per group limit).
455 // We don't strictly maintain |may_have_stalled_group_|, since that would
456 // require a linear search through all groups in |group_map_| to see if one
457 // of them is stalled.
458 bool may_have_stalled_group_;
459
[email protected]ab838892009-06-30 18:49:05460 const scoped_ptr<ConnectJobFactory> connect_job_factory_;
[email protected]ff579d42009-06-24 15:47:02461
[email protected]7c28e9a2010-03-20 01:16:13462 // TODO(vandebo) Remove when backup jobs move to TCPClientSocketPool
463 bool backup_jobs_enabled_;
464
[email protected]6b624c62010-03-14 08:37:32465 // A factory to pin the backup_job tasks.
466 ScopedRunnableMethodFactory<ClientSocketPoolBaseHelper> method_factory_;
[email protected]a7e38572010-06-07 18:22:24467
468 // A unique id for the pool. It gets incremented every time we Flush() the
469 // pool. This is so that when sockets get released back to the pool, we can
470 // make sure that they are discarded rather than reused.
471 int pool_generation_number_;
[email protected]d80a4322009-08-14 07:07:49472};
473
474} // namespace internal
475
[email protected]9bf28db2009-08-29 01:35:16476// The maximum duration, in seconds, to keep used idle persistent sockets alive.
477static const int kUsedIdleSocketTimeout = 300; // 5 minutes
478
[email protected]d80a4322009-08-14 07:07:49479template <typename SocketParams>
480class ClientSocketPoolBase {
481 public:
482 class Request : public internal::ClientSocketPoolBaseHelper::Request {
483 public:
484 Request(ClientSocketHandle* handle,
485 CompletionCallback* callback,
[email protected]ac790b42009-12-02 04:31:31486 RequestPriority priority,
[email protected]d80a4322009-08-14 07:07:49487 const SocketParams& params,
[email protected]9e743cd2010-03-16 07:03:53488 const BoundNetLog& net_log)
[email protected]d80a4322009-08-14 07:07:49489 : internal::ClientSocketPoolBaseHelper::Request(
[email protected]9e743cd2010-03-16 07:03:53490 handle, callback, priority, net_log),
[email protected]d80a4322009-08-14 07:07:49491 params_(params) {}
492
493 const SocketParams& params() const { return params_; }
494
495 private:
496 SocketParams params_;
497 };
498
499 class ConnectJobFactory {
500 public:
501 ConnectJobFactory() {}
502 virtual ~ConnectJobFactory() {}
503
504 virtual ConnectJob* NewConnectJob(
505 const std::string& group_name,
506 const Request& request,
[email protected]06650c52010-06-03 00:49:17507 ConnectJob::Delegate* delegate) const = 0;
[email protected]d80a4322009-08-14 07:07:49508
[email protected]a796bcec2010-03-22 17:17:26509 virtual base::TimeDelta ConnectionTimeout() const = 0;
510
[email protected]d80a4322009-08-14 07:07:49511 private:
512 DISALLOW_COPY_AND_ASSIGN(ConnectJobFactory);
513 };
514
[email protected]9bf28db2009-08-29 01:35:16515 // |max_sockets| is the maximum number of sockets to be maintained by this
516 // ClientSocketPool. |max_sockets_per_group| specifies the maximum number of
517 // sockets a "group" can have. |unused_idle_socket_timeout| specifies how
518 // long to leave an unused idle socket open before closing it.
519 // |used_idle_socket_timeout| specifies how long to leave a previously used
520 // idle socket open before closing it.
[email protected]100d5fb92009-12-21 21:08:35521 ClientSocketPoolBase(
522 int max_sockets,
523 int max_sockets_per_group,
[email protected]b89f7e42010-05-20 20:37:00524 const scoped_refptr<ClientSocketPoolHistograms>& histograms,
[email protected]100d5fb92009-12-21 21:08:35525 base::TimeDelta unused_idle_socket_timeout,
526 base::TimeDelta used_idle_socket_timeout,
[email protected]66761b952010-06-25 21:30:38527 ConnectJobFactory* connect_job_factory)
[email protected]b89f7e42010-05-20 20:37:00528 : histograms_(histograms),
[email protected]a796bcec2010-03-22 17:17:26529 helper_(new internal::ClientSocketPoolBaseHelper(
[email protected]d80a4322009-08-14 07:07:49530 max_sockets, max_sockets_per_group,
[email protected]9bf28db2009-08-29 01:35:16531 unused_idle_socket_timeout, used_idle_socket_timeout,
[email protected]66761b952010-06-25 21:30:38532 new ConnectJobFactoryAdaptor(connect_job_factory))) {}
[email protected]d80a4322009-08-14 07:07:49533
[email protected]20cb5f482009-12-16 01:01:25534 virtual ~ClientSocketPoolBase() {}
[email protected]d80a4322009-08-14 07:07:49535
536 // These member functions simply forward to ClientSocketPoolBaseHelper.
537
538 // RequestSocket bundles up the parameters into a Request and then forwards to
539 // ClientSocketPoolBaseHelper::RequestSocket(). Note that the memory
540 // ownership is transferred in the asynchronous (ERR_IO_PENDING) case.
541 int RequestSocket(const std::string& group_name,
542 const SocketParams& params,
[email protected]ac790b42009-12-02 04:31:31543 RequestPriority priority,
[email protected]d80a4322009-08-14 07:07:49544 ClientSocketHandle* handle,
545 CompletionCallback* callback,
[email protected]9e743cd2010-03-16 07:03:53546 const BoundNetLog& net_log) {
[email protected]e7e99322010-05-04 23:30:17547 Request* request = new Request(handle, callback, priority, params, net_log);
548 return helper_->RequestSocket(group_name, request);
[email protected]d80a4322009-08-14 07:07:49549 }
550
551 void CancelRequest(const std::string& group_name,
552 const ClientSocketHandle* handle) {
553 return helper_->CancelRequest(group_name, handle);
554 }
555
[email protected]241c5c2c2010-06-21 18:46:00556 void ReleaseSocket(const std::string& group_name, ClientSocket* socket,
557 int id) {
[email protected]a7e38572010-06-07 18:22:24558 return helper_->ReleaseSocket(group_name, socket, id);
[email protected]d80a4322009-08-14 07:07:49559 }
560
561 void CloseIdleSockets() { return helper_->CloseIdleSockets(); }
562
563 int idle_socket_count() const { return helper_->idle_socket_count(); }
564
565 int IdleSocketCountInGroup(const std::string& group_name) const {
566 return helper_->IdleSocketCountInGroup(group_name);
567 }
568
569 LoadState GetLoadState(const std::string& group_name,
570 const ClientSocketHandle* handle) const {
571 return helper_->GetLoadState(group_name, handle);
572 }
573
574 virtual void OnConnectJobComplete(int result, ConnectJob* job) {
575 return helper_->OnConnectJobComplete(result, job);
576 }
577
[email protected]8ae03f42010-07-07 19:08:10578 // For testing.
579 bool may_have_stalled_group() const {
580 return helper_->may_have_stalled_group();
581 }
582
[email protected]d80a4322009-08-14 07:07:49583 int NumConnectJobsInGroup(const std::string& group_name) const {
584 return helper_->NumConnectJobsInGroup(group_name);
585 }
586
[email protected]9bf28db2009-08-29 01:35:16587 void CleanupIdleSockets(bool force) {
588 return helper_->CleanupIdleSockets(force);
589 }
590
[email protected]a796bcec2010-03-22 17:17:26591 base::TimeDelta ConnectionTimeout() const {
592 return helper_->ConnectionTimeout();
593 }
594
[email protected]b89f7e42010-05-20 20:37:00595 scoped_refptr<ClientSocketPoolHistograms> histograms() const {
596 return histograms_;
597 }
[email protected]a796bcec2010-03-22 17:17:26598
[email protected]43a21b82010-06-10 21:30:54599 void EnableBackupJobs() { helper_->EnableBackupJobs(); }
[email protected]7c28e9a2010-03-20 01:16:13600
[email protected]a7e38572010-06-07 18:22:24601 void Flush() { helper_->Flush(); }
602
[email protected]d80a4322009-08-14 07:07:49603 private:
604 // This adaptor class exists to bridge the
605 // internal::ClientSocketPoolBaseHelper::ConnectJobFactory and
606 // ClientSocketPoolBase::ConnectJobFactory types, allowing clients to use the
607 // typesafe ClientSocketPoolBase::ConnectJobFactory, rather than having to
608 // static_cast themselves.
609 class ConnectJobFactoryAdaptor
610 : public internal::ClientSocketPoolBaseHelper::ConnectJobFactory {
611 public:
612 typedef typename ClientSocketPoolBase<SocketParams>::ConnectJobFactory
613 ConnectJobFactory;
614
615 explicit ConnectJobFactoryAdaptor(
616 ConnectJobFactory* connect_job_factory)
617 : connect_job_factory_(connect_job_factory) {}
618 virtual ~ConnectJobFactoryAdaptor() {}
619
620 virtual ConnectJob* NewConnectJob(
621 const std::string& group_name,
622 const internal::ClientSocketPoolBaseHelper::Request& request,
[email protected]06650c52010-06-03 00:49:17623 ConnectJob::Delegate* delegate) const {
[email protected]d80a4322009-08-14 07:07:49624 const Request* casted_request = static_cast<const Request*>(&request);
625 return connect_job_factory_->NewConnectJob(
[email protected]06650c52010-06-03 00:49:17626 group_name, *casted_request, delegate);
[email protected]d80a4322009-08-14 07:07:49627 }
628
[email protected]a796bcec2010-03-22 17:17:26629 virtual base::TimeDelta ConnectionTimeout() const {
630 return connect_job_factory_->ConnectionTimeout();
631 }
632
[email protected]d80a4322009-08-14 07:07:49633 const scoped_ptr<ConnectJobFactory> connect_job_factory_;
634 };
635
[email protected]b89f7e42010-05-20 20:37:00636 // Histograms for the pool
637 const scoped_refptr<ClientSocketPoolHistograms> histograms_;
[email protected]a796bcec2010-03-22 17:17:26638
[email protected]8ae03f42010-07-07 19:08:10639 // One might ask why ClientSocketPoolBaseHelper is also refcounted if its
640 // containing ClientSocketPool is already refcounted. The reason is because
641 // DoReleaseSocket() posts a task. If ClientSocketPool gets deleted between
642 // the posting of the task and the execution, then we'll hit the DCHECK that
643 // |ClientSocketPoolBaseHelper::group_map_| is empty.
[email protected]d80a4322009-08-14 07:07:49644 scoped_refptr<internal::ClientSocketPoolBaseHelper> helper_;
645
[email protected]ff579d42009-06-24 15:47:02646 DISALLOW_COPY_AND_ASSIGN(ClientSocketPoolBase);
647};
648
[email protected]ff579d42009-06-24 15:47:02649} // namespace net
650
651#endif // NET_SOCKET_CLIENT_SOCKET_POOL_BASE_H_