| OLD | NEW |
| (Empty) |
| 1 // 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_BASE_TCP_CLIENT_SOCKET_POOL_H_ | |
| 6 #define NET_BASE_TCP_CLIENT_SOCKET_POOL_H_ | |
| 7 | |
| 8 #include <deque> | |
| 9 #include <map> | |
| 10 #include <string> | |
| 11 | |
| 12 #include "base/scoped_ptr.h" | |
| 13 #include "base/timer.h" | |
| 14 #include "net/base/address_list.h" | |
| 15 #include "net/base/client_socket_pool.h" | |
| 16 #include "net/base/host_resolver.h" | |
| 17 | |
| 18 namespace net { | |
| 19 | |
| 20 class ClientSocketFactory; | |
| 21 class ClientSocketPoolBase; | |
| 22 | |
| 23 // ConnectingSocket provides an abstract interface for "connecting" a socket. | |
| 24 // The connection may involve host resolution, tcp connection, ssl connection, | |
| 25 // etc. | |
| 26 class ConnectingSocket { | |
| 27 public: | |
| 28 ConnectingSocket() {} | |
| 29 virtual ~ConnectingSocket() {} | |
| 30 | |
| 31 // Begins connecting the socket. Returns OK on success, ERR_IO_PENDING if it | |
| 32 // cannot complete synchronously without blocking, or another net error code | |
| 33 // on error. | |
| 34 virtual int Connect() = 0; | |
| 35 | |
| 36 private: | |
| 37 DISALLOW_COPY_AND_ASSIGN(ConnectingSocket); | |
| 38 }; | |
| 39 | |
| 40 // TCPConnectingSocket handles the host resolution necessary for socket creation | |
| 41 // and the tcp connect. | |
| 42 class TCPConnectingSocket : public ConnectingSocket { | |
| 43 public: | |
| 44 TCPConnectingSocket(const std::string& group_name, | |
| 45 const HostResolver::RequestInfo& resolve_info, | |
| 46 const ClientSocketHandle* handle, | |
| 47 ClientSocketFactory* client_socket_factory, | |
| 48 ClientSocketPoolBase* pool); | |
| 49 ~TCPConnectingSocket(); | |
| 50 | |
| 51 // ConnectingSocket methods. | |
| 52 | |
| 53 // Begins the host resolution and the TCP connect. Returns OK on success | |
| 54 // and ERR_IO_PENDING if it cannot immediately service the request. | |
| 55 // Otherwise, it returns a net error code. | |
| 56 virtual int Connect(); | |
| 57 | |
| 58 private: | |
| 59 // Handles asynchronous completion of IO. |result| represents the result of | |
| 60 // the IO operation. | |
| 61 void OnIOComplete(int result); | |
| 62 | |
| 63 // Handles both asynchronous and synchronous completion of IO. |result| | |
| 64 // represents the result of the IO operation. |synchronous| indicates | |
| 65 // whether or not the previous IO operation completed synchronously or | |
| 66 // asynchronously. OnIOCompleteInternal returns the result of the next IO | |
| 67 // operation that executes, or just the value of |result|. | |
| 68 int OnIOCompleteInternal(int result, bool synchronous); | |
| 69 | |
| 70 const std::string group_name_; | |
| 71 const HostResolver::RequestInfo resolve_info_; | |
| 72 const ClientSocketHandle* const handle_; | |
| 73 ClientSocketFactory* const client_socket_factory_; | |
| 74 CompletionCallbackImpl<TCPConnectingSocket> callback_; | |
| 75 scoped_ptr<ClientSocket> socket_; | |
| 76 ClientSocketPoolBase* const pool_; | |
| 77 SingleRequestHostResolver resolver_; | |
| 78 AddressList addresses_; | |
| 79 | |
| 80 // The time the Connect() method was called (if it got called). | |
| 81 base::TimeTicks connect_start_time_; | |
| 82 | |
| 83 DISALLOW_COPY_AND_ASSIGN(TCPConnectingSocket); | |
| 84 }; | |
| 85 | |
| 86 // A ClientSocketPoolBase is used to restrict the number of sockets open at | |
| 87 // a time. It also maintains a list of idle persistent sockets. | |
| 88 // | |
| 89 class ClientSocketPoolBase : public base::RefCounted<ClientSocketPoolBase> { | |
| 90 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. | |
| 95 Request() : resolve_info(std::string(), 0) {} | |
| 96 | |
| 97 Request(ClientSocketHandle* handle, | |
| 98 CompletionCallback* callback, | |
| 99 int priority, | |
| 100 const HostResolver::RequestInfo& resolve_info, | |
| 101 LoadState load_state) | |
| 102 : handle(handle), callback(callback), priority(priority), | |
| 103 resolve_info(resolve_info), load_state(load_state) { | |
| 104 } | |
| 105 | |
| 106 ClientSocketHandle* handle; | |
| 107 CompletionCallback* callback; | |
| 108 int priority; | |
| 109 HostResolver::RequestInfo resolve_info; | |
| 110 LoadState load_state; | |
| 111 }; | |
| 112 | |
| 113 class ConnectingSocketFactory { | |
| 114 public: | |
| 115 ConnectingSocketFactory() {} | |
| 116 virtual ~ConnectingSocketFactory() {} | |
| 117 | |
| 118 virtual ConnectingSocket* NewConnectingSocket( | |
| 119 const std::string& group_name, | |
| 120 const Request& request, | |
| 121 ClientSocketPoolBase* pool) const = 0; | |
| 122 | |
| 123 private: | |
| 124 DISALLOW_COPY_AND_ASSIGN(ConnectingSocketFactory); | |
| 125 }; | |
| 126 | |
| 127 ClientSocketPoolBase(int max_sockets_per_group, | |
| 128 HostResolver* host_resolver, | |
| 129 ConnectingSocketFactory* connecting_socket_factory); | |
| 130 | |
| 131 ~ClientSocketPoolBase(); | |
| 132 | |
| 133 int RequestSocket(const std::string& group_name, | |
| 134 const HostResolver::RequestInfo& resolve_info, | |
| 135 int priority, | |
| 136 ClientSocketHandle* handle, | |
| 137 CompletionCallback* callback); | |
| 138 | |
| 139 void CancelRequest(const std::string& group_name, | |
| 140 const ClientSocketHandle* handle); | |
| 141 | |
| 142 void ReleaseSocket(const std::string& group_name, | |
| 143 ClientSocket* socket); | |
| 144 | |
| 145 void CloseIdleSockets(); | |
| 146 | |
| 147 HostResolver* GetHostResolver() const { | |
| 148 return host_resolver_; | |
| 149 } | |
| 150 | |
| 151 int idle_socket_count() const { | |
| 152 return idle_socket_count_; | |
| 153 } | |
| 154 | |
| 155 int IdleSocketCountInGroup(const std::string& group_name) const; | |
| 156 | |
| 157 LoadState GetLoadState(const std::string& group_name, | |
| 158 const ClientSocketHandle* handle) const; | |
| 159 | |
| 160 // Used by ConnectingSocket until we remove the coupling between a specific | |
| 161 // ConnectingSocket and a ClientSocketHandle: | |
| 162 | |
| 163 // Returns NULL if not found. Otherwise it returns the Request* | |
| 164 // corresponding to the ConnectingSocket (keyed by |group_name| and |handle|. | |
| 165 // Note that this pointer may be invalidated after any call that might mutate | |
| 166 // the RequestMap or GroupMap, so the user should not hold onto the pointer | |
| 167 // for long. | |
| 168 Request* GetConnectingRequest(const std::string& group_name, | |
| 169 const ClientSocketHandle* handle); | |
| 170 | |
| 171 // Handles the completed Request corresponding to the ConnectingSocket (keyed | |
| 172 // by |group_name| and |handle|. |deactivate| indicates whether or not to | |
| 173 // deactivate the socket, making the socket slot available for a new socket | |
| 174 // connection. If |deactivate| is false, then set |socket| into |handle|. | |
| 175 // Returns the callback to run. | |
| 176 CompletionCallback* OnConnectingRequestComplete( | |
| 177 const std::string& group_name, | |
| 178 const ClientSocketHandle* handle, | |
| 179 bool deactivate, | |
| 180 ClientSocket* socket); | |
| 181 | |
| 182 private: | |
| 183 // Entry for a persistent socket which became idle at time |start_time|. | |
| 184 struct IdleSocket { | |
| 185 ClientSocket* socket; | |
| 186 base::TimeTicks start_time; | |
| 187 | |
| 188 // An idle socket should be removed if it can't be reused, or has been idle | |
| 189 // for too long. |now| is the current time value (TimeTicks::Now()). | |
| 190 // | |
| 191 // An idle socket can't be reused if it is disconnected or has received | |
| 192 // data unexpectedly (hence no longer idle). The unread data would be | |
| 193 // mistaken for the beginning of the next response if we were to reuse the | |
| 194 // socket for a new request. | |
| 195 bool ShouldCleanup(base::TimeTicks now) const; | |
| 196 }; | |
| 197 | |
| 198 typedef std::deque<Request> RequestQueue; | |
| 199 typedef std::map<const ClientSocketHandle*, Request> RequestMap; | |
| 200 | |
| 201 // A Group is allocated per group_name when there are idle sockets or pending | |
| 202 // requests. Otherwise, the Group object is removed from the map. | |
| 203 struct Group { | |
| 204 Group() : active_socket_count(0), sockets_handed_out_count(0) {} | |
| 205 std::deque<IdleSocket> idle_sockets; | |
| 206 RequestQueue pending_requests; | |
| 207 RequestMap connecting_requests; | |
| 208 int active_socket_count; // number of active sockets | |
| 209 int sockets_handed_out_count; // number of sockets given to clients | |
| 210 }; | |
| 211 | |
| 212 typedef std::map<std::string, Group> GroupMap; | |
| 213 | |
| 214 typedef std::map<const ClientSocketHandle*, ConnectingSocket*> | |
| 215 ConnectingSocketMap; | |
| 216 | |
| 217 static void InsertRequestIntoQueue(const Request& r, | |
| 218 RequestQueue* pending_requests); | |
| 219 | |
| 220 // Closes all idle sockets if |force| is true. Else, only closes idle | |
| 221 // sockets that timed out or can't be reused. | |
| 222 void CleanupIdleSockets(bool force); | |
| 223 | |
| 224 // Called when the number of idle sockets changes. | |
| 225 void IncrementIdleCount(); | |
| 226 void DecrementIdleCount(); | |
| 227 | |
| 228 // Called via PostTask by ReleaseSocket. | |
| 229 void DoReleaseSocket(const std::string& group_name, ClientSocket* socket); | |
| 230 | |
| 231 // Called when timer_ fires. This method scans the idle sockets removing | |
| 232 // sockets that timed out or can't be reused. | |
| 233 void OnCleanupTimerFired() { | |
| 234 CleanupIdleSockets(false); | |
| 235 } | |
| 236 | |
| 237 // Removes the ConnectingSocket corresponding to |handle| from the | |
| 238 // |connecting_socket_map_|. | |
| 239 void RemoveConnectingSocket(const ClientSocketHandle* handle); | |
| 240 | |
| 241 static void CheckSocketCounts(const Group& group); | |
| 242 | |
| 243 // Process a request from a group's pending_requests queue. | |
| 244 void ProcessPendingRequest(const std::string& group_name, Group* group); | |
| 245 | |
| 246 GroupMap group_map_; | |
| 247 | |
| 248 ConnectingSocketMap connecting_socket_map_; | |
| 249 | |
| 250 // Timer used to periodically prune idle sockets that timed out or can't be | |
| 251 // reused. | |
| 252 base::RepeatingTimer<ClientSocketPoolBase> timer_; | |
| 253 | |
| 254 // The total number of idle sockets in the system. | |
| 255 int idle_socket_count_; | |
| 256 | |
| 257 // The maximum number of sockets kept per group. | |
| 258 const int max_sockets_per_group_; | |
| 259 | |
| 260 // The host resolver that will be used to do DNS lookups for connecting | |
| 261 // sockets. | |
| 262 HostResolver* const host_resolver_; | |
| 263 | |
| 264 scoped_ptr<ConnectingSocketFactory> connecting_socket_factory_; | |
| 265 | |
| 266 DISALLOW_COPY_AND_ASSIGN(ClientSocketPoolBase); | |
| 267 }; | |
| 268 | |
| 269 class TCPClientSocketPool : public ClientSocketPool { | |
| 270 public: | |
| 271 TCPClientSocketPool(int max_sockets_per_group, | |
| 272 HostResolver* host_resolver, | |
| 273 ClientSocketFactory* client_socket_factory); | |
| 274 | |
| 275 // ClientSocketPool methods: | |
| 276 | |
| 277 virtual int RequestSocket(const std::string& group_name, | |
| 278 const HostResolver::RequestInfo& resolve_info, | |
| 279 int priority, | |
| 280 ClientSocketHandle* handle, | |
| 281 CompletionCallback* callback); | |
| 282 | |
| 283 virtual void CancelRequest(const std::string& group_name, | |
| 284 const ClientSocketHandle* handle); | |
| 285 | |
| 286 virtual void ReleaseSocket(const std::string& group_name, | |
| 287 ClientSocket* socket); | |
| 288 | |
| 289 virtual void CloseIdleSockets(); | |
| 290 | |
| 291 virtual HostResolver* GetHostResolver() const { | |
| 292 return base_->GetHostResolver(); | |
| 293 } | |
| 294 | |
| 295 virtual int IdleSocketCount() const { | |
| 296 return base_->idle_socket_count(); | |
| 297 } | |
| 298 | |
| 299 virtual int IdleSocketCountInGroup(const std::string& group_name) const; | |
| 300 | |
| 301 virtual LoadState GetLoadState(const std::string& group_name, | |
| 302 const ClientSocketHandle* handle) const; | |
| 303 | |
| 304 private: | |
| 305 virtual ~TCPClientSocketPool(); | |
| 306 | |
| 307 class TCPConnectingSocketFactory | |
| 308 : public ClientSocketPoolBase::ConnectingSocketFactory { | |
| 309 public: | |
| 310 TCPConnectingSocketFactory(ClientSocketFactory* client_socket_factory) | |
| 311 : client_socket_factory_(client_socket_factory) {} | |
| 312 | |
| 313 virtual ~TCPConnectingSocketFactory() {} | |
| 314 | |
| 315 // ClientSocketPoolBase::ConnectingSocketFactory methods. | |
| 316 | |
| 317 virtual ConnectingSocket* NewConnectingSocket( | |
| 318 const std::string& group_name, | |
| 319 const ClientSocketPoolBase::Request& request, | |
| 320 ClientSocketPoolBase* pool) const; | |
| 321 | |
| 322 private: | |
| 323 ClientSocketFactory* const client_socket_factory_; | |
| 324 | |
| 325 DISALLOW_COPY_AND_ASSIGN(TCPConnectingSocketFactory); | |
| 326 }; | |
| 327 | |
| 328 // One might ask why ClientSocketPoolBase is also refcounted if its | |
| 329 // containing ClientSocketPool is already refcounted. The reason is because | |
| 330 // DoReleaseSocket() posts a task. If ClientSocketPool gets deleted between | |
| 331 // the posting of the task and the execution, then we'll hit the DCHECK that | |
| 332 // |ClientSocketPoolBase::group_map_| is empty. | |
| 333 scoped_refptr<ClientSocketPoolBase> base_; | |
| 334 | |
| 335 DISALLOW_COPY_AND_ASSIGN(TCPClientSocketPool); | |
| 336 }; | |
| 337 | |
| 338 } // namespace net | |
| 339 | |
| 340 #endif // NET_BASE_TCP_CLIENT_SOCKET_POOL_H_ | |
| OLD | NEW |