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 #ifndef NET_SOCKET_TRANSPORT_CLIENT_SOCKET_POOL_H_
6 #define NET_SOCKET_TRANSPORT_CLIENT_SOCKET_POOL_H_
7 
8 #include <stddef.h>
9 #include <stdint.h>
10 
11 #include <cstddef>
12 #include <list>
13 #include <map>
14 #include <memory>
15 #include <set>
16 #include <string>
17 #include <utility>
18 #include <vector>
19 
20 #include "base/macros.h"
21 #include "base/memory/ref_counted.h"
22 #include "base/memory/weak_ptr.h"
23 #include "base/optional.h"
24 #include "base/time/time.h"
25 #include "base/timer/timer.h"
26 #include "net/base/address_list.h"
27 #include "net/base/completion_once_callback.h"
28 #include "net/base/load_states.h"
29 #include "net/base/load_timing_info.h"
30 #include "net/base/net_errors.h"
31 #include "net/base/net_export.h"
32 #include "net/base/network_change_notifier.h"
33 #include "net/base/priority_queue.h"
34 #include "net/base/proxy_server.h"
35 #include "net/base/request_priority.h"
36 #include "net/log/net_log_with_source.h"
37 #include "net/socket/client_socket_handle.h"
38 #include "net/socket/client_socket_pool.h"
39 #include "net/socket/connect_job.h"
40 #include "net/socket/connection_attempts.h"
41 #include "net/socket/socket_tag.h"
42 #include "net/socket/ssl_client_socket.h"
43 #include "net/socket/stream_socket.h"
44 
45 namespace base {
46 namespace trace_event {
47 class ProcessMemoryDump;
48 }
49 }  // namespace base
50 
51 namespace net {
52 
53 struct CommonConnectJobParams;
54 struct NetLogSource;
55 struct NetworkTrafficAnnotationTag;
56 
57 // TransportClientSocketPool establishes network connections through using
58 // ConnectJobs, and maintains a list of idle persistent sockets available for
59 // reuse. It restricts the number of sockets open at a time, both globally, and
60 // for each unique GroupId, which rougly corresponds to origin and privacy mode
61 // setting. TransportClientSocketPools is designed to work with HTTP reuse
62 // semantics, handling each request serially, before reusable sockets are
63 // returned to the socket pool.
64 //
65 // In order to manage connection limits on a per-Proxy basis, separate
66 // TransportClientSocketPools are created for each proxy, and another for
67 // connections that have no proxy.
68 // TransportClientSocketPool is an internal class that implements almost all
69 // the functionality from ClientSocketPool.
70 class NET_EXPORT_PRIVATE TransportClientSocketPool
71     : public ClientSocketPool,
72       public NetworkChangeNotifier::IPAddressObserver,
73       public SSLClientContext::Observer {
74  public:
75   // Reasons for closing sockets. Exposed here for testing.
76   static const char kCertDatabaseChanged[];
77   static const char kClosedConnectionReturnedToPool[];
78   static const char kDataReceivedUnexpectedly[];
79   static const char kIdleTimeLimitExpired[];
80   static const char kNetworkChanged[];
81   static const char kRemoteSideClosedConnection[];
82   static const char kSocketGenerationOutOfDate[];
83   static const char kSocketPoolDestroyed[];
84   static const char kSslConfigChanged[];
85 
86   using Flags = uint32_t;
87 
88   // Used to specify specific behavior for the ClientSocketPool.
89   enum Flag {
90     NORMAL = 0,             // Normal behavior.
91     NO_IDLE_SOCKETS = 0x1,  // Do not return an idle socket. Create a new one.
92   };
93 
94   class NET_EXPORT_PRIVATE Request {
95    public:
96     // If |proxy_auth_callback| is null, proxy auth challenges will
97     // result in an error.
98     Request(
99         ClientSocketHandle* handle,
100         CompletionOnceCallback callback,
101         const ProxyAuthCallback& proxy_auth_callback,
102         RequestPriority priority,
103         const SocketTag& socket_tag,
104         RespectLimits respect_limits,
105         Flags flags,
106         scoped_refptr<SocketParams> socket_params,
107         const base::Optional<NetworkTrafficAnnotationTag>& proxy_annotation_tag,
108         const NetLogWithSource& net_log);
109 
110     ~Request();
111 
handle()112     ClientSocketHandle* handle() const { return handle_; }
release_callback()113     CompletionOnceCallback release_callback() { return std::move(callback_); }
proxy_auth_callback()114     const ProxyAuthCallback& proxy_auth_callback() const {
115       return proxy_auth_callback_;
116     }
priority()117     RequestPriority priority() const { return priority_; }
set_priority(RequestPriority priority)118     void set_priority(RequestPriority priority) { priority_ = priority; }
respect_limits()119     RespectLimits respect_limits() const { return respect_limits_; }
flags()120     Flags flags() const { return flags_; }
socket_params()121     SocketParams* socket_params() const { return socket_params_.get(); }
proxy_annotation_tag()122     const base::Optional<NetworkTrafficAnnotationTag>& proxy_annotation_tag()
123         const {
124       return proxy_annotation_tag_;
125     }
net_log()126     const NetLogWithSource& net_log() const { return net_log_; }
socket_tag()127     const SocketTag& socket_tag() const { return socket_tag_; }
job()128     ConnectJob* job() const { return job_; }
129 
130     // Associates a ConnectJob with the request. Must be called on a request
131     // that does not already have a job.
132     void AssignJob(ConnectJob* job);
133 
134     // Unassigns the request's |job_| and returns it. Must be called on a
135     // request with a job.
136     ConnectJob* ReleaseJob();
137 
138    private:
139     ClientSocketHandle* const handle_;
140     CompletionOnceCallback callback_;
141     const ProxyAuthCallback proxy_auth_callback_;
142     RequestPriority priority_;
143     const RespectLimits respect_limits_;
144     const Flags flags_;
145     const scoped_refptr<SocketParams> socket_params_;
146     const base::Optional<NetworkTrafficAnnotationTag> proxy_annotation_tag_;
147     const NetLogWithSource net_log_;
148     const SocketTag socket_tag_;
149     ConnectJob* job_;
150 
151     DISALLOW_COPY_AND_ASSIGN(Request);
152   };
153 
154   class ConnectJobFactory {
155    public:
ConnectJobFactory()156     ConnectJobFactory() {}
~ConnectJobFactory()157     virtual ~ConnectJobFactory() {}
158 
159     virtual std::unique_ptr<ConnectJob> NewConnectJob(
160         ClientSocketPool::GroupId group_id,
161         scoped_refptr<ClientSocketPool::SocketParams> socket_params,
162         const base::Optional<NetworkTrafficAnnotationTag>& proxy_annotation_tag,
163         RequestPriority request_priority,
164         SocketTag socket_tag,
165         ConnectJob::Delegate* delegate) const = 0;
166 
167    private:
168     DISALLOW_COPY_AND_ASSIGN(ConnectJobFactory);
169   };
170 
171   TransportClientSocketPool(
172       int max_sockets,
173       int max_sockets_per_group,
174       base::TimeDelta unused_idle_socket_timeout,
175       const ProxyServer& proxy_server,
176       bool is_for_websockets,
177       const CommonConnectJobParams* common_connect_job_params);
178 
179   // Creates a socket pool with an alternative ConnectJobFactory, for use in
180   // testing.
181   //
182   // |connect_backup_jobs_enabled| can be set to false to disable backup connect
183   // jobs (Which are normally enabled).
184   static std::unique_ptr<TransportClientSocketPool> CreateForTesting(
185       int max_sockets,
186       int max_sockets_per_group,
187       base::TimeDelta unused_idle_socket_timeout,
188       base::TimeDelta used_idle_socket_timeout,
189       const ProxyServer& proxy_server,
190       std::unique_ptr<ConnectJobFactory> connect_job_factory,
191       SSLClientContext* ssl_client_context,
192       bool connect_backup_jobs_enabled);
193 
194   ~TransportClientSocketPool() override;
195 
196   // See LowerLayeredPool::IsStalled for documentation on this function.
197   bool IsStalled() const override;
198 
199   // See LowerLayeredPool for documentation on these functions. It is expected
200   // in the destructor that no higher layer pools remain.
201   void AddHigherLayeredPool(HigherLayeredPool* higher_pool) override;
202   void RemoveHigherLayeredPool(HigherLayeredPool* higher_pool) override;
203 
204   // ClientSocketPool implementation:
205   int RequestSocket(
206       const GroupId& group_id,
207       scoped_refptr<SocketParams> params,
208       const base::Optional<NetworkTrafficAnnotationTag>& proxy_annotation_tag,
209       RequestPriority priority,
210       const SocketTag& socket_tag,
211       RespectLimits respect_limits,
212       ClientSocketHandle* handle,
213       CompletionOnceCallback callback,
214       const ProxyAuthCallback& proxy_auth_callback,
215       const NetLogWithSource& net_log) override;
216   void RequestSockets(
217       const GroupId& group_id,
218       scoped_refptr<SocketParams> params,
219       const base::Optional<NetworkTrafficAnnotationTag>& proxy_annotation_tag,
220       int num_sockets,
221       const NetLogWithSource& net_log) override;
222   void SetPriority(const GroupId& group_id,
223                    ClientSocketHandle* handle,
224                    RequestPriority priority) override;
225   void CancelRequest(const GroupId& group_id,
226                      ClientSocketHandle* handle,
227                      bool cancel_connect_job) override;
228   void ReleaseSocket(const GroupId& group_id,
229                      std::unique_ptr<StreamSocket> socket,
230                      int64_t group_generation) override;
231   void FlushWithError(int error, const char* net_log_reason_utf8) override;
232   void CloseIdleSockets(const char* net_log_reason_utf8) override;
233   void CloseIdleSocketsInGroup(const GroupId& group_id,
234                                const char* net_log_reason_utf8) override;
235   int IdleSocketCount() const override;
236   size_t IdleSocketCountInGroup(const GroupId& group_id) const override;
237   LoadState GetLoadState(const GroupId& group_id,
238                          const ClientSocketHandle* handle) const override;
239   base::Value GetInfoAsValue(const std::string& name,
240                              const std::string& type) const override;
241   void DumpMemoryStats(
242       base::trace_event::ProcessMemoryDump* pmd,
243       const std::string& parent_dump_absolute_name) const override;
244 
RequestInGroupWithHandleHasJobForTesting(const GroupId & group_id,const ClientSocketHandle * handle)245   bool RequestInGroupWithHandleHasJobForTesting(
246       const GroupId& group_id,
247       const ClientSocketHandle* handle) const {
248     return group_map_.find(group_id)->second->RequestWithHandleHasJobForTesting(
249         handle);
250   }
251 
NumNeverAssignedConnectJobsInGroupForTesting(const GroupId & group_id)252   size_t NumNeverAssignedConnectJobsInGroupForTesting(
253       const GroupId& group_id) const {
254     return NumNeverAssignedConnectJobsInGroup(group_id);
255   }
256 
NumUnassignedConnectJobsInGroupForTesting(const GroupId & group_id)257   size_t NumUnassignedConnectJobsInGroupForTesting(
258       const GroupId& group_id) const {
259     return NumUnassignedConnectJobsInGroup(group_id);
260   }
261 
NumConnectJobsInGroupForTesting(const GroupId & group_id)262   size_t NumConnectJobsInGroupForTesting(const GroupId& group_id) const {
263     return NumConnectJobsInGroup(group_id);
264   }
265 
NumActiveSocketsInGroupForTesting(const GroupId & group_id)266   int NumActiveSocketsInGroupForTesting(const GroupId& group_id) const {
267     return NumActiveSocketsInGroup(group_id);
268   }
269 
HasGroupForTesting(const GroupId & group_id)270   bool HasGroupForTesting(const GroupId& group_id) const {
271     return HasGroup(group_id);
272   }
273 
274   static bool connect_backup_jobs_enabled();
275   static bool set_connect_backup_jobs_enabled(bool enabled);
276 
277   // NetworkChangeNotifier::IPAddressObserver methods:
278   void OnIPAddressChanged() override;
279 
280   // SSLClientContext::Observer methods.
281   void OnSSLConfigChanged(bool is_cert_database_change) override;
282   void OnSSLConfigForServerChanged(const HostPortPair& server) override;
283 
284  private:
285   class ConnectJobFactoryImpl;
286 
287   // Entry for a persistent socket which became idle at time |start_time|.
288   struct IdleSocket {
IdleSocketIdleSocket289     IdleSocket() : socket(nullptr) {}
290 
291     // An idle socket can't be used if it is disconnected or has been used
292     // before and has received data unexpectedly (hence no longer idle).  The
293     // unread data would be mistaken for the beginning of the next response if
294     // we were to use the socket for a new request.
295     //
296     // Note that a socket that has never been used before (like a preconnected
297     // socket) may be used even with unread data.  This may be, e.g., a SPDY
298     // SETTINGS frame.
299     //
300     // If the socket is not usable, |net_log_reason_utf8| is set to a string
301     // indicating why the socket is not usable.
302     bool IsUsable(const char** net_log_reason_utf8) const;
303 
304     StreamSocket* socket;
305     base::TimeTicks start_time;
306   };
307 
308   using RequestQueue = PriorityQueue<std::unique_ptr<Request>>;
309 
310   // A Group is allocated per GroupId when there are idle sockets, unbound
311   // request, or bound requests. Otherwise, the Group object is removed from the
312   // map.
313   //
314   // A request is "bound" to a ConnectJob when an unbound ConnectJob encounters
315   // a proxy HTTP auth challenge, and the auth challenge is presented to that
316   // request. Once a request and ConnectJob are bound together:
317   // * All auth challenges the ConnectJob sees will be sent to that request.
318   // * Cancelling the request will cancel the ConnectJob.
319   // * The final result of the ConnectJob, and any returned socket, will only be
320   //   sent to that bound request, though if the returned socket is returned to
321   //   the socket pool, it can then be used to service any request.
322   //
323   // "assigned" jobs are unbound ConnectJobs that have a corresponding Request.
324   // If there are 5 Jobs and 10 Requests, the 5 highest priority requests are
325   // each assigned a Job. If there are 10 Jobs and 5 Requests, the first 5 Jobs
326   // are each assigned to a request. Assignment is determined by order in their
327   // corresponding arrays. The assignment concept is used to deal with
328   // reprioritizing Jobs, and computing a Request's LoadState.
329   //
330   // |active_socket_count| tracks the number of sockets held by clients.
331   // SanityCheck() will always be true, except during the invocation of a
332   // method.  So all public methods expect the Group to pass SanityCheck() when
333   // invoked.
334   class NET_EXPORT_PRIVATE Group : public ConnectJob::Delegate {
335    public:
336     using JobList = std::list<std::unique_ptr<ConnectJob>>;
337 
338     struct BoundRequest {
339       BoundRequest();
340       BoundRequest(std::unique_ptr<ConnectJob> connect_job,
341                    std::unique_ptr<Request> request,
342                    int64_t generation);
343       BoundRequest(BoundRequest&& other);
344       BoundRequest& operator=(BoundRequest&& other);
345       ~BoundRequest();
346 
347       std::unique_ptr<ConnectJob> connect_job;
348       std::unique_ptr<Request> request;
349 
350       // Generation of |connect_job|. If it doesn't match the current
351       // generation, ConnectJob will be destroyed, and a new one created on
352       // completion.
353       int64_t generation;
354 
355       // It's not safe to fail a request in a |CancelAllRequestsWithError| call
356       // while it's waiting on user input, as the request may have raw pointers
357       // to objects owned by |connect_job| that it could racily write to after
358       // |connect_job| is destroyed. Instead, just track an error in that case,
359       // and fail the request once the ConnectJob completes.
360       int pending_error;
361     };
362 
363     Group(const GroupId& group_id,
364           TransportClientSocketPool* client_socket_pool);
365     ~Group() override;
366 
367     // ConnectJob::Delegate methods:
368     void OnConnectJobComplete(int result, ConnectJob* job) override;
369     void OnNeedsProxyAuth(const HttpResponseInfo& response,
370                           HttpAuthController* auth_controller,
371                           base::OnceClosure restart_with_auth_callback,
372                           ConnectJob* job) override;
373 
IsEmpty()374     bool IsEmpty() const {
375       return active_socket_count_ == 0 && idle_sockets_.empty() &&
376              jobs_.empty() && unbound_requests_.empty() &&
377              bound_requests_.empty();
378     }
379 
HasAvailableSocketSlot(int max_sockets_per_group)380     bool HasAvailableSocketSlot(int max_sockets_per_group) const {
381       return NumActiveSocketSlots() < max_sockets_per_group;
382     }
383 
NumActiveSocketSlots()384     int NumActiveSocketSlots() const {
385       return active_socket_count_ + static_cast<int>(jobs_.size()) +
386              static_cast<int>(idle_sockets_.size()) +
387              static_cast<int>(bound_requests_.size());
388     }
389 
390     // Returns true if the group could make use of an additional socket slot, if
391     // it were given one.
CanUseAdditionalSocketSlot(int max_sockets_per_group)392     bool CanUseAdditionalSocketSlot(int max_sockets_per_group) const {
393       return HasAvailableSocketSlot(max_sockets_per_group) &&
394              unbound_requests_.size() > jobs_.size();
395     }
396 
397     // Returns the priority of the top of the unbound request queue
398     // (which may be less than the maximum priority over the entire
399     // queue, due to how we prioritize requests with |respect_limits|
400     // DISABLED over others).
TopPendingPriority()401     RequestPriority TopPendingPriority() const {
402       // NOTE: FirstMax().value()->priority() is not the same as
403       // FirstMax().priority()!
404       return unbound_requests_.FirstMax().value()->priority();
405     }
406 
407     // Set a timer to create a backup job if it takes too long to
408     // create one and if a timer isn't already running.
409     void StartBackupJobTimer(const GroupId& group_id);
410 
411     bool BackupJobTimerIsRunning() const;
412 
413     // If there's a ConnectJob that's never been assigned to Request,
414     // decrements |never_assigned_job_count_| and returns true.
415     // Otherwise, returns false.
416     bool TryToUseNeverAssignedConnectJob();
417 
418     void AddJob(std::unique_ptr<ConnectJob> job, bool is_preconnect);
419     // Remove |job| from this group, which must already own |job|. Returns the
420     // removed ConnectJob.
421     std::unique_ptr<ConnectJob> RemoveUnboundJob(ConnectJob* job);
422     void RemoveAllUnboundJobs();
423 
has_unbound_requests()424     bool has_unbound_requests() const { return !unbound_requests_.empty(); }
425 
unbound_request_count()426     size_t unbound_request_count() const { return unbound_requests_.size(); }
427 
428     size_t ConnectJobCount() const;
429 
430     // Returns the connect job correspding to |handle|. In particular, if
431     // |handle| is bound to a ConnectJob, returns that job. If |handle| is
432     // "assigned" a ConnectJob, return that job. Otherwise, returns nullptr.
433     ConnectJob* GetConnectJobForHandle(const ClientSocketHandle* handle) const;
434 
435     // Inserts the request into the queue based on priority
436     // order. Older requests are prioritized over requests of equal
437     // priority.
438     void InsertUnboundRequest(std::unique_ptr<Request> request);
439 
440     // Gets (but does not remove) the next unbound request. Returns
441     // NULL if there are no unbound requests.
442     const Request* GetNextUnboundRequest() const;
443 
444     // Gets and removes the next unbound request. Returns NULL if
445     // there are no unbound requests.
446     std::unique_ptr<Request> PopNextUnboundRequest();
447 
448     // Finds the unbound request for |handle| and removes it. Returns
449     // the removed unbound request, or NULL if there was none.
450     std::unique_ptr<Request> FindAndRemoveUnboundRequest(
451         ClientSocketHandle* handle);
452 
453     // Sets a pending error for all bound requests. Bound requests may be in the
454     // middle of a callback, so can't be failed at arbitrary points in time.
455     void SetPendingErrorForAllBoundRequests(int pending_error);
456 
457     // Attempts to bind the highest priority unbound request to |connect_job|,
458     // and returns the bound request. If the request has previously been bound
459     // to |connect_job|, returns the previously bound request. If there are no
460     // requests, or the highest priority request doesn't have a proxy auth
461     // callback, returns nullptr.
462     const Request* BindRequestToConnectJob(ConnectJob* connect_job);
463 
464     // Finds the request, if any, bound to |connect_job|, and returns the
465     // BoundRequest or base::nullopt if there was none.
466     base::Optional<BoundRequest> FindAndRemoveBoundRequestForConnectJob(
467         ConnectJob* connect_job);
468 
469     // Finds the bound request, if any, corresponding to |client_socket_handle|
470     // and returns it. Destroys the ConnectJob bound to the request, if there
471     // was one.
472     std::unique_ptr<Request> FindAndRemoveBoundRequest(
473         ClientSocketHandle* client_socket_handle);
474 
475     // Change the priority of the request named by |*handle|.  |*handle|
476     // must refer to a request currently present in the group.  If |priority|
477     // is the same as the current priority of the request, this is a no-op.
478     void SetPriority(ClientSocketHandle* handle, RequestPriority priority);
479 
IncrementActiveSocketCount()480     void IncrementActiveSocketCount() { active_socket_count_++; }
DecrementActiveSocketCount()481     void DecrementActiveSocketCount() { active_socket_count_--; }
482 
IncrementGeneration()483     void IncrementGeneration() { generation_++; }
484 
485     // Whether the request in |unbound_requests_| with a given handle has a job.
486     bool RequestWithHandleHasJobForTesting(
487         const ClientSocketHandle* handle) const;
488 
group_id()489     const GroupId& group_id() { return group_id_; }
unassigned_job_count()490     size_t unassigned_job_count() const { return unassigned_jobs_.size(); }
jobs()491     const JobList& jobs() const { return jobs_; }
idle_sockets()492     const std::list<IdleSocket>& idle_sockets() const { return idle_sockets_; }
active_socket_count()493     int active_socket_count() const { return active_socket_count_; }
mutable_idle_sockets()494     std::list<IdleSocket>* mutable_idle_sockets() { return &idle_sockets_; }
never_assigned_job_count()495     size_t never_assigned_job_count() const {
496       return never_assigned_job_count_;
497     }
generation()498     int64_t generation() const { return generation_; }
499 
500    private:
501     // Returns the iterator's unbound request after removing it from
502     // the queue. Expects the Group to pass SanityCheck() when called.
503     std::unique_ptr<Request> RemoveUnboundRequest(
504         const RequestQueue::Pointer& pointer);
505 
506     // Finds the Request which is associated with the given ConnectJob.
507     // Returns nullptr if none is found. Expects the Group to pass SanityCheck()
508     // when called.
509     RequestQueue::Pointer FindUnboundRequestWithJob(
510         const ConnectJob* job) const;
511 
512     // Finds the Request in |unbound_requests_| which is the first request
513     // without a job. Returns a null pointer if all requests have jobs. Does not
514     // expect the Group to pass SanityCheck() when called, but does expect all
515     // jobs to either be assigned to a request or in |unassigned_jobs_|. Expects
516     // that no requests with jobs come after any requests without a job.
517     RequestQueue::Pointer GetFirstRequestWithoutJob() const;
518 
519     // Tries to assign an unassigned |job| to a request. If no requests need a
520     // job, |job| is added to |unassigned_jobs_|.
521     // When called, does not expect the Group to pass SanityCheck(), but does
522     // expect it to have passed SanityCheck() before the given ConnectJob was
523     // either created or had the request it was assigned to removed.
524     void TryToAssignUnassignedJob(ConnectJob* job);
525 
526     // Tries to assign a job to the given request. If any unassigned jobs are
527     // available, the first unassigned job is assigned to the request.
528     // Otherwise, if the request is ahead of the last request with a job, the
529     // job is stolen from the last request with a job.
530     // When called, does not expect the Group to pass SanityCheck(), but does
531     // expect that:
532     //  - the request associated with |request_pointer| must not have
533     //    an assigned ConnectJob,
534     //  - the first min( jobs_.size(), unbound_requests_.size() - 1 ) Requests
535     //    other than the given request must have ConnectJobs, i.e. the group
536     //    must have passed SanityCheck() before the passed in Request was either
537     //    added or had its job unassigned.
538     void TryToAssignJobToRequest(RequestQueue::Pointer request_pointer);
539 
540     // Transfers the associated ConnectJob from one Request to another. Expects
541     // the source request to have a job, and the destination request to not have
542     // a job. Does not expect the Group to pass SanityCheck() when called.
543     void TransferJobBetweenRequests(Request* source, Request* dest);
544 
545     // Called when the backup socket timer fires.
546     void OnBackupJobTimerFired(const GroupId& group_id);
547 
548     // Checks that:
549     //  - |unassigned_jobs_| is empty iff there are at least as many requests
550     //    as jobs.
551     //  - Exactly the first |jobs_.size() - unassigned_jobs_.size()| requests
552     //    have ConnectJobs.
553     //  - No requests are assigned a ConnectJob in |unassigned_jobs_|.
554     //  - No requests are assigned a ConnectJob not in |jobs_|.
555     //  - No two requests are assigned the same ConnectJob.
556     //  - All entries in |unassigned_jobs_| are also in |jobs_|.
557     //  - There are no duplicate entries in |unassigned_jobs_|.
558     void SanityCheck() const;
559 
560     const GroupId group_id_;
561     TransportClientSocketPool* const client_socket_pool_;
562 
563     // Total number of ConnectJobs that have never been assigned to a Request.
564     // Since jobs use late binding to requests, which ConnectJobs have or have
565     // not been assigned to a request are not tracked.  This is incremented on
566     // preconnect and decremented when a preconnect is assigned, or when there
567     // are fewer than |never_assigned_job_count_| ConnectJobs.  Not incremented
568     // when a request is cancelled.
569     size_t never_assigned_job_count_;
570 
571     std::list<IdleSocket> idle_sockets_;
572     JobList jobs_;  // For bookkeeping purposes, there is a copy of the raw
573                     // pointer of each element of |jobs_| stored either in
574                     // |unassigned_jobs_|, or as the associated |job_| of an
575                     // element of |unbound_requests_|.
576     std::list<ConnectJob*> unassigned_jobs_;
577     RequestQueue unbound_requests_;
578     int active_socket_count_;  // number of active sockets used by clients
579     // A timer for when to start the backup job.
580     base::OneShotTimer backup_job_timer_;
581 
582     // List of Requests bound to ConnectJobs currently undergoing proxy auth.
583     // The Requests and ConnectJobs in this list do not appear in
584     // |unbound_requests_| or |jobs_|.
585     std::vector<BoundRequest> bound_requests_;
586 
587     // An id for the group.  It gets incremented every time we FlushWithError()
588     // the socket pool, or refresh the group.  This is so that when sockets get
589     // released back to the group, we can make sure that they are discarded
590     // rather than reused. Destroying a group will reset the generation number,
591     // but as that only happens once there are no outstanding sockets or
592     // requests associated with the group, that's harmless.
593     int64_t generation_;
594   };
595 
596   using GroupMap = std::map<GroupId, Group*>;
597 
598   struct CallbackResultPair {
599     CallbackResultPair();
600     CallbackResultPair(CompletionOnceCallback callback_in, int result_in);
601     CallbackResultPair(CallbackResultPair&& other);
602     CallbackResultPair& operator=(CallbackResultPair&& other);
603     ~CallbackResultPair();
604 
605     CompletionOnceCallback callback;
606     int result;
607   };
608 
609   using PendingCallbackMap =
610       std::map<const ClientSocketHandle*, CallbackResultPair>;
611 
612   TransportClientSocketPool(
613       int max_sockets,
614       int max_sockets_per_group,
615       base::TimeDelta unused_idle_socket_timeout,
616       base::TimeDelta used_idle_socket_timeout,
617       const ProxyServer& proxy_server,
618       std::unique_ptr<ConnectJobFactory> connect_job_factory,
619       SSLClientContext* ssl_client_context,
620       bool connect_backup_jobs_enabled);
621 
ConnectRetryInterval()622   base::TimeDelta ConnectRetryInterval() const {
623     // TODO(mbelshe): Make this tuned dynamically based on measured RTT.
624     //                For now, just use the max retry interval.
625     return base::TimeDelta::FromMilliseconds(kMaxConnectRetryIntervalMs);
626   }
627 
628   // TODO(mmenke): de-inline these.
NumNeverAssignedConnectJobsInGroup(const GroupId & group_id)629   size_t NumNeverAssignedConnectJobsInGroup(const GroupId& group_id) const {
630     return group_map_.find(group_id)->second->never_assigned_job_count();
631   }
632 
NumUnassignedConnectJobsInGroup(const GroupId & group_id)633   size_t NumUnassignedConnectJobsInGroup(const GroupId& group_id) const {
634     return group_map_.find(group_id)->second->unassigned_job_count();
635   }
636 
NumConnectJobsInGroup(const GroupId & group_id)637   size_t NumConnectJobsInGroup(const GroupId& group_id) const {
638     return group_map_.find(group_id)->second->ConnectJobCount();
639   }
640 
NumActiveSocketsInGroup(const GroupId & group_id)641   int NumActiveSocketsInGroup(const GroupId& group_id) const {
642     return group_map_.find(group_id)->second->active_socket_count();
643   }
644 
645   bool HasGroup(const GroupId& group_id) const;
646 
647   // Closes all idle sockets if |force| is true.  Else, only closes idle
648   // sockets that timed out or can't be reused.  Made public for testing.
649   // |reason| must be non-empty when |force| is true.
650   void CleanupIdleSockets(bool force, const char* net_log_reason_utf8);
651 
652   // Closes one idle socket.  Picks the first one encountered.
653   // TODO(willchan): Consider a better algorithm for doing this.  Perhaps we
654   // should keep an ordered list of idle sockets, and close them in order.
655   // Requires maintaining more state.  It's not clear if it's worth it since
656   // I'm not sure if we hit this situation often.
657   bool CloseOneIdleSocket();
658 
659   // Checks higher layered pools to see if they can close an idle connection.
660   bool CloseOneIdleConnectionInHigherLayeredPool();
661 
662   // Closes all idle sockets in |group| if |force| is true.  Else, only closes
663   // idle sockets in |group| that timed out with respect to |now| or can't be
664   // reused.
665   void CleanupIdleSocketsInGroup(bool force,
666                                  Group* group,
667                                  const base::TimeTicks& now,
668                                  const char* net_log_reason_utf8);
669 
670   Group* GetOrCreateGroup(const GroupId& group_id);
671   void RemoveGroup(const GroupId& group_id);
672   void RemoveGroup(GroupMap::iterator it);
673 
674   // Called when the number of idle sockets changes.
675   void IncrementIdleCount();
676   void DecrementIdleCount();
677 
678   // Scans the group map for groups which have an available socket slot and
679   // at least one pending request. Returns true if any groups are stalled, and
680   // if so (and if both |group| and |group_id| are not NULL), fills |group|
681   // and |group_id| with data of the stalled group having highest priority.
682   bool FindTopStalledGroup(Group** group, GroupId* group_id) const;
683 
684   // Removes |job| from |group|, which must already own |job|.
685   void RemoveConnectJob(ConnectJob* job, Group* group);
686 
687   // Tries to see if we can handle any more requests for |group|.
688   void OnAvailableSocketSlot(const GroupId& group_id, Group* group);
689 
690   // Process a pending socket request for a group.
691   void ProcessPendingRequest(const GroupId& group_id, Group* group);
692 
693   // Assigns |socket| to |handle| and updates |group|'s counters appropriately.
694   void HandOutSocket(std::unique_ptr<StreamSocket> socket,
695                      ClientSocketHandle::SocketReuseType reuse_type,
696                      const LoadTimingInfo::ConnectTiming& connect_timing,
697                      ClientSocketHandle* handle,
698                      base::TimeDelta time_idle,
699                      Group* group,
700                      const NetLogWithSource& net_log);
701 
702   // Adds |socket| to the list of idle sockets for |group|.
703   void AddIdleSocket(std::unique_ptr<StreamSocket> socket, Group* group);
704 
705   // Iterates through |group_map_|, canceling all ConnectJobs and deleting
706   // groups if they are no longer needed.
707   void CancelAllConnectJobs();
708 
709   // Iterates through |group_map_|, posting |error| callbacks for all
710   // requests, and then deleting groups if they are no longer needed.
711   void CancelAllRequestsWithError(int error);
712 
713   // Returns true if we can't create any more sockets due to the total limit.
714   bool ReachedMaxSocketsLimit() const;
715 
716   // This is the internal implementation of RequestSocket().  It differs in that
717   // it does not handle logging into NetLog of the queueing status of
718   // |request|.
719   int RequestSocketInternal(const GroupId& group_id, const Request& request);
720 
721   // Assigns an idle socket for the group to the request.
722   // Returns |true| if an idle socket is available, false otherwise.
723   bool AssignIdleSocketToRequest(const Request& request, Group* group);
724 
725   static void LogBoundConnectJobToRequest(
726       const NetLogSource& connect_job_source,
727       const Request& request);
728 
729   // Same as CloseOneIdleSocket() except it won't close an idle socket in
730   // |group|.  If |group| is NULL, it is ignored.  Returns true if it closed a
731   // socket.
732   bool CloseOneIdleSocketExceptInGroup(const Group* group);
733 
734   // Checks if there are stalled socket groups that should be notified
735   // for possible wakeup.
736   void CheckForStalledSocketGroups();
737 
738   // Posts a task to call InvokeUserCallback() on the next iteration through the
739   // current message loop.  Inserts |callback| into |pending_callback_map_|,
740   // keyed by |handle|. Apply |socket_tag| to the socket if socket successfully
741   // created.
742   void InvokeUserCallbackLater(ClientSocketHandle* handle,
743                                CompletionOnceCallback callback,
744                                int rv,
745                                const SocketTag& socket_tag);
746 
747   // These correspond to ConnectJob::Delegate methods, and are invoked by the
748   // Group a ConnectJob belongs to.
749   void OnConnectJobComplete(Group* group, int result, ConnectJob* job);
750   void OnNeedsProxyAuth(Group* group,
751                         const HttpResponseInfo& response,
752                         HttpAuthController* auth_controller,
753                         base::OnceClosure restart_with_auth_callback,
754                         ConnectJob* job);
755 
756   // Invokes the user callback for |handle|.  By the time this task has run,
757   // it's possible that the request has been cancelled, so |handle| may not
758   // exist in |pending_callback_map_|.  We look up the callback and result code
759   // in |pending_callback_map_|.
760   void InvokeUserCallback(ClientSocketHandle* handle);
761 
762   // Tries to close idle sockets in a higher level socket pool as long as this
763   // this pool is stalled.
764   void TryToCloseSocketsInLayeredPools();
765 
766   // Closes all idle sockets and cancels all unbound ConnectJobs associated with
767   // |it->second|. Also increments the group's generation number, ensuring any
768   // currently existing handed out socket will be silently closed when it is
769   // returned to the socket pool. Bound ConnectJobs will only be destroyed on
770   // once they complete, as they may be waiting on user input. No request
771   // (including bound ones) will be failed as a result of this call - instead,
772   // new ConnectJobs will be created.
773   //
774   // The group may be removed if this leaves the group empty. The caller must
775   // call CheckForStalledSocketGroups() after all applicable groups have been
776   // refreshed.
777   void RefreshGroup(GroupMap::iterator it,
778                     const base::TimeTicks& now,
779                     const char* net_log_reason_utf8);
780 
781   GroupMap group_map_;
782 
783   // Map of the ClientSocketHandles for which we have a pending Task to invoke a
784   // callback.  This is necessary since, before we invoke said callback, it's
785   // possible that the request is cancelled.
786   PendingCallbackMap pending_callback_map_;
787 
788   // The total number of idle sockets in the system.
789   int idle_socket_count_;
790 
791   // Number of connecting sockets across all groups.
792   int connecting_socket_count_;
793 
794   // Number of connected sockets we handed out across all groups.
795   int handed_out_socket_count_;
796 
797   // The maximum total number of sockets. See ReachedMaxSocketsLimit.
798   const int max_sockets_;
799 
800   // The maximum number of sockets kept per group.
801   const int max_sockets_per_group_;
802 
803   // The time to wait until closing idle sockets.
804   const base::TimeDelta unused_idle_socket_timeout_;
805   const base::TimeDelta used_idle_socket_timeout_;
806 
807   const ProxyServer proxy_server_;
808 
809   const std::unique_ptr<ConnectJobFactory> connect_job_factory_;
810 
811   // TODO(vandebo) Remove when backup jobs move to TransportClientSocketPool
812   bool connect_backup_jobs_enabled_;
813 
814   // Pools that create connections through |this|.  |this| will try to close
815   // their idle sockets when it stalls.  Must be empty on destruction.
816   std::set<HigherLayeredPool*> higher_pools_;
817 
818   SSLClientContext* const ssl_client_context_;
819 
820   base::WeakPtrFactory<TransportClientSocketPool> weak_factory_{this};
821 
822   DISALLOW_COPY_AND_ASSIGN(TransportClientSocketPool);
823 };
824 
825 }  // namespace net
826 
827 #endif  // NET_SOCKET_TRANSPORT_CLIENT_SOCKET_POOL_H_
828