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 virtual ~ClientSocketPoolBaseHelper(); 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 virtual void OnConnectJobComplete(int result, ConnectJob* job) OVERRIDE; 331 332 // NetworkChangeNotifier::IPAddressObserver methods: 333 virtual 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( 745 group_name, 746 request.template PassAs< 747 const internal::ClientSocketPoolBaseHelper::Request>()); 748 } 749 750 // RequestSockets bundles up the parameters into a Request and then forwards 751 // to ClientSocketPoolBaseHelper::RequestSockets(). Note that it assigns the 752 // priority to DEFAULT_PRIORITY and specifies the NO_IDLE_SOCKETS flag. 753 void RequestSockets(const std::string& group_name, 754 const scoped_refptr<SocketParams>& params, 755 int num_sockets, 756 const BoundNetLog& net_log) { 757 const Request request(NULL /* no handle */, 758 CompletionCallback(), 759 DEFAULT_PRIORITY, 760 internal::ClientSocketPoolBaseHelper::NO_IDLE_SOCKETS, 761 params->ignore_limits(), 762 params, 763 net_log); 764 helper_.RequestSockets(group_name, request, num_sockets); 765 } 766 767 void CancelRequest(const std::string& group_name, 768 ClientSocketHandle* handle) { 769 return helper_.CancelRequest(group_name, handle); 770 } 771 772 void ReleaseSocket(const std::string& group_name, 773 scoped_ptr<StreamSocket> socket, 774 int id) { 775 return helper_.ReleaseSocket(group_name, socket.Pass(), id); 776 } 777 778 void FlushWithError(int error) { helper_.FlushWithError(error); } 779 780 bool IsStalled() const { return helper_.IsStalled(); } 781 782 void CloseIdleSockets() { return helper_.CloseIdleSockets(); } 783 784 int idle_socket_count() const { return helper_.idle_socket_count(); } 785 786 int IdleSocketCountInGroup(const std::string& group_name) const { 787 return helper_.IdleSocketCountInGroup(group_name); 788 } 789 790 LoadState GetLoadState(const std::string& group_name, 791 const ClientSocketHandle* handle) const { 792 return helper_.GetLoadState(group_name, handle); 793 } 794 795 virtual void OnConnectJobComplete(int result, ConnectJob* job) { 796 return helper_.OnConnectJobComplete(result, job); 797 } 798 799 int NumUnassignedConnectJobsInGroup(const std::string& group_name) const { 800 return helper_.NumUnassignedConnectJobsInGroup(group_name); 801 } 802 803 int NumConnectJobsInGroup(const std::string& group_name) const { 804 return helper_.NumConnectJobsInGroup(group_name); 805 } 806 807 int NumActiveSocketsInGroup(const std::string& group_name) const { 808 return helper_.NumActiveSocketsInGroup(group_name); 809 } 810 811 bool HasGroup(const std::string& group_name) const { 812 return helper_.HasGroup(group_name); 813 } 814 815 void CleanupIdleSockets(bool force) { 816 return helper_.CleanupIdleSockets(force); 817 } 818 819 base::DictionaryValue* GetInfoAsValue(const std::string& name, 820 const std::string& type) const { 821 return helper_.GetInfoAsValue(name, type); 822 } 823 824 base::TimeDelta ConnectionTimeout() const { 825 return helper_.ConnectionTimeout(); 826 } 827 828 ClientSocketPoolHistograms* histograms() const { 829 return histograms_; 830 } 831 832 void EnableConnectBackupJobs() { helper_.EnableConnectBackupJobs(); } 833 834 bool CloseOneIdleSocket() { return helper_.CloseOneIdleSocket(); } 835 836 bool CloseOneIdleConnectionInHigherLayeredPool() { 837 return helper_.CloseOneIdleConnectionInHigherLayeredPool(); 838 } 839 840 private: 841 // This adaptor class exists to bridge the 842 // internal::ClientSocketPoolBaseHelper::ConnectJobFactory and 843 // ClientSocketPoolBase::ConnectJobFactory types, allowing clients to use the 844 // typesafe ClientSocketPoolBase::ConnectJobFactory, rather than having to 845 // static_cast themselves. 846 class ConnectJobFactoryAdaptor 847 : public internal::ClientSocketPoolBaseHelper::ConnectJobFactory { 848 public: 849 typedef typename ClientSocketPoolBase<SocketParams>::ConnectJobFactory 850 ConnectJobFactory; 851 852 explicit ConnectJobFactoryAdaptor(ConnectJobFactory* connect_job_factory) 853 : connect_job_factory_(connect_job_factory) {} 854 virtual ~ConnectJobFactoryAdaptor() {} 855 856 virtual scoped_ptr<ConnectJob> NewConnectJob( 857 const std::string& group_name, 858 const internal::ClientSocketPoolBaseHelper::Request& request, 859 ConnectJob::Delegate* delegate) const OVERRIDE { 860 const Request& casted_request = static_cast<const Request&>(request); 861 return connect_job_factory_->NewConnectJob( 862 group_name, casted_request, delegate); 863 } 864 865 virtual base::TimeDelta ConnectionTimeout() const { 866 return connect_job_factory_->ConnectionTimeout(); 867 } 868 869 const scoped_ptr<ConnectJobFactory> connect_job_factory_; 870 }; 871 872 // Histograms for the pool 873 ClientSocketPoolHistograms* const histograms_; 874 internal::ClientSocketPoolBaseHelper helper_; 875 876 DISALLOW_COPY_AND_ASSIGN(ClientSocketPoolBase); 877 }; 878 879 } // namespace net 880 881 #endif // NET_SOCKET_CLIENT_SOCKET_POOL_BASE_H_ 882