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