// 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 #include #include "base/basictypes.h" #include "base/memory/ref_counted.h" #include "base/time.h" #include "base/template_util.h" #include "net/base/completion_callback.h" #include "net/base/host_resolver.h" #include "net/base/load_states.h" #include "net/base/net_export.h" #include "net/base/request_priority.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 LayeredPool { public: virtual ~LayeredPool() {}; // Instructs the LayeredPool to close an idle connection. Return true if one // was closed. virtual bool CloseOneIdleConnection() = 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: // 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, StreamSocket* socket, int id) = 0; // This flushes all state from the ClientSocketPool. This means that all // idle and connecting sockets are discarded. 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 Flush() = 0; // Returns true if a there is currently a request blocked on the // per-pool (not per-host) max socket limit. virtual bool IsStalled() const = 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; // Adds a LayeredPool on top of |this|. virtual void AddLayeredPool(LayeredPool* layered_pool) = 0; // Removes a LayeredPool from |this|. virtual void RemoveLayeredPool(LayeredPool* layered_pool) = 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); }; // ClientSocketPool subclasses should indicate valid SocketParams via the // REGISTER_SOCKET_PARAMS_FOR_POOL macro below. By default, any given // pair will have its SocketParamsTrait inherit from // base::false_type, but REGISTER_SOCKET_PARAMS_FOR_POOL will specialize that // pairing to inherit from base::true_type. This provides compile time // verification that the correct SocketParams type is used with the appropriate // PoolType. template struct SocketParamTraits : public base::false_type { }; template void CheckIsValidSocketParamsForPool() { COMPILE_ASSERT(!base::is_pointer >::value, socket_params_cannot_be_pointer); COMPILE_ASSERT((SocketParamTraits >::value), invalid_socket_params_for_pool); } // Provides an empty definition for CheckIsValidSocketParamsForPool() which // should be optimized out by the compiler. #define REGISTER_SOCKET_PARAMS_FOR_POOL(pool_type, socket_params) \ template<> \ struct SocketParamTraits > \ : public base::true_type { \ } template void RequestSocketsForPool(PoolType* pool, const std::string& group_name, const scoped_refptr& params, int num_sockets, const BoundNetLog& net_log) { CheckIsValidSocketParamsForPool(); pool->RequestSockets(group_name, ¶ms, num_sockets, net_log); } } // namespace net #endif // NET_SOCKET_CLIENT_SOCKET_POOL_H_