blob: 54e939666707f37d7c2388700a52b27b16febcf2 [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>
10#include <string>
11
12#include "base/basictypes.h"
13#include "base/scoped_ptr.h"
14#include "base/time.h"
15#include "base/timer.h"
16#include "net/base/address_list.h"
17#include "net/base/completion_callback.h"
18#include "net/base/host_resolver.h"
19#include "net/base/load_states.h"
[email protected]2ab05b52009-07-01 23:57:5820#include "net/socket/client_socket.h"
[email protected]ff579d42009-06-24 15:47:0221#include "net/socket/client_socket_pool.h"
22
23namespace net {
24
[email protected]ff579d42009-06-24 15:47:0225class ClientSocketHandle;
26class ClientSocketPoolBase;
27
28// ConnectJob provides an abstract interface for "connecting" a socket.
29// The connection may involve host resolution, tcp connection, ssl connection,
30// etc.
31class ConnectJob {
32 public:
[email protected]ab838892009-06-30 18:49:0533 class Delegate {
34 public:
35 Delegate() {}
36 virtual ~Delegate() {}
37
[email protected]2ab05b52009-07-01 23:57:5838 // Alerts the delegate that the connection completed.
39 virtual void OnConnectJobComplete(int result, ConnectJob* job) = 0;
[email protected]ab838892009-06-30 18:49:0540
41 private:
42 DISALLOW_COPY_AND_ASSIGN(Delegate);
43 };
44
[email protected]2ab05b52009-07-01 23:57:5845 ConnectJob(const std::string& group_name,
46 const ClientSocketHandle* key_handle,
47 Delegate* delegate);
48 virtual ~ConnectJob();
[email protected]ff579d42009-06-24 15:47:0249
[email protected]2ab05b52009-07-01 23:57:5850 // Accessors
51 const std::string& group_name() const { return group_name_; }
[email protected]ab838892009-06-30 18:49:0552 LoadState load_state() const { return load_state_; }
[email protected]2ab05b52009-07-01 23:57:5853 const ClientSocketHandle* key_handle() const { return key_handle_; }
54
[email protected]8e12ae02009-07-02 16:15:0455 // Releases |socket_| to the client. On connection error, this should return
56 // NULL.
[email protected]2ab05b52009-07-01 23:57:5857 ClientSocket* ReleaseSocket() { return socket_.release(); }
[email protected]ab838892009-06-30 18:49:0558
[email protected]ff579d42009-06-24 15:47:0259 // Begins connecting the socket. Returns OK on success, ERR_IO_PENDING if it
60 // cannot complete synchronously without blocking, or another net error code
[email protected]2ab05b52009-07-01 23:57:5861 // on error. In asynchronous completion, the ConnectJob will notify
62 // |delegate_| via OnConnectJobComplete. In both asynchronous and synchronous
63 // completion, ReleaseSocket() can be called to acquire the connected socket
64 // if it succeeded.
[email protected]ff579d42009-06-24 15:47:0265 virtual int Connect() = 0;
66
[email protected]ab838892009-06-30 18:49:0567 protected:
68 void set_load_state(LoadState load_state) { load_state_ = load_state; }
[email protected]2ab05b52009-07-01 23:57:5869 void set_socket(ClientSocket* socket) { socket_.reset(socket); }
70 ClientSocket* socket() { return socket_.get(); }
71 Delegate* delegate() { return delegate_; }
[email protected]ab838892009-06-30 18:49:0572
[email protected]ff579d42009-06-24 15:47:0273 private:
[email protected]2ab05b52009-07-01 23:57:5874 const std::string group_name_;
75 // Temporarily needed until we switch to late binding.
76 const ClientSocketHandle* const key_handle_;
77 Delegate* const delegate_;
[email protected]ab838892009-06-30 18:49:0578 LoadState load_state_;
[email protected]2ab05b52009-07-01 23:57:5879 scoped_ptr<ClientSocket> socket_;
[email protected]ab838892009-06-30 18:49:0580
[email protected]ff579d42009-06-24 15:47:0281 DISALLOW_COPY_AND_ASSIGN(ConnectJob);
82};
83
84// A ClientSocketPoolBase is used to restrict the number of sockets open at
85// a time. It also maintains a list of idle persistent sockets.
86//
[email protected]ab838892009-06-30 18:49:0587class ClientSocketPoolBase
88 : public base::RefCounted<ClientSocketPoolBase>,
89 public ConnectJob::Delegate {
[email protected]ff579d42009-06-24 15:47:0290 public:
91 // A Request is allocated per call to RequestSocket that results in
92 // ERR_IO_PENDING.
93 struct Request {
94 // HostResolver::RequestInfo has no default constructor, so fudge something.
[email protected]3a6bc9042009-07-06 18:32:2195 Request()
96 : handle(NULL),
97 callback(NULL),
98 priority(0),
99 resolve_info(std::string(), 0) {}
[email protected]ff579d42009-06-24 15:47:02100
101 Request(ClientSocketHandle* handle,
102 CompletionCallback* callback,
103 int priority,
[email protected]ab838892009-06-30 18:49:05104 const HostResolver::RequestInfo& resolve_info)
[email protected]ff579d42009-06-24 15:47:02105 : handle(handle), callback(callback), priority(priority),
[email protected]ab838892009-06-30 18:49:05106 resolve_info(resolve_info) {
[email protected]ff579d42009-06-24 15:47:02107 }
108
109 ClientSocketHandle* handle;
110 CompletionCallback* callback;
111 int priority;
112 HostResolver::RequestInfo resolve_info;
[email protected]ff579d42009-06-24 15:47:02113 };
114
115 class ConnectJobFactory {
116 public:
117 ConnectJobFactory() {}
118 virtual ~ConnectJobFactory() {}
119
120 virtual ConnectJob* NewConnectJob(
121 const std::string& group_name,
122 const Request& request,
[email protected]ab838892009-06-30 18:49:05123 ConnectJob::Delegate* delegate) const = 0;
[email protected]ff579d42009-06-24 15:47:02124
125 private:
126 DISALLOW_COPY_AND_ASSIGN(ConnectJobFactory);
127 };
128
129 ClientSocketPoolBase(int max_sockets_per_group,
[email protected]ff579d42009-06-24 15:47:02130 ConnectJobFactory* connect_job_factory);
131
132 ~ClientSocketPoolBase();
133
134 int RequestSocket(const std::string& group_name,
135 const HostResolver::RequestInfo& resolve_info,
136 int priority,
137 ClientSocketHandle* handle,
138 CompletionCallback* callback);
139
140 void CancelRequest(const std::string& group_name,
141 const ClientSocketHandle* handle);
142
143 void ReleaseSocket(const std::string& group_name,
144 ClientSocket* socket);
145
146 void CloseIdleSockets();
147
[email protected]ff579d42009-06-24 15:47:02148 int idle_socket_count() const {
149 return idle_socket_count_;
150 }
151
152 int IdleSocketCountInGroup(const std::string& group_name) const;
153
154 LoadState GetLoadState(const std::string& group_name,
155 const ClientSocketHandle* handle) const;
156
[email protected]2ab05b52009-07-01 23:57:58157 virtual void OnConnectJobComplete(int result, ConnectJob* job);
[email protected]ff579d42009-06-24 15:47:02158
159 private:
160 // Entry for a persistent socket which became idle at time |start_time|.
161 struct IdleSocket {
162 ClientSocket* socket;
163 base::TimeTicks start_time;
164
165 // An idle socket should be removed if it can't be reused, or has been idle
166 // for too long. |now| is the current time value (TimeTicks::Now()).
167 //
168 // An idle socket can't be reused if it is disconnected or has received
169 // data unexpectedly (hence no longer idle). The unread data would be
170 // mistaken for the beginning of the next response if we were to reuse the
171 // socket for a new request.
172 bool ShouldCleanup(base::TimeTicks now) const;
173 };
174
175 typedef std::deque<Request> RequestQueue;
176 typedef std::map<const ClientSocketHandle*, Request> RequestMap;
177
178 // A Group is allocated per group_name when there are idle sockets or pending
179 // requests. Otherwise, the Group object is removed from the map.
180 struct Group {
[email protected]2ab05b52009-07-01 23:57:58181 Group() : active_socket_count(0) {}
182
183 bool IsEmpty() const {
184 return active_socket_count == 0 && idle_sockets.empty() &&
185 connecting_requests.empty();
186 }
187
188 bool HasAvailableSocketSlot(int max_sockets_per_group) const {
189 return active_socket_count +
190 static_cast<int>(connecting_requests.size()) <
191 max_sockets_per_group;
192 }
193
[email protected]ff579d42009-06-24 15:47:02194 std::deque<IdleSocket> idle_sockets;
195 RequestQueue pending_requests;
196 RequestMap connecting_requests;
[email protected]2ab05b52009-07-01 23:57:58197 int active_socket_count; // number of active sockets used by clients
[email protected]ff579d42009-06-24 15:47:02198 };
199
200 typedef std::map<std::string, Group> GroupMap;
201
202 typedef std::map<const ClientSocketHandle*, ConnectJob*> ConnectJobMap;
203
204 static void InsertRequestIntoQueue(const Request& r,
205 RequestQueue* pending_requests);
206
207 // Closes all idle sockets if |force| is true. Else, only closes idle
208 // sockets that timed out or can't be reused.
209 void CleanupIdleSockets(bool force);
210
211 // Called when the number of idle sockets changes.
212 void IncrementIdleCount();
213 void DecrementIdleCount();
214
215 // Called via PostTask by ReleaseSocket.
216 void DoReleaseSocket(const std::string& group_name, ClientSocket* socket);
217
218 // Called when timer_ fires. This method scans the idle sockets removing
219 // sockets that timed out or can't be reused.
220 void OnCleanupTimerFired() {
221 CleanupIdleSockets(false);
222 }
223
224 // Removes the ConnectJob corresponding to |handle| from the
225 // |connect_job_map_|.
226 void RemoveConnectJob(const ClientSocketHandle* handle);
227
[email protected]2ab05b52009-07-01 23:57:58228 // Same as OnAvailableSocketSlot except it looks up the Group first to see if
229 // it's there.
230 void MaybeOnAvailableSocketSlot(const std::string& group_name);
[email protected]ff579d42009-06-24 15:47:02231
[email protected]2ab05b52009-07-01 23:57:58232 // Might delete the Group from |group_map_|.
233 void OnAvailableSocketSlot(const std::string& group_name, Group* group);
[email protected]ff579d42009-06-24 15:47:02234
235 // Process a request from a group's pending_requests queue.
236 void ProcessPendingRequest(const std::string& group_name, Group* group);
237
[email protected]2ab05b52009-07-01 23:57:58238 // Assigns |socket| to |handle| and updates |group|'s counters appropriately.
239 void HandOutSocket(ClientSocket* socket,
240 bool reused,
241 ClientSocketHandle* handle,
242 Group* group);
243
[email protected]ff579d42009-06-24 15:47:02244 GroupMap group_map_;
245
246 ConnectJobMap connect_job_map_;
247
248 // Timer used to periodically prune idle sockets that timed out or can't be
249 // reused.
250 base::RepeatingTimer<ClientSocketPoolBase> timer_;
251
252 // The total number of idle sockets in the system.
253 int idle_socket_count_;
254
255 // The maximum number of sockets kept per group.
256 const int max_sockets_per_group_;
257
[email protected]ab838892009-06-30 18:49:05258 const scoped_ptr<ConnectJobFactory> connect_job_factory_;
[email protected]ff579d42009-06-24 15:47:02259
260 DISALLOW_COPY_AND_ASSIGN(ClientSocketPoolBase);
261};
262
263} // namespace net
264
265#endif // NET_SOCKET_CLIENT_SOCKET_POOL_BASE_H_