Home | History | Annotate | Download | only in socket
      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