blob: 8d3fba76c14b6cfbb7bfdb98ac9790f6b4f800cf [file] [log] [blame]
[email protected]20cb5f482009-12-16 01:01:251// Copyright (c) 2009 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]100d5fb92009-12-21 21:08:3531#include "base/ref_counted.h"
[email protected]ff579d42009-06-24 15:47:0232#include "base/scoped_ptr.h"
33#include "base/time.h"
34#include "base/timer.h"
35#include "net/base/address_list.h"
36#include "net/base/completion_callback.h"
[email protected]ec08bb22009-08-12 00:25:1237#include "net/base/load_log.h"
[email protected]ff579d42009-06-24 15:47:0238#include "net/base/load_states.h"
[email protected]d80a4322009-08-14 07:07:4939#include "net/base/net_errors.h"
[email protected]100d5fb92009-12-21 21:08:3540#include "net/base/network_change_notifier.h"
[email protected]ac790b42009-12-02 04:31:3141#include "net/base/request_priority.h"
[email protected]2ab05b52009-07-01 23:57:5842#include "net/socket/client_socket.h"
[email protected]ff579d42009-06-24 15:47:0243#include "net/socket/client_socket_pool.h"
44
45namespace net {
46
[email protected]ff579d42009-06-24 15:47:0247class ClientSocketHandle;
[email protected]ff579d42009-06-24 15:47:0248
49// ConnectJob provides an abstract interface for "connecting" a socket.
50// The connection may involve host resolution, tcp connection, ssl connection,
51// etc.
52class ConnectJob {
53 public:
[email protected]ab838892009-06-30 18:49:0554 class Delegate {
55 public:
56 Delegate() {}
57 virtual ~Delegate() {}
58
[email protected]2ab05b52009-07-01 23:57:5859 // Alerts the delegate that the connection completed.
60 virtual void OnConnectJobComplete(int result, ConnectJob* job) = 0;
[email protected]ab838892009-06-30 18:49:0561
62 private:
63 DISALLOW_COPY_AND_ASSIGN(Delegate);
64 };
65
[email protected]974ebd62009-08-03 23:14:3466 // A |timeout_duration| of 0 corresponds to no timeout.
[email protected]2ab05b52009-07-01 23:57:5867 ConnectJob(const std::string& group_name,
[email protected]974ebd62009-08-03 23:14:3468 base::TimeDelta timeout_duration,
[email protected]fd7b7c92009-08-20 19:38:3069 Delegate* delegate,
70 LoadLog* load_log);
[email protected]2ab05b52009-07-01 23:57:5871 virtual ~ConnectJob();
[email protected]ff579d42009-06-24 15:47:0272
[email protected]2ab05b52009-07-01 23:57:5873 // Accessors
74 const std::string& group_name() const { return group_name_; }
[email protected]46451352009-09-01 14:54:2175 LoadLog* load_log() { return load_log_; }
[email protected]2ab05b52009-07-01 23:57:5876
[email protected]8e12ae02009-07-02 16:15:0477 // Releases |socket_| to the client. On connection error, this should return
78 // NULL.
[email protected]2ab05b52009-07-01 23:57:5879 ClientSocket* ReleaseSocket() { return socket_.release(); }
[email protected]ab838892009-06-30 18:49:0580
[email protected]ff579d42009-06-24 15:47:0281 // Begins connecting the socket. Returns OK on success, ERR_IO_PENDING if it
82 // cannot complete synchronously without blocking, or another net error code
[email protected]2ab05b52009-07-01 23:57:5883 // on error. In asynchronous completion, the ConnectJob will notify
84 // |delegate_| via OnConnectJobComplete. In both asynchronous and synchronous
85 // completion, ReleaseSocket() can be called to acquire the connected socket
86 // if it succeeded.
[email protected]974ebd62009-08-03 23:14:3487 int Connect();
[email protected]ff579d42009-06-24 15:47:0288
[email protected]46451352009-09-01 14:54:2189 virtual LoadState GetLoadState() const = 0;
[email protected]fd7b7c92009-08-20 19:38:3090
[email protected]ab838892009-06-30 18:49:0591 protected:
[email protected]2ab05b52009-07-01 23:57:5892 void set_socket(ClientSocket* socket) { socket_.reset(socket); }
93 ClientSocket* socket() { return socket_.get(); }
[email protected]fd7b7c92009-08-20 19:38:3094 void NotifyDelegateOfCompletion(int rv);
[email protected]ab838892009-06-30 18:49:0595
[email protected]ff579d42009-06-24 15:47:0296 private:
[email protected]974ebd62009-08-03 23:14:3497 virtual int ConnectInternal() = 0;
98
99 // Alerts the delegate that the ConnectJob has timed out.
100 void OnTimeout();
101
[email protected]2ab05b52009-07-01 23:57:58102 const std::string group_name_;
[email protected]974ebd62009-08-03 23:14:34103 const base::TimeDelta timeout_duration_;
104 // Timer to abort jobs that take too long.
105 base::OneShotTimer<ConnectJob> timer_;
106 Delegate* delegate_;
[email protected]2ab05b52009-07-01 23:57:58107 scoped_ptr<ClientSocket> socket_;
[email protected]fd7b7c92009-08-20 19:38:30108 scoped_refptr<LoadLog> load_log_;
[email protected]ab838892009-06-30 18:49:05109
[email protected]ff579d42009-06-24 15:47:02110 DISALLOW_COPY_AND_ASSIGN(ConnectJob);
111};
112
[email protected]d80a4322009-08-14 07:07:49113namespace internal {
114
115// ClientSocketPoolBaseHelper is an internal class that implements almost all
116// the functionality from ClientSocketPoolBase without using templates.
117// ClientSocketPoolBase adds templated definitions built on top of
118// ClientSocketPoolBaseHelper. This class is not for external use, please use
119// ClientSocketPoolBase instead.
120class ClientSocketPoolBaseHelper
121 : public base::RefCounted<ClientSocketPoolBaseHelper>,
[email protected]100d5fb92009-12-21 21:08:35122 public ConnectJob::Delegate,
123 public NetworkChangeNotifier::Observer {
[email protected]ff579d42009-06-24 15:47:02124 public:
[email protected]d80a4322009-08-14 07:07:49125 class Request {
126 public:
[email protected]684970b2009-08-14 04:54:46127 Request(ClientSocketHandle* handle,
[email protected]ff579d42009-06-24 15:47:02128 CompletionCallback* callback,
[email protected]ac790b42009-12-02 04:31:31129 RequestPriority priority,
[email protected]684970b2009-08-14 04:54:46130 LoadLog* load_log)
[email protected]fd7b7c92009-08-20 19:38:30131 : handle_(handle), callback_(callback), priority_(priority),
132 load_log_(load_log) {}
[email protected]ff579d42009-06-24 15:47:02133
[email protected]d80a4322009-08-14 07:07:49134 virtual ~Request() {}
135
136 ClientSocketHandle* handle() const { return handle_; }
137 CompletionCallback* callback() const { return callback_; }
[email protected]ac790b42009-12-02 04:31:31138 RequestPriority priority() const { return priority_; }
[email protected]d80a4322009-08-14 07:07:49139 LoadLog* load_log() const { return load_log_.get(); }
140
141 private:
142 ClientSocketHandle* const handle_;
143 CompletionCallback* const callback_;
[email protected]ac790b42009-12-02 04:31:31144 const RequestPriority priority_;
[email protected]d80a4322009-08-14 07:07:49145 const scoped_refptr<LoadLog> load_log_;
146
147 DISALLOW_COPY_AND_ASSIGN(Request);
[email protected]ff579d42009-06-24 15:47:02148 };
149
150 class ConnectJobFactory {
151 public:
152 ConnectJobFactory() {}
153 virtual ~ConnectJobFactory() {}
154
155 virtual ConnectJob* NewConnectJob(
156 const std::string& group_name,
157 const Request& request,
[email protected]fd7b7c92009-08-20 19:38:30158 ConnectJob::Delegate* delegate,
159 LoadLog* load_log) const = 0;
[email protected]ff579d42009-06-24 15:47:02160
161 private:
162 DISALLOW_COPY_AND_ASSIGN(ConnectJobFactory);
163 };
164
[email protected]100d5fb92009-12-21 21:08:35165 ClientSocketPoolBaseHelper(
166 int max_sockets,
167 int max_sockets_per_group,
168 base::TimeDelta unused_idle_socket_timeout,
169 base::TimeDelta used_idle_socket_timeout,
170 ConnectJobFactory* connect_job_factory,
171 const scoped_refptr<NetworkChangeNotifier>& network_change_notifier);
[email protected]ff579d42009-06-24 15:47:02172
[email protected]d80a4322009-08-14 07:07:49173 // See ClientSocketPool::RequestSocket for documentation on this function.
174 // Note that |request| must be heap allocated. If ERR_IO_PENDING is returned,
175 // then ClientSocketPoolBaseHelper takes ownership of |request|.
176 int RequestSocket(const std::string& group_name, const Request* request);
[email protected]ff579d42009-06-24 15:47:02177
[email protected]d80a4322009-08-14 07:07:49178 // See ClientSocketPool::CancelRequest for documentation on this function.
[email protected]ff579d42009-06-24 15:47:02179 void CancelRequest(const std::string& group_name,
180 const ClientSocketHandle* handle);
181
[email protected]d80a4322009-08-14 07:07:49182 // See ClientSocketPool::ReleaseSocket for documentation on this function.
[email protected]ff579d42009-06-24 15:47:02183 void ReleaseSocket(const std::string& group_name,
184 ClientSocket* socket);
185
[email protected]d80a4322009-08-14 07:07:49186 // See ClientSocketPool::CloseIdleSockets for documentation on this function.
[email protected]ff579d42009-06-24 15:47:02187 void CloseIdleSockets();
188
[email protected]d80a4322009-08-14 07:07:49189 // See ClientSocketPool::IdleSocketCount() for documentation on this function.
[email protected]ff579d42009-06-24 15:47:02190 int idle_socket_count() const {
191 return idle_socket_count_;
192 }
193
[email protected]d80a4322009-08-14 07:07:49194 // See ClientSocketPool::IdleSocketCountInGroup() for documentation on this
195 // function.
[email protected]ff579d42009-06-24 15:47:02196 int IdleSocketCountInGroup(const std::string& group_name) const;
197
[email protected]d80a4322009-08-14 07:07:49198 // See ClientSocketPool::GetLoadState() for documentation on this function.
[email protected]ff579d42009-06-24 15:47:02199 LoadState GetLoadState(const std::string& group_name,
200 const ClientSocketHandle* handle) const;
201
[email protected]d80a4322009-08-14 07:07:49202 // ConnectJob::Delegate methods:
[email protected]2ab05b52009-07-01 23:57:58203 virtual void OnConnectJobComplete(int result, ConnectJob* job);
[email protected]ff579d42009-06-24 15:47:02204
[email protected]100d5fb92009-12-21 21:08:35205 // NetworkChangeNotifier::Observer methods:
206 virtual void OnIPAddressChanged();
207
[email protected]211d2172009-07-22 15:48:53208 // For testing.
209 bool may_have_stalled_group() const { return may_have_stalled_group_; }
[email protected]d80a4322009-08-14 07:07:49210
[email protected]974ebd62009-08-03 23:14:34211 int NumConnectJobsInGroup(const std::string& group_name) const {
212 return group_map_.find(group_name)->second.jobs.size();
213 }
[email protected]211d2172009-07-22 15:48:53214
[email protected]9bf28db2009-08-29 01:35:16215 // Closes all idle sockets if |force| is true. Else, only closes idle
216 // sockets that timed out or can't be reused. Made public for testing.
217 void CleanupIdleSockets(bool force);
218
[email protected]ff579d42009-06-24 15:47:02219 private:
[email protected]5389bc72009-11-05 23:34:24220 friend class base::RefCounted<ClientSocketPoolBaseHelper>;
221
222 ~ClientSocketPoolBaseHelper();
223
[email protected]ff579d42009-06-24 15:47:02224 // Entry for a persistent socket which became idle at time |start_time|.
225 struct IdleSocket {
[email protected]5fc08e32009-07-15 17:09:57226 IdleSocket() : socket(NULL), used(false) {}
[email protected]ff579d42009-06-24 15:47:02227 ClientSocket* socket;
228 base::TimeTicks start_time;
[email protected]5fc08e32009-07-15 17:09:57229 bool used; // Indicates whether or not the socket has been used yet.
[email protected]ff579d42009-06-24 15:47:02230
231 // An idle socket should be removed if it can't be reused, or has been idle
232 // for too long. |now| is the current time value (TimeTicks::Now()).
[email protected]9bf28db2009-08-29 01:35:16233 // |timeout| is the length of time to wait before timing out an idle socket.
[email protected]ff579d42009-06-24 15:47:02234 //
235 // An idle socket can't be reused if it is disconnected or has received
236 // data unexpectedly (hence no longer idle). The unread data would be
237 // mistaken for the beginning of the next response if we were to reuse the
238 // socket for a new request.
[email protected]9bf28db2009-08-29 01:35:16239 bool ShouldCleanup(base::TimeTicks now, base::TimeDelta timeout) const;
[email protected]ff579d42009-06-24 15:47:02240 };
241
[email protected]d80a4322009-08-14 07:07:49242 typedef std::deque<const Request*> RequestQueue;
243 typedef std::map<const ClientSocketHandle*, const Request*> RequestMap;
[email protected]ff579d42009-06-24 15:47:02244
245 // A Group is allocated per group_name when there are idle sockets or pending
246 // requests. Otherwise, the Group object is removed from the map.
[email protected]5edbf8d2010-01-13 18:44:11247 // |active_socket_count| tracks the number of sockets held by clients. Of
248 // this number of sockets held by clients, some of them may be released soon,
249 // since ReleaseSocket() was called of them, but the DoReleaseSocket() task
250 // has not run yet for them. |num_releasing_sockets| tracks these values,
251 // which is useful for not starting up new ConnectJobs when sockets may become
252 // available really soon.
[email protected]ff579d42009-06-24 15:47:02253 struct Group {
[email protected]5edbf8d2010-01-13 18:44:11254 Group() : active_socket_count(0), num_releasing_sockets(0) {}
[email protected]2ab05b52009-07-01 23:57:58255
256 bool IsEmpty() const {
[email protected]2b7523d2009-07-29 20:29:23257 return active_socket_count == 0 && idle_sockets.empty() && jobs.empty() &&
[email protected]4d3b05d2010-01-27 21:27:29258 pending_requests.empty();
[email protected]2ab05b52009-07-01 23:57:58259 }
260
261 bool HasAvailableSocketSlot(int max_sockets_per_group) const {
[email protected]5fc08e32009-07-15 17:09:57262 return active_socket_count + static_cast<int>(jobs.size()) <
[email protected]2ab05b52009-07-01 23:57:58263 max_sockets_per_group;
264 }
265
[email protected]5edbf8d2010-01-13 18:44:11266 bool HasReleasingSockets() const {
267 return num_releasing_sockets > 0;
268 }
269
[email protected]ac790b42009-12-02 04:31:31270 RequestPriority TopPendingPriority() const {
[email protected]d80a4322009-08-14 07:07:49271 return pending_requests.front()->priority();
[email protected]211d2172009-07-22 15:48:53272 }
273
[email protected]ff579d42009-06-24 15:47:02274 std::deque<IdleSocket> idle_sockets;
[email protected]5fc08e32009-07-15 17:09:57275 std::set<const ConnectJob*> jobs;
[email protected]ff579d42009-06-24 15:47:02276 RequestQueue pending_requests;
[email protected]2ab05b52009-07-01 23:57:58277 int active_socket_count; // number of active sockets used by clients
[email protected]5edbf8d2010-01-13 18:44:11278 // Number of sockets being released within one loop through the MessageLoop.
279 int num_releasing_sockets;
[email protected]ff579d42009-06-24 15:47:02280 };
281
282 typedef std::map<std::string, Group> GroupMap;
283
[email protected]5fc08e32009-07-15 17:09:57284 typedef std::set<const ConnectJob*> ConnectJobSet;
[email protected]ff579d42009-06-24 15:47:02285
[email protected]d80a4322009-08-14 07:07:49286 static void InsertRequestIntoQueue(const Request* r,
[email protected]ff579d42009-06-24 15:47:02287 RequestQueue* pending_requests);
[email protected]fd7b7c92009-08-20 19:38:30288 static const Request* RemoveRequestFromQueue(RequestQueue::iterator it,
289 RequestQueue* pending_requests);
[email protected]ff579d42009-06-24 15:47:02290
[email protected]ff579d42009-06-24 15:47:02291 // Called when the number of idle sockets changes.
292 void IncrementIdleCount();
293 void DecrementIdleCount();
294
295 // Called via PostTask by ReleaseSocket.
296 void DoReleaseSocket(const std::string& group_name, ClientSocket* socket);
297
[email protected]211d2172009-07-22 15:48:53298 // Scans the group map for groups which have an available socket slot and
299 // at least one pending request. Returns number of groups found, and if found
300 // at least one, fills |group| and |group_name| with data of the stalled group
301 // having highest priority.
302 int FindTopStalledGroup(Group** group, std::string* group_name);
303
[email protected]ff579d42009-06-24 15:47:02304 // Called when timer_ fires. This method scans the idle sockets removing
305 // sockets that timed out or can't be reused.
306 void OnCleanupTimerFired() {
307 CleanupIdleSockets(false);
308 }
309
[email protected]4d3b05d2010-01-27 21:27:29310 // Removes |job| from |connect_job_set_|. Also updates |group| if non-NULL.
311 void RemoveConnectJob(const ConnectJob* job, Group* group);
[email protected]ff579d42009-06-24 15:47:02312
[email protected]2ab05b52009-07-01 23:57:58313 // Same as OnAvailableSocketSlot except it looks up the Group first to see if
314 // it's there.
315 void MaybeOnAvailableSocketSlot(const std::string& group_name);
[email protected]ff579d42009-06-24 15:47:02316
[email protected]2ab05b52009-07-01 23:57:58317 // Might delete the Group from |group_map_|.
318 void OnAvailableSocketSlot(const std::string& group_name, Group* group);
[email protected]ff579d42009-06-24 15:47:02319
320 // Process a request from a group's pending_requests queue.
321 void ProcessPendingRequest(const std::string& group_name, Group* group);
322
[email protected]2ab05b52009-07-01 23:57:58323 // Assigns |socket| to |handle| and updates |group|'s counters appropriately.
324 void HandOutSocket(ClientSocket* socket,
325 bool reused,
326 ClientSocketHandle* handle,
[email protected]f9d285c2009-08-17 19:54:29327 base::TimeDelta time_idle,
[email protected]2ab05b52009-07-01 23:57:58328 Group* group);
329
[email protected]5fc08e32009-07-15 17:09:57330 // Adds |socket| to the list of idle sockets for |group|. |used| indicates
331 // whether or not the socket has previously been used.
332 void AddIdleSocket(ClientSocket* socket, bool used, Group* group);
333
334 // Iterates through |connect_job_map_|, canceling all ConnectJobs.
335 // Afterwards, it iterates through all groups and deletes them if they are no
336 // longer needed.
337 void CancelAllConnectJobs();
338
[email protected]211d2172009-07-22 15:48:53339 // Returns true if we can't create any more sockets due to the total limit.
340 // TODO(phajdan.jr): Also take idle sockets into account.
341 bool ReachedMaxSocketsLimit() const;
342
[email protected]ff579d42009-06-24 15:47:02343 GroupMap group_map_;
344
[email protected]ff579d42009-06-24 15:47:02345 // Timer used to periodically prune idle sockets that timed out or can't be
346 // reused.
[email protected]d80a4322009-08-14 07:07:49347 base::RepeatingTimer<ClientSocketPoolBaseHelper> timer_;
[email protected]ff579d42009-06-24 15:47:02348
349 // The total number of idle sockets in the system.
350 int idle_socket_count_;
351
[email protected]211d2172009-07-22 15:48:53352 // Number of connecting sockets across all groups.
353 int connecting_socket_count_;
354
355 // Number of connected sockets we handed out across all groups.
356 int handed_out_socket_count_;
357
358 // The maximum total number of sockets. See ReachedMaxSocketsLimit.
359 const int max_sockets_;
360
[email protected]ff579d42009-06-24 15:47:02361 // The maximum number of sockets kept per group.
362 const int max_sockets_per_group_;
363
[email protected]9bf28db2009-08-29 01:35:16364 // The time to wait until closing idle sockets.
365 const base::TimeDelta unused_idle_socket_timeout_;
366 const base::TimeDelta used_idle_socket_timeout_;
367
[email protected]211d2172009-07-22 15:48:53368 // Until the maximum number of sockets limit is reached, a group can only
369 // have pending requests if it exceeds the "max sockets per group" limit.
370 //
371 // This means when a socket is released, the only pending requests that can
372 // be started next belong to the same group.
373 //
374 // However once the |max_sockets_| limit is reached, this stops being true:
375 // groups can now have pending requests without having first reached the
376 // |max_sockets_per_group_| limit. So choosing the next request involves
377 // selecting the highest priority request across *all* groups.
378 //
379 // Since reaching the maximum number of sockets is an edge case, we make note
380 // of when it happens, and thus avoid doing the slower "scan all groups"
381 // in the common case.
382 bool may_have_stalled_group_;
383
[email protected]ab838892009-06-30 18:49:05384 const scoped_ptr<ConnectJobFactory> connect_job_factory_;
[email protected]ff579d42009-06-24 15:47:02385
[email protected]100d5fb92009-12-21 21:08:35386 const scoped_refptr<NetworkChangeNotifier> network_change_notifier_;
[email protected]d80a4322009-08-14 07:07:49387};
388
389} // namespace internal
390
[email protected]9bf28db2009-08-29 01:35:16391// The maximum duration, in seconds, to keep unused idle persistent sockets
392// alive.
393// TODO(willchan): Change this timeout after getting histogram data on how
394// long it should be.
395static const int kUnusedIdleSocketTimeout = 10;
396// The maximum duration, in seconds, to keep used idle persistent sockets alive.
397static const int kUsedIdleSocketTimeout = 300; // 5 minutes
398
[email protected]d80a4322009-08-14 07:07:49399template <typename SocketParams>
400class ClientSocketPoolBase {
401 public:
402 class Request : public internal::ClientSocketPoolBaseHelper::Request {
403 public:
404 Request(ClientSocketHandle* handle,
405 CompletionCallback* callback,
[email protected]ac790b42009-12-02 04:31:31406 RequestPriority priority,
[email protected]d80a4322009-08-14 07:07:49407 const SocketParams& params,
408 LoadLog* load_log)
409 : internal::ClientSocketPoolBaseHelper::Request(
410 handle, callback, priority, load_log),
411 params_(params) {}
412
413 const SocketParams& params() const { return params_; }
414
415 private:
416 SocketParams params_;
417 };
418
419 class ConnectJobFactory {
420 public:
421 ConnectJobFactory() {}
422 virtual ~ConnectJobFactory() {}
423
424 virtual ConnectJob* NewConnectJob(
425 const std::string& group_name,
426 const Request& request,
[email protected]fd7b7c92009-08-20 19:38:30427 ConnectJob::Delegate* delegate,
428 LoadLog* load_log) const = 0;
[email protected]d80a4322009-08-14 07:07:49429
430 private:
431 DISALLOW_COPY_AND_ASSIGN(ConnectJobFactory);
432 };
433
[email protected]9bf28db2009-08-29 01:35:16434 // |max_sockets| is the maximum number of sockets to be maintained by this
435 // ClientSocketPool. |max_sockets_per_group| specifies the maximum number of
436 // sockets a "group" can have. |unused_idle_socket_timeout| specifies how
437 // long to leave an unused idle socket open before closing it.
438 // |used_idle_socket_timeout| specifies how long to leave a previously used
439 // idle socket open before closing it.
[email protected]100d5fb92009-12-21 21:08:35440 ClientSocketPoolBase(
441 int max_sockets,
442 int max_sockets_per_group,
443 base::TimeDelta unused_idle_socket_timeout,
444 base::TimeDelta used_idle_socket_timeout,
445 ConnectJobFactory* connect_job_factory,
446 const scoped_refptr<NetworkChangeNotifier>& network_change_notifier)
[email protected]d80a4322009-08-14 07:07:49447 : helper_(new internal::ClientSocketPoolBaseHelper(
448 max_sockets, max_sockets_per_group,
[email protected]9bf28db2009-08-29 01:35:16449 unused_idle_socket_timeout, used_idle_socket_timeout,
[email protected]100d5fb92009-12-21 21:08:35450 new ConnectJobFactoryAdaptor(connect_job_factory),
451 network_change_notifier)) {}
[email protected]d80a4322009-08-14 07:07:49452
[email protected]20cb5f482009-12-16 01:01:25453 virtual ~ClientSocketPoolBase() {}
[email protected]d80a4322009-08-14 07:07:49454
455 // These member functions simply forward to ClientSocketPoolBaseHelper.
456
457 // RequestSocket bundles up the parameters into a Request and then forwards to
458 // ClientSocketPoolBaseHelper::RequestSocket(). Note that the memory
459 // ownership is transferred in the asynchronous (ERR_IO_PENDING) case.
460 int RequestSocket(const std::string& group_name,
461 const SocketParams& params,
[email protected]ac790b42009-12-02 04:31:31462 RequestPriority priority,
[email protected]d80a4322009-08-14 07:07:49463 ClientSocketHandle* handle,
464 CompletionCallback* callback,
465 LoadLog* load_log) {
466 scoped_ptr<Request> request(
467 new Request(handle, callback, priority, params, load_log));
[email protected]fd7b7c92009-08-20 19:38:30468 LoadLog::BeginEvent(load_log, LoadLog::TYPE_SOCKET_POOL);
[email protected]d80a4322009-08-14 07:07:49469 int rv = helper_->RequestSocket(group_name, request.get());
470 if (rv == ERR_IO_PENDING)
471 request.release();
[email protected]fd7b7c92009-08-20 19:38:30472 else
473 LoadLog::EndEvent(load_log, LoadLog::TYPE_SOCKET_POOL);
[email protected]d80a4322009-08-14 07:07:49474 return rv;
475 }
476
477 void CancelRequest(const std::string& group_name,
478 const ClientSocketHandle* handle) {
479 return helper_->CancelRequest(group_name, handle);
480 }
481
482 void ReleaseSocket(const std::string& group_name, ClientSocket* socket) {
483 return helper_->ReleaseSocket(group_name, socket);
484 }
485
486 void CloseIdleSockets() { return helper_->CloseIdleSockets(); }
487
488 int idle_socket_count() const { return helper_->idle_socket_count(); }
489
490 int IdleSocketCountInGroup(const std::string& group_name) const {
491 return helper_->IdleSocketCountInGroup(group_name);
492 }
493
494 LoadState GetLoadState(const std::string& group_name,
495 const ClientSocketHandle* handle) const {
496 return helper_->GetLoadState(group_name, handle);
497 }
498
499 virtual void OnConnectJobComplete(int result, ConnectJob* job) {
500 return helper_->OnConnectJobComplete(result, job);
501 }
502
503 // For testing.
504 bool may_have_stalled_group() const {
505 return helper_->may_have_stalled_group();
506 }
507
508 int NumConnectJobsInGroup(const std::string& group_name) const {
509 return helper_->NumConnectJobsInGroup(group_name);
510 }
511
[email protected]9bf28db2009-08-29 01:35:16512 void CleanupIdleSockets(bool force) {
513 return helper_->CleanupIdleSockets(force);
514 }
515
[email protected]d80a4322009-08-14 07:07:49516 private:
517 // This adaptor class exists to bridge the
518 // internal::ClientSocketPoolBaseHelper::ConnectJobFactory and
519 // ClientSocketPoolBase::ConnectJobFactory types, allowing clients to use the
520 // typesafe ClientSocketPoolBase::ConnectJobFactory, rather than having to
521 // static_cast themselves.
522 class ConnectJobFactoryAdaptor
523 : public internal::ClientSocketPoolBaseHelper::ConnectJobFactory {
524 public:
525 typedef typename ClientSocketPoolBase<SocketParams>::ConnectJobFactory
526 ConnectJobFactory;
527
528 explicit ConnectJobFactoryAdaptor(
529 ConnectJobFactory* connect_job_factory)
530 : connect_job_factory_(connect_job_factory) {}
531 virtual ~ConnectJobFactoryAdaptor() {}
532
533 virtual ConnectJob* NewConnectJob(
534 const std::string& group_name,
535 const internal::ClientSocketPoolBaseHelper::Request& request,
[email protected]fd7b7c92009-08-20 19:38:30536 ConnectJob::Delegate* delegate,
537 LoadLog* load_log) const {
[email protected]d80a4322009-08-14 07:07:49538 const Request* casted_request = static_cast<const Request*>(&request);
539 return connect_job_factory_->NewConnectJob(
[email protected]fd7b7c92009-08-20 19:38:30540 group_name, *casted_request, delegate, load_log);
[email protected]d80a4322009-08-14 07:07:49541 }
542
543 const scoped_ptr<ConnectJobFactory> connect_job_factory_;
544 };
545
546 // One might ask why ClientSocketPoolBaseHelper is also refcounted if its
547 // containing ClientSocketPool is already refcounted. The reason is because
548 // DoReleaseSocket() posts a task. If ClientSocketPool gets deleted between
549 // the posting of the task and the execution, then we'll hit the DCHECK that
550 // |ClientSocketPoolBaseHelper::group_map_| is empty.
551 scoped_refptr<internal::ClientSocketPoolBaseHelper> helper_;
552
[email protected]ff579d42009-06-24 15:47:02553 DISALLOW_COPY_AND_ASSIGN(ClientSocketPoolBase);
554};
555
[email protected]ff579d42009-06-24 15:47:02556} // namespace net
557
558#endif // NET_SOCKET_CLIENT_SOCKET_POOL_BASE_H_