transport_client_socket_pool.h 34 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809
  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. #ifndef NET_SOCKET_TRANSPORT_CLIENT_SOCKET_POOL_H_
  5. #define NET_SOCKET_TRANSPORT_CLIENT_SOCKET_POOL_H_
  6. #include <stddef.h>
  7. #include <stdint.h>
  8. #include <list>
  9. #include <map>
  10. #include <memory>
  11. #include <set>
  12. #include <string>
  13. #include <utility>
  14. #include <vector>
  15. #include "base/memory/raw_ptr.h"
  16. #include "base/memory/ref_counted.h"
  17. #include "base/memory/weak_ptr.h"
  18. #include "base/time/time.h"
  19. #include "base/timer/timer.h"
  20. #include "net/base/address_list.h"
  21. #include "net/base/completion_once_callback.h"
  22. #include "net/base/load_states.h"
  23. #include "net/base/load_timing_info.h"
  24. #include "net/base/net_errors.h"
  25. #include "net/base/net_export.h"
  26. #include "net/base/network_change_notifier.h"
  27. #include "net/base/priority_queue.h"
  28. #include "net/base/proxy_server.h"
  29. #include "net/base/request_priority.h"
  30. #include "net/log/net_log_with_source.h"
  31. #include "net/socket/client_socket_handle.h"
  32. #include "net/socket/client_socket_pool.h"
  33. #include "net/socket/connect_job.h"
  34. #include "net/socket/connection_attempts.h"
  35. #include "net/socket/socket_tag.h"
  36. #include "net/socket/ssl_client_socket.h"
  37. #include "net/socket/stream_socket.h"
  38. #include "third_party/abseil-cpp/absl/types/optional.h"
  39. namespace net {
  40. struct CommonConnectJobParams;
  41. class ConnectJobFactory;
  42. struct NetLogSource;
  43. struct NetworkTrafficAnnotationTag;
  44. // TransportClientSocketPool establishes network connections through using
  45. // ConnectJobs, and maintains a list of idle persistent sockets available for
  46. // reuse. It restricts the number of sockets open at a time, both globally, and
  47. // for each unique GroupId, which roughly corresponds to origin and privacy mode
  48. // setting. TransportClientSocketPool is designed to work with HTTP reuse
  49. // semantics, handling each request serially, before reusable sockets are
  50. // returned to the socket pool.
  51. //
  52. // In order to manage connection limits on a per-Proxy basis, separate
  53. // TransportClientSocketPools are created for each proxy, and another for
  54. // connections that have no proxy.
  55. // TransportClientSocketPool is an internal class that implements almost all
  56. // the functionality from ClientSocketPool.
  57. class NET_EXPORT_PRIVATE TransportClientSocketPool
  58. : public ClientSocketPool,
  59. public NetworkChangeNotifier::IPAddressObserver,
  60. public SSLClientContext::Observer {
  61. public:
  62. // Reasons for closing sockets. Exposed here for testing.
  63. static const char kCertDatabaseChanged[];
  64. static const char kClosedConnectionReturnedToPool[];
  65. static const char kDataReceivedUnexpectedly[];
  66. static const char kIdleTimeLimitExpired[];
  67. static const char kNetworkChanged[];
  68. static const char kRemoteSideClosedConnection[];
  69. static const char kSocketGenerationOutOfDate[];
  70. static const char kSocketPoolDestroyed[];
  71. static const char kSslConfigChanged[];
  72. using Flags = uint32_t;
  73. // Used to specify specific behavior for the ClientSocketPool.
  74. enum Flag {
  75. NORMAL = 0, // Normal behavior.
  76. NO_IDLE_SOCKETS = 0x1, // Do not return an idle socket. Create a new one.
  77. };
  78. class NET_EXPORT_PRIVATE Request {
  79. public:
  80. // If |proxy_auth_callback| is null, proxy auth challenges will
  81. // result in an error.
  82. Request(
  83. ClientSocketHandle* handle,
  84. CompletionOnceCallback callback,
  85. const ProxyAuthCallback& proxy_auth_callback,
  86. RequestPriority priority,
  87. const SocketTag& socket_tag,
  88. RespectLimits respect_limits,
  89. Flags flags,
  90. scoped_refptr<SocketParams> socket_params,
  91. const absl::optional<NetworkTrafficAnnotationTag>& proxy_annotation_tag,
  92. const NetLogWithSource& net_log);
  93. Request(const Request&) = delete;
  94. Request& operator=(const Request&) = delete;
  95. ~Request();
  96. ClientSocketHandle* handle() const { return handle_; }
  97. CompletionOnceCallback release_callback() { return std::move(callback_); }
  98. const ProxyAuthCallback& proxy_auth_callback() const {
  99. return proxy_auth_callback_;
  100. }
  101. RequestPriority priority() const { return priority_; }
  102. void set_priority(RequestPriority priority) { priority_ = priority; }
  103. RespectLimits respect_limits() const { return respect_limits_; }
  104. Flags flags() const { return flags_; }
  105. SocketParams* socket_params() const { return socket_params_.get(); }
  106. const absl::optional<NetworkTrafficAnnotationTag>& proxy_annotation_tag()
  107. const {
  108. return proxy_annotation_tag_;
  109. }
  110. const NetLogWithSource& net_log() const { return net_log_; }
  111. const SocketTag& socket_tag() const { return socket_tag_; }
  112. ConnectJob* job() const { return job_; }
  113. // Associates a ConnectJob with the request. Must be called on a request
  114. // that does not already have a job.
  115. void AssignJob(ConnectJob* job);
  116. // Unassigns the request's |job_| and returns it. Must be called on a
  117. // request with a job.
  118. ConnectJob* ReleaseJob();
  119. private:
  120. const raw_ptr<ClientSocketHandle> handle_;
  121. CompletionOnceCallback callback_;
  122. const ProxyAuthCallback proxy_auth_callback_;
  123. RequestPriority priority_;
  124. const RespectLimits respect_limits_;
  125. const Flags flags_;
  126. const scoped_refptr<SocketParams> socket_params_;
  127. const absl::optional<NetworkTrafficAnnotationTag> proxy_annotation_tag_;
  128. const NetLogWithSource net_log_;
  129. const SocketTag socket_tag_;
  130. raw_ptr<ConnectJob> job_ = nullptr;
  131. };
  132. TransportClientSocketPool(
  133. int max_sockets,
  134. int max_sockets_per_group,
  135. base::TimeDelta unused_idle_socket_timeout,
  136. const ProxyServer& proxy_server,
  137. bool is_for_websockets,
  138. const CommonConnectJobParams* common_connect_job_params,
  139. bool cleanup_on_ip_address_change = true);
  140. TransportClientSocketPool(const TransportClientSocketPool&) = delete;
  141. TransportClientSocketPool& operator=(const TransportClientSocketPool&) =
  142. delete;
  143. // Creates a socket pool with an alternative ConnectJobFactory, for use in
  144. // testing.
  145. //
  146. // |connect_backup_jobs_enabled| can be set to false to disable backup connect
  147. // jobs (Which are normally enabled).
  148. static std::unique_ptr<TransportClientSocketPool> CreateForTesting(
  149. int max_sockets,
  150. int max_sockets_per_group,
  151. base::TimeDelta unused_idle_socket_timeout,
  152. base::TimeDelta used_idle_socket_timeout,
  153. const ProxyServer& proxy_server,
  154. bool is_for_websockets,
  155. const CommonConnectJobParams* common_connect_job_params,
  156. std::unique_ptr<ConnectJobFactory> connect_job_factory,
  157. SSLClientContext* ssl_client_context,
  158. bool connect_backup_jobs_enabled);
  159. ~TransportClientSocketPool() override;
  160. // See LowerLayeredPool::IsStalled for documentation on this function.
  161. bool IsStalled() const override;
  162. // See LowerLayeredPool for documentation on these functions. It is expected
  163. // in the destructor that no higher layer pools remain.
  164. void AddHigherLayeredPool(HigherLayeredPool* higher_pool) override;
  165. void RemoveHigherLayeredPool(HigherLayeredPool* higher_pool) override;
  166. // ClientSocketPool implementation:
  167. int RequestSocket(
  168. const GroupId& group_id,
  169. scoped_refptr<SocketParams> params,
  170. const absl::optional<NetworkTrafficAnnotationTag>& proxy_annotation_tag,
  171. RequestPriority priority,
  172. const SocketTag& socket_tag,
  173. RespectLimits respect_limits,
  174. ClientSocketHandle* handle,
  175. CompletionOnceCallback callback,
  176. const ProxyAuthCallback& proxy_auth_callback,
  177. const NetLogWithSource& net_log) override;
  178. int RequestSockets(
  179. const GroupId& group_id,
  180. scoped_refptr<SocketParams> params,
  181. const absl::optional<NetworkTrafficAnnotationTag>& proxy_annotation_tag,
  182. int num_sockets,
  183. CompletionOnceCallback callback,
  184. const NetLogWithSource& net_log) override;
  185. void SetPriority(const GroupId& group_id,
  186. ClientSocketHandle* handle,
  187. RequestPriority priority) override;
  188. void CancelRequest(const GroupId& group_id,
  189. ClientSocketHandle* handle,
  190. bool cancel_connect_job) override;
  191. void ReleaseSocket(const GroupId& group_id,
  192. std::unique_ptr<StreamSocket> socket,
  193. int64_t group_generation) override;
  194. void FlushWithError(int error, const char* net_log_reason_utf8) override;
  195. void CloseIdleSockets(const char* net_log_reason_utf8) override;
  196. void CloseIdleSocketsInGroup(const GroupId& group_id,
  197. const char* net_log_reason_utf8) override;
  198. int IdleSocketCount() const override;
  199. size_t IdleSocketCountInGroup(const GroupId& group_id) const override;
  200. LoadState GetLoadState(const GroupId& group_id,
  201. const ClientSocketHandle* handle) const override;
  202. base::Value GetInfoAsValue(const std::string& name,
  203. const std::string& type) const override;
  204. bool HasActiveSocket(const GroupId& group_id) const override;
  205. bool RequestInGroupWithHandleHasJobForTesting(
  206. const GroupId& group_id,
  207. const ClientSocketHandle* handle) const {
  208. return group_map_.find(group_id)->second->RequestWithHandleHasJobForTesting(
  209. handle);
  210. }
  211. size_t NumNeverAssignedConnectJobsInGroupForTesting(
  212. const GroupId& group_id) const {
  213. return NumNeverAssignedConnectJobsInGroup(group_id);
  214. }
  215. size_t NumUnassignedConnectJobsInGroupForTesting(
  216. const GroupId& group_id) const {
  217. return NumUnassignedConnectJobsInGroup(group_id);
  218. }
  219. size_t NumConnectJobsInGroupForTesting(const GroupId& group_id) const {
  220. return NumConnectJobsInGroup(group_id);
  221. }
  222. int NumActiveSocketsInGroupForTesting(const GroupId& group_id) const {
  223. return NumActiveSocketsInGroup(group_id);
  224. }
  225. bool HasGroupForTesting(const GroupId& group_id) const {
  226. return HasGroup(group_id);
  227. }
  228. static bool connect_backup_jobs_enabled();
  229. static bool set_connect_backup_jobs_enabled(bool enabled);
  230. // NetworkChangeNotifier::IPAddressObserver methods:
  231. void OnIPAddressChanged() override;
  232. // SSLClientContext::Observer methods.
  233. void OnSSLConfigChanged(bool is_cert_database_change) override;
  234. void OnSSLConfigForServerChanged(const HostPortPair& server) override;
  235. private:
  236. // Entry for a persistent socket which became idle at time |start_time|.
  237. struct IdleSocket;
  238. using RequestQueue = PriorityQueue<std::unique_ptr<Request>>;
  239. // A Group is allocated per GroupId when there are idle sockets, unbound
  240. // request, or bound requests. Otherwise, the Group object is removed from the
  241. // map.
  242. //
  243. // A request is "bound" to a ConnectJob when an unbound ConnectJob encounters
  244. // a proxy HTTP auth challenge, and the auth challenge is presented to that
  245. // request. Once a request and ConnectJob are bound together:
  246. // * All auth challenges the ConnectJob sees will be sent to that request.
  247. // * Cancelling the request will cancel the ConnectJob.
  248. // * The final result of the ConnectJob, and any returned socket, will only be
  249. // sent to that bound request, though if the returned socket is returned to
  250. // the socket pool, it can then be used to service any request.
  251. //
  252. // "assigned" jobs are unbound ConnectJobs that have a corresponding Request.
  253. // If there are 5 Jobs and 10 Requests, the 5 highest priority requests are
  254. // each assigned a Job. If there are 10 Jobs and 5 Requests, the first 5 Jobs
  255. // are each assigned to a request. Assignment is determined by order in their
  256. // corresponding arrays. The assignment concept is used to deal with
  257. // reprioritizing Jobs, and computing a Request's LoadState.
  258. //
  259. // |active_socket_count| tracks the number of sockets held by clients.
  260. // SanityCheck() will always be true, except during the invocation of a
  261. // method. So all public methods expect the Group to pass SanityCheck() when
  262. // invoked.
  263. class NET_EXPORT_PRIVATE Group : public ConnectJob::Delegate {
  264. public:
  265. using JobList = std::list<std::unique_ptr<ConnectJob>>;
  266. struct BoundRequest {
  267. BoundRequest();
  268. BoundRequest(std::unique_ptr<ConnectJob> connect_job,
  269. std::unique_ptr<Request> request,
  270. int64_t generation);
  271. BoundRequest(BoundRequest&& other);
  272. BoundRequest& operator=(BoundRequest&& other);
  273. ~BoundRequest();
  274. std::unique_ptr<ConnectJob> connect_job;
  275. std::unique_ptr<Request> request;
  276. // Generation of |connect_job|. If it doesn't match the current
  277. // generation, ConnectJob will be destroyed, and a new one created on
  278. // completion.
  279. int64_t generation;
  280. // It's not safe to fail a request in a |CancelAllRequestsWithError| call
  281. // while it's waiting on user input, as the request may have raw pointers
  282. // to objects owned by |connect_job| that it could racily write to after
  283. // |connect_job| is destroyed. Instead, just track an error in that case,
  284. // and fail the request once the ConnectJob completes.
  285. int pending_error;
  286. };
  287. Group(const GroupId& group_id,
  288. TransportClientSocketPool* client_socket_pool);
  289. ~Group() override;
  290. // ConnectJob::Delegate methods:
  291. void OnConnectJobComplete(int result, ConnectJob* job) override;
  292. void OnNeedsProxyAuth(const HttpResponseInfo& response,
  293. HttpAuthController* auth_controller,
  294. base::OnceClosure restart_with_auth_callback,
  295. ConnectJob* job) override;
  296. bool IsEmpty() const {
  297. return active_socket_count_ == 0 && idle_sockets_.empty() &&
  298. jobs_.empty() && unbound_requests_.empty() &&
  299. bound_requests_.empty();
  300. }
  301. bool HasAvailableSocketSlot(int max_sockets_per_group) const {
  302. return NumActiveSocketSlots() < max_sockets_per_group;
  303. }
  304. int NumActiveSocketSlots() const {
  305. return active_socket_count_ + static_cast<int>(jobs_.size()) +
  306. static_cast<int>(idle_sockets_.size()) +
  307. static_cast<int>(bound_requests_.size());
  308. }
  309. // Returns true if the group could make use of an additional socket slot, if
  310. // it were given one.
  311. bool CanUseAdditionalSocketSlot(int max_sockets_per_group) const {
  312. return HasAvailableSocketSlot(max_sockets_per_group) &&
  313. unbound_requests_.size() > jobs_.size();
  314. }
  315. // Returns the priority of the top of the unbound request queue
  316. // (which may be less than the maximum priority over the entire
  317. // queue, due to how we prioritize requests with |respect_limits|
  318. // DISABLED over others).
  319. RequestPriority TopPendingPriority() const {
  320. // NOTE: FirstMax().value()->priority() is not the same as
  321. // FirstMax().priority()!
  322. return unbound_requests_.FirstMax().value()->priority();
  323. }
  324. // Set a timer to create a backup job if it takes too long to
  325. // create one and if a timer isn't already running.
  326. void StartBackupJobTimer(const GroupId& group_id);
  327. bool BackupJobTimerIsRunning() const;
  328. // If there's a ConnectJob that's never been assigned to Request,
  329. // decrements |never_assigned_job_count_| and returns true.
  330. // Otherwise, returns false.
  331. bool TryToUseNeverAssignedConnectJob();
  332. void AddJob(std::unique_ptr<ConnectJob> job, bool is_preconnect);
  333. // Remove |job| from this group, which must already own |job|. Returns the
  334. // removed ConnectJob.
  335. std::unique_ptr<ConnectJob> RemoveUnboundJob(ConnectJob* job);
  336. void RemoveAllUnboundJobs();
  337. bool has_unbound_requests() const { return !unbound_requests_.empty(); }
  338. size_t unbound_request_count() const { return unbound_requests_.size(); }
  339. size_t ConnectJobCount() const;
  340. // Returns the connect job correspding to |handle|. In particular, if
  341. // |handle| is bound to a ConnectJob, returns that job. If |handle| is
  342. // "assigned" a ConnectJob, return that job. Otherwise, returns nullptr.
  343. ConnectJob* GetConnectJobForHandle(const ClientSocketHandle* handle) const;
  344. // Inserts the request into the queue based on priority
  345. // order. Older requests are prioritized over requests of equal
  346. // priority.
  347. void InsertUnboundRequest(std::unique_ptr<Request> request);
  348. // Gets (but does not remove) the next unbound request. Returns
  349. // NULL if there are no unbound requests.
  350. const Request* GetNextUnboundRequest() const;
  351. // Gets and removes the next unbound request. Returns NULL if
  352. // there are no unbound requests.
  353. std::unique_ptr<Request> PopNextUnboundRequest();
  354. // Finds the unbound request for |handle| and removes it. Returns
  355. // the removed unbound request, or NULL if there was none.
  356. std::unique_ptr<Request> FindAndRemoveUnboundRequest(
  357. ClientSocketHandle* handle);
  358. // Sets a pending error for all bound requests. Bound requests may be in the
  359. // middle of a callback, so can't be failed at arbitrary points in time.
  360. void SetPendingErrorForAllBoundRequests(int pending_error);
  361. // Attempts to bind the highest priority unbound request to |connect_job|,
  362. // and returns the bound request. If the request has previously been bound
  363. // to |connect_job|, returns the previously bound request. If there are no
  364. // requests, or the highest priority request doesn't have a proxy auth
  365. // callback, returns nullptr.
  366. const Request* BindRequestToConnectJob(ConnectJob* connect_job);
  367. // Finds the request, if any, bound to |connect_job|, and returns the
  368. // BoundRequest or absl::nullopt if there was none.
  369. absl::optional<BoundRequest> FindAndRemoveBoundRequestForConnectJob(
  370. ConnectJob* connect_job);
  371. // Finds the bound request, if any, corresponding to |client_socket_handle|
  372. // and returns it. Destroys the ConnectJob bound to the request, if there
  373. // was one.
  374. std::unique_ptr<Request> FindAndRemoveBoundRequest(
  375. ClientSocketHandle* client_socket_handle);
  376. // Change the priority of the request named by |*handle|. |*handle|
  377. // must refer to a request currently present in the group. If |priority|
  378. // is the same as the current priority of the request, this is a no-op.
  379. void SetPriority(ClientSocketHandle* handle, RequestPriority priority);
  380. void IncrementActiveSocketCount() { active_socket_count_++; }
  381. void DecrementActiveSocketCount() { active_socket_count_--; }
  382. void IncrementGeneration() { generation_++; }
  383. // Whether the request in |unbound_requests_| with a given handle has a job.
  384. bool RequestWithHandleHasJobForTesting(
  385. const ClientSocketHandle* handle) const;
  386. const GroupId& group_id() { return group_id_; }
  387. size_t unassigned_job_count() const { return unassigned_jobs_.size(); }
  388. const JobList& jobs() const { return jobs_; }
  389. const std::list<IdleSocket>& idle_sockets() const { return idle_sockets_; }
  390. int active_socket_count() const { return active_socket_count_; }
  391. std::list<IdleSocket>* mutable_idle_sockets() { return &idle_sockets_; }
  392. size_t never_assigned_job_count() const {
  393. return never_assigned_job_count_;
  394. }
  395. int64_t generation() const { return generation_; }
  396. private:
  397. // Returns the iterator's unbound request after removing it from
  398. // the queue. Expects the Group to pass SanityCheck() when called.
  399. std::unique_ptr<Request> RemoveUnboundRequest(
  400. const RequestQueue::Pointer& pointer);
  401. // Finds the Request which is associated with the given ConnectJob.
  402. // Returns nullptr if none is found. Expects the Group to pass SanityCheck()
  403. // when called.
  404. RequestQueue::Pointer FindUnboundRequestWithJob(
  405. const ConnectJob* job) const;
  406. // Finds the Request in |unbound_requests_| which is the first request
  407. // without a job. Returns a null pointer if all requests have jobs. Does not
  408. // expect the Group to pass SanityCheck() when called, but does expect all
  409. // jobs to either be assigned to a request or in |unassigned_jobs_|. Expects
  410. // that no requests with jobs come after any requests without a job.
  411. RequestQueue::Pointer GetFirstRequestWithoutJob() const;
  412. // Tries to assign an unassigned |job| to a request. If no requests need a
  413. // job, |job| is added to |unassigned_jobs_|.
  414. // When called, does not expect the Group to pass SanityCheck(), but does
  415. // expect it to have passed SanityCheck() before the given ConnectJob was
  416. // either created or had the request it was assigned to removed.
  417. void TryToAssignUnassignedJob(ConnectJob* job);
  418. // Tries to assign a job to the given request. If any unassigned jobs are
  419. // available, the first unassigned job is assigned to the request.
  420. // Otherwise, if the request is ahead of the last request with a job, the
  421. // job is stolen from the last request with a job.
  422. // When called, does not expect the Group to pass SanityCheck(), but does
  423. // expect that:
  424. // - the request associated with |request_pointer| must not have
  425. // an assigned ConnectJob,
  426. // - the first min( jobs_.size(), unbound_requests_.size() - 1 ) Requests
  427. // other than the given request must have ConnectJobs, i.e. the group
  428. // must have passed SanityCheck() before the passed in Request was either
  429. // added or had its job unassigned.
  430. void TryToAssignJobToRequest(RequestQueue::Pointer request_pointer);
  431. // Transfers the associated ConnectJob from one Request to another. Expects
  432. // the source request to have a job, and the destination request to not have
  433. // a job. Does not expect the Group to pass SanityCheck() when called.
  434. void TransferJobBetweenRequests(Request* source, Request* dest);
  435. // Called when the backup socket timer fires.
  436. void OnBackupJobTimerFired(const GroupId& group_id);
  437. // Checks that:
  438. // - |unassigned_jobs_| is empty iff there are at least as many requests
  439. // as jobs.
  440. // - Exactly the first |jobs_.size() - unassigned_jobs_.size()| requests
  441. // have ConnectJobs.
  442. // - No requests are assigned a ConnectJob in |unassigned_jobs_|.
  443. // - No requests are assigned a ConnectJob not in |jobs_|.
  444. // - No two requests are assigned the same ConnectJob.
  445. // - All entries in |unassigned_jobs_| are also in |jobs_|.
  446. // - There are no duplicate entries in |unassigned_jobs_|.
  447. void SanityCheck() const;
  448. const GroupId group_id_;
  449. const raw_ptr<TransportClientSocketPool> client_socket_pool_;
  450. // Total number of ConnectJobs that have never been assigned to a Request.
  451. // Since jobs use late binding to requests, which ConnectJobs have or have
  452. // not been assigned to a request are not tracked. This is incremented on
  453. // preconnect and decremented when a preconnect is assigned, or when there
  454. // are fewer than |never_assigned_job_count_| ConnectJobs. Not incremented
  455. // when a request is cancelled.
  456. size_t never_assigned_job_count_ = 0;
  457. std::list<IdleSocket> idle_sockets_;
  458. JobList jobs_; // For bookkeeping purposes, there is a copy of the raw
  459. // pointer of each element of |jobs_| stored either in
  460. // |unassigned_jobs_|, or as the associated |job_| of an
  461. // element of |unbound_requests_|.
  462. std::list<ConnectJob*> unassigned_jobs_;
  463. RequestQueue unbound_requests_;
  464. int active_socket_count_ = 0; // number of active sockets used by clients
  465. // A timer for when to start the backup job.
  466. base::OneShotTimer backup_job_timer_;
  467. // List of Requests bound to ConnectJobs currently undergoing proxy auth.
  468. // The Requests and ConnectJobs in this list do not appear in
  469. // |unbound_requests_| or |jobs_|.
  470. std::vector<BoundRequest> bound_requests_;
  471. // An id for the group. It gets incremented every time we FlushWithError()
  472. // the socket pool, or refresh the group. This is so that when sockets get
  473. // released back to the group, we can make sure that they are discarded
  474. // rather than reused. Destroying a group will reset the generation number,
  475. // but as that only happens once there are no outstanding sockets or
  476. // requests associated with the group, that's harmless.
  477. int64_t generation_ = 0;
  478. };
  479. using GroupMap = std::map<GroupId, Group*>;
  480. struct CallbackResultPair {
  481. CallbackResultPair();
  482. CallbackResultPair(CompletionOnceCallback callback_in, int result_in);
  483. CallbackResultPair(CallbackResultPair&& other);
  484. CallbackResultPair& operator=(CallbackResultPair&& other);
  485. ~CallbackResultPair();
  486. CompletionOnceCallback callback;
  487. int result;
  488. };
  489. using PendingCallbackMap =
  490. std::map<const ClientSocketHandle*, CallbackResultPair>;
  491. TransportClientSocketPool(
  492. int max_sockets,
  493. int max_sockets_per_group,
  494. base::TimeDelta unused_idle_socket_timeout,
  495. base::TimeDelta used_idle_socket_timeout,
  496. const ProxyServer& proxy_server,
  497. bool is_for_websockets,
  498. const CommonConnectJobParams* common_connect_job_params,
  499. bool cleanup_on_ip_address_change,
  500. std::unique_ptr<ConnectJobFactory> connect_job_factory,
  501. SSLClientContext* ssl_client_context,
  502. bool connect_backup_jobs_enabled);
  503. base::TimeDelta ConnectRetryInterval() const {
  504. // TODO(mbelshe): Make this tuned dynamically based on measured RTT.
  505. // For now, just use the max retry interval.
  506. return base::Milliseconds(kMaxConnectRetryIntervalMs);
  507. }
  508. // TODO(mmenke): de-inline these.
  509. size_t NumNeverAssignedConnectJobsInGroup(const GroupId& group_id) const {
  510. return group_map_.find(group_id)->second->never_assigned_job_count();
  511. }
  512. size_t NumUnassignedConnectJobsInGroup(const GroupId& group_id) const {
  513. return group_map_.find(group_id)->second->unassigned_job_count();
  514. }
  515. size_t NumConnectJobsInGroup(const GroupId& group_id) const {
  516. return group_map_.find(group_id)->second->ConnectJobCount();
  517. }
  518. int NumActiveSocketsInGroup(const GroupId& group_id) const {
  519. return group_map_.find(group_id)->second->active_socket_count();
  520. }
  521. bool HasGroup(const GroupId& group_id) const;
  522. // Closes all idle sockets if |force| is true. Else, only closes idle
  523. // sockets that timed out or can't be reused. Made public for testing.
  524. // |reason| must be non-empty when |force| is true.
  525. void CleanupIdleSockets(bool force, const char* net_log_reason_utf8);
  526. // Closes one idle socket. Picks the first one encountered.
  527. // TODO(willchan): Consider a better algorithm for doing this. Perhaps we
  528. // should keep an ordered list of idle sockets, and close them in order.
  529. // Requires maintaining more state. It's not clear if it's worth it since
  530. // I'm not sure if we hit this situation often.
  531. bool CloseOneIdleSocket();
  532. // Checks higher layered pools to see if they can close an idle connection.
  533. bool CloseOneIdleConnectionInHigherLayeredPool();
  534. // Closes all idle sockets in |group| if |force| is true. Else, only closes
  535. // idle sockets in |group| that timed out with respect to |now| or can't be
  536. // reused.
  537. void CleanupIdleSocketsInGroup(bool force,
  538. Group* group,
  539. const base::TimeTicks& now,
  540. const char* net_log_reason_utf8);
  541. Group* GetOrCreateGroup(const GroupId& group_id);
  542. void RemoveGroup(const GroupId& group_id);
  543. void RemoveGroup(GroupMap::iterator it);
  544. // Called when the number of idle sockets changes.
  545. void IncrementIdleCount();
  546. void DecrementIdleCount();
  547. // Scans the group map for groups which have an available socket slot and
  548. // at least one pending request. Returns true if any groups are stalled, and
  549. // if so (and if both |group| and |group_id| are not NULL), fills |group|
  550. // and |group_id| with data of the stalled group having highest priority.
  551. bool FindTopStalledGroup(Group** group, GroupId* group_id) const;
  552. // Removes |job| from |group|, which must already own |job|.
  553. void RemoveConnectJob(ConnectJob* job, Group* group);
  554. // Tries to see if we can handle any more requests for |group|.
  555. void OnAvailableSocketSlot(const GroupId& group_id, Group* group);
  556. // Process a pending socket request for a group.
  557. void ProcessPendingRequest(const GroupId& group_id, Group* group);
  558. // Assigns |socket| to |handle| and updates |group|'s counters appropriately.
  559. void HandOutSocket(std::unique_ptr<StreamSocket> socket,
  560. ClientSocketHandle::SocketReuseType reuse_type,
  561. const LoadTimingInfo::ConnectTiming& connect_timing,
  562. ClientSocketHandle* handle,
  563. base::TimeDelta time_idle,
  564. Group* group,
  565. const NetLogWithSource& net_log);
  566. // Adds |socket| to the list of idle sockets for |group|.
  567. void AddIdleSocket(std::unique_ptr<StreamSocket> socket, Group* group);
  568. // Iterates through |group_map_|, canceling all ConnectJobs and deleting
  569. // groups if they are no longer needed.
  570. void CancelAllConnectJobs();
  571. // Iterates through |group_map_|, posting |error| callbacks for all
  572. // requests, and then deleting groups if they are no longer needed.
  573. void CancelAllRequestsWithError(int error);
  574. // Returns true if we can't create any more sockets due to the total limit.
  575. bool ReachedMaxSocketsLimit() const;
  576. // This is the internal implementation of RequestSocket(). It differs in that
  577. // it does not handle logging into NetLog of the queueing status of
  578. // |request|.
  579. // |preconnect_done_closure| is used only for preconnect requests. For
  580. // preconnect requests, this method returns ERR_IO_PENDING only if a connect
  581. // job is created and the connect job didn't finish synchronously. In such
  582. // case, |preconnect_done_closure| will be called when the created connect job
  583. // will be deleted.
  584. // For normal non-preconnect requests, |preconnect_done_closure| must be null.
  585. // And this method returns ERR_IO_PENDING when the number of sockets has
  586. // reached the limit or the created connect job didn't finish synchronously.
  587. // In such a case, the Request with a ClientSocketHandle must be registered to
  588. // |group_map_| to receive the completion callback.
  589. int RequestSocketInternal(const GroupId& group_id,
  590. const Request& request,
  591. base::OnceClosure preconnect_done_closure);
  592. // Assigns an idle socket for the group to the request.
  593. // Returns |true| if an idle socket is available, false otherwise.
  594. bool AssignIdleSocketToRequest(const Request& request, Group* group);
  595. static void LogBoundConnectJobToRequest(
  596. const NetLogSource& connect_job_source,
  597. const Request& request);
  598. // Same as CloseOneIdleSocket() except it won't close an idle socket in
  599. // |group|. If |group| is NULL, it is ignored. Returns true if it closed a
  600. // socket.
  601. bool CloseOneIdleSocketExceptInGroup(const Group* group);
  602. // Checks if there are stalled socket groups that should be notified
  603. // for possible wakeup.
  604. void CheckForStalledSocketGroups();
  605. // Posts a task to call InvokeUserCallback() on the next iteration through the
  606. // current message loop. Inserts |callback| into |pending_callback_map_|,
  607. // keyed by |handle|. Apply |socket_tag| to the socket if socket successfully
  608. // created.
  609. void InvokeUserCallbackLater(ClientSocketHandle* handle,
  610. CompletionOnceCallback callback,
  611. int rv,
  612. const SocketTag& socket_tag);
  613. // These correspond to ConnectJob::Delegate methods, and are invoked by the
  614. // Group a ConnectJob belongs to.
  615. void OnConnectJobComplete(Group* group, int result, ConnectJob* job);
  616. void OnNeedsProxyAuth(Group* group,
  617. const HttpResponseInfo& response,
  618. HttpAuthController* auth_controller,
  619. base::OnceClosure restart_with_auth_callback,
  620. ConnectJob* job);
  621. // Invokes the user callback for |handle|. By the time this task has run,
  622. // it's possible that the request has been cancelled, so |handle| may not
  623. // exist in |pending_callback_map_|. We look up the callback and result code
  624. // in |pending_callback_map_|.
  625. void InvokeUserCallback(ClientSocketHandle* handle);
  626. // Tries to close idle sockets in a higher level socket pool as long as this
  627. // this pool is stalled.
  628. void TryToCloseSocketsInLayeredPools();
  629. // Closes all idle sockets and cancels all unbound ConnectJobs associated with
  630. // |it->second|. Also increments the group's generation number, ensuring any
  631. // currently existing handed out socket will be silently closed when it is
  632. // returned to the socket pool. Bound ConnectJobs will only be destroyed on
  633. // once they complete, as they may be waiting on user input. No request
  634. // (including bound ones) will be failed as a result of this call - instead,
  635. // new ConnectJobs will be created.
  636. //
  637. // The group may be removed if this leaves the group empty. The caller must
  638. // call CheckForStalledSocketGroups() after all applicable groups have been
  639. // refreshed.
  640. void RefreshGroup(GroupMap::iterator it,
  641. const base::TimeTicks& now,
  642. const char* net_log_reason_utf8);
  643. GroupMap group_map_;
  644. // Map of the ClientSocketHandles for which we have a pending Task to invoke a
  645. // callback. This is necessary since, before we invoke said callback, it's
  646. // possible that the request is cancelled.
  647. PendingCallbackMap pending_callback_map_;
  648. // The total number of idle sockets in the system.
  649. int idle_socket_count_ = 0;
  650. // Number of connecting sockets across all groups.
  651. int connecting_socket_count_ = 0;
  652. // Number of connected sockets we handed out across all groups.
  653. int handed_out_socket_count_ = 0;
  654. // The maximum total number of sockets. See ReachedMaxSocketsLimit.
  655. const int max_sockets_;
  656. // The maximum number of sockets kept per group.
  657. const int max_sockets_per_group_;
  658. // The time to wait until closing idle sockets.
  659. const base::TimeDelta unused_idle_socket_timeout_;
  660. const base::TimeDelta used_idle_socket_timeout_;
  661. const ProxyServer proxy_server_;
  662. const bool cleanup_on_ip_address_change_;
  663. // TODO(vandebo) Remove when backup jobs move to TransportClientSocketPool
  664. bool connect_backup_jobs_enabled_;
  665. // Pools that create connections through |this|. |this| will try to close
  666. // their idle sockets when it stalls. Must be empty on destruction.
  667. std::set<HigherLayeredPool*> higher_pools_;
  668. const raw_ptr<SSLClientContext> ssl_client_context_;
  669. #if DCHECK_IS_ON()
  670. // Reentrancy guard for RequestSocketInternal().
  671. bool request_in_process_ = false;
  672. #endif // DCHECK_IS_ON()
  673. base::WeakPtrFactory<TransportClientSocketPool> weak_factory_{this};
  674. };
  675. } // namespace net
  676. #endif // NET_SOCKET_TRANSPORT_CLIENT_SOCKET_POOL_H_