| OLD | NEW |
| (Empty) |
| 1 // Copyright (c) 2012 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 // 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 // | |
| 22 #ifndef NET_SOCKET_CLIENT_SOCKET_POOL_BASE_H_ | |
| 23 #define NET_SOCKET_CLIENT_SOCKET_POOL_BASE_H_ | |
| 24 | |
| 25 #include <cstddef> | |
| 26 #include <deque> | |
| 27 #include <list> | |
| 28 #include <map> | |
| 29 #include <set> | |
| 30 #include <string> | |
| 31 #include <vector> | |
| 32 | |
| 33 #include "base/basictypes.h" | |
| 34 #include "base/memory/ref_counted.h" | |
| 35 #include "base/memory/scoped_ptr.h" | |
| 36 #include "base/memory/weak_ptr.h" | |
| 37 #include "base/time/time.h" | |
| 38 #include "base/timer/timer.h" | |
| 39 #include "net/base/address_list.h" | |
| 40 #include "net/base/completion_callback.h" | |
| 41 #include "net/base/load_states.h" | |
| 42 #include "net/base/load_timing_info.h" | |
| 43 #include "net/base/net_errors.h" | |
| 44 #include "net/base/net_export.h" | |
| 45 #include "net/base/net_log.h" | |
| 46 #include "net/base/network_change_notifier.h" | |
| 47 #include "net/base/priority_queue.h" | |
| 48 #include "net/base/request_priority.h" | |
| 49 #include "net/socket/client_socket_handle.h" | |
| 50 #include "net/socket/client_socket_pool.h" | |
| 51 #include "net/socket/stream_socket.h" | |
| 52 | |
| 53 namespace net { | |
| 54 | |
| 55 class ClientSocketHandle; | |
| 56 | |
| 57 // ConnectJob provides an abstract interface for "connecting" a socket. | |
| 58 // The connection may involve host resolution, tcp connection, ssl connection, | |
| 59 // etc. | |
| 60 class NET_EXPORT_PRIVATE ConnectJob { | |
| 61 public: | |
| 62 class NET_EXPORT_PRIVATE Delegate { | |
| 63 public: | |
| 64 Delegate() {} | |
| 65 virtual ~Delegate() {} | |
| 66 | |
| 67 // Alerts the delegate that the connection completed. |job| must | |
| 68 // be destroyed by the delegate. A scoped_ptr<> isn't used because | |
| 69 // the caller of this function doesn't own |job|. | |
| 70 virtual void OnConnectJobComplete(int result, | |
| 71 ConnectJob* job) = 0; | |
| 72 | |
| 73 private: | |
| 74 DISALLOW_COPY_AND_ASSIGN(Delegate); | |
| 75 }; | |
| 76 | |
| 77 // A |timeout_duration| of 0 corresponds to no timeout. | |
| 78 ConnectJob(const std::string& group_name, | |
| 79 base::TimeDelta timeout_duration, | |
| 80 RequestPriority priority, | |
| 81 Delegate* delegate, | |
| 82 const BoundNetLog& net_log); | |
| 83 virtual ~ConnectJob(); | |
| 84 | |
| 85 // Accessors | |
| 86 const std::string& group_name() const { return group_name_; } | |
| 87 const BoundNetLog& net_log() { return net_log_; } | |
| 88 | |
| 89 // Releases ownership of the underlying socket to the caller. | |
| 90 // Returns the released socket, or NULL if there was a connection | |
| 91 // error. | |
| 92 scoped_ptr<StreamSocket> PassSocket(); | |
| 93 | |
| 94 // Begins connecting the socket. Returns OK on success, ERR_IO_PENDING if it | |
| 95 // cannot complete synchronously without blocking, or another net error code | |
| 96 // on error. In asynchronous completion, the ConnectJob will notify | |
| 97 // |delegate_| via OnConnectJobComplete. In both asynchronous and synchronous | |
| 98 // completion, ReleaseSocket() can be called to acquire the connected socket | |
| 99 // if it succeeded. | |
| 100 int Connect(); | |
| 101 | |
| 102 virtual LoadState GetLoadState() const = 0; | |
| 103 | |
| 104 // If Connect returns an error (or OnConnectJobComplete reports an error | |
| 105 // result) this method will be called, allowing the pool to add | |
| 106 // additional error state to the ClientSocketHandle (post late-binding). | |
| 107 virtual void GetAdditionalErrorState(ClientSocketHandle* handle) {} | |
| 108 | |
| 109 const LoadTimingInfo::ConnectTiming& connect_timing() const { | |
| 110 return connect_timing_; | |
| 111 } | |
| 112 | |
| 113 const BoundNetLog& net_log() const { return net_log_; } | |
| 114 | |
| 115 protected: | |
| 116 RequestPriority priority() const { return priority_; } | |
| 117 void SetSocket(scoped_ptr<StreamSocket> socket); | |
| 118 StreamSocket* socket() { return socket_.get(); } | |
| 119 void NotifyDelegateOfCompletion(int rv); | |
| 120 void ResetTimer(base::TimeDelta remainingTime); | |
| 121 | |
| 122 // Connection establishment timing information. | |
| 123 LoadTimingInfo::ConnectTiming connect_timing_; | |
| 124 | |
| 125 private: | |
| 126 virtual int ConnectInternal() = 0; | |
| 127 | |
| 128 void LogConnectStart(); | |
| 129 void LogConnectCompletion(int net_error); | |
| 130 | |
| 131 // Alerts the delegate that the ConnectJob has timed out. | |
| 132 void OnTimeout(); | |
| 133 | |
| 134 const std::string group_name_; | |
| 135 const base::TimeDelta timeout_duration_; | |
| 136 // TODO(akalin): Support reprioritization. | |
| 137 const RequestPriority priority_; | |
| 138 // Timer to abort jobs that take too long. | |
| 139 base::OneShotTimer<ConnectJob> timer_; | |
| 140 Delegate* delegate_; | |
| 141 scoped_ptr<StreamSocket> socket_; | |
| 142 BoundNetLog net_log_; | |
| 143 // A ConnectJob is idle until Connect() has been called. | |
| 144 bool idle_; | |
| 145 | |
| 146 DISALLOW_COPY_AND_ASSIGN(ConnectJob); | |
| 147 }; | |
| 148 | |
| 149 namespace internal { | |
| 150 | |
| 151 // ClientSocketPoolBaseHelper is an internal class that implements almost all | |
| 152 // the functionality from ClientSocketPoolBase without using templates. | |
| 153 // ClientSocketPoolBase adds templated definitions built on top of | |
| 154 // ClientSocketPoolBaseHelper. This class is not for external use, please use | |
| 155 // ClientSocketPoolBase instead. | |
| 156 class NET_EXPORT_PRIVATE ClientSocketPoolBaseHelper | |
| 157 : public ConnectJob::Delegate, | |
| 158 public NetworkChangeNotifier::IPAddressObserver { | |
| 159 public: | |
| 160 typedef uint32 Flags; | |
| 161 | |
| 162 // Used to specify specific behavior for the ClientSocketPool. | |
| 163 enum Flag { | |
| 164 NORMAL = 0, // Normal behavior. | |
| 165 NO_IDLE_SOCKETS = 0x1, // Do not return an idle socket. Create a new one. | |
| 166 }; | |
| 167 | |
| 168 class NET_EXPORT_PRIVATE Request { | |
| 169 public: | |
| 170 Request(ClientSocketHandle* handle, | |
| 171 const CompletionCallback& callback, | |
| 172 RequestPriority priority, | |
| 173 bool ignore_limits, | |
| 174 Flags flags, | |
| 175 const BoundNetLog& net_log); | |
| 176 | |
| 177 virtual ~Request(); | |
| 178 | |
| 179 ClientSocketHandle* handle() const { return handle_; } | |
| 180 const CompletionCallback& callback() const { return callback_; } | |
| 181 RequestPriority priority() const { return priority_; } | |
| 182 bool ignore_limits() const { return ignore_limits_; } | |
| 183 Flags flags() const { return flags_; } | |
| 184 const BoundNetLog& net_log() const { return net_log_; } | |
| 185 | |
| 186 private: | |
| 187 ClientSocketHandle* const handle_; | |
| 188 const CompletionCallback callback_; | |
| 189 // TODO(akalin): Support reprioritization. | |
| 190 const RequestPriority priority_; | |
| 191 const bool ignore_limits_; | |
| 192 const Flags flags_; | |
| 193 const BoundNetLog net_log_; | |
| 194 | |
| 195 DISALLOW_COPY_AND_ASSIGN(Request); | |
| 196 }; | |
| 197 | |
| 198 class ConnectJobFactory { | |
| 199 public: | |
| 200 ConnectJobFactory() {} | |
| 201 virtual ~ConnectJobFactory() {} | |
| 202 | |
| 203 virtual scoped_ptr<ConnectJob> NewConnectJob( | |
| 204 const std::string& group_name, | |
| 205 const Request& request, | |
| 206 ConnectJob::Delegate* delegate) const = 0; | |
| 207 | |
| 208 virtual base::TimeDelta ConnectionTimeout() const = 0; | |
| 209 | |
| 210 private: | |
| 211 DISALLOW_COPY_AND_ASSIGN(ConnectJobFactory); | |
| 212 }; | |
| 213 | |
| 214 ClientSocketPoolBaseHelper( | |
| 215 HigherLayeredPool* pool, | |
| 216 int max_sockets, | |
| 217 int max_sockets_per_group, | |
| 218 base::TimeDelta unused_idle_socket_timeout, | |
| 219 base::TimeDelta used_idle_socket_timeout, | |
| 220 ConnectJobFactory* connect_job_factory); | |
| 221 | |
| 222 ~ClientSocketPoolBaseHelper() override; | |
| 223 | |
| 224 // Adds a lower layered pool to |this|, and adds |this| as a higher layered | |
| 225 // pool on top of |lower_pool|. | |
| 226 void AddLowerLayeredPool(LowerLayeredPool* lower_pool); | |
| 227 | |
| 228 // See LowerLayeredPool::IsStalled for documentation on this function. | |
| 229 bool IsStalled() const; | |
| 230 | |
| 231 // See LowerLayeredPool for documentation on these functions. It is expected | |
| 232 // in the destructor that no higher layer pools remain. | |
| 233 void AddHigherLayeredPool(HigherLayeredPool* higher_pool); | |
| 234 void RemoveHigherLayeredPool(HigherLayeredPool* higher_pool); | |
| 235 | |
| 236 // See ClientSocketPool::RequestSocket for documentation on this function. | |
| 237 int RequestSocket(const std::string& group_name, | |
| 238 scoped_ptr<const Request> request); | |
| 239 | |
| 240 // See ClientSocketPool::RequestSocket for documentation on this function. | |
| 241 void RequestSockets(const std::string& group_name, | |
| 242 const Request& request, | |
| 243 int num_sockets); | |
| 244 | |
| 245 // See ClientSocketPool::CancelRequest for documentation on this function. | |
| 246 void CancelRequest(const std::string& group_name, | |
| 247 ClientSocketHandle* handle); | |
| 248 | |
| 249 // See ClientSocketPool::ReleaseSocket for documentation on this function. | |
| 250 void ReleaseSocket(const std::string& group_name, | |
| 251 scoped_ptr<StreamSocket> socket, | |
| 252 int id); | |
| 253 | |
| 254 // See ClientSocketPool::FlushWithError for documentation on this function. | |
| 255 void FlushWithError(int error); | |
| 256 | |
| 257 // See ClientSocketPool::CloseIdleSockets for documentation on this function. | |
| 258 void CloseIdleSockets(); | |
| 259 | |
| 260 // See ClientSocketPool::IdleSocketCount() for documentation on this function. | |
| 261 int idle_socket_count() const { | |
| 262 return idle_socket_count_; | |
| 263 } | |
| 264 | |
| 265 // See ClientSocketPool::IdleSocketCountInGroup() for documentation on this | |
| 266 // function. | |
| 267 int IdleSocketCountInGroup(const std::string& group_name) const; | |
| 268 | |
| 269 // See ClientSocketPool::GetLoadState() for documentation on this function. | |
| 270 LoadState GetLoadState(const std::string& group_name, | |
| 271 const ClientSocketHandle* handle) const; | |
| 272 | |
| 273 base::TimeDelta ConnectRetryInterval() const { | |
| 274 // TODO(mbelshe): Make this tuned dynamically based on measured RTT. | |
| 275 // For now, just use the max retry interval. | |
| 276 return base::TimeDelta::FromMilliseconds( | |
| 277 ClientSocketPool::kMaxConnectRetryIntervalMs); | |
| 278 } | |
| 279 | |
| 280 int NumUnassignedConnectJobsInGroup(const std::string& group_name) const { | |
| 281 return group_map_.find(group_name)->second->unassigned_job_count(); | |
| 282 } | |
| 283 | |
| 284 int NumConnectJobsInGroup(const std::string& group_name) const { | |
| 285 return group_map_.find(group_name)->second->jobs().size(); | |
| 286 } | |
| 287 | |
| 288 int NumActiveSocketsInGroup(const std::string& group_name) const { | |
| 289 return group_map_.find(group_name)->second->active_socket_count(); | |
| 290 } | |
| 291 | |
| 292 bool HasGroup(const std::string& group_name) const; | |
| 293 | |
| 294 // Called to enable/disable cleaning up idle sockets. When enabled, | |
| 295 // idle sockets that have been around for longer than a period defined | |
| 296 // by kCleanupInterval are cleaned up using a timer. Otherwise they are | |
| 297 // closed next time client makes a request. This may reduce network | |
| 298 // activity and power consumption. | |
| 299 static bool cleanup_timer_enabled(); | |
| 300 static bool set_cleanup_timer_enabled(bool enabled); | |
| 301 | |
| 302 // Closes all idle sockets if |force| is true. Else, only closes idle | |
| 303 // sockets that timed out or can't be reused. Made public for testing. | |
| 304 void CleanupIdleSockets(bool force); | |
| 305 | |
| 306 // Closes one idle socket. Picks the first one encountered. | |
| 307 // TODO(willchan): Consider a better algorithm for doing this. Perhaps we | |
| 308 // should keep an ordered list of idle sockets, and close them in order. | |
| 309 // Requires maintaining more state. It's not clear if it's worth it since | |
| 310 // I'm not sure if we hit this situation often. | |
| 311 bool CloseOneIdleSocket(); | |
| 312 | |
| 313 // Checks higher layered pools to see if they can close an idle connection. | |
| 314 bool CloseOneIdleConnectionInHigherLayeredPool(); | |
| 315 | |
| 316 // See ClientSocketPool::GetInfoAsValue for documentation on this function. | |
| 317 base::DictionaryValue* GetInfoAsValue(const std::string& name, | |
| 318 const std::string& type) const; | |
| 319 | |
| 320 base::TimeDelta ConnectionTimeout() const { | |
| 321 return connect_job_factory_->ConnectionTimeout(); | |
| 322 } | |
| 323 | |
| 324 static bool connect_backup_jobs_enabled(); | |
| 325 static bool set_connect_backup_jobs_enabled(bool enabled); | |
| 326 | |
| 327 void EnableConnectBackupJobs(); | |
| 328 | |
| 329 // ConnectJob::Delegate methods: | |
| 330 void OnConnectJobComplete(int result, ConnectJob* job) override; | |
| 331 | |
| 332 // NetworkChangeNotifier::IPAddressObserver methods: | |
| 333 void OnIPAddressChanged() override; | |
| 334 | |
| 335 private: | |
| 336 friend class base::RefCounted<ClientSocketPoolBaseHelper>; | |
| 337 | |
| 338 // Entry for a persistent socket which became idle at time |start_time|. | |
| 339 struct IdleSocket { | |
| 340 IdleSocket() : socket(NULL) {} | |
| 341 | |
| 342 // An idle socket can't be used if it is disconnected or has been used | |
| 343 // before and has received data unexpectedly (hence no longer idle). The | |
| 344 // unread data would be mistaken for the beginning of the next response if | |
| 345 // we were to use the socket for a new request. | |
| 346 // | |
| 347 // Note that a socket that has never been used before (like a preconnected | |
| 348 // socket) may be used even with unread data. This may be, e.g., a SPDY | |
| 349 // SETTINGS frame. | |
| 350 bool IsUsable() const; | |
| 351 | |
| 352 // An idle socket should be removed if it can't be reused, or has been idle | |
| 353 // for too long. |now| is the current time value (TimeTicks::Now()). | |
| 354 // |timeout| is the length of time to wait before timing out an idle socket. | |
| 355 bool ShouldCleanup(base::TimeTicks now, base::TimeDelta timeout) const; | |
| 356 | |
| 357 StreamSocket* socket; | |
| 358 base::TimeTicks start_time; | |
| 359 }; | |
| 360 | |
| 361 typedef PriorityQueue<const Request*> RequestQueue; | |
| 362 typedef std::map<const ClientSocketHandle*, const Request*> RequestMap; | |
| 363 | |
| 364 // A Group is allocated per group_name when there are idle sockets or pending | |
| 365 // requests. Otherwise, the Group object is removed from the map. | |
| 366 // |active_socket_count| tracks the number of sockets held by clients. | |
| 367 class Group { | |
| 368 public: | |
| 369 Group(); | |
| 370 ~Group(); | |
| 371 | |
| 372 bool IsEmpty() const { | |
| 373 return active_socket_count_ == 0 && idle_sockets_.empty() && | |
| 374 jobs_.empty() && pending_requests_.empty(); | |
| 375 } | |
| 376 | |
| 377 bool HasAvailableSocketSlot(int max_sockets_per_group) const { | |
| 378 return NumActiveSocketSlots() < max_sockets_per_group; | |
| 379 } | |
| 380 | |
| 381 int NumActiveSocketSlots() const { | |
| 382 return active_socket_count_ + static_cast<int>(jobs_.size()) + | |
| 383 static_cast<int>(idle_sockets_.size()); | |
| 384 } | |
| 385 | |
| 386 bool IsStalledOnPoolMaxSockets(int max_sockets_per_group) const { | |
| 387 return HasAvailableSocketSlot(max_sockets_per_group) && | |
| 388 pending_requests_.size() > jobs_.size(); | |
| 389 } | |
| 390 | |
| 391 // Returns the priority of the top of the pending request queue | |
| 392 // (which may be less than the maximum priority over the entire | |
| 393 // queue, due to how we prioritize requests with |ignore_limits| | |
| 394 // set over others). | |
| 395 RequestPriority TopPendingPriority() const { | |
| 396 // NOTE: FirstMax().value()->priority() is not the same as | |
| 397 // FirstMax().priority()! | |
| 398 return pending_requests_.FirstMax().value()->priority(); | |
| 399 } | |
| 400 | |
| 401 // Set a timer to create a backup job if it takes too long to | |
| 402 // create one and if a timer isn't already running. | |
| 403 void StartBackupJobTimer(const std::string& group_name, | |
| 404 ClientSocketPoolBaseHelper* pool); | |
| 405 | |
| 406 bool BackupJobTimerIsRunning() const; | |
| 407 | |
| 408 // If there's a ConnectJob that's never been assigned to Request, | |
| 409 // decrements |unassigned_job_count_| and returns true. | |
| 410 // Otherwise, returns false. | |
| 411 bool TryToUseUnassignedConnectJob(); | |
| 412 | |
| 413 void AddJob(scoped_ptr<ConnectJob> job, bool is_preconnect); | |
| 414 // Remove |job| from this group, which must already own |job|. | |
| 415 void RemoveJob(ConnectJob* job); | |
| 416 void RemoveAllJobs(); | |
| 417 | |
| 418 bool has_pending_requests() const { | |
| 419 return !pending_requests_.empty(); | |
| 420 } | |
| 421 | |
| 422 size_t pending_request_count() const { | |
| 423 return pending_requests_.size(); | |
| 424 } | |
| 425 | |
| 426 // Gets (but does not remove) the next pending request. Returns | |
| 427 // NULL if there are no pending requests. | |
| 428 const Request* GetNextPendingRequest() const; | |
| 429 | |
| 430 // Returns true if there is a connect job for |handle|. | |
| 431 bool HasConnectJobForHandle(const ClientSocketHandle* handle) const; | |
| 432 | |
| 433 // Inserts the request into the queue based on priority | |
| 434 // order. Older requests are prioritized over requests of equal | |
| 435 // priority. | |
| 436 void InsertPendingRequest(scoped_ptr<const Request> request); | |
| 437 | |
| 438 // Gets and removes the next pending request. Returns NULL if | |
| 439 // there are no pending requests. | |
| 440 scoped_ptr<const Request> PopNextPendingRequest(); | |
| 441 | |
| 442 // Finds the pending request for |handle| and removes it. Returns | |
| 443 // the removed pending request, or NULL if there was none. | |
| 444 scoped_ptr<const Request> FindAndRemovePendingRequest( | |
| 445 ClientSocketHandle* handle); | |
| 446 | |
| 447 void IncrementActiveSocketCount() { active_socket_count_++; } | |
| 448 void DecrementActiveSocketCount() { active_socket_count_--; } | |
| 449 | |
| 450 int unassigned_job_count() const { return unassigned_job_count_; } | |
| 451 const std::set<ConnectJob*>& jobs() const { return jobs_; } | |
| 452 const std::list<IdleSocket>& idle_sockets() const { return idle_sockets_; } | |
| 453 int active_socket_count() const { return active_socket_count_; } | |
| 454 std::list<IdleSocket>* mutable_idle_sockets() { return &idle_sockets_; } | |
| 455 | |
| 456 private: | |
| 457 // Returns the iterator's pending request after removing it from | |
| 458 // the queue. | |
| 459 scoped_ptr<const Request> RemovePendingRequest( | |
| 460 const RequestQueue::Pointer& pointer); | |
| 461 | |
| 462 // Called when the backup socket timer fires. | |
| 463 void OnBackupJobTimerFired( | |
| 464 std::string group_name, | |
| 465 ClientSocketPoolBaseHelper* pool); | |
| 466 | |
| 467 // Checks that |unassigned_job_count_| does not execeed the number of | |
| 468 // ConnectJobs. | |
| 469 void SanityCheck(); | |
| 470 | |
| 471 // Total number of ConnectJobs that have never been assigned to a Request. | |
| 472 // Since jobs use late binding to requests, which ConnectJobs have or have | |
| 473 // not been assigned to a request are not tracked. This is incremented on | |
| 474 // preconnect and decremented when a preconnect is assigned, or when there | |
| 475 // are fewer than |unassigned_job_count_| ConnectJobs. Not incremented | |
| 476 // when a request is cancelled. | |
| 477 size_t unassigned_job_count_; | |
| 478 | |
| 479 std::list<IdleSocket> idle_sockets_; | |
| 480 std::set<ConnectJob*> jobs_; | |
| 481 RequestQueue pending_requests_; | |
| 482 int active_socket_count_; // number of active sockets used by clients | |
| 483 // A timer for when to start the backup job. | |
| 484 base::OneShotTimer<Group> backup_job_timer_; | |
| 485 }; | |
| 486 | |
| 487 typedef std::map<std::string, Group*> GroupMap; | |
| 488 | |
| 489 typedef std::set<ConnectJob*> ConnectJobSet; | |
| 490 | |
| 491 struct CallbackResultPair { | |
| 492 CallbackResultPair(); | |
| 493 CallbackResultPair(const CompletionCallback& callback_in, int result_in); | |
| 494 ~CallbackResultPair(); | |
| 495 | |
| 496 CompletionCallback callback; | |
| 497 int result; | |
| 498 }; | |
| 499 | |
| 500 typedef std::map<const ClientSocketHandle*, CallbackResultPair> | |
| 501 PendingCallbackMap; | |
| 502 | |
| 503 Group* GetOrCreateGroup(const std::string& group_name); | |
| 504 void RemoveGroup(const std::string& group_name); | |
| 505 void RemoveGroup(GroupMap::iterator it); | |
| 506 | |
| 507 // Called when the number of idle sockets changes. | |
| 508 void IncrementIdleCount(); | |
| 509 void DecrementIdleCount(); | |
| 510 | |
| 511 // Start cleanup timer for idle sockets. | |
| 512 void StartIdleSocketTimer(); | |
| 513 | |
| 514 // Scans the group map for groups which have an available socket slot and | |
| 515 // at least one pending request. Returns true if any groups are stalled, and | |
| 516 // if so (and if both |group| and |group_name| are not NULL), fills |group| | |
| 517 // and |group_name| with data of the stalled group having highest priority. | |
| 518 bool FindTopStalledGroup(Group** group, std::string* group_name) const; | |
| 519 | |
| 520 // Called when timer_ fires. This method scans the idle sockets removing | |
| 521 // sockets that timed out or can't be reused. | |
| 522 void OnCleanupTimerFired() { | |
| 523 CleanupIdleSockets(false); | |
| 524 } | |
| 525 | |
| 526 // Removes |job| from |group|, which must already own |job|. | |
| 527 void RemoveConnectJob(ConnectJob* job, Group* group); | |
| 528 | |
| 529 // Tries to see if we can handle any more requests for |group|. | |
| 530 void OnAvailableSocketSlot(const std::string& group_name, Group* group); | |
| 531 | |
| 532 // Process a pending socket request for a group. | |
| 533 void ProcessPendingRequest(const std::string& group_name, Group* group); | |
| 534 | |
| 535 // Assigns |socket| to |handle| and updates |group|'s counters appropriately. | |
| 536 void HandOutSocket(scoped_ptr<StreamSocket> socket, | |
| 537 ClientSocketHandle::SocketReuseType reuse_type, | |
| 538 const LoadTimingInfo::ConnectTiming& connect_timing, | |
| 539 ClientSocketHandle* handle, | |
| 540 base::TimeDelta time_idle, | |
| 541 Group* group, | |
| 542 const BoundNetLog& net_log); | |
| 543 | |
| 544 // Adds |socket| to the list of idle sockets for |group|. | |
| 545 void AddIdleSocket(scoped_ptr<StreamSocket> socket, Group* group); | |
| 546 | |
| 547 // Iterates through |group_map_|, canceling all ConnectJobs and deleting | |
| 548 // groups if they are no longer needed. | |
| 549 void CancelAllConnectJobs(); | |
| 550 | |
| 551 // Iterates through |group_map_|, posting |error| callbacks for all | |
| 552 // requests, and then deleting groups if they are no longer needed. | |
| 553 void CancelAllRequestsWithError(int error); | |
| 554 | |
| 555 // Returns true if we can't create any more sockets due to the total limit. | |
| 556 bool ReachedMaxSocketsLimit() const; | |
| 557 | |
| 558 // This is the internal implementation of RequestSocket(). It differs in that | |
| 559 // it does not handle logging into NetLog of the queueing status of | |
| 560 // |request|. | |
| 561 int RequestSocketInternal(const std::string& group_name, | |
| 562 const Request& request); | |
| 563 | |
| 564 // Assigns an idle socket for the group to the request. | |
| 565 // Returns |true| if an idle socket is available, false otherwise. | |
| 566 bool AssignIdleSocketToRequest(const Request& request, Group* group); | |
| 567 | |
| 568 static void LogBoundConnectJobToRequest( | |
| 569 const NetLog::Source& connect_job_source, const Request& request); | |
| 570 | |
| 571 // Same as CloseOneIdleSocket() except it won't close an idle socket in | |
| 572 // |group|. If |group| is NULL, it is ignored. Returns true if it closed a | |
| 573 // socket. | |
| 574 bool CloseOneIdleSocketExceptInGroup(const Group* group); | |
| 575 | |
| 576 // Checks if there are stalled socket groups that should be notified | |
| 577 // for possible wakeup. | |
| 578 void CheckForStalledSocketGroups(); | |
| 579 | |
| 580 // Posts a task to call InvokeUserCallback() on the next iteration through the | |
| 581 // current message loop. Inserts |callback| into |pending_callback_map_|, | |
| 582 // keyed by |handle|. | |
| 583 void InvokeUserCallbackLater( | |
| 584 ClientSocketHandle* handle, const CompletionCallback& callback, int rv); | |
| 585 | |
| 586 // Invokes the user callback for |handle|. By the time this task has run, | |
| 587 // it's possible that the request has been cancelled, so |handle| may not | |
| 588 // exist in |pending_callback_map_|. We look up the callback and result code | |
| 589 // in |pending_callback_map_|. | |
| 590 void InvokeUserCallback(ClientSocketHandle* handle); | |
| 591 | |
| 592 // Tries to close idle sockets in a higher level socket pool as long as this | |
| 593 // this pool is stalled. | |
| 594 void TryToCloseSocketsInLayeredPools(); | |
| 595 | |
| 596 GroupMap group_map_; | |
| 597 | |
| 598 // Map of the ClientSocketHandles for which we have a pending Task to invoke a | |
| 599 // callback. This is necessary since, before we invoke said callback, it's | |
| 600 // possible that the request is cancelled. | |
| 601 PendingCallbackMap pending_callback_map_; | |
| 602 | |
| 603 // Timer used to periodically prune idle sockets that timed out or can't be | |
| 604 // reused. | |
| 605 base::RepeatingTimer<ClientSocketPoolBaseHelper> timer_; | |
| 606 | |
| 607 // The total number of idle sockets in the system. | |
| 608 int idle_socket_count_; | |
| 609 | |
| 610 // Number of connecting sockets across all groups. | |
| 611 int connecting_socket_count_; | |
| 612 | |
| 613 // Number of connected sockets we handed out across all groups. | |
| 614 int handed_out_socket_count_; | |
| 615 | |
| 616 // The maximum total number of sockets. See ReachedMaxSocketsLimit. | |
| 617 const int max_sockets_; | |
| 618 | |
| 619 // The maximum number of sockets kept per group. | |
| 620 const int max_sockets_per_group_; | |
| 621 | |
| 622 // Whether to use timer to cleanup idle sockets. | |
| 623 bool use_cleanup_timer_; | |
| 624 | |
| 625 // The time to wait until closing idle sockets. | |
| 626 const base::TimeDelta unused_idle_socket_timeout_; | |
| 627 const base::TimeDelta used_idle_socket_timeout_; | |
| 628 | |
| 629 const scoped_ptr<ConnectJobFactory> connect_job_factory_; | |
| 630 | |
| 631 // TODO(vandebo) Remove when backup jobs move to TransportClientSocketPool | |
| 632 bool connect_backup_jobs_enabled_; | |
| 633 | |
| 634 // A unique id for the pool. It gets incremented every time we | |
| 635 // FlushWithError() the pool. This is so that when sockets get released back | |
| 636 // to the pool, we can make sure that they are discarded rather than reused. | |
| 637 int pool_generation_number_; | |
| 638 | |
| 639 // Used to add |this| as a higher layer pool on top of lower layer pools. May | |
| 640 // be NULL if no lower layer pools will be added. | |
| 641 HigherLayeredPool* pool_; | |
| 642 | |
| 643 // Pools that create connections through |this|. |this| will try to close | |
| 644 // their idle sockets when it stalls. Must be empty on destruction. | |
| 645 std::set<HigherLayeredPool*> higher_pools_; | |
| 646 | |
| 647 // Pools that this goes through. Typically there's only one, but not always. | |
| 648 // |this| will check if they're stalled when it has a new idle socket. |this| | |
| 649 // will remove itself from all lower layered pools on destruction. | |
| 650 std::set<LowerLayeredPool*> lower_pools_; | |
| 651 | |
| 652 base::WeakPtrFactory<ClientSocketPoolBaseHelper> weak_factory_; | |
| 653 | |
| 654 DISALLOW_COPY_AND_ASSIGN(ClientSocketPoolBaseHelper); | |
| 655 }; | |
| 656 | |
| 657 } // namespace internal | |
| 658 | |
| 659 template <typename SocketParams> | |
| 660 class ClientSocketPoolBase { | |
| 661 public: | |
| 662 class Request : public internal::ClientSocketPoolBaseHelper::Request { | |
| 663 public: | |
| 664 Request(ClientSocketHandle* handle, | |
| 665 const CompletionCallback& callback, | |
| 666 RequestPriority priority, | |
| 667 internal::ClientSocketPoolBaseHelper::Flags flags, | |
| 668 bool ignore_limits, | |
| 669 const scoped_refptr<SocketParams>& params, | |
| 670 const BoundNetLog& net_log) | |
| 671 : internal::ClientSocketPoolBaseHelper::Request( | |
| 672 handle, callback, priority, ignore_limits, flags, net_log), | |
| 673 params_(params) {} | |
| 674 | |
| 675 const scoped_refptr<SocketParams>& params() const { return params_; } | |
| 676 | |
| 677 private: | |
| 678 const scoped_refptr<SocketParams> params_; | |
| 679 }; | |
| 680 | |
| 681 class ConnectJobFactory { | |
| 682 public: | |
| 683 ConnectJobFactory() {} | |
| 684 virtual ~ConnectJobFactory() {} | |
| 685 | |
| 686 virtual scoped_ptr<ConnectJob> NewConnectJob( | |
| 687 const std::string& group_name, | |
| 688 const Request& request, | |
| 689 ConnectJob::Delegate* delegate) const = 0; | |
| 690 | |
| 691 virtual base::TimeDelta ConnectionTimeout() const = 0; | |
| 692 | |
| 693 private: | |
| 694 DISALLOW_COPY_AND_ASSIGN(ConnectJobFactory); | |
| 695 }; | |
| 696 | |
| 697 // |max_sockets| is the maximum number of sockets to be maintained by this | |
| 698 // ClientSocketPool. |max_sockets_per_group| specifies the maximum number of | |
| 699 // sockets a "group" can have. |unused_idle_socket_timeout| specifies how | |
| 700 // long to leave an unused idle socket open before closing it. | |
| 701 // |used_idle_socket_timeout| specifies how long to leave a previously used | |
| 702 // idle socket open before closing it. | |
| 703 ClientSocketPoolBase( | |
| 704 HigherLayeredPool* self, | |
| 705 int max_sockets, | |
| 706 int max_sockets_per_group, | |
| 707 ClientSocketPoolHistograms* histograms, | |
| 708 base::TimeDelta unused_idle_socket_timeout, | |
| 709 base::TimeDelta used_idle_socket_timeout, | |
| 710 ConnectJobFactory* connect_job_factory) | |
| 711 : histograms_(histograms), | |
| 712 helper_(self, max_sockets, max_sockets_per_group, | |
| 713 unused_idle_socket_timeout, used_idle_socket_timeout, | |
| 714 new ConnectJobFactoryAdaptor(connect_job_factory)) {} | |
| 715 | |
| 716 virtual ~ClientSocketPoolBase() {} | |
| 717 | |
| 718 // These member functions simply forward to ClientSocketPoolBaseHelper. | |
| 719 void AddLowerLayeredPool(LowerLayeredPool* lower_pool) { | |
| 720 helper_.AddLowerLayeredPool(lower_pool); | |
| 721 } | |
| 722 | |
| 723 void AddHigherLayeredPool(HigherLayeredPool* higher_pool) { | |
| 724 helper_.AddHigherLayeredPool(higher_pool); | |
| 725 } | |
| 726 | |
| 727 void RemoveHigherLayeredPool(HigherLayeredPool* higher_pool) { | |
| 728 helper_.RemoveHigherLayeredPool(higher_pool); | |
| 729 } | |
| 730 | |
| 731 // RequestSocket bundles up the parameters into a Request and then forwards to | |
| 732 // ClientSocketPoolBaseHelper::RequestSocket(). | |
| 733 int RequestSocket(const std::string& group_name, | |
| 734 const scoped_refptr<SocketParams>& params, | |
| 735 RequestPriority priority, | |
| 736 ClientSocketHandle* handle, | |
| 737 const CompletionCallback& callback, | |
| 738 const BoundNetLog& net_log) { | |
| 739 scoped_ptr<const Request> request( | |
| 740 new Request(handle, callback, priority, | |
| 741 internal::ClientSocketPoolBaseHelper::NORMAL, | |
| 742 params->ignore_limits(), | |
| 743 params, net_log)); | |
| 744 return helper_.RequestSocket(group_name, request.Pass()); | |
| 745 } | |
| 746 | |
| 747 // RequestSockets bundles up the parameters into a Request and then forwards | |
| 748 // to ClientSocketPoolBaseHelper::RequestSockets(). Note that it assigns the | |
| 749 // priority to DEFAULT_PRIORITY and specifies the NO_IDLE_SOCKETS flag. | |
| 750 void RequestSockets(const std::string& group_name, | |
| 751 const scoped_refptr<SocketParams>& params, | |
| 752 int num_sockets, | |
| 753 const BoundNetLog& net_log) { | |
| 754 const Request request(NULL /* no handle */, | |
| 755 CompletionCallback(), | |
| 756 DEFAULT_PRIORITY, | |
| 757 internal::ClientSocketPoolBaseHelper::NO_IDLE_SOCKETS, | |
| 758 params->ignore_limits(), | |
| 759 params, | |
| 760 net_log); | |
| 761 helper_.RequestSockets(group_name, request, num_sockets); | |
| 762 } | |
| 763 | |
| 764 void CancelRequest(const std::string& group_name, | |
| 765 ClientSocketHandle* handle) { | |
| 766 return helper_.CancelRequest(group_name, handle); | |
| 767 } | |
| 768 | |
| 769 void ReleaseSocket(const std::string& group_name, | |
| 770 scoped_ptr<StreamSocket> socket, | |
| 771 int id) { | |
| 772 return helper_.ReleaseSocket(group_name, socket.Pass(), id); | |
| 773 } | |
| 774 | |
| 775 void FlushWithError(int error) { helper_.FlushWithError(error); } | |
| 776 | |
| 777 bool IsStalled() const { return helper_.IsStalled(); } | |
| 778 | |
| 779 void CloseIdleSockets() { return helper_.CloseIdleSockets(); } | |
| 780 | |
| 781 int idle_socket_count() const { return helper_.idle_socket_count(); } | |
| 782 | |
| 783 int IdleSocketCountInGroup(const std::string& group_name) const { | |
| 784 return helper_.IdleSocketCountInGroup(group_name); | |
| 785 } | |
| 786 | |
| 787 LoadState GetLoadState(const std::string& group_name, | |
| 788 const ClientSocketHandle* handle) const { | |
| 789 return helper_.GetLoadState(group_name, handle); | |
| 790 } | |
| 791 | |
| 792 virtual void OnConnectJobComplete(int result, ConnectJob* job) { | |
| 793 return helper_.OnConnectJobComplete(result, job); | |
| 794 } | |
| 795 | |
| 796 int NumUnassignedConnectJobsInGroup(const std::string& group_name) const { | |
| 797 return helper_.NumUnassignedConnectJobsInGroup(group_name); | |
| 798 } | |
| 799 | |
| 800 int NumConnectJobsInGroup(const std::string& group_name) const { | |
| 801 return helper_.NumConnectJobsInGroup(group_name); | |
| 802 } | |
| 803 | |
| 804 int NumActiveSocketsInGroup(const std::string& group_name) const { | |
| 805 return helper_.NumActiveSocketsInGroup(group_name); | |
| 806 } | |
| 807 | |
| 808 bool HasGroup(const std::string& group_name) const { | |
| 809 return helper_.HasGroup(group_name); | |
| 810 } | |
| 811 | |
| 812 void CleanupIdleSockets(bool force) { | |
| 813 return helper_.CleanupIdleSockets(force); | |
| 814 } | |
| 815 | |
| 816 base::DictionaryValue* GetInfoAsValue(const std::string& name, | |
| 817 const std::string& type) const { | |
| 818 return helper_.GetInfoAsValue(name, type); | |
| 819 } | |
| 820 | |
| 821 base::TimeDelta ConnectionTimeout() const { | |
| 822 return helper_.ConnectionTimeout(); | |
| 823 } | |
| 824 | |
| 825 ClientSocketPoolHistograms* histograms() const { | |
| 826 return histograms_; | |
| 827 } | |
| 828 | |
| 829 void EnableConnectBackupJobs() { helper_.EnableConnectBackupJobs(); } | |
| 830 | |
| 831 bool CloseOneIdleSocket() { return helper_.CloseOneIdleSocket(); } | |
| 832 | |
| 833 bool CloseOneIdleConnectionInHigherLayeredPool() { | |
| 834 return helper_.CloseOneIdleConnectionInHigherLayeredPool(); | |
| 835 } | |
| 836 | |
| 837 private: | |
| 838 // This adaptor class exists to bridge the | |
| 839 // internal::ClientSocketPoolBaseHelper::ConnectJobFactory and | |
| 840 // ClientSocketPoolBase::ConnectJobFactory types, allowing clients to use the | |
| 841 // typesafe ClientSocketPoolBase::ConnectJobFactory, rather than having to | |
| 842 // static_cast themselves. | |
| 843 class ConnectJobFactoryAdaptor | |
| 844 : public internal::ClientSocketPoolBaseHelper::ConnectJobFactory { | |
| 845 public: | |
| 846 typedef typename ClientSocketPoolBase<SocketParams>::ConnectJobFactory | |
| 847 ConnectJobFactory; | |
| 848 | |
| 849 explicit ConnectJobFactoryAdaptor(ConnectJobFactory* connect_job_factory) | |
| 850 : connect_job_factory_(connect_job_factory) {} | |
| 851 virtual ~ConnectJobFactoryAdaptor() {} | |
| 852 | |
| 853 virtual scoped_ptr<ConnectJob> NewConnectJob( | |
| 854 const std::string& group_name, | |
| 855 const internal::ClientSocketPoolBaseHelper::Request& request, | |
| 856 ConnectJob::Delegate* delegate) const override { | |
| 857 const Request& casted_request = static_cast<const Request&>(request); | |
| 858 return connect_job_factory_->NewConnectJob( | |
| 859 group_name, casted_request, delegate); | |
| 860 } | |
| 861 | |
| 862 base::TimeDelta ConnectionTimeout() const override { | |
| 863 return connect_job_factory_->ConnectionTimeout(); | |
| 864 } | |
| 865 | |
| 866 const scoped_ptr<ConnectJobFactory> connect_job_factory_; | |
| 867 }; | |
| 868 | |
| 869 // Histograms for the pool | |
| 870 ClientSocketPoolHistograms* const histograms_; | |
| 871 internal::ClientSocketPoolBaseHelper helper_; | |
| 872 | |
| 873 DISALLOW_COPY_AND_ASSIGN(ClientSocketPoolBase); | |
| 874 }; | |
| 875 | |
| 876 } // namespace net | |
| 877 | |
| 878 #endif // NET_SOCKET_CLIENT_SOCKET_POOL_BASE_H_ | |
| OLD | NEW |