blob: 23c194cc2e26e79bfb111a1f7386b2f9f1c6af51 [file] [log] [blame]
[email protected]5a3b9142009-08-28 21:03:171// Copyright (c) 2006-2008 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"
31#include "base/scoped_ptr.h"
32#include "base/time.h"
33#include "base/timer.h"
34#include "net/base/address_list.h"
35#include "net/base/completion_callback.h"
[email protected]ec08bb22009-08-12 00:25:1236#include "net/base/load_log.h"
[email protected]ff579d42009-06-24 15:47:0237#include "net/base/load_states.h"
[email protected]d80a4322009-08-14 07:07:4938#include "net/base/net_errors.h"
[email protected]2ab05b52009-07-01 23:57:5839#include "net/socket/client_socket.h"
[email protected]ff579d42009-06-24 15:47:0240#include "net/socket/client_socket_pool.h"
41
42namespace net {
43
[email protected]ff579d42009-06-24 15:47:0244class ClientSocketHandle;
[email protected]ff579d42009-06-24 15:47:0245
46// ConnectJob provides an abstract interface for "connecting" a socket.
47// The connection may involve host resolution, tcp connection, ssl connection,
48// etc.
49class ConnectJob {
50 public:
[email protected]ab838892009-06-30 18:49:0551 class Delegate {
52 public:
53 Delegate() {}
54 virtual ~Delegate() {}
55
[email protected]2ab05b52009-07-01 23:57:5856 // Alerts the delegate that the connection completed.
57 virtual void OnConnectJobComplete(int result, ConnectJob* job) = 0;
[email protected]ab838892009-06-30 18:49:0558
59 private:
60 DISALLOW_COPY_AND_ASSIGN(Delegate);
61 };
62
[email protected]974ebd62009-08-03 23:14:3463 // A |timeout_duration| of 0 corresponds to no timeout.
[email protected]2ab05b52009-07-01 23:57:5864 ConnectJob(const std::string& group_name,
65 const ClientSocketHandle* key_handle,
[email protected]974ebd62009-08-03 23:14:3466 base::TimeDelta timeout_duration,
[email protected]fd7b7c92009-08-20 19:38:3067 Delegate* delegate,
68 LoadLog* load_log);
[email protected]2ab05b52009-07-01 23:57:5869 virtual ~ConnectJob();
[email protected]ff579d42009-06-24 15:47:0270
[email protected]2ab05b52009-07-01 23:57:5871 // Accessors
72 const std::string& group_name() const { return group_name_; }
[email protected]2ab05b52009-07-01 23:57:5873 const ClientSocketHandle* key_handle() const { return key_handle_; }
[email protected]46451352009-09-01 14:54:2174 LoadLog* load_log() { return load_log_; }
[email protected]2ab05b52009-07-01 23:57:5875
[email protected]8e12ae02009-07-02 16:15:0476 // Releases |socket_| to the client. On connection error, this should return
77 // NULL.
[email protected]2ab05b52009-07-01 23:57:5878 ClientSocket* ReleaseSocket() { return socket_.release(); }
[email protected]ab838892009-06-30 18:49:0579
[email protected]ff579d42009-06-24 15:47:0280 // Begins connecting the socket. Returns OK on success, ERR_IO_PENDING if it
81 // cannot complete synchronously without blocking, or another net error code
[email protected]2ab05b52009-07-01 23:57:5882 // on error. In asynchronous completion, the ConnectJob will notify
83 // |delegate_| via OnConnectJobComplete. In both asynchronous and synchronous
84 // completion, ReleaseSocket() can be called to acquire the connected socket
85 // if it succeeded.
[email protected]974ebd62009-08-03 23:14:3486 int Connect();
[email protected]ff579d42009-06-24 15:47:0287
[email protected]46451352009-09-01 14:54:2188 virtual LoadState GetLoadState() const = 0;
[email protected]fd7b7c92009-08-20 19:38:3089
[email protected]ab838892009-06-30 18:49:0590 protected:
[email protected]2ab05b52009-07-01 23:57:5891 void set_socket(ClientSocket* socket) { socket_.reset(socket); }
92 ClientSocket* socket() { return socket_.get(); }
[email protected]fd7b7c92009-08-20 19:38:3093 void NotifyDelegateOfCompletion(int rv);
[email protected]ab838892009-06-30 18:49:0594
[email protected]ff579d42009-06-24 15:47:0295 private:
[email protected]974ebd62009-08-03 23:14:3496 virtual int ConnectInternal() = 0;
97
98 // Alerts the delegate that the ConnectJob has timed out.
99 void OnTimeout();
100
[email protected]2ab05b52009-07-01 23:57:58101 const std::string group_name_;
102 // Temporarily needed until we switch to late binding.
103 const ClientSocketHandle* const key_handle_;
[email protected]974ebd62009-08-03 23:14:34104 const base::TimeDelta timeout_duration_;
105 // Timer to abort jobs that take too long.
106 base::OneShotTimer<ConnectJob> timer_;
107 Delegate* delegate_;
[email protected]2ab05b52009-07-01 23:57:58108 scoped_ptr<ClientSocket> socket_;
[email protected]fd7b7c92009-08-20 19:38:30109 scoped_refptr<LoadLog> load_log_;
[email protected]ab838892009-06-30 18:49:05110
[email protected]ff579d42009-06-24 15:47:02111 DISALLOW_COPY_AND_ASSIGN(ConnectJob);
112};
113
[email protected]d80a4322009-08-14 07:07:49114namespace internal {
115
116// ClientSocketPoolBaseHelper is an internal class that implements almost all
117// the functionality from ClientSocketPoolBase without using templates.
118// ClientSocketPoolBase adds templated definitions built on top of
119// ClientSocketPoolBaseHelper. This class is not for external use, please use
120// ClientSocketPoolBase instead.
121class ClientSocketPoolBaseHelper
122 : public base::RefCounted<ClientSocketPoolBaseHelper>,
[email protected]ab838892009-06-30 18:49:05123 public ConnectJob::Delegate {
[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,
129 int 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_; }
138 int priority() const { return priority_; }
139 LoadLog* load_log() const { return load_log_.get(); }
140
141 private:
142 ClientSocketHandle* const handle_;
143 CompletionCallback* const callback_;
144 const int priority_;
145 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]d80a4322009-08-14 07:07:49165 ClientSocketPoolBaseHelper(int max_sockets,
166 int max_sockets_per_group,
[email protected]9bf28db2009-08-29 01:35:16167 base::TimeDelta unused_idle_socket_timeout,
168 base::TimeDelta used_idle_socket_timeout,
[email protected]d80a4322009-08-14 07:07:49169 ConnectJobFactory* connect_job_factory);
[email protected]ff579d42009-06-24 15:47:02170
[email protected]d80a4322009-08-14 07:07:49171 ~ClientSocketPoolBaseHelper();
[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]5fc08e32009-07-15 17:09:57205 // Enables late binding of sockets. In this mode, socket requests are
206 // decoupled from socket connection jobs. A socket request may initiate a
207 // socket connection job, but there is no guarantee that that socket
208 // connection will service the request (for example, a released socket may
209 // service the request sooner, or a higher priority request may come in
210 // afterward and receive the socket from the job).
211 static void EnableLateBindingOfSockets(bool enabled);
212
[email protected]211d2172009-07-22 15:48:53213 // For testing.
214 bool may_have_stalled_group() const { return may_have_stalled_group_; }
[email protected]d80a4322009-08-14 07:07:49215
[email protected]974ebd62009-08-03 23:14:34216 int NumConnectJobsInGroup(const std::string& group_name) const {
217 return group_map_.find(group_name)->second.jobs.size();
218 }
[email protected]211d2172009-07-22 15:48:53219
[email protected]9bf28db2009-08-29 01:35:16220 // Closes all idle sockets if |force| is true. Else, only closes idle
221 // sockets that timed out or can't be reused. Made public for testing.
222 void CleanupIdleSockets(bool force);
223
[email protected]ff579d42009-06-24 15:47:02224 private:
225 // Entry for a persistent socket which became idle at time |start_time|.
226 struct IdleSocket {
[email protected]5fc08e32009-07-15 17:09:57227 IdleSocket() : socket(NULL), used(false) {}
[email protected]ff579d42009-06-24 15:47:02228 ClientSocket* socket;
229 base::TimeTicks start_time;
[email protected]5fc08e32009-07-15 17:09:57230 bool used; // Indicates whether or not the socket has been used yet.
[email protected]ff579d42009-06-24 15:47:02231
232 // An idle socket should be removed if it can't be reused, or has been idle
233 // for too long. |now| is the current time value (TimeTicks::Now()).
[email protected]9bf28db2009-08-29 01:35:16234 // |timeout| is the length of time to wait before timing out an idle socket.
[email protected]ff579d42009-06-24 15:47:02235 //
236 // An idle socket can't be reused if it is disconnected or has received
237 // data unexpectedly (hence no longer idle). The unread data would be
238 // mistaken for the beginning of the next response if we were to reuse the
239 // socket for a new request.
[email protected]9bf28db2009-08-29 01:35:16240 bool ShouldCleanup(base::TimeTicks now, base::TimeDelta timeout) const;
[email protected]ff579d42009-06-24 15:47:02241 };
242
[email protected]d80a4322009-08-14 07:07:49243 typedef std::deque<const Request*> RequestQueue;
244 typedef std::map<const ClientSocketHandle*, const Request*> RequestMap;
[email protected]ff579d42009-06-24 15:47:02245
246 // A Group is allocated per group_name when there are idle sockets or pending
247 // requests. Otherwise, the Group object is removed from the map.
248 struct Group {
[email protected]2ab05b52009-07-01 23:57:58249 Group() : active_socket_count(0) {}
250
251 bool IsEmpty() const {
[email protected]2b7523d2009-07-29 20:29:23252 return active_socket_count == 0 && idle_sockets.empty() && jobs.empty() &&
253 pending_requests.empty() && connecting_requests.empty();
[email protected]2ab05b52009-07-01 23:57:58254 }
255
256 bool HasAvailableSocketSlot(int max_sockets_per_group) const {
[email protected]5fc08e32009-07-15 17:09:57257 return active_socket_count + static_cast<int>(jobs.size()) <
[email protected]2ab05b52009-07-01 23:57:58258 max_sockets_per_group;
259 }
260
[email protected]211d2172009-07-22 15:48:53261 int TopPendingPriority() const {
[email protected]d80a4322009-08-14 07:07:49262 return pending_requests.front()->priority();
[email protected]211d2172009-07-22 15:48:53263 }
264
[email protected]ff579d42009-06-24 15:47:02265 std::deque<IdleSocket> idle_sockets;
[email protected]5fc08e32009-07-15 17:09:57266 std::set<const ConnectJob*> jobs;
[email protected]ff579d42009-06-24 15:47:02267 RequestQueue pending_requests;
268 RequestMap connecting_requests;
[email protected]2ab05b52009-07-01 23:57:58269 int active_socket_count; // number of active sockets used by clients
[email protected]ff579d42009-06-24 15:47:02270 };
271
272 typedef std::map<std::string, Group> GroupMap;
273
274 typedef std::map<const ClientSocketHandle*, ConnectJob*> ConnectJobMap;
[email protected]5fc08e32009-07-15 17:09:57275 typedef std::set<const ConnectJob*> ConnectJobSet;
[email protected]ff579d42009-06-24 15:47:02276
[email protected]d80a4322009-08-14 07:07:49277 static void InsertRequestIntoQueue(const Request* r,
[email protected]ff579d42009-06-24 15:47:02278 RequestQueue* pending_requests);
[email protected]fd7b7c92009-08-20 19:38:30279 static const Request* RemoveRequestFromQueue(RequestQueue::iterator it,
280 RequestQueue* pending_requests);
[email protected]ff579d42009-06-24 15:47:02281
[email protected]ff579d42009-06-24 15:47:02282 // Called when the number of idle sockets changes.
283 void IncrementIdleCount();
284 void DecrementIdleCount();
285
286 // Called via PostTask by ReleaseSocket.
287 void DoReleaseSocket(const std::string& group_name, ClientSocket* socket);
288
[email protected]211d2172009-07-22 15:48:53289 // Scans the group map for groups which have an available socket slot and
290 // at least one pending request. Returns number of groups found, and if found
291 // at least one, fills |group| and |group_name| with data of the stalled group
292 // having highest priority.
293 int FindTopStalledGroup(Group** group, std::string* group_name);
294
[email protected]ff579d42009-06-24 15:47:02295 // Called when timer_ fires. This method scans the idle sockets removing
296 // sockets that timed out or can't be reused.
297 void OnCleanupTimerFired() {
298 CleanupIdleSockets(false);
299 }
300
301 // Removes the ConnectJob corresponding to |handle| from the
[email protected]5fc08e32009-07-15 17:09:57302 // |connect_job_map_| or |connect_job_set_| depending on whether or not late
303 // binding is enabled. |job| must be non-NULL when late binding is
[email protected]d80a4322009-08-14 07:07:49304 // enabled. Also updates |group| if non-NULL. When late binding is disabled,
305 // this will also delete the Request from |group->connecting_requests|.
[email protected]5fc08e32009-07-15 17:09:57306 void RemoveConnectJob(const ClientSocketHandle* handle,
[email protected]974ebd62009-08-03 23:14:34307 const ConnectJob* job,
[email protected]5fc08e32009-07-15 17:09:57308 Group* group);
[email protected]ff579d42009-06-24 15:47:02309
[email protected]2ab05b52009-07-01 23:57:58310 // Same as OnAvailableSocketSlot except it looks up the Group first to see if
311 // it's there.
312 void MaybeOnAvailableSocketSlot(const std::string& group_name);
[email protected]ff579d42009-06-24 15:47:02313
[email protected]2ab05b52009-07-01 23:57:58314 // Might delete the Group from |group_map_|.
315 void OnAvailableSocketSlot(const std::string& group_name, Group* group);
[email protected]ff579d42009-06-24 15:47:02316
317 // Process a request from a group's pending_requests queue.
318 void ProcessPendingRequest(const std::string& group_name, Group* group);
319
[email protected]2ab05b52009-07-01 23:57:58320 // Assigns |socket| to |handle| and updates |group|'s counters appropriately.
321 void HandOutSocket(ClientSocket* socket,
322 bool reused,
323 ClientSocketHandle* handle,
[email protected]f9d285c2009-08-17 19:54:29324 base::TimeDelta time_idle,
[email protected]2ab05b52009-07-01 23:57:58325 Group* group);
326
[email protected]5fc08e32009-07-15 17:09:57327 // Adds |socket| to the list of idle sockets for |group|. |used| indicates
328 // whether or not the socket has previously been used.
329 void AddIdleSocket(ClientSocket* socket, bool used, Group* group);
330
331 // Iterates through |connect_job_map_|, canceling all ConnectJobs.
332 // Afterwards, it iterates through all groups and deletes them if they are no
333 // longer needed.
334 void CancelAllConnectJobs();
335
[email protected]211d2172009-07-22 15:48:53336 // Returns true if we can't create any more sockets due to the total limit.
337 // TODO(phajdan.jr): Also take idle sockets into account.
338 bool ReachedMaxSocketsLimit() const;
339
[email protected]ff579d42009-06-24 15:47:02340 GroupMap group_map_;
341
342 ConnectJobMap connect_job_map_;
343
344 // Timer used to periodically prune idle sockets that timed out or can't be
345 // reused.
[email protected]d80a4322009-08-14 07:07:49346 base::RepeatingTimer<ClientSocketPoolBaseHelper> timer_;
[email protected]ff579d42009-06-24 15:47:02347
348 // The total number of idle sockets in the system.
349 int idle_socket_count_;
350
[email protected]211d2172009-07-22 15:48:53351 // Number of connecting sockets across all groups.
352 int connecting_socket_count_;
353
354 // Number of connected sockets we handed out across all groups.
355 int handed_out_socket_count_;
356
357 // The maximum total number of sockets. See ReachedMaxSocketsLimit.
358 const int max_sockets_;
359
[email protected]ff579d42009-06-24 15:47:02360 // The maximum number of sockets kept per group.
361 const int max_sockets_per_group_;
362
[email protected]9bf28db2009-08-29 01:35:16363 // The time to wait until closing idle sockets.
364 const base::TimeDelta unused_idle_socket_timeout_;
365 const base::TimeDelta used_idle_socket_timeout_;
366
[email protected]211d2172009-07-22 15:48:53367 // Until the maximum number of sockets limit is reached, a group can only
368 // have pending requests if it exceeds the "max sockets per group" limit.
369 //
370 // This means when a socket is released, the only pending requests that can
371 // be started next belong to the same group.
372 //
373 // However once the |max_sockets_| limit is reached, this stops being true:
374 // groups can now have pending requests without having first reached the
375 // |max_sockets_per_group_| limit. So choosing the next request involves
376 // selecting the highest priority request across *all* groups.
377 //
378 // Since reaching the maximum number of sockets is an edge case, we make note
379 // of when it happens, and thus avoid doing the slower "scan all groups"
380 // in the common case.
381 bool may_have_stalled_group_;
382
[email protected]ab838892009-06-30 18:49:05383 const scoped_ptr<ConnectJobFactory> connect_job_factory_;
[email protected]ff579d42009-06-24 15:47:02384
[email protected]5fc08e32009-07-15 17:09:57385 // Controls whether or not we use late binding of sockets.
386 static bool g_late_binding;
387
[email protected]d80a4322009-08-14 07:07:49388};
389
390} // namespace internal
391
[email protected]9bf28db2009-08-29 01:35:16392// The maximum duration, in seconds, to keep unused idle persistent sockets
393// alive.
394// TODO(willchan): Change this timeout after getting histogram data on how
395// long it should be.
396static const int kUnusedIdleSocketTimeout = 10;
397// The maximum duration, in seconds, to keep used idle persistent sockets alive.
398static const int kUsedIdleSocketTimeout = 300; // 5 minutes
399
[email protected]d80a4322009-08-14 07:07:49400template <typename SocketParams>
401class ClientSocketPoolBase {
402 public:
403 class Request : public internal::ClientSocketPoolBaseHelper::Request {
404 public:
405 Request(ClientSocketHandle* handle,
406 CompletionCallback* callback,
407 int priority,
408 const SocketParams& params,
409 LoadLog* load_log)
410 : internal::ClientSocketPoolBaseHelper::Request(
411 handle, callback, priority, load_log),
412 params_(params) {}
413
414 const SocketParams& params() const { return params_; }
415
416 private:
417 SocketParams params_;
418 };
419
420 class ConnectJobFactory {
421 public:
422 ConnectJobFactory() {}
423 virtual ~ConnectJobFactory() {}
424
425 virtual ConnectJob* NewConnectJob(
426 const std::string& group_name,
427 const Request& request,
[email protected]fd7b7c92009-08-20 19:38:30428 ConnectJob::Delegate* delegate,
429 LoadLog* load_log) const = 0;
[email protected]d80a4322009-08-14 07:07:49430
431 private:
432 DISALLOW_COPY_AND_ASSIGN(ConnectJobFactory);
433 };
434
[email protected]9bf28db2009-08-29 01:35:16435 // |max_sockets| is the maximum number of sockets to be maintained by this
436 // ClientSocketPool. |max_sockets_per_group| specifies the maximum number of
437 // sockets a "group" can have. |unused_idle_socket_timeout| specifies how
438 // long to leave an unused idle socket open before closing it.
439 // |used_idle_socket_timeout| specifies how long to leave a previously used
440 // idle socket open before closing it.
[email protected]d80a4322009-08-14 07:07:49441 ClientSocketPoolBase(int max_sockets,
442 int max_sockets_per_group,
[email protected]9bf28db2009-08-29 01:35:16443 base::TimeDelta unused_idle_socket_timeout,
444 base::TimeDelta used_idle_socket_timeout,
[email protected]d80a4322009-08-14 07:07:49445 ConnectJobFactory* connect_job_factory)
446 : helper_(new internal::ClientSocketPoolBaseHelper(
447 max_sockets, max_sockets_per_group,
[email protected]9bf28db2009-08-29 01:35:16448 unused_idle_socket_timeout, used_idle_socket_timeout,
[email protected]d80a4322009-08-14 07:07:49449 new ConnectJobFactoryAdaptor(connect_job_factory))) {}
450
[email protected]5a3b9142009-08-28 21:03:17451 ~ClientSocketPoolBase() {}
[email protected]d80a4322009-08-14 07:07:49452
453 // These member functions simply forward to ClientSocketPoolBaseHelper.
454
455 // RequestSocket bundles up the parameters into a Request and then forwards to
456 // ClientSocketPoolBaseHelper::RequestSocket(). Note that the memory
457 // ownership is transferred in the asynchronous (ERR_IO_PENDING) case.
458 int RequestSocket(const std::string& group_name,
459 const SocketParams& params,
460 int priority,
461 ClientSocketHandle* handle,
462 CompletionCallback* callback,
463 LoadLog* load_log) {
464 scoped_ptr<Request> request(
465 new Request(handle, callback, priority, params, load_log));
[email protected]fd7b7c92009-08-20 19:38:30466 LoadLog::BeginEvent(load_log, LoadLog::TYPE_SOCKET_POOL);
[email protected]d80a4322009-08-14 07:07:49467 int rv = helper_->RequestSocket(group_name, request.get());
468 if (rv == ERR_IO_PENDING)
469 request.release();
[email protected]fd7b7c92009-08-20 19:38:30470 else
471 LoadLog::EndEvent(load_log, LoadLog::TYPE_SOCKET_POOL);
[email protected]d80a4322009-08-14 07:07:49472 return rv;
473 }
474
475 void CancelRequest(const std::string& group_name,
476 const ClientSocketHandle* handle) {
477 return helper_->CancelRequest(group_name, handle);
478 }
479
480 void ReleaseSocket(const std::string& group_name, ClientSocket* socket) {
481 return helper_->ReleaseSocket(group_name, socket);
482 }
483
484 void CloseIdleSockets() { return helper_->CloseIdleSockets(); }
485
486 int idle_socket_count() const { return helper_->idle_socket_count(); }
487
488 int IdleSocketCountInGroup(const std::string& group_name) const {
489 return helper_->IdleSocketCountInGroup(group_name);
490 }
491
492 LoadState GetLoadState(const std::string& group_name,
493 const ClientSocketHandle* handle) const {
494 return helper_->GetLoadState(group_name, handle);
495 }
496
497 virtual void OnConnectJobComplete(int result, ConnectJob* job) {
498 return helper_->OnConnectJobComplete(result, job);
499 }
500
501 // For testing.
502 bool may_have_stalled_group() const {
503 return helper_->may_have_stalled_group();
504 }
505
506 int NumConnectJobsInGroup(const std::string& group_name) const {
507 return helper_->NumConnectJobsInGroup(group_name);
508 }
509
[email protected]9bf28db2009-08-29 01:35:16510 void CleanupIdleSockets(bool force) {
511 return helper_->CleanupIdleSockets(force);
512 }
513
[email protected]d80a4322009-08-14 07:07:49514 private:
515 // This adaptor class exists to bridge the
516 // internal::ClientSocketPoolBaseHelper::ConnectJobFactory and
517 // ClientSocketPoolBase::ConnectJobFactory types, allowing clients to use the
518 // typesafe ClientSocketPoolBase::ConnectJobFactory, rather than having to
519 // static_cast themselves.
520 class ConnectJobFactoryAdaptor
521 : public internal::ClientSocketPoolBaseHelper::ConnectJobFactory {
522 public:
523 typedef typename ClientSocketPoolBase<SocketParams>::ConnectJobFactory
524 ConnectJobFactory;
525
526 explicit ConnectJobFactoryAdaptor(
527 ConnectJobFactory* connect_job_factory)
528 : connect_job_factory_(connect_job_factory) {}
529 virtual ~ConnectJobFactoryAdaptor() {}
530
531 virtual ConnectJob* NewConnectJob(
532 const std::string& group_name,
533 const internal::ClientSocketPoolBaseHelper::Request& request,
[email protected]fd7b7c92009-08-20 19:38:30534 ConnectJob::Delegate* delegate,
535 LoadLog* load_log) const {
[email protected]d80a4322009-08-14 07:07:49536 const Request* casted_request = static_cast<const Request*>(&request);
537 return connect_job_factory_->NewConnectJob(
[email protected]fd7b7c92009-08-20 19:38:30538 group_name, *casted_request, delegate, load_log);
[email protected]d80a4322009-08-14 07:07:49539 }
540
541 const scoped_ptr<ConnectJobFactory> connect_job_factory_;
542 };
543
544 // One might ask why ClientSocketPoolBaseHelper is also refcounted if its
545 // containing ClientSocketPool is already refcounted. The reason is because
546 // DoReleaseSocket() posts a task. If ClientSocketPool gets deleted between
547 // the posting of the task and the execution, then we'll hit the DCHECK that
548 // |ClientSocketPoolBaseHelper::group_map_| is empty.
549 scoped_refptr<internal::ClientSocketPoolBaseHelper> helper_;
550
[email protected]ff579d42009-06-24 15:47:02551 DISALLOW_COPY_AND_ASSIGN(ClientSocketPoolBase);
552};
553
[email protected]d80a4322009-08-14 07:07:49554// Enables late binding of sockets. In this mode, socket requests are
555// decoupled from socket connection jobs. A socket request may initiate a
556// socket connection job, but there is no guarantee that that socket
557// connection will service the request (for example, a released socket may
558// service the request sooner, or a higher priority request may come in
559// afterward and receive the socket from the job).
560void EnableLateBindingOfSockets(bool enabled);
561
[email protected]ff579d42009-06-24 15:47:02562} // namespace net
563
564#endif // NET_SOCKET_CLIENT_SOCKET_POOL_BASE_H_