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