// 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_CLIENT_SOCKET_POOL_H_ #define NET_SOCKET_CLIENT_SOCKET_POOL_H_ #include <deque> #include <string> #include "base/basictypes.h" #include "base/memory/ref_counted.h" #include "base/memory/scoped_ptr.h" #include "base/template_util.h" #include "base/time/time.h" #include "net/base/completion_callback.h" #include "net/base/load_states.h" #include "net/base/net_export.h" #include "net/base/request_priority.h" #include "net/dns/host_resolver.h" namespace base { class DictionaryValue; } namespace net { class ClientSocketHandle; class ClientSocketPoolHistograms; class StreamSocket; // ClientSocketPools are layered. This defines an interface for lower level // socket pools to communicate with higher layer pools. class NET_EXPORT HigherLayeredPool { public: virtual ~HigherLayeredPool() {} // Instructs the HigherLayeredPool to close an idle connection. Return true if // one was closed. Closing an idle connection will call into the lower layer // pool it came from, so must be careful of re-entrancy when using this. virtual bool CloseOneIdleConnection() = 0; }; // ClientSocketPools are layered. This defines an interface for higher level // socket pools to communicate with lower layer pools. class NET_EXPORT LowerLayeredPool { public: virtual ~LowerLayeredPool() {} // Returns true if a there is currently a request blocked on the per-pool // (not per-host) max socket limit, either in this pool, or one that it is // layered on top of. virtual bool IsStalled() const = 0; // Called to add or remove a higher layer pool on top of |this|. A higher // layer pool may be added at most once to |this|, and must be removed prior // to destruction of |this|. virtual void AddHigherLayeredPool(HigherLayeredPool* higher_pool) = 0; virtual void RemoveHigherLayeredPool(HigherLayeredPool* higher_pool) = 0; }; // A ClientSocketPool is used to restrict the number of sockets open at a time. // It also maintains a list of idle persistent sockets. // class NET_EXPORT ClientSocketPool : public LowerLayeredPool { public: // Subclasses must also have an inner class SocketParams which is // the type for the |params| argument in RequestSocket() and // RequestSockets() below. // Requests a connected socket for a group_name. // // There are five possible results from calling this function: // 1) RequestSocket returns OK and initializes |handle| with a reused socket. // 2) RequestSocket returns OK with a newly connected socket. // 3) RequestSocket returns ERR_IO_PENDING. The handle will be added to a // wait list until a socket is available to reuse or a new socket finishes // connecting. |priority| will determine the placement into the wait list. // 4) An error occurred early on, so RequestSocket returns an error code. // 5) A recoverable error occurred while setting up the socket. An error // code is returned, but the |handle| is initialized with the new socket. // The caller must recover from the error before using the connection, or // Disconnect the socket before releasing or resetting the |handle|. // The current recoverable errors are: the errors accepted by // IsCertificateError(err) and PROXY_AUTH_REQUESTED, or // HTTPS_PROXY_TUNNEL_RESPONSE when reported by HttpProxyClientSocketPool. // // If this function returns OK, then |handle| is initialized upon return. // The |handle|'s is_initialized method will return true in this case. If a // StreamSocket was reused, then ClientSocketPool will call // |handle|->set_reused(true). In either case, the socket will have been // allocated and will be connected. A client might want to know whether or // not the socket is reused in order to request a new socket if he encounters // an error with the reused socket. // // If ERR_IO_PENDING is returned, then the callback will be used to notify the // client of completion. // // Profiling information for the request is saved to |net_log| if non-NULL. virtual int RequestSocket(const std::string& group_name, const void* params, RequestPriority priority, ClientSocketHandle* handle, const CompletionCallback& callback, const BoundNetLog& net_log) = 0; // RequestSockets is used to request that |num_sockets| be connected in the // connection group for |group_name|. If the connection group already has // |num_sockets| idle sockets / active sockets / currently connecting sockets, // then this function doesn't do anything. Otherwise, it will start up as // many connections as necessary to reach |num_sockets| total sockets for the // group. It uses |params| to control how to connect the sockets. The // ClientSocketPool will assign a priority to the new connections, if any. // This priority will probably be lower than all others, since this method // is intended to make sure ahead of time that |num_sockets| sockets are // available to talk to a host. virtual void RequestSockets(const std::string& group_name, const void* params, int num_sockets, const BoundNetLog& net_log) = 0; // Called to cancel a RequestSocket call that returned ERR_IO_PENDING. The // same handle parameter must be passed to this method as was passed to the // RequestSocket call being cancelled. The associated CompletionCallback is // not run. However, for performance, we will let one ConnectJob complete // and go idle. virtual void CancelRequest(const std::string& group_name, ClientSocketHandle* handle) = 0; // Called to release a socket once the socket is no longer needed. If the // socket still has an established connection, then it will be added to the // set of idle sockets to be used to satisfy future RequestSocket calls. // Otherwise, the StreamSocket is destroyed. |id| is used to differentiate // between updated versions of the same pool instance. The pool's id will // change when it flushes, so it can use this |id| to discard sockets with // mismatched ids. virtual void ReleaseSocket(const std::string& group_name, scoped_ptr<StreamSocket> socket, int id) = 0; // This flushes all state from the ClientSocketPool. This means that all // idle and connecting sockets are discarded with the given |error|. // Active sockets being held by ClientSocketPool clients will be discarded // when released back to the pool. // Does not flush any pools wrapped by |this|. virtual void FlushWithError(int error) = 0; // Called to close any idle connections held by the connection manager. virtual void CloseIdleSockets() = 0; // The total number of idle sockets in the pool. virtual int IdleSocketCount() const = 0; // The total number of idle sockets in a connection group. virtual int IdleSocketCountInGroup(const std::string& group_name) const = 0; // Determine the LoadState of a connecting ClientSocketHandle. virtual LoadState GetLoadState(const std::string& group_name, const ClientSocketHandle* handle) const = 0; // Retrieves information on the current state of the pool as a // DictionaryValue. Caller takes possession of the returned value. // If |include_nested_pools| is true, the states of any nested // ClientSocketPools will be included. virtual base::DictionaryValue* GetInfoAsValue( const std::string& name, const std::string& type, bool include_nested_pools) const = 0; // Returns the maximum amount of time to wait before retrying a connect. static const int kMaxConnectRetryIntervalMs = 250; // The set of histograms specific to this pool. We can't use the standard // UMA_HISTOGRAM_* macros because they are callsite static. virtual ClientSocketPoolHistograms* histograms() const = 0; static base::TimeDelta unused_idle_socket_timeout(); static void set_unused_idle_socket_timeout(base::TimeDelta timeout); static base::TimeDelta used_idle_socket_timeout(); static void set_used_idle_socket_timeout(base::TimeDelta timeout); protected: ClientSocketPool(); virtual ~ClientSocketPool(); // Return the connection timeout for this pool. virtual base::TimeDelta ConnectionTimeout() const = 0; private: DISALLOW_COPY_AND_ASSIGN(ClientSocketPool); }; template <typename PoolType> void RequestSocketsForPool( PoolType* pool, const std::string& group_name, const scoped_refptr<typename PoolType::SocketParams>& params, int num_sockets, const BoundNetLog& net_log) { pool->RequestSockets(group_name, ¶ms, num_sockets, net_log); } } // namespace net #endif // NET_SOCKET_CLIENT_SOCKET_POOL_H_