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