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