blob: fc3582daddf1e78ca3196a58f92b6dd4a9aa3ad3 [file] [log] [blame]
[email protected]ff579d42009-06-24 15:47:021// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#ifndef NET_SOCKET_CLIENT_SOCKET_POOL_BASE_H_
6#define NET_SOCKET_CLIENT_SOCKET_POOL_BASE_H_
7
8#include <deque>
9#include <map>
[email protected]5fc08e32009-07-15 17:09:5710#include <set>
[email protected]ff579d42009-06-24 15:47:0211#include <string>
12
13#include "base/basictypes.h"
14#include "base/scoped_ptr.h"
15#include "base/time.h"
16#include "base/timer.h"
17#include "net/base/address_list.h"
18#include "net/base/completion_callback.h"
19#include "net/base/host_resolver.h"
20#include "net/base/load_states.h"
[email protected]2ab05b52009-07-01 23:57:5821#include "net/socket/client_socket.h"
[email protected]ff579d42009-06-24 15:47:0222#include "net/socket/client_socket_pool.h"
23
24namespace net {
25
[email protected]ff579d42009-06-24 15:47:0226class ClientSocketHandle;
27class ClientSocketPoolBase;
28
29// ConnectJob provides an abstract interface for "connecting" a socket.
30// The connection may involve host resolution, tcp connection, ssl connection,
31// etc.
32class ConnectJob {
33 public:
[email protected]ab838892009-06-30 18:49:0534 class Delegate {
35 public:
36 Delegate() {}
37 virtual ~Delegate() {}
38
[email protected]2ab05b52009-07-01 23:57:5839 // Alerts the delegate that the connection completed.
40 virtual void OnConnectJobComplete(int result, ConnectJob* job) = 0;
[email protected]ab838892009-06-30 18:49:0541
42 private:
43 DISALLOW_COPY_AND_ASSIGN(Delegate);
44 };
45
[email protected]2ab05b52009-07-01 23:57:5846 ConnectJob(const std::string& group_name,
47 const ClientSocketHandle* key_handle,
48 Delegate* delegate);
49 virtual ~ConnectJob();
[email protected]ff579d42009-06-24 15:47:0250
[email protected]2ab05b52009-07-01 23:57:5851 // Accessors
52 const std::string& group_name() const { return group_name_; }
[email protected]ab838892009-06-30 18:49:0553 LoadState load_state() const { return load_state_; }
[email protected]2ab05b52009-07-01 23:57:5854 const ClientSocketHandle* key_handle() const { return key_handle_; }
55
[email protected]8e12ae02009-07-02 16:15:0456 // Releases |socket_| to the client. On connection error, this should return
57 // NULL.
[email protected]2ab05b52009-07-01 23:57:5858 ClientSocket* ReleaseSocket() { return socket_.release(); }
[email protected]ab838892009-06-30 18:49:0559
[email protected]ff579d42009-06-24 15:47:0260 // Begins connecting the socket. Returns OK on success, ERR_IO_PENDING if it
61 // cannot complete synchronously without blocking, or another net error code
[email protected]2ab05b52009-07-01 23:57:5862 // on error. In asynchronous completion, the ConnectJob will notify
63 // |delegate_| via OnConnectJobComplete. In both asynchronous and synchronous
64 // completion, ReleaseSocket() can be called to acquire the connected socket
65 // if it succeeded.
[email protected]ff579d42009-06-24 15:47:0266 virtual int Connect() = 0;
67
[email protected]ab838892009-06-30 18:49:0568 protected:
69 void set_load_state(LoadState load_state) { load_state_ = load_state; }
[email protected]2ab05b52009-07-01 23:57:5870 void set_socket(ClientSocket* socket) { socket_.reset(socket); }
71 ClientSocket* socket() { return socket_.get(); }
72 Delegate* delegate() { return delegate_; }
[email protected]ab838892009-06-30 18:49:0573
[email protected]ff579d42009-06-24 15:47:0274 private:
[email protected]2ab05b52009-07-01 23:57:5875 const std::string group_name_;
76 // Temporarily needed until we switch to late binding.
77 const ClientSocketHandle* const key_handle_;
78 Delegate* const delegate_;
[email protected]ab838892009-06-30 18:49:0579 LoadState load_state_;
[email protected]2ab05b52009-07-01 23:57:5880 scoped_ptr<ClientSocket> socket_;
[email protected]ab838892009-06-30 18:49:0581
[email protected]ff579d42009-06-24 15:47:0282 DISALLOW_COPY_AND_ASSIGN(ConnectJob);
83};
84
85// A ClientSocketPoolBase is used to restrict the number of sockets open at
86// a time. It also maintains a list of idle persistent sockets.
87//
[email protected]ab838892009-06-30 18:49:0588class ClientSocketPoolBase
89 : public base::RefCounted<ClientSocketPoolBase>,
90 public ConnectJob::Delegate {
[email protected]ff579d42009-06-24 15:47:0291 public:
92 // A Request is allocated per call to RequestSocket that results in
93 // ERR_IO_PENDING.
94 struct Request {
95 // HostResolver::RequestInfo has no default constructor, so fudge something.
[email protected]3a6bc9042009-07-06 18:32:2196 Request()
97 : handle(NULL),
98 callback(NULL),
99 priority(0),
100 resolve_info(std::string(), 0) {}
[email protected]ff579d42009-06-24 15:47:02101
102 Request(ClientSocketHandle* handle,
103 CompletionCallback* callback,
104 int priority,
[email protected]ab838892009-06-30 18:49:05105 const HostResolver::RequestInfo& resolve_info)
[email protected]ff579d42009-06-24 15:47:02106 : handle(handle), callback(callback), priority(priority),
[email protected]ab838892009-06-30 18:49:05107 resolve_info(resolve_info) {
[email protected]ff579d42009-06-24 15:47:02108 }
109
110 ClientSocketHandle* handle;
111 CompletionCallback* callback;
112 int priority;
113 HostResolver::RequestInfo resolve_info;
[email protected]ff579d42009-06-24 15:47:02114 };
115
116 class ConnectJobFactory {
117 public:
118 ConnectJobFactory() {}
119 virtual ~ConnectJobFactory() {}
120
121 virtual ConnectJob* NewConnectJob(
122 const std::string& group_name,
123 const Request& request,
[email protected]ab838892009-06-30 18:49:05124 ConnectJob::Delegate* delegate) const = 0;
[email protected]ff579d42009-06-24 15:47:02125
126 private:
127 DISALLOW_COPY_AND_ASSIGN(ConnectJobFactory);
128 };
129
130 ClientSocketPoolBase(int max_sockets_per_group,
[email protected]ff579d42009-06-24 15:47:02131 ConnectJobFactory* connect_job_factory);
132
133 ~ClientSocketPoolBase();
134
135 int RequestSocket(const std::string& group_name,
136 const HostResolver::RequestInfo& resolve_info,
137 int priority,
138 ClientSocketHandle* handle,
139 CompletionCallback* callback);
140
141 void CancelRequest(const std::string& group_name,
142 const ClientSocketHandle* handle);
143
144 void ReleaseSocket(const std::string& group_name,
145 ClientSocket* socket);
146
147 void CloseIdleSockets();
148
[email protected]ff579d42009-06-24 15:47:02149 int idle_socket_count() const {
150 return idle_socket_count_;
151 }
152
[email protected]c9d6a1d2009-07-14 16:15:20153 int max_sockets_per_group() const {
154 return max_sockets_per_group_;
155 }
156
[email protected]ff579d42009-06-24 15:47:02157 int IdleSocketCountInGroup(const std::string& group_name) const;
158
159 LoadState GetLoadState(const std::string& group_name,
160 const ClientSocketHandle* handle) const;
161
[email protected]2ab05b52009-07-01 23:57:58162 virtual void OnConnectJobComplete(int result, ConnectJob* job);
[email protected]ff579d42009-06-24 15:47:02163
[email protected]5fc08e32009-07-15 17:09:57164 // Enables late binding of sockets. In this mode, socket requests are
165 // decoupled from socket connection jobs. A socket request may initiate a
166 // socket connection job, but there is no guarantee that that socket
167 // connection will service the request (for example, a released socket may
168 // service the request sooner, or a higher priority request may come in
169 // afterward and receive the socket from the job).
170 static void EnableLateBindingOfSockets(bool enabled);
171
[email protected]ff579d42009-06-24 15:47:02172 private:
173 // Entry for a persistent socket which became idle at time |start_time|.
174 struct IdleSocket {
[email protected]5fc08e32009-07-15 17:09:57175 IdleSocket() : socket(NULL), used(false) {}
[email protected]ff579d42009-06-24 15:47:02176 ClientSocket* socket;
177 base::TimeTicks start_time;
[email protected]5fc08e32009-07-15 17:09:57178 bool used; // Indicates whether or not the socket has been used yet.
[email protected]ff579d42009-06-24 15:47:02179
180 // An idle socket should be removed if it can't be reused, or has been idle
181 // for too long. |now| is the current time value (TimeTicks::Now()).
182 //
183 // An idle socket can't be reused if it is disconnected or has received
184 // data unexpectedly (hence no longer idle). The unread data would be
185 // mistaken for the beginning of the next response if we were to reuse the
186 // socket for a new request.
187 bool ShouldCleanup(base::TimeTicks now) const;
188 };
189
190 typedef std::deque<Request> RequestQueue;
191 typedef std::map<const ClientSocketHandle*, Request> RequestMap;
192
193 // A Group is allocated per group_name when there are idle sockets or pending
194 // requests. Otherwise, the Group object is removed from the map.
195 struct Group {
[email protected]2ab05b52009-07-01 23:57:58196 Group() : active_socket_count(0) {}
197
198 bool IsEmpty() const {
[email protected]5fc08e32009-07-15 17:09:57199 return active_socket_count == 0 && idle_sockets.empty() && jobs.empty();
[email protected]2ab05b52009-07-01 23:57:58200 }
201
202 bool HasAvailableSocketSlot(int max_sockets_per_group) const {
[email protected]5fc08e32009-07-15 17:09:57203 return active_socket_count + static_cast<int>(jobs.size()) <
[email protected]2ab05b52009-07-01 23:57:58204 max_sockets_per_group;
205 }
206
[email protected]ff579d42009-06-24 15:47:02207 std::deque<IdleSocket> idle_sockets;
[email protected]5fc08e32009-07-15 17:09:57208 std::set<const ConnectJob*> jobs;
[email protected]ff579d42009-06-24 15:47:02209 RequestQueue pending_requests;
210 RequestMap connecting_requests;
[email protected]2ab05b52009-07-01 23:57:58211 int active_socket_count; // number of active sockets used by clients
[email protected]ff579d42009-06-24 15:47:02212 };
213
214 typedef std::map<std::string, Group> GroupMap;
215
216 typedef std::map<const ClientSocketHandle*, ConnectJob*> ConnectJobMap;
[email protected]5fc08e32009-07-15 17:09:57217 typedef std::set<const ConnectJob*> ConnectJobSet;
[email protected]ff579d42009-06-24 15:47:02218
219 static void InsertRequestIntoQueue(const Request& r,
220 RequestQueue* pending_requests);
221
222 // Closes all idle sockets if |force| is true. Else, only closes idle
223 // sockets that timed out or can't be reused.
224 void CleanupIdleSockets(bool force);
225
226 // Called when the number of idle sockets changes.
227 void IncrementIdleCount();
228 void DecrementIdleCount();
229
230 // Called via PostTask by ReleaseSocket.
231 void DoReleaseSocket(const std::string& group_name, ClientSocket* socket);
232
233 // Called when timer_ fires. This method scans the idle sockets removing
234 // sockets that timed out or can't be reused.
235 void OnCleanupTimerFired() {
236 CleanupIdleSockets(false);
237 }
238
239 // Removes the ConnectJob corresponding to |handle| from the
[email protected]5fc08e32009-07-15 17:09:57240 // |connect_job_map_| or |connect_job_set_| depending on whether or not late
241 // binding is enabled. |job| must be non-NULL when late binding is
242 // enabled. Also updates |group| if non-NULL.
243 void RemoveConnectJob(const ClientSocketHandle* handle,
244 ConnectJob* job,
245 Group* group);
[email protected]ff579d42009-06-24 15:47:02246
[email protected]2ab05b52009-07-01 23:57:58247 // Same as OnAvailableSocketSlot except it looks up the Group first to see if
248 // it's there.
249 void MaybeOnAvailableSocketSlot(const std::string& group_name);
[email protected]ff579d42009-06-24 15:47:02250
[email protected]2ab05b52009-07-01 23:57:58251 // Might delete the Group from |group_map_|.
252 void OnAvailableSocketSlot(const std::string& group_name, Group* group);
[email protected]ff579d42009-06-24 15:47:02253
254 // Process a request from a group's pending_requests queue.
255 void ProcessPendingRequest(const std::string& group_name, Group* group);
256
[email protected]2ab05b52009-07-01 23:57:58257 // Assigns |socket| to |handle| and updates |group|'s counters appropriately.
258 void HandOutSocket(ClientSocket* socket,
259 bool reused,
260 ClientSocketHandle* handle,
261 Group* group);
262
[email protected]5fc08e32009-07-15 17:09:57263 // Adds |socket| to the list of idle sockets for |group|. |used| indicates
264 // whether or not the socket has previously been used.
265 void AddIdleSocket(ClientSocket* socket, bool used, Group* group);
266
267 // Iterates through |connect_job_map_|, canceling all ConnectJobs.
268 // Afterwards, it iterates through all groups and deletes them if they are no
269 // longer needed.
270 void CancelAllConnectJobs();
271
[email protected]ff579d42009-06-24 15:47:02272 GroupMap group_map_;
273
274 ConnectJobMap connect_job_map_;
275
276 // Timer used to periodically prune idle sockets that timed out or can't be
277 // reused.
278 base::RepeatingTimer<ClientSocketPoolBase> timer_;
279
280 // The total number of idle sockets in the system.
281 int idle_socket_count_;
282
283 // The maximum number of sockets kept per group.
284 const int max_sockets_per_group_;
285
[email protected]ab838892009-06-30 18:49:05286 const scoped_ptr<ConnectJobFactory> connect_job_factory_;
[email protected]ff579d42009-06-24 15:47:02287
[email protected]5fc08e32009-07-15 17:09:57288 // Controls whether or not we use late binding of sockets.
289 static bool g_late_binding;
290
[email protected]ff579d42009-06-24 15:47:02291 DISALLOW_COPY_AND_ASSIGN(ClientSocketPoolBase);
292};
293
294} // namespace net
295
296#endif // NET_SOCKET_CLIENT_SOCKET_POOL_BASE_H_