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