xref: /aosp_15_r20/external/cronet/net/socket/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_CLIENT_SOCKET_POOL_H_
6 #define NET_SOCKET_CLIENT_SOCKET_POOL_H_
7 
8 #include <memory>
9 #include <optional>
10 #include <string>
11 #include <vector>
12 
13 #include "base/memory/raw_ptr.h"
14 #include "base/memory/ref_counted.h"
15 #include "base/time/time.h"
16 #include "base/values.h"
17 #include "net/base/completion_once_callback.h"
18 #include "net/base/load_states.h"
19 #include "net/base/net_export.h"
20 #include "net/base/network_anonymization_key.h"
21 #include "net/base/privacy_mode.h"
22 #include "net/base/request_priority.h"
23 #include "net/dns/host_resolver.h"
24 #include "net/dns/public/secure_dns_policy.h"
25 #include "net/http/http_request_info.h"
26 #include "net/log/net_log_capture_mode.h"
27 #include "net/socket/connect_job.h"
28 #include "net/socket/socket_tag.h"
29 #include "net/ssl/ssl_config.h"
30 #include "url/scheme_host_port.h"
31 
32 namespace net {
33 
34 class ClientSocketHandle;
35 class ConnectJobFactory;
36 class HttpAuthController;
37 class HttpResponseInfo;
38 class NetLogWithSource;
39 struct NetworkTrafficAnnotationTag;
40 class ProxyChain;
41 struct SSLConfig;
42 class StreamSocket;
43 
44 // ClientSocketPools are layered. This defines an interface for lower level
45 // socket pools to communicate with higher layer pools.
46 class NET_EXPORT HigherLayeredPool {
47  public:
48   virtual ~HigherLayeredPool() = default;
49 
50   // Instructs the HigherLayeredPool to close an idle connection. Return true if
51   // one was closed.  Closing an idle connection will call into the lower layer
52   // pool it came from, so must be careful of re-entrancy when using this.
53   virtual bool CloseOneIdleConnection() = 0;
54 };
55 
56 // ClientSocketPools are layered. This defines an interface for higher level
57 // socket pools to communicate with lower layer pools.
58 class NET_EXPORT LowerLayeredPool {
59  public:
60   virtual ~LowerLayeredPool() = default;
61 
62   // Returns true if a there is currently a request blocked on the per-pool
63   // (not per-host) max socket limit, either in this pool, or one that it is
64   // layered on top of.
65   virtual bool IsStalled() const = 0;
66 
67   // Called to add or remove a higher layer pool on top of |this|.  A higher
68   // layer pool may be added at most once to |this|, and must be removed prior
69   // to destruction of |this|.
70   virtual void AddHigherLayeredPool(HigherLayeredPool* higher_pool) = 0;
71   virtual void RemoveHigherLayeredPool(HigherLayeredPool* higher_pool) = 0;
72 };
73 
74 // A ClientSocketPool is used to restrict the number of sockets open at a time.
75 // It also maintains a list of idle persistent sockets.
76 //
77 // Subclasses must also have an inner class SocketParams which is
78 // the type for the |params| argument in RequestSocket() and
79 // RequestSockets() below.
80 class NET_EXPORT ClientSocketPool : public LowerLayeredPool {
81  public:
82   // Indicates whether or not a request for a socket should respect the
83   // SocketPool's global and per-group socket limits.
84   enum class RespectLimits { DISABLED, ENABLED };
85 
86   // ProxyAuthCallback is invoked when there is an auth challenge while
87   // connecting to a tunnel. When |restart_with_auth_callback| is invoked, the
88   // corresponding socket request is guaranteed not to be completed
89   // synchronously, nor will the ProxyAuthCallback be invoked against
90   // synchronously.
91   typedef base::RepeatingCallback<void(
92       const HttpResponseInfo& response,
93       HttpAuthController* auth_controller,
94       base::OnceClosure restart_with_auth_callback)>
95       ProxyAuthCallback;
96 
97   // Group ID for a socket request. Requests with the same group ID are
98   // considered indistinguishable.
99   class NET_EXPORT GroupId {
100    public:
101     GroupId();
102     GroupId(url::SchemeHostPort destination,
103             PrivacyMode privacy_mode,
104             NetworkAnonymizationKey network_anonymization_key,
105             SecureDnsPolicy secure_dns_policy,
106             bool disable_cert_network_fetches);
107     GroupId(const GroupId& group_id);
108 
109     ~GroupId();
110 
111     GroupId& operator=(const GroupId& group_id);
112     GroupId& operator=(GroupId&& group_id);
113 
destination()114     const url::SchemeHostPort& destination() const { return destination_; }
115 
privacy_mode()116     PrivacyMode privacy_mode() const { return privacy_mode_; }
117 
network_anonymization_key()118     const NetworkAnonymizationKey& network_anonymization_key() const {
119       return network_anonymization_key_;
120     }
121 
secure_dns_policy()122     SecureDnsPolicy secure_dns_policy() const { return secure_dns_policy_; }
123 
disable_cert_network_fetches()124     bool disable_cert_network_fetches() const {
125       return disable_cert_network_fetches_;
126     }
127 
128     // Returns the group ID as a string, for logging.
129     std::string ToString() const;
130 
131     bool operator==(const GroupId& other) const {
132       return std::tie(destination_, privacy_mode_, network_anonymization_key_,
133                       secure_dns_policy_, disable_cert_network_fetches_) ==
134              std::tie(other.destination_, other.privacy_mode_,
135                       other.network_anonymization_key_,
136                       other.secure_dns_policy_,
137                       other.disable_cert_network_fetches_);
138     }
139 
140     bool operator<(const GroupId& other) const {
141       return std::tie(destination_, privacy_mode_, network_anonymization_key_,
142                       secure_dns_policy_, disable_cert_network_fetches_) <
143              std::tie(other.destination_, other.privacy_mode_,
144                       other.network_anonymization_key_,
145                       other.secure_dns_policy_,
146                       other.disable_cert_network_fetches_);
147     }
148 
149    private:
150     // The endpoint of the final destination (not the proxy).
151     url::SchemeHostPort destination_;
152 
153     // If this request is for a privacy mode / uncredentialed connection.
154     PrivacyMode privacy_mode_;
155 
156     // Used to separate requests made in different contexts.
157     NetworkAnonymizationKey network_anonymization_key_;
158 
159     // Controls the Secure DNS behavior to use when creating this socket.
160     SecureDnsPolicy secure_dns_policy_;
161 
162     // Whether cert validation-related network fetches are allowed. Should only
163     // be true for a very limited number of network-configuration related
164     // scripts (e.g., PAC fetches).
165     bool disable_cert_network_fetches_;
166   };
167 
168   // Parameters that, in combination with GroupId, proxy, websocket information,
169   // and global state, are sufficient to create a ConnectJob.
170   //
171   // DO NOT ADD ANY FIELDS TO THIS CLASS.
172   //
173   // TODO(https://crbug.com/921369) In order to resolve longstanding issues
174   // related to pooling distinguishable sockets together, remove this class
175   // entirely.
176   class NET_EXPORT_PRIVATE SocketParams
177       : public base::RefCounted<SocketParams> {
178    public:
179     // For non-SSL requests, `allowed_bad_certs` argument will be ignored (and
180     // is likely empty, anyways).
181     explicit SocketParams(
182         const std::vector<SSLConfig::CertAndStatus>& allowed_bad_certs);
183 
184     SocketParams(const SocketParams&) = delete;
185     SocketParams& operator=(const SocketParams&) = delete;
186 
187     // Creates a SocketParams object with none of the fields populated. This
188     // works for the HTTP case only.
189     static scoped_refptr<SocketParams> CreateForHttpForTesting();
190 
allowed_bad_certs()191     const std::vector<SSLConfig::CertAndStatus>& allowed_bad_certs() const {
192       return allowed_bad_certs_;
193     }
194 
195    private:
196     friend class base::RefCounted<SocketParams>;
197     ~SocketParams();
198 
199     std::vector<SSLConfig::CertAndStatus> allowed_bad_certs_;
200   };
201 
202   ClientSocketPool(const ClientSocketPool&) = delete;
203   ClientSocketPool& operator=(const ClientSocketPool&) = delete;
204 
205   ~ClientSocketPool() override;
206 
207   // Requests a connected socket with a specified GroupId.
208   //
209   // There are five possible results from calling this function:
210   // 1) RequestSocket returns OK and initializes |handle| with a reused socket.
211   // 2) RequestSocket returns OK with a newly connected socket.
212   // 3) RequestSocket returns ERR_IO_PENDING.  The handle will be added to a
213   // wait list until a socket is available to reuse or a new socket finishes
214   // connecting.  |priority| will determine the placement into the wait list.
215   // 4) An error occurred early on, so RequestSocket returns an error code.
216   // 5) A recoverable error occurred while setting up the socket.  An error
217   // code is returned, but the |handle| is initialized with the new socket.
218   // The caller must recover from the error before using the connection, or
219   // Disconnect the socket before releasing or resetting the |handle|.
220   // The current recoverable errors are: the errors accepted by
221   // IsCertificateError(err) and HTTPS_PROXY_TUNNEL_RESPONSE when reported by
222   // HttpProxyClientSocketPool.
223   //
224   // If this function returns OK, then |handle| is initialized upon return.
225   // The |handle|'s is_initialized method will return true in this case.  If a
226   // StreamSocket was reused, then ClientSocketPool will call
227   // |handle|->set_reused(true).  In either case, the socket will have been
228   // allocated and will be connected.  A client might want to know whether or
229   // not the socket is reused in order to request a new socket if it encounters
230   // an error with the reused socket.
231   //
232   // If ERR_IO_PENDING is returned, then the callback will be used to notify the
233   // client of completion.
234   //
235   // Profiling information for the request is saved to |net_log| if non-NULL.
236   //
237   // If |respect_limits| is DISABLED, priority must be HIGHEST.
238   //
239   // |proxy_annotation_tag| is the annotation used for proxy-related reads and
240   // writes, and may be nullopt if (and only if) no proxy is in use.
241   //
242   // |proxy_auth_callback| will be invoked each time an auth challenge is seen
243   // while establishing a tunnel. It will be invoked asynchronously, once for
244   // each auth challenge seen.
245   virtual int RequestSocket(
246       const GroupId& group_id,
247       scoped_refptr<SocketParams> params,
248       const std::optional<NetworkTrafficAnnotationTag>& proxy_annotation_tag,
249       RequestPriority priority,
250       const SocketTag& socket_tag,
251       RespectLimits respect_limits,
252       ClientSocketHandle* handle,
253       CompletionOnceCallback callback,
254       const ProxyAuthCallback& proxy_auth_callback,
255       const NetLogWithSource& net_log) = 0;
256 
257   // RequestSockets is used to request that |num_sockets| be connected in the
258   // connection group for |group_id|.  If the connection group already has
259   // |num_sockets| idle sockets / active sockets / currently connecting sockets,
260   // then this function doesn't do anything and returns OK.  Otherwise, it will
261   // start up as many connections as necessary to reach |num_sockets| total
262   // sockets for the group and returns ERR_IO_PENDING. And |callback| will be
263   // called with OK when the connection tasks are finished.
264   // It uses |params| to control how to connect the sockets. The
265   // ClientSocketPool will assign a priority to the new connections, if any.
266   // This priority will probably be lower than all others, since this method
267   // is intended to make sure ahead of time that |num_sockets| sockets are
268   // available to talk to a host.
269   virtual int RequestSockets(
270       const GroupId& group_id,
271       scoped_refptr<SocketParams> params,
272       const std::optional<NetworkTrafficAnnotationTag>& proxy_annotation_tag,
273       int num_sockets,
274       CompletionOnceCallback callback,
275       const NetLogWithSource& net_log) = 0;
276 
277   // Called to change the priority of a RequestSocket call that returned
278   // ERR_IO_PENDING and has not yet asynchronously completed.  The same handle
279   // parameter must be passed to this method as was passed to the
280   // RequestSocket call being modified.
281   // This function is a no-op if |priority| is the same as the current
282   // request priority.
283   virtual void SetPriority(const GroupId& group_id,
284                            ClientSocketHandle* handle,
285                            RequestPriority priority) = 0;
286 
287   // Called to cancel a RequestSocket call that returned ERR_IO_PENDING.  The
288   // same handle parameter must be passed to this method as was passed to the
289   // RequestSocket call being cancelled.  The associated callback is not run.
290   // If |cancel_connect_job| is true, and there are more ConnectJobs than
291   // requests, a ConnectJob will be canceled. If it's false, excess ConnectJobs
292   // may be allowed to continue, just in case there are new requests to the same
293   // endpoint.
294   virtual void CancelRequest(const GroupId& group_id,
295                              ClientSocketHandle* handle,
296                              bool cancel_connect_job) = 0;
297 
298   // Called to release a socket once the socket is no longer needed.  If the
299   // socket still has an established connection, then it will be added to the
300   // set of idle sockets to be used to satisfy future RequestSocket calls.
301   // Otherwise, the StreamSocket is destroyed.  |generation| is used to
302   // differentiate between updated versions of the same pool instance.  The
303   // pool's generation will change when it flushes, so it can use this
304   // |generation| to discard sockets with mismatched ids.
305   virtual void ReleaseSocket(const GroupId& group_id,
306                              std::unique_ptr<StreamSocket> socket,
307                              int64_t generation) = 0;
308 
309   // This flushes all state from the ClientSocketPool.  Pending socket requests
310   // are failed with |error|, while |reason| is logged to the NetLog.
311   //
312   // Active sockets being held by ClientSocketPool clients will be discarded
313   // when released back to the pool, though they will be closed with an error
314   // about being of the wrong generation, rather than |net_log_reason_utf8|.
315   virtual void FlushWithError(int error, const char* net_log_reason_utf8) = 0;
316 
317   // Called to close any idle connections held by the connection manager.
318   // |reason| is logged to NetLog for debugging purposes.
319   virtual void CloseIdleSockets(const char* net_log_reason_utf8) = 0;
320 
321   // Called to close any idle connections held by the connection manager.
322   // |reason| is logged to NetLog for debugging purposes.
323   virtual void CloseIdleSocketsInGroup(const GroupId& group_id,
324                                        const char* net_log_reason_utf8) = 0;
325 
326   // The total number of idle sockets in the pool.
327   virtual int IdleSocketCount() const = 0;
328 
329   // The total number of idle sockets in a connection group.
330   virtual size_t IdleSocketCountInGroup(const GroupId& group_id) const = 0;
331 
332   // Determine the LoadState of a connecting ClientSocketHandle.
333   virtual LoadState GetLoadState(const GroupId& group_id,
334                                  const ClientSocketHandle* handle) const = 0;
335 
336   // Retrieves information on the current state of the pool as a
337   // Value.
338   // If |include_nested_pools| is true, the states of any nested
339   // ClientSocketPools will be included.
340   virtual base::Value GetInfoAsValue(const std::string& name,
341                                      const std::string& type) const = 0;
342 
343   // Returns whether a connected (idle or handed out) or connecting socket
344   // exists for the group. This method is not supported for WebSockets.
345   virtual bool HasActiveSocket(const GroupId& group_id) const = 0;
346 
347   // Returns the maximum amount of time to wait before retrying a connect.
348   static const int kMaxConnectRetryIntervalMs = 250;
349 
350   static base::TimeDelta used_idle_socket_timeout();
351   static void set_used_idle_socket_timeout(base::TimeDelta timeout);
352 
353  protected:
354   ClientSocketPool(bool is_for_websockets,
355                    const CommonConnectJobParams* common_connect_job_params,
356                    std::unique_ptr<ConnectJobFactory> connect_job_factory);
357 
358   void NetLogTcpClientSocketPoolRequestedSocket(const NetLogWithSource& net_log,
359                                                 const GroupId& group_id);
360 
361   // Utility method to log a GroupId with a NetLog event.
362   static base::Value::Dict NetLogGroupIdParams(const GroupId& group_id);
363 
364   std::unique_ptr<ConnectJob> CreateConnectJob(
365       GroupId group_id,
366       scoped_refptr<SocketParams> socket_params,
367       const ProxyChain& proxy_chain,
368       const std::optional<NetworkTrafficAnnotationTag>& proxy_annotation_tag,
369       RequestPriority request_priority,
370       SocketTag socket_tag,
371       ConnectJob::Delegate* delegate);
372 
373  private:
374   const bool is_for_websockets_;
375   const raw_ptr<const CommonConnectJobParams> common_connect_job_params_;
376   const std::unique_ptr<ConnectJobFactory> connect_job_factory_;
377 };
378 
379 }  // namespace net
380 
381 #endif  // NET_SOCKET_CLIENT_SOCKET_POOL_H_
382