blob: db408a20c87830c76d662aedb94e51409c73d057 [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]2ab05b52009-07-01 23:57:5894 void set_socket(ClientSocket* socket) { socket_.reset(socket); }
95 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
102 // Alerts the delegate that the ConnectJob has timed out.
103 void OnTimeout();
104
[email protected]2ab05b52009-07-01 23:57:58105 const std::string group_name_;
[email protected]974ebd62009-08-03 23:14:34106 const base::TimeDelta timeout_duration_;
107 // Timer to abort jobs that take too long.
108 base::OneShotTimer<ConnectJob> timer_;
109 Delegate* delegate_;
[email protected]2ab05b52009-07-01 23:57:58110 scoped_ptr<ClientSocket> socket_;
[email protected]9e743cd2010-03-16 07:03:53111 BoundNetLog net_log_;
[email protected]a2006ece2010-04-23 16:44:02112 // A ConnectJob is idle until Connect() has been called.
113 bool idle_;
[email protected]ab838892009-06-30 18:49:05114
[email protected]ff579d42009-06-24 15:47:02115 DISALLOW_COPY_AND_ASSIGN(ConnectJob);
116};
117
[email protected]d80a4322009-08-14 07:07:49118namespace internal {
119
120// ClientSocketPoolBaseHelper is an internal class that implements almost all
121// the functionality from ClientSocketPoolBase without using templates.
122// ClientSocketPoolBase adds templated definitions built on top of
123// ClientSocketPoolBaseHelper. This class is not for external use, please use
124// ClientSocketPoolBase instead.
125class ClientSocketPoolBaseHelper
126 : public base::RefCounted<ClientSocketPoolBaseHelper>,
[email protected]a554a8262010-05-20 00:13:52127 public ConnectJob::Delegate,
128 public NetworkChangeNotifier::Observer {
[email protected]ff579d42009-06-24 15:47:02129 public:
[email protected]d80a4322009-08-14 07:07:49130 class Request {
131 public:
[email protected]684970b2009-08-14 04:54:46132 Request(ClientSocketHandle* handle,
[email protected]ff579d42009-06-24 15:47:02133 CompletionCallback* callback,
[email protected]ac790b42009-12-02 04:31:31134 RequestPriority priority,
[email protected]9e743cd2010-03-16 07:03:53135 const BoundNetLog& net_log);
[email protected]ff579d42009-06-24 15:47:02136
[email protected]fd4fe0b2010-02-08 23:02:15137 virtual ~Request();
[email protected]d80a4322009-08-14 07:07:49138
139 ClientSocketHandle* handle() const { return handle_; }
140 CompletionCallback* callback() const { return callback_; }
[email protected]ac790b42009-12-02 04:31:31141 RequestPriority priority() const { return priority_; }
[email protected]9e743cd2010-03-16 07:03:53142 const BoundNetLog& net_log() const { return net_log_; }
[email protected]d80a4322009-08-14 07:07:49143
144 private:
145 ClientSocketHandle* const handle_;
146 CompletionCallback* const callback_;
[email protected]ac790b42009-12-02 04:31:31147 const RequestPriority priority_;
[email protected]9e743cd2010-03-16 07:03:53148 BoundNetLog net_log_;
[email protected]d80a4322009-08-14 07:07:49149
150 DISALLOW_COPY_AND_ASSIGN(Request);
[email protected]ff579d42009-06-24 15:47:02151 };
152
153 class ConnectJobFactory {
154 public:
155 ConnectJobFactory() {}
156 virtual ~ConnectJobFactory() {}
157
158 virtual ConnectJob* NewConnectJob(
159 const std::string& group_name,
160 const Request& request,
[email protected]fd7b7c92009-08-20 19:38:30161 ConnectJob::Delegate* delegate,
[email protected]9e743cd2010-03-16 07:03:53162 const BoundNetLog& net_log) const = 0;
[email protected]ff579d42009-06-24 15:47:02163
[email protected]a796bcec2010-03-22 17:17:26164 virtual base::TimeDelta ConnectionTimeout() const = 0;
165
[email protected]ff579d42009-06-24 15:47:02166 private:
167 DISALLOW_COPY_AND_ASSIGN(ConnectJobFactory);
168 };
169
[email protected]100d5fb92009-12-21 21:08:35170 ClientSocketPoolBaseHelper(
171 int max_sockets,
172 int max_sockets_per_group,
173 base::TimeDelta unused_idle_socket_timeout,
174 base::TimeDelta used_idle_socket_timeout,
[email protected]a554a8262010-05-20 00:13:52175 ConnectJobFactory* connect_job_factory,
176 NetworkChangeNotifier* network_change_notifier);
[email protected]ff579d42009-06-24 15:47:02177
[email protected]d80a4322009-08-14 07:07:49178 // See ClientSocketPool::RequestSocket for documentation on this function.
[email protected]e7e99322010-05-04 23:30:17179 // ClientSocketPoolBaseHelper takes ownership of |request|, which must be
180 // heap allocated.
[email protected]d80a4322009-08-14 07:07:49181 int RequestSocket(const std::string& group_name, const Request* request);
[email protected]ff579d42009-06-24 15:47:02182
[email protected]d80a4322009-08-14 07:07:49183 // See ClientSocketPool::CancelRequest for documentation on this function.
[email protected]ff579d42009-06-24 15:47:02184 void CancelRequest(const std::string& group_name,
185 const ClientSocketHandle* handle);
186
[email protected]d80a4322009-08-14 07:07:49187 // See ClientSocketPool::ReleaseSocket for documentation on this function.
[email protected]ff579d42009-06-24 15:47:02188 void ReleaseSocket(const std::string& group_name,
189 ClientSocket* socket);
190
[email protected]d80a4322009-08-14 07:07:49191 // See ClientSocketPool::CloseIdleSockets for documentation on this function.
[email protected]ff579d42009-06-24 15:47:02192 void CloseIdleSockets();
193
[email protected]d80a4322009-08-14 07:07:49194 // See ClientSocketPool::IdleSocketCount() for documentation on this function.
[email protected]ff579d42009-06-24 15:47:02195 int idle_socket_count() const {
196 return idle_socket_count_;
197 }
198
[email protected]d80a4322009-08-14 07:07:49199 // See ClientSocketPool::IdleSocketCountInGroup() for documentation on this
200 // function.
[email protected]ff579d42009-06-24 15:47:02201 int IdleSocketCountInGroup(const std::string& group_name) const;
202
[email protected]d80a4322009-08-14 07:07:49203 // See ClientSocketPool::GetLoadState() for documentation on this function.
[email protected]ff579d42009-06-24 15:47:02204 LoadState GetLoadState(const std::string& group_name,
205 const ClientSocketHandle* handle) const;
206
[email protected]6b624c62010-03-14 08:37:32207 int ConnectRetryIntervalMs() const {
208 // TODO(mbelshe): Make this tuned dynamically based on measured RTT.
209 // For now, just use the max retry interval.
210 return ClientSocketPool::kMaxConnectRetryIntervalMs;
211 }
212
[email protected]d80a4322009-08-14 07:07:49213 // ConnectJob::Delegate methods:
[email protected]2ab05b52009-07-01 23:57:58214 virtual void OnConnectJobComplete(int result, ConnectJob* job);
[email protected]ff579d42009-06-24 15:47:02215
[email protected]a554a8262010-05-20 00:13:52216 // NetworkChangeNotifier::Observer methods:
217 virtual void OnIPAddressChanged();
218
[email protected]211d2172009-07-22 15:48:53219 // For testing.
220 bool may_have_stalled_group() const { return may_have_stalled_group_; }
[email protected]d80a4322009-08-14 07:07:49221
[email protected]974ebd62009-08-03 23:14:34222 int NumConnectJobsInGroup(const std::string& group_name) const {
223 return group_map_.find(group_name)->second.jobs.size();
224 }
[email protected]211d2172009-07-22 15:48:53225
[email protected]9bf28db2009-08-29 01:35:16226 // Closes all idle sockets if |force| is true. Else, only closes idle
227 // sockets that timed out or can't be reused. Made public for testing.
228 void CleanupIdleSockets(bool force);
229
[email protected]a796bcec2010-03-22 17:17:26230 base::TimeDelta ConnectionTimeout() const {
231 return connect_job_factory_->ConnectionTimeout();
232 }
233
[email protected]4751c742010-05-19 02:44:36234 void enable_backup_jobs() { backup_jobs_enabled_ = true; };
[email protected]7c28e9a2010-03-20 01:16:13235
[email protected]ff579d42009-06-24 15:47:02236 private:
[email protected]5389bc72009-11-05 23:34:24237 friend class base::RefCounted<ClientSocketPoolBaseHelper>;
238
239 ~ClientSocketPoolBaseHelper();
240
[email protected]ff579d42009-06-24 15:47:02241 // Entry for a persistent socket which became idle at time |start_time|.
242 struct IdleSocket {
[email protected]5fc08e32009-07-15 17:09:57243 IdleSocket() : socket(NULL), used(false) {}
[email protected]ff579d42009-06-24 15:47:02244 ClientSocket* socket;
245 base::TimeTicks start_time;
[email protected]5fc08e32009-07-15 17:09:57246 bool used; // Indicates whether or not the socket has been used yet.
[email protected]ff579d42009-06-24 15:47:02247
248 // An idle socket should be removed if it can't be reused, or has been idle
249 // for too long. |now| is the current time value (TimeTicks::Now()).
[email protected]9bf28db2009-08-29 01:35:16250 // |timeout| is the length of time to wait before timing out an idle socket.
[email protected]ff579d42009-06-24 15:47:02251 //
252 // An idle socket can't be reused if it is disconnected or has received
253 // data unexpectedly (hence no longer idle). The unread data would be
254 // mistaken for the beginning of the next response if we were to reuse the
255 // socket for a new request.
[email protected]9bf28db2009-08-29 01:35:16256 bool ShouldCleanup(base::TimeTicks now, base::TimeDelta timeout) const;
[email protected]ff579d42009-06-24 15:47:02257 };
258
[email protected]d80a4322009-08-14 07:07:49259 typedef std::deque<const Request*> RequestQueue;
260 typedef std::map<const ClientSocketHandle*, const Request*> RequestMap;
[email protected]ff579d42009-06-24 15:47:02261
262 // A Group is allocated per group_name when there are idle sockets or pending
263 // requests. Otherwise, the Group object is removed from the map.
[email protected]5edbf8d2010-01-13 18:44:11264 // |active_socket_count| tracks the number of sockets held by clients. Of
265 // this number of sockets held by clients, some of them may be released soon,
266 // since ReleaseSocket() was called of them, but the DoReleaseSocket() task
267 // has not run yet for them. |num_releasing_sockets| tracks these values,
[email protected]6b624c62010-03-14 08:37:32268 // which is useful for not starting up new ConnectJobs when sockets may
269 // become available really soon.
[email protected]ff579d42009-06-24 15:47:02270 struct Group {
[email protected]6b624c62010-03-14 08:37:32271 Group()
272 : active_socket_count(0),
273 num_releasing_sockets(0),
274 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]5edbf8d2010-01-13 18:44:11292 bool HasReleasingSockets() const {
293 return num_releasing_sockets > 0;
294 }
295
[email protected]ac790b42009-12-02 04:31:31296 RequestPriority TopPendingPriority() const {
[email protected]d80a4322009-08-14 07:07:49297 return pending_requests.front()->priority();
[email protected]211d2172009-07-22 15:48:53298 }
299
[email protected]6b624c62010-03-14 08:37:32300 void CleanupBackupJob() {
301 if (backup_job) {
302 delete backup_job;
303 backup_job = NULL;
304 }
305 if (backup_task) {
306 backup_task->Cancel();
307 backup_task = NULL;
308 }
309 }
310
[email protected]ff579d42009-06-24 15:47:02311 std::deque<IdleSocket> idle_sockets;
[email protected]5fc08e32009-07-15 17:09:57312 std::set<const ConnectJob*> jobs;
[email protected]ff579d42009-06-24 15:47:02313 RequestQueue pending_requests;
[email protected]2ab05b52009-07-01 23:57:58314 int active_socket_count; // number of active sockets used by clients
[email protected]5edbf8d2010-01-13 18:44:11315 // Number of sockets being released within one loop through the MessageLoop.
316 int num_releasing_sockets;
[email protected]6b624c62010-03-14 08:37:32317 // A backup job in case the connect for this group takes too long.
318 ConnectJob* backup_job;
319 CancelableTask* backup_task;
[email protected]ff579d42009-06-24 15:47:02320 };
321
322 typedef std::map<std::string, Group> GroupMap;
323
[email protected]5fc08e32009-07-15 17:09:57324 typedef std::set<const ConnectJob*> ConnectJobSet;
[email protected]ff579d42009-06-24 15:47:02325
[email protected]d80a4322009-08-14 07:07:49326 static void InsertRequestIntoQueue(const Request* r,
[email protected]ff579d42009-06-24 15:47:02327 RequestQueue* pending_requests);
[email protected]fd7b7c92009-08-20 19:38:30328 static const Request* RemoveRequestFromQueue(RequestQueue::iterator it,
329 RequestQueue* pending_requests);
[email protected]ff579d42009-06-24 15:47:02330
[email protected]ff579d42009-06-24 15:47:02331 // Called when the number of idle sockets changes.
332 void IncrementIdleCount();
333 void DecrementIdleCount();
334
335 // Called via PostTask by ReleaseSocket.
336 void DoReleaseSocket(const std::string& group_name, ClientSocket* socket);
337
[email protected]211d2172009-07-22 15:48:53338 // Scans the group map for groups which have an available socket slot and
339 // at least one pending request. Returns number of groups found, and if found
340 // at least one, fills |group| and |group_name| with data of the stalled group
341 // having highest priority.
342 int FindTopStalledGroup(Group** group, std::string* group_name);
343
[email protected]ff579d42009-06-24 15:47:02344 // Called when timer_ fires. This method scans the idle sockets removing
345 // sockets that timed out or can't be reused.
346 void OnCleanupTimerFired() {
347 CleanupIdleSockets(false);
348 }
349
[email protected]4d3b05d2010-01-27 21:27:29350 // Removes |job| from |connect_job_set_|. Also updates |group| if non-NULL.
351 void RemoveConnectJob(const ConnectJob* job, Group* group);
[email protected]ff579d42009-06-24 15:47:02352
[email protected]2ab05b52009-07-01 23:57:58353 // Same as OnAvailableSocketSlot except it looks up the Group first to see if
354 // it's there.
355 void MaybeOnAvailableSocketSlot(const std::string& group_name);
[email protected]ff579d42009-06-24 15:47:02356
[email protected]2ab05b52009-07-01 23:57:58357 // Might delete the Group from |group_map_|.
358 void OnAvailableSocketSlot(const std::string& group_name, Group* group);
[email protected]ff579d42009-06-24 15:47:02359
360 // Process a request from a group's pending_requests queue.
361 void ProcessPendingRequest(const std::string& group_name, Group* group);
362
[email protected]2ab05b52009-07-01 23:57:58363 // Assigns |socket| to |handle| and updates |group|'s counters appropriately.
364 void HandOutSocket(ClientSocket* socket,
365 bool reused,
366 ClientSocketHandle* handle,
[email protected]f9d285c2009-08-17 19:54:29367 base::TimeDelta time_idle,
[email protected]fd4fe0b2010-02-08 23:02:15368 Group* group,
[email protected]9e743cd2010-03-16 07:03:53369 const BoundNetLog& net_log);
[email protected]2ab05b52009-07-01 23:57:58370
[email protected]5fc08e32009-07-15 17:09:57371 // Adds |socket| to the list of idle sockets for |group|. |used| indicates
372 // whether or not the socket has previously been used.
373 void AddIdleSocket(ClientSocket* socket, bool used, Group* group);
374
375 // Iterates through |connect_job_map_|, canceling all ConnectJobs.
376 // Afterwards, it iterates through all groups and deletes them if they are no
377 // longer needed.
378 void CancelAllConnectJobs();
379
[email protected]211d2172009-07-22 15:48:53380 // Returns true if we can't create any more sockets due to the total limit.
381 // TODO(phajdan.jr): Also take idle sockets into account.
382 bool ReachedMaxSocketsLimit() const;
383
[email protected]fd4fe0b2010-02-08 23:02:15384 // This is the internal implementation of RequestSocket(). It differs in that
[email protected]9e743cd2010-03-16 07:03:53385 // it does not handle logging into NetLog of the queueing status of
[email protected]fd4fe0b2010-02-08 23:02:15386 // |request|.
387 int RequestSocketInternal(const std::string& group_name,
388 const Request* request);
389
[email protected]6b624c62010-03-14 08:37:32390 // Set a timer to create a backup socket if it takes too long to create one.
391 void StartBackupSocketTimer(const std::string& group_name);
392
393 // Called when the backup socket timer fires.
394 void OnBackupSocketTimerFired(const std::string& group_name);
395
[email protected]ff579d42009-06-24 15:47:02396 GroupMap group_map_;
397
[email protected]ff579d42009-06-24 15:47:02398 // Timer used to periodically prune idle sockets that timed out or can't be
399 // reused.
[email protected]d80a4322009-08-14 07:07:49400 base::RepeatingTimer<ClientSocketPoolBaseHelper> timer_;
[email protected]ff579d42009-06-24 15:47:02401
402 // The total number of idle sockets in the system.
403 int idle_socket_count_;
404
[email protected]211d2172009-07-22 15:48:53405 // Number of connecting sockets across all groups.
406 int connecting_socket_count_;
407
408 // Number of connected sockets we handed out across all groups.
409 int handed_out_socket_count_;
410
[email protected]d7027bb2010-05-10 18:58:54411 // Number of sockets being released.
412 int num_releasing_sockets_;
413
[email protected]211d2172009-07-22 15:48:53414 // The maximum total number of sockets. See ReachedMaxSocketsLimit.
415 const int max_sockets_;
416
[email protected]ff579d42009-06-24 15:47:02417 // The maximum number of sockets kept per group.
418 const int max_sockets_per_group_;
419
[email protected]9bf28db2009-08-29 01:35:16420 // The time to wait until closing idle sockets.
421 const base::TimeDelta unused_idle_socket_timeout_;
422 const base::TimeDelta used_idle_socket_timeout_;
423
[email protected]211d2172009-07-22 15:48:53424 // Until the maximum number of sockets limit is reached, a group can only
425 // have pending requests if it exceeds the "max sockets per group" limit.
426 //
427 // This means when a socket is released, the only pending requests that can
428 // be started next belong to the same group.
429 //
430 // However once the |max_sockets_| limit is reached, this stops being true:
431 // groups can now have pending requests without having first reached the
432 // |max_sockets_per_group_| limit. So choosing the next request involves
433 // selecting the highest priority request across *all* groups.
434 //
[email protected]4751c742010-05-19 02:44:36435 // Since reaching the maximum number of sockets is an edge case, we make note
436 // of when it happens, and thus avoid doing the slower "scan all groups"
437 // in the common case.
[email protected]211d2172009-07-22 15:48:53438 bool may_have_stalled_group_;
439
[email protected]ab838892009-06-30 18:49:05440 const scoped_ptr<ConnectJobFactory> connect_job_factory_;
[email protected]ff579d42009-06-24 15:47:02441
[email protected]a554a8262010-05-20 00:13:52442 NetworkChangeNotifier* const network_change_notifier_;
443
[email protected]7c28e9a2010-03-20 01:16:13444 // TODO(vandebo) Remove when backup jobs move to TCPClientSocketPool
445 bool backup_jobs_enabled_;
446
[email protected]6b624c62010-03-14 08:37:32447 // A factory to pin the backup_job tasks.
448 ScopedRunnableMethodFactory<ClientSocketPoolBaseHelper> method_factory_;
[email protected]d80a4322009-08-14 07:07:49449};
450
451} // namespace internal
452
[email protected]9bf28db2009-08-29 01:35:16453// The maximum duration, in seconds, to keep unused idle persistent sockets
454// alive.
455// TODO(willchan): Change this timeout after getting histogram data on how
456// long it should be.
457static const int kUnusedIdleSocketTimeout = 10;
458// The maximum duration, in seconds, to keep used idle persistent sockets alive.
459static const int kUsedIdleSocketTimeout = 300; // 5 minutes
460
[email protected]d80a4322009-08-14 07:07:49461template <typename SocketParams>
462class ClientSocketPoolBase {
463 public:
464 class Request : public internal::ClientSocketPoolBaseHelper::Request {
465 public:
466 Request(ClientSocketHandle* handle,
467 CompletionCallback* callback,
[email protected]ac790b42009-12-02 04:31:31468 RequestPriority priority,
[email protected]d80a4322009-08-14 07:07:49469 const SocketParams& params,
[email protected]9e743cd2010-03-16 07:03:53470 const BoundNetLog& net_log)
[email protected]d80a4322009-08-14 07:07:49471 : internal::ClientSocketPoolBaseHelper::Request(
[email protected]9e743cd2010-03-16 07:03:53472 handle, callback, priority, net_log),
[email protected]d80a4322009-08-14 07:07:49473 params_(params) {}
474
475 const SocketParams& params() const { return params_; }
476
477 private:
478 SocketParams params_;
479 };
480
481 class ConnectJobFactory {
482 public:
483 ConnectJobFactory() {}
484 virtual ~ConnectJobFactory() {}
485
486 virtual ConnectJob* NewConnectJob(
487 const std::string& group_name,
488 const Request& request,
[email protected]fd7b7c92009-08-20 19:38:30489 ConnectJob::Delegate* delegate,
[email protected]9e743cd2010-03-16 07:03:53490 const BoundNetLog& net_log) const = 0;
[email protected]d80a4322009-08-14 07:07:49491
[email protected]a796bcec2010-03-22 17:17:26492 virtual base::TimeDelta ConnectionTimeout() const = 0;
493
[email protected]d80a4322009-08-14 07:07:49494 private:
495 DISALLOW_COPY_AND_ASSIGN(ConnectJobFactory);
496 };
497
[email protected]9bf28db2009-08-29 01:35:16498 // |max_sockets| is the maximum number of sockets to be maintained by this
499 // ClientSocketPool. |max_sockets_per_group| specifies the maximum number of
500 // sockets a "group" can have. |unused_idle_socket_timeout| specifies how
501 // long to leave an unused idle socket open before closing it.
502 // |used_idle_socket_timeout| specifies how long to leave a previously used
503 // idle socket open before closing it.
[email protected]100d5fb92009-12-21 21:08:35504 ClientSocketPoolBase(
505 int max_sockets,
506 int max_sockets_per_group,
[email protected]b89f7e42010-05-20 20:37:00507 const scoped_refptr<ClientSocketPoolHistograms>& histograms,
[email protected]100d5fb92009-12-21 21:08:35508 base::TimeDelta unused_idle_socket_timeout,
509 base::TimeDelta used_idle_socket_timeout,
[email protected]a554a8262010-05-20 00:13:52510 ConnectJobFactory* connect_job_factory,
511 NetworkChangeNotifier* network_change_notifier)
[email protected]b89f7e42010-05-20 20:37:00512 : histograms_(histograms),
[email protected]a796bcec2010-03-22 17:17:26513 helper_(new internal::ClientSocketPoolBaseHelper(
[email protected]d80a4322009-08-14 07:07:49514 max_sockets, max_sockets_per_group,
[email protected]9bf28db2009-08-29 01:35:16515 unused_idle_socket_timeout, used_idle_socket_timeout,
[email protected]a554a8262010-05-20 00:13:52516 new ConnectJobFactoryAdaptor(connect_job_factory),
517 network_change_notifier)) {}
[email protected]d80a4322009-08-14 07:07:49518
[email protected]20cb5f482009-12-16 01:01:25519 virtual ~ClientSocketPoolBase() {}
[email protected]d80a4322009-08-14 07:07:49520
521 // These member functions simply forward to ClientSocketPoolBaseHelper.
522
523 // RequestSocket bundles up the parameters into a Request and then forwards to
524 // ClientSocketPoolBaseHelper::RequestSocket(). Note that the memory
525 // ownership is transferred in the asynchronous (ERR_IO_PENDING) case.
526 int RequestSocket(const std::string& group_name,
527 const SocketParams& params,
[email protected]ac790b42009-12-02 04:31:31528 RequestPriority priority,
[email protected]d80a4322009-08-14 07:07:49529 ClientSocketHandle* handle,
530 CompletionCallback* callback,
[email protected]9e743cd2010-03-16 07:03:53531 const BoundNetLog& net_log) {
[email protected]e7e99322010-05-04 23:30:17532 Request* request = new Request(handle, callback, priority, params, net_log);
533 return helper_->RequestSocket(group_name, request);
[email protected]d80a4322009-08-14 07:07:49534 }
535
536 void CancelRequest(const std::string& group_name,
537 const ClientSocketHandle* handle) {
538 return helper_->CancelRequest(group_name, handle);
539 }
540
541 void ReleaseSocket(const std::string& group_name, ClientSocket* socket) {
542 return helper_->ReleaseSocket(group_name, socket);
543 }
544
545 void CloseIdleSockets() { return helper_->CloseIdleSockets(); }
546
547 int idle_socket_count() const { return helper_->idle_socket_count(); }
548
549 int IdleSocketCountInGroup(const std::string& group_name) const {
550 return helper_->IdleSocketCountInGroup(group_name);
551 }
552
553 LoadState GetLoadState(const std::string& group_name,
554 const ClientSocketHandle* handle) const {
555 return helper_->GetLoadState(group_name, handle);
556 }
557
558 virtual void OnConnectJobComplete(int result, ConnectJob* job) {
559 return helper_->OnConnectJobComplete(result, job);
560 }
561
562 // For testing.
563 bool may_have_stalled_group() const {
564 return helper_->may_have_stalled_group();
565 }
566
567 int NumConnectJobsInGroup(const std::string& group_name) const {
568 return helper_->NumConnectJobsInGroup(group_name);
569 }
570
[email protected]9bf28db2009-08-29 01:35:16571 void CleanupIdleSockets(bool force) {
572 return helper_->CleanupIdleSockets(force);
573 }
574
[email protected]a796bcec2010-03-22 17:17:26575 base::TimeDelta ConnectionTimeout() const {
576 return helper_->ConnectionTimeout();
577 }
578
[email protected]b89f7e42010-05-20 20:37:00579 scoped_refptr<ClientSocketPoolHistograms> histograms() const {
580 return histograms_;
581 }
[email protected]a796bcec2010-03-22 17:17:26582
[email protected]4751c742010-05-19 02:44:36583 void enable_backup_jobs() { helper_->enable_backup_jobs(); };
[email protected]7c28e9a2010-03-20 01:16:13584
[email protected]d80a4322009-08-14 07:07:49585 private:
586 // This adaptor class exists to bridge the
587 // internal::ClientSocketPoolBaseHelper::ConnectJobFactory and
588 // ClientSocketPoolBase::ConnectJobFactory types, allowing clients to use the
589 // typesafe ClientSocketPoolBase::ConnectJobFactory, rather than having to
590 // static_cast themselves.
591 class ConnectJobFactoryAdaptor
592 : public internal::ClientSocketPoolBaseHelper::ConnectJobFactory {
593 public:
594 typedef typename ClientSocketPoolBase<SocketParams>::ConnectJobFactory
595 ConnectJobFactory;
596
597 explicit ConnectJobFactoryAdaptor(
598 ConnectJobFactory* connect_job_factory)
599 : connect_job_factory_(connect_job_factory) {}
600 virtual ~ConnectJobFactoryAdaptor() {}
601
602 virtual ConnectJob* NewConnectJob(
603 const std::string& group_name,
604 const internal::ClientSocketPoolBaseHelper::Request& request,
[email protected]fd7b7c92009-08-20 19:38:30605 ConnectJob::Delegate* delegate,
[email protected]9e743cd2010-03-16 07:03:53606 const BoundNetLog& net_log) const {
[email protected]d80a4322009-08-14 07:07:49607 const Request* casted_request = static_cast<const Request*>(&request);
608 return connect_job_factory_->NewConnectJob(
[email protected]9e743cd2010-03-16 07:03:53609 group_name, *casted_request, delegate, net_log);
[email protected]d80a4322009-08-14 07:07:49610 }
611
[email protected]a796bcec2010-03-22 17:17:26612 virtual base::TimeDelta ConnectionTimeout() const {
613 return connect_job_factory_->ConnectionTimeout();
614 }
615
[email protected]d80a4322009-08-14 07:07:49616 const scoped_ptr<ConnectJobFactory> connect_job_factory_;
617 };
618
[email protected]b89f7e42010-05-20 20:37:00619 // Histograms for the pool
620 const scoped_refptr<ClientSocketPoolHistograms> histograms_;
[email protected]a796bcec2010-03-22 17:17:26621
[email protected]d80a4322009-08-14 07:07:49622 // One might ask why ClientSocketPoolBaseHelper is also refcounted if its
623 // containing ClientSocketPool is already refcounted. The reason is because
624 // DoReleaseSocket() posts a task. If ClientSocketPool gets deleted between
625 // the posting of the task and the execution, then we'll hit the DCHECK that
626 // |ClientSocketPoolBaseHelper::group_map_| is empty.
627 scoped_refptr<internal::ClientSocketPoolBaseHelper> helper_;
628
[email protected]ff579d42009-06-24 15:47:02629 DISALLOW_COPY_AND_ASSIGN(ClientSocketPoolBase);
630};
631
[email protected]ff579d42009-06-24 15:47:02632} // namespace net
633
634#endif // NET_SOCKET_CLIENT_SOCKET_POOL_BASE_H_