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