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