123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809 |
- // Copyright (c) 2012 The Chromium Authors. All rights reserved.
- // Use of this source code is governed by a BSD-style license that can be
- // found in the LICENSE file.
- #ifndef NET_SOCKET_TRANSPORT_CLIENT_SOCKET_POOL_H_
- #define NET_SOCKET_TRANSPORT_CLIENT_SOCKET_POOL_H_
- #include <stddef.h>
- #include <stdint.h>
- #include <list>
- #include <map>
- #include <memory>
- #include <set>
- #include <string>
- #include <utility>
- #include <vector>
- #include "base/memory/raw_ptr.h"
- #include "base/memory/ref_counted.h"
- #include "base/memory/weak_ptr.h"
- #include "base/time/time.h"
- #include "base/timer/timer.h"
- #include "net/base/address_list.h"
- #include "net/base/completion_once_callback.h"
- #include "net/base/load_states.h"
- #include "net/base/load_timing_info.h"
- #include "net/base/net_errors.h"
- #include "net/base/net_export.h"
- #include "net/base/network_change_notifier.h"
- #include "net/base/priority_queue.h"
- #include "net/base/proxy_server.h"
- #include "net/base/request_priority.h"
- #include "net/log/net_log_with_source.h"
- #include "net/socket/client_socket_handle.h"
- #include "net/socket/client_socket_pool.h"
- #include "net/socket/connect_job.h"
- #include "net/socket/connection_attempts.h"
- #include "net/socket/socket_tag.h"
- #include "net/socket/ssl_client_socket.h"
- #include "net/socket/stream_socket.h"
- #include "third_party/abseil-cpp/absl/types/optional.h"
- namespace net {
- struct CommonConnectJobParams;
- class ConnectJobFactory;
- struct NetLogSource;
- struct NetworkTrafficAnnotationTag;
- // TransportClientSocketPool establishes network connections through using
- // ConnectJobs, and maintains a list of idle persistent sockets available for
- // reuse. It restricts the number of sockets open at a time, both globally, and
- // for each unique GroupId, which roughly corresponds to origin and privacy mode
- // setting. TransportClientSocketPool is designed to work with HTTP reuse
- // semantics, handling each request serially, before reusable sockets are
- // returned to the socket pool.
- //
- // In order to manage connection limits on a per-Proxy basis, separate
- // TransportClientSocketPools are created for each proxy, and another for
- // connections that have no proxy.
- // TransportClientSocketPool is an internal class that implements almost all
- // the functionality from ClientSocketPool.
- class NET_EXPORT_PRIVATE TransportClientSocketPool
- : public ClientSocketPool,
- public NetworkChangeNotifier::IPAddressObserver,
- public SSLClientContext::Observer {
- public:
- // Reasons for closing sockets. Exposed here for testing.
- static const char kCertDatabaseChanged[];
- static const char kClosedConnectionReturnedToPool[];
- static const char kDataReceivedUnexpectedly[];
- static const char kIdleTimeLimitExpired[];
- static const char kNetworkChanged[];
- static const char kRemoteSideClosedConnection[];
- static const char kSocketGenerationOutOfDate[];
- static const char kSocketPoolDestroyed[];
- static const char kSslConfigChanged[];
- using Flags = uint32_t;
- // Used to specify specific behavior for the ClientSocketPool.
- enum Flag {
- NORMAL = 0, // Normal behavior.
- NO_IDLE_SOCKETS = 0x1, // Do not return an idle socket. Create a new one.
- };
- class NET_EXPORT_PRIVATE Request {
- public:
- // If |proxy_auth_callback| is null, proxy auth challenges will
- // result in an error.
- Request(
- ClientSocketHandle* handle,
- CompletionOnceCallback callback,
- const ProxyAuthCallback& proxy_auth_callback,
- RequestPriority priority,
- const SocketTag& socket_tag,
- RespectLimits respect_limits,
- Flags flags,
- scoped_refptr<SocketParams> socket_params,
- const absl::optional<NetworkTrafficAnnotationTag>& proxy_annotation_tag,
- const NetLogWithSource& net_log);
- Request(const Request&) = delete;
- Request& operator=(const Request&) = delete;
- ~Request();
- ClientSocketHandle* handle() const { return handle_; }
- CompletionOnceCallback release_callback() { return std::move(callback_); }
- const ProxyAuthCallback& proxy_auth_callback() const {
- return proxy_auth_callback_;
- }
- RequestPriority priority() const { return priority_; }
- void set_priority(RequestPriority priority) { priority_ = priority; }
- RespectLimits respect_limits() const { return respect_limits_; }
- Flags flags() const { return flags_; }
- SocketParams* socket_params() const { return socket_params_.get(); }
- const absl::optional<NetworkTrafficAnnotationTag>& proxy_annotation_tag()
- const {
- return proxy_annotation_tag_;
- }
- const NetLogWithSource& net_log() const { return net_log_; }
- const SocketTag& socket_tag() const { return socket_tag_; }
- ConnectJob* job() const { return job_; }
- // Associates a ConnectJob with the request. Must be called on a request
- // that does not already have a job.
- void AssignJob(ConnectJob* job);
- // Unassigns the request's |job_| and returns it. Must be called on a
- // request with a job.
- ConnectJob* ReleaseJob();
- private:
- const raw_ptr<ClientSocketHandle> handle_;
- CompletionOnceCallback callback_;
- const ProxyAuthCallback proxy_auth_callback_;
- RequestPriority priority_;
- const RespectLimits respect_limits_;
- const Flags flags_;
- const scoped_refptr<SocketParams> socket_params_;
- const absl::optional<NetworkTrafficAnnotationTag> proxy_annotation_tag_;
- const NetLogWithSource net_log_;
- const SocketTag socket_tag_;
- raw_ptr<ConnectJob> job_ = nullptr;
- };
- TransportClientSocketPool(
- int max_sockets,
- int max_sockets_per_group,
- base::TimeDelta unused_idle_socket_timeout,
- const ProxyServer& proxy_server,
- bool is_for_websockets,
- const CommonConnectJobParams* common_connect_job_params,
- bool cleanup_on_ip_address_change = true);
- TransportClientSocketPool(const TransportClientSocketPool&) = delete;
- TransportClientSocketPool& operator=(const TransportClientSocketPool&) =
- delete;
- // Creates a socket pool with an alternative ConnectJobFactory, for use in
- // testing.
- //
- // |connect_backup_jobs_enabled| can be set to false to disable backup connect
- // jobs (Which are normally enabled).
- static std::unique_ptr<TransportClientSocketPool> CreateForTesting(
- int max_sockets,
- int max_sockets_per_group,
- base::TimeDelta unused_idle_socket_timeout,
- base::TimeDelta used_idle_socket_timeout,
- const ProxyServer& proxy_server,
- bool is_for_websockets,
- const CommonConnectJobParams* common_connect_job_params,
- std::unique_ptr<ConnectJobFactory> connect_job_factory,
- SSLClientContext* ssl_client_context,
- bool connect_backup_jobs_enabled);
- ~TransportClientSocketPool() override;
- // See LowerLayeredPool::IsStalled for documentation on this function.
- bool IsStalled() const override;
- // See LowerLayeredPool for documentation on these functions. It is expected
- // in the destructor that no higher layer pools remain.
- void AddHigherLayeredPool(HigherLayeredPool* higher_pool) override;
- void RemoveHigherLayeredPool(HigherLayeredPool* higher_pool) override;
- // ClientSocketPool implementation:
- int RequestSocket(
- const GroupId& group_id,
- scoped_refptr<SocketParams> params,
- const absl::optional<NetworkTrafficAnnotationTag>& proxy_annotation_tag,
- RequestPriority priority,
- const SocketTag& socket_tag,
- RespectLimits respect_limits,
- ClientSocketHandle* handle,
- CompletionOnceCallback callback,
- const ProxyAuthCallback& proxy_auth_callback,
- const NetLogWithSource& net_log) override;
- int RequestSockets(
- const GroupId& group_id,
- scoped_refptr<SocketParams> params,
- const absl::optional<NetworkTrafficAnnotationTag>& proxy_annotation_tag,
- int num_sockets,
- CompletionOnceCallback callback,
- const NetLogWithSource& net_log) override;
- void SetPriority(const GroupId& group_id,
- ClientSocketHandle* handle,
- RequestPriority priority) override;
- void CancelRequest(const GroupId& group_id,
- ClientSocketHandle* handle,
- bool cancel_connect_job) override;
- void ReleaseSocket(const GroupId& group_id,
- std::unique_ptr<StreamSocket> socket,
- int64_t group_generation) override;
- void FlushWithError(int error, const char* net_log_reason_utf8) override;
- void CloseIdleSockets(const char* net_log_reason_utf8) override;
- void CloseIdleSocketsInGroup(const GroupId& group_id,
- const char* net_log_reason_utf8) override;
- int IdleSocketCount() const override;
- size_t IdleSocketCountInGroup(const GroupId& group_id) const override;
- LoadState GetLoadState(const GroupId& group_id,
- const ClientSocketHandle* handle) const override;
- base::Value GetInfoAsValue(const std::string& name,
- const std::string& type) const override;
- bool HasActiveSocket(const GroupId& group_id) const override;
- bool RequestInGroupWithHandleHasJobForTesting(
- const GroupId& group_id,
- const ClientSocketHandle* handle) const {
- return group_map_.find(group_id)->second->RequestWithHandleHasJobForTesting(
- handle);
- }
- size_t NumNeverAssignedConnectJobsInGroupForTesting(
- const GroupId& group_id) const {
- return NumNeverAssignedConnectJobsInGroup(group_id);
- }
- size_t NumUnassignedConnectJobsInGroupForTesting(
- const GroupId& group_id) const {
- return NumUnassignedConnectJobsInGroup(group_id);
- }
- size_t NumConnectJobsInGroupForTesting(const GroupId& group_id) const {
- return NumConnectJobsInGroup(group_id);
- }
- int NumActiveSocketsInGroupForTesting(const GroupId& group_id) const {
- return NumActiveSocketsInGroup(group_id);
- }
- bool HasGroupForTesting(const GroupId& group_id) const {
- return HasGroup(group_id);
- }
- static bool connect_backup_jobs_enabled();
- static bool set_connect_backup_jobs_enabled(bool enabled);
- // NetworkChangeNotifier::IPAddressObserver methods:
- void OnIPAddressChanged() override;
- // SSLClientContext::Observer methods.
- void OnSSLConfigChanged(bool is_cert_database_change) override;
- void OnSSLConfigForServerChanged(const HostPortPair& server) override;
- private:
- // Entry for a persistent socket which became idle at time |start_time|.
- struct IdleSocket;
- using RequestQueue = PriorityQueue<std::unique_ptr<Request>>;
- // A Group is allocated per GroupId when there are idle sockets, unbound
- // request, or bound requests. Otherwise, the Group object is removed from the
- // map.
- //
- // A request is "bound" to a ConnectJob when an unbound ConnectJob encounters
- // a proxy HTTP auth challenge, and the auth challenge is presented to that
- // request. Once a request and ConnectJob are bound together:
- // * All auth challenges the ConnectJob sees will be sent to that request.
- // * Cancelling the request will cancel the ConnectJob.
- // * The final result of the ConnectJob, and any returned socket, will only be
- // sent to that bound request, though if the returned socket is returned to
- // the socket pool, it can then be used to service any request.
- //
- // "assigned" jobs are unbound ConnectJobs that have a corresponding Request.
- // If there are 5 Jobs and 10 Requests, the 5 highest priority requests are
- // each assigned a Job. If there are 10 Jobs and 5 Requests, the first 5 Jobs
- // are each assigned to a request. Assignment is determined by order in their
- // corresponding arrays. The assignment concept is used to deal with
- // reprioritizing Jobs, and computing a Request's LoadState.
- //
- // |active_socket_count| tracks the number of sockets held by clients.
- // SanityCheck() will always be true, except during the invocation of a
- // method. So all public methods expect the Group to pass SanityCheck() when
- // invoked.
- class NET_EXPORT_PRIVATE Group : public ConnectJob::Delegate {
- public:
- using JobList = std::list<std::unique_ptr<ConnectJob>>;
- struct BoundRequest {
- BoundRequest();
- BoundRequest(std::unique_ptr<ConnectJob> connect_job,
- std::unique_ptr<Request> request,
- int64_t generation);
- BoundRequest(BoundRequest&& other);
- BoundRequest& operator=(BoundRequest&& other);
- ~BoundRequest();
- std::unique_ptr<ConnectJob> connect_job;
- std::unique_ptr<Request> request;
- // Generation of |connect_job|. If it doesn't match the current
- // generation, ConnectJob will be destroyed, and a new one created on
- // completion.
- int64_t generation;
- // It's not safe to fail a request in a |CancelAllRequestsWithError| call
- // while it's waiting on user input, as the request may have raw pointers
- // to objects owned by |connect_job| that it could racily write to after
- // |connect_job| is destroyed. Instead, just track an error in that case,
- // and fail the request once the ConnectJob completes.
- int pending_error;
- };
- Group(const GroupId& group_id,
- TransportClientSocketPool* client_socket_pool);
- ~Group() override;
- // ConnectJob::Delegate methods:
- void OnConnectJobComplete(int result, ConnectJob* job) override;
- void OnNeedsProxyAuth(const HttpResponseInfo& response,
- HttpAuthController* auth_controller,
- base::OnceClosure restart_with_auth_callback,
- ConnectJob* job) override;
- bool IsEmpty() const {
- return active_socket_count_ == 0 && idle_sockets_.empty() &&
- jobs_.empty() && unbound_requests_.empty() &&
- bound_requests_.empty();
- }
- bool HasAvailableSocketSlot(int max_sockets_per_group) const {
- return NumActiveSocketSlots() < max_sockets_per_group;
- }
- int NumActiveSocketSlots() const {
- return active_socket_count_ + static_cast<int>(jobs_.size()) +
- static_cast<int>(idle_sockets_.size()) +
- static_cast<int>(bound_requests_.size());
- }
- // Returns true if the group could make use of an additional socket slot, if
- // it were given one.
- bool CanUseAdditionalSocketSlot(int max_sockets_per_group) const {
- return HasAvailableSocketSlot(max_sockets_per_group) &&
- unbound_requests_.size() > jobs_.size();
- }
- // Returns the priority of the top of the unbound request queue
- // (which may be less than the maximum priority over the entire
- // queue, due to how we prioritize requests with |respect_limits|
- // DISABLED over others).
- RequestPriority TopPendingPriority() const {
- // NOTE: FirstMax().value()->priority() is not the same as
- // FirstMax().priority()!
- return unbound_requests_.FirstMax().value()->priority();
- }
- // Set a timer to create a backup job if it takes too long to
- // create one and if a timer isn't already running.
- void StartBackupJobTimer(const GroupId& group_id);
- bool BackupJobTimerIsRunning() const;
- // If there's a ConnectJob that's never been assigned to Request,
- // decrements |never_assigned_job_count_| and returns true.
- // Otherwise, returns false.
- bool TryToUseNeverAssignedConnectJob();
- void AddJob(std::unique_ptr<ConnectJob> job, bool is_preconnect);
- // Remove |job| from this group, which must already own |job|. Returns the
- // removed ConnectJob.
- std::unique_ptr<ConnectJob> RemoveUnboundJob(ConnectJob* job);
- void RemoveAllUnboundJobs();
- bool has_unbound_requests() const { return !unbound_requests_.empty(); }
- size_t unbound_request_count() const { return unbound_requests_.size(); }
- size_t ConnectJobCount() const;
- // Returns the connect job correspding to |handle|. In particular, if
- // |handle| is bound to a ConnectJob, returns that job. If |handle| is
- // "assigned" a ConnectJob, return that job. Otherwise, returns nullptr.
- ConnectJob* GetConnectJobForHandle(const ClientSocketHandle* handle) const;
- // Inserts the request into the queue based on priority
- // order. Older requests are prioritized over requests of equal
- // priority.
- void InsertUnboundRequest(std::unique_ptr<Request> request);
- // Gets (but does not remove) the next unbound request. Returns
- // NULL if there are no unbound requests.
- const Request* GetNextUnboundRequest() const;
- // Gets and removes the next unbound request. Returns NULL if
- // there are no unbound requests.
- std::unique_ptr<Request> PopNextUnboundRequest();
- // Finds the unbound request for |handle| and removes it. Returns
- // the removed unbound request, or NULL if there was none.
- std::unique_ptr<Request> FindAndRemoveUnboundRequest(
- ClientSocketHandle* handle);
- // Sets a pending error for all bound requests. Bound requests may be in the
- // middle of a callback, so can't be failed at arbitrary points in time.
- void SetPendingErrorForAllBoundRequests(int pending_error);
- // Attempts to bind the highest priority unbound request to |connect_job|,
- // and returns the bound request. If the request has previously been bound
- // to |connect_job|, returns the previously bound request. If there are no
- // requests, or the highest priority request doesn't have a proxy auth
- // callback, returns nullptr.
- const Request* BindRequestToConnectJob(ConnectJob* connect_job);
- // Finds the request, if any, bound to |connect_job|, and returns the
- // BoundRequest or absl::nullopt if there was none.
- absl::optional<BoundRequest> FindAndRemoveBoundRequestForConnectJob(
- ConnectJob* connect_job);
- // Finds the bound request, if any, corresponding to |client_socket_handle|
- // and returns it. Destroys the ConnectJob bound to the request, if there
- // was one.
- std::unique_ptr<Request> FindAndRemoveBoundRequest(
- ClientSocketHandle* client_socket_handle);
- // Change the priority of the request named by |*handle|. |*handle|
- // must refer to a request currently present in the group. If |priority|
- // is the same as the current priority of the request, this is a no-op.
- void SetPriority(ClientSocketHandle* handle, RequestPriority priority);
- void IncrementActiveSocketCount() { active_socket_count_++; }
- void DecrementActiveSocketCount() { active_socket_count_--; }
- void IncrementGeneration() { generation_++; }
- // Whether the request in |unbound_requests_| with a given handle has a job.
- bool RequestWithHandleHasJobForTesting(
- const ClientSocketHandle* handle) const;
- const GroupId& group_id() { return group_id_; }
- size_t unassigned_job_count() const { return unassigned_jobs_.size(); }
- const JobList& jobs() const { return jobs_; }
- const std::list<IdleSocket>& idle_sockets() const { return idle_sockets_; }
- int active_socket_count() const { return active_socket_count_; }
- std::list<IdleSocket>* mutable_idle_sockets() { return &idle_sockets_; }
- size_t never_assigned_job_count() const {
- return never_assigned_job_count_;
- }
- int64_t generation() const { return generation_; }
- private:
- // Returns the iterator's unbound request after removing it from
- // the queue. Expects the Group to pass SanityCheck() when called.
- std::unique_ptr<Request> RemoveUnboundRequest(
- const RequestQueue::Pointer& pointer);
- // Finds the Request which is associated with the given ConnectJob.
- // Returns nullptr if none is found. Expects the Group to pass SanityCheck()
- // when called.
- RequestQueue::Pointer FindUnboundRequestWithJob(
- const ConnectJob* job) const;
- // Finds the Request in |unbound_requests_| which is the first request
- // without a job. Returns a null pointer if all requests have jobs. Does not
- // expect the Group to pass SanityCheck() when called, but does expect all
- // jobs to either be assigned to a request or in |unassigned_jobs_|. Expects
- // that no requests with jobs come after any requests without a job.
- RequestQueue::Pointer GetFirstRequestWithoutJob() const;
- // Tries to assign an unassigned |job| to a request. If no requests need a
- // job, |job| is added to |unassigned_jobs_|.
- // When called, does not expect the Group to pass SanityCheck(), but does
- // expect it to have passed SanityCheck() before the given ConnectJob was
- // either created or had the request it was assigned to removed.
- void TryToAssignUnassignedJob(ConnectJob* job);
- // Tries to assign a job to the given request. If any unassigned jobs are
- // available, the first unassigned job is assigned to the request.
- // Otherwise, if the request is ahead of the last request with a job, the
- // job is stolen from the last request with a job.
- // When called, does not expect the Group to pass SanityCheck(), but does
- // expect that:
- // - the request associated with |request_pointer| must not have
- // an assigned ConnectJob,
- // - the first min( jobs_.size(), unbound_requests_.size() - 1 ) Requests
- // other than the given request must have ConnectJobs, i.e. the group
- // must have passed SanityCheck() before the passed in Request was either
- // added or had its job unassigned.
- void TryToAssignJobToRequest(RequestQueue::Pointer request_pointer);
- // Transfers the associated ConnectJob from one Request to another. Expects
- // the source request to have a job, and the destination request to not have
- // a job. Does not expect the Group to pass SanityCheck() when called.
- void TransferJobBetweenRequests(Request* source, Request* dest);
- // Called when the backup socket timer fires.
- void OnBackupJobTimerFired(const GroupId& group_id);
- // Checks that:
- // - |unassigned_jobs_| is empty iff there are at least as many requests
- // as jobs.
- // - Exactly the first |jobs_.size() - unassigned_jobs_.size()| requests
- // have ConnectJobs.
- // - No requests are assigned a ConnectJob in |unassigned_jobs_|.
- // - No requests are assigned a ConnectJob not in |jobs_|.
- // - No two requests are assigned the same ConnectJob.
- // - All entries in |unassigned_jobs_| are also in |jobs_|.
- // - There are no duplicate entries in |unassigned_jobs_|.
- void SanityCheck() const;
- const GroupId group_id_;
- const raw_ptr<TransportClientSocketPool> client_socket_pool_;
- // Total number of ConnectJobs that have never been assigned to a Request.
- // Since jobs use late binding to requests, which ConnectJobs have or have
- // not been assigned to a request are not tracked. This is incremented on
- // preconnect and decremented when a preconnect is assigned, or when there
- // are fewer than |never_assigned_job_count_| ConnectJobs. Not incremented
- // when a request is cancelled.
- size_t never_assigned_job_count_ = 0;
- std::list<IdleSocket> idle_sockets_;
- JobList jobs_; // For bookkeeping purposes, there is a copy of the raw
- // pointer of each element of |jobs_| stored either in
- // |unassigned_jobs_|, or as the associated |job_| of an
- // element of |unbound_requests_|.
- std::list<ConnectJob*> unassigned_jobs_;
- RequestQueue unbound_requests_;
- int active_socket_count_ = 0; // number of active sockets used by clients
- // A timer for when to start the backup job.
- base::OneShotTimer backup_job_timer_;
- // List of Requests bound to ConnectJobs currently undergoing proxy auth.
- // The Requests and ConnectJobs in this list do not appear in
- // |unbound_requests_| or |jobs_|.
- std::vector<BoundRequest> bound_requests_;
- // An id for the group. It gets incremented every time we FlushWithError()
- // the socket pool, or refresh the group. This is so that when sockets get
- // released back to the group, we can make sure that they are discarded
- // rather than reused. Destroying a group will reset the generation number,
- // but as that only happens once there are no outstanding sockets or
- // requests associated with the group, that's harmless.
- int64_t generation_ = 0;
- };
- using GroupMap = std::map<GroupId, Group*>;
- struct CallbackResultPair {
- CallbackResultPair();
- CallbackResultPair(CompletionOnceCallback callback_in, int result_in);
- CallbackResultPair(CallbackResultPair&& other);
- CallbackResultPair& operator=(CallbackResultPair&& other);
- ~CallbackResultPair();
- CompletionOnceCallback callback;
- int result;
- };
- using PendingCallbackMap =
- std::map<const ClientSocketHandle*, CallbackResultPair>;
- TransportClientSocketPool(
- int max_sockets,
- int max_sockets_per_group,
- base::TimeDelta unused_idle_socket_timeout,
- base::TimeDelta used_idle_socket_timeout,
- const ProxyServer& proxy_server,
- bool is_for_websockets,
- const CommonConnectJobParams* common_connect_job_params,
- bool cleanup_on_ip_address_change,
- std::unique_ptr<ConnectJobFactory> connect_job_factory,
- SSLClientContext* ssl_client_context,
- bool connect_backup_jobs_enabled);
- base::TimeDelta ConnectRetryInterval() const {
- // TODO(mbelshe): Make this tuned dynamically based on measured RTT.
- // For now, just use the max retry interval.
- return base::Milliseconds(kMaxConnectRetryIntervalMs);
- }
- // TODO(mmenke): de-inline these.
- size_t NumNeverAssignedConnectJobsInGroup(const GroupId& group_id) const {
- return group_map_.find(group_id)->second->never_assigned_job_count();
- }
- size_t NumUnassignedConnectJobsInGroup(const GroupId& group_id) const {
- return group_map_.find(group_id)->second->unassigned_job_count();
- }
- size_t NumConnectJobsInGroup(const GroupId& group_id) const {
- return group_map_.find(group_id)->second->ConnectJobCount();
- }
- int NumActiveSocketsInGroup(const GroupId& group_id) const {
- return group_map_.find(group_id)->second->active_socket_count();
- }
- bool HasGroup(const GroupId& group_id) const;
- // Closes all idle sockets if |force| is true. Else, only closes idle
- // sockets that timed out or can't be reused. Made public for testing.
- // |reason| must be non-empty when |force| is true.
- void CleanupIdleSockets(bool force, const char* net_log_reason_utf8);
- // Closes one idle socket. Picks the first one encountered.
- // TODO(willchan): Consider a better algorithm for doing this. Perhaps we
- // should keep an ordered list of idle sockets, and close them in order.
- // Requires maintaining more state. It's not clear if it's worth it since
- // I'm not sure if we hit this situation often.
- bool CloseOneIdleSocket();
- // Checks higher layered pools to see if they can close an idle connection.
- bool CloseOneIdleConnectionInHigherLayeredPool();
- // Closes all idle sockets in |group| if |force| is true. Else, only closes
- // idle sockets in |group| that timed out with respect to |now| or can't be
- // reused.
- void CleanupIdleSocketsInGroup(bool force,
- Group* group,
- const base::TimeTicks& now,
- const char* net_log_reason_utf8);
- Group* GetOrCreateGroup(const GroupId& group_id);
- void RemoveGroup(const GroupId& group_id);
- void RemoveGroup(GroupMap::iterator it);
- // Called when the number of idle sockets changes.
- void IncrementIdleCount();
- void DecrementIdleCount();
- // Scans the group map for groups which have an available socket slot and
- // at least one pending request. Returns true if any groups are stalled, and
- // if so (and if both |group| and |group_id| are not NULL), fills |group|
- // and |group_id| with data of the stalled group having highest priority.
- bool FindTopStalledGroup(Group** group, GroupId* group_id) const;
- // Removes |job| from |group|, which must already own |job|.
- void RemoveConnectJob(ConnectJob* job, Group* group);
- // Tries to see if we can handle any more requests for |group|.
- void OnAvailableSocketSlot(const GroupId& group_id, Group* group);
- // Process a pending socket request for a group.
- void ProcessPendingRequest(const GroupId& group_id, Group* group);
- // Assigns |socket| to |handle| and updates |group|'s counters appropriately.
- void HandOutSocket(std::unique_ptr<StreamSocket> socket,
- ClientSocketHandle::SocketReuseType reuse_type,
- const LoadTimingInfo::ConnectTiming& connect_timing,
- ClientSocketHandle* handle,
- base::TimeDelta time_idle,
- Group* group,
- const NetLogWithSource& net_log);
- // Adds |socket| to the list of idle sockets for |group|.
- void AddIdleSocket(std::unique_ptr<StreamSocket> socket, Group* group);
- // Iterates through |group_map_|, canceling all ConnectJobs and deleting
- // groups if they are no longer needed.
- void CancelAllConnectJobs();
- // Iterates through |group_map_|, posting |error| callbacks for all
- // requests, and then deleting groups if they are no longer needed.
- void CancelAllRequestsWithError(int error);
- // Returns true if we can't create any more sockets due to the total limit.
- bool ReachedMaxSocketsLimit() const;
- // This is the internal implementation of RequestSocket(). It differs in that
- // it does not handle logging into NetLog of the queueing status of
- // |request|.
- // |preconnect_done_closure| is used only for preconnect requests. For
- // preconnect requests, this method returns ERR_IO_PENDING only if a connect
- // job is created and the connect job didn't finish synchronously. In such
- // case, |preconnect_done_closure| will be called when the created connect job
- // will be deleted.
- // For normal non-preconnect requests, |preconnect_done_closure| must be null.
- // And this method returns ERR_IO_PENDING when the number of sockets has
- // reached the limit or the created connect job didn't finish synchronously.
- // In such a case, the Request with a ClientSocketHandle must be registered to
- // |group_map_| to receive the completion callback.
- int RequestSocketInternal(const GroupId& group_id,
- const Request& request,
- base::OnceClosure preconnect_done_closure);
- // Assigns an idle socket for the group to the request.
- // Returns |true| if an idle socket is available, false otherwise.
- bool AssignIdleSocketToRequest(const Request& request, Group* group);
- static void LogBoundConnectJobToRequest(
- const NetLogSource& connect_job_source,
- const Request& request);
- // Same as CloseOneIdleSocket() except it won't close an idle socket in
- // |group|. If |group| is NULL, it is ignored. Returns true if it closed a
- // socket.
- bool CloseOneIdleSocketExceptInGroup(const Group* group);
- // Checks if there are stalled socket groups that should be notified
- // for possible wakeup.
- void CheckForStalledSocketGroups();
- // Posts a task to call InvokeUserCallback() on the next iteration through the
- // current message loop. Inserts |callback| into |pending_callback_map_|,
- // keyed by |handle|. Apply |socket_tag| to the socket if socket successfully
- // created.
- void InvokeUserCallbackLater(ClientSocketHandle* handle,
- CompletionOnceCallback callback,
- int rv,
- const SocketTag& socket_tag);
- // These correspond to ConnectJob::Delegate methods, and are invoked by the
- // Group a ConnectJob belongs to.
- void OnConnectJobComplete(Group* group, int result, ConnectJob* job);
- void OnNeedsProxyAuth(Group* group,
- const HttpResponseInfo& response,
- HttpAuthController* auth_controller,
- base::OnceClosure restart_with_auth_callback,
- ConnectJob* job);
- // Invokes the user callback for |handle|. By the time this task has run,
- // it's possible that the request has been cancelled, so |handle| may not
- // exist in |pending_callback_map_|. We look up the callback and result code
- // in |pending_callback_map_|.
- void InvokeUserCallback(ClientSocketHandle* handle);
- // Tries to close idle sockets in a higher level socket pool as long as this
- // this pool is stalled.
- void TryToCloseSocketsInLayeredPools();
- // Closes all idle sockets and cancels all unbound ConnectJobs associated with
- // |it->second|. Also increments the group's generation number, ensuring any
- // currently existing handed out socket will be silently closed when it is
- // returned to the socket pool. Bound ConnectJobs will only be destroyed on
- // once they complete, as they may be waiting on user input. No request
- // (including bound ones) will be failed as a result of this call - instead,
- // new ConnectJobs will be created.
- //
- // The group may be removed if this leaves the group empty. The caller must
- // call CheckForStalledSocketGroups() after all applicable groups have been
- // refreshed.
- void RefreshGroup(GroupMap::iterator it,
- const base::TimeTicks& now,
- const char* net_log_reason_utf8);
- GroupMap group_map_;
- // Map of the ClientSocketHandles for which we have a pending Task to invoke a
- // callback. This is necessary since, before we invoke said callback, it's
- // possible that the request is cancelled.
- PendingCallbackMap pending_callback_map_;
- // The total number of idle sockets in the system.
- int idle_socket_count_ = 0;
- // Number of connecting sockets across all groups.
- int connecting_socket_count_ = 0;
- // Number of connected sockets we handed out across all groups.
- int handed_out_socket_count_ = 0;
- // The maximum total number of sockets. See ReachedMaxSocketsLimit.
- const int max_sockets_;
- // The maximum number of sockets kept per group.
- const int max_sockets_per_group_;
- // The time to wait until closing idle sockets.
- const base::TimeDelta unused_idle_socket_timeout_;
- const base::TimeDelta used_idle_socket_timeout_;
- const ProxyServer proxy_server_;
- const bool cleanup_on_ip_address_change_;
- // TODO(vandebo) Remove when backup jobs move to TransportClientSocketPool
- bool connect_backup_jobs_enabled_;
- // Pools that create connections through |this|. |this| will try to close
- // their idle sockets when it stalls. Must be empty on destruction.
- std::set<HigherLayeredPool*> higher_pools_;
- const raw_ptr<SSLClientContext> ssl_client_context_;
- #if DCHECK_IS_ON()
- // Reentrancy guard for RequestSocketInternal().
- bool request_in_process_ = false;
- #endif // DCHECK_IS_ON()
- base::WeakPtrFactory<TransportClientSocketPool> weak_factory_{this};
- };
- } // namespace net
- #endif // NET_SOCKET_TRANSPORT_CLIENT_SOCKET_POOL_H_
|