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_CLIENT_SOCKET_POOL_H_
6#define NET_SOCKET_CLIENT_SOCKET_POOL_H_
7
8#include <deque>
9#include <string>
10
11#include "base/basictypes.h"
12#include "base/memory/ref_counted.h"
13#include "base/memory/scoped_ptr.h"
14#include "base/template_util.h"
15#include "base/time/time.h"
16#include "net/base/completion_callback.h"
17#include "net/base/load_states.h"
18#include "net/base/net_export.h"
19#include "net/base/request_priority.h"
20#include "net/dns/host_resolver.h"
21
22namespace base {
23class DictionaryValue;
24}
25
26namespace net {
27
28class ClientSocketHandle;
29class ClientSocketPoolHistograms;
30class StreamSocket;
31
32// ClientSocketPools are layered. This defines an interface for lower level
33// socket pools to communicate with higher layer pools.
34class NET_EXPORT HigherLayeredPool {
35 public:
36  virtual ~HigherLayeredPool() {}
37
38  // Instructs the HigherLayeredPool to close an idle connection. Return true if
39  // one was closed.  Closing an idle connection will call into the lower layer
40  // pool it came from, so must be careful of re-entrancy when using this.
41  virtual bool CloseOneIdleConnection() = 0;
42};
43
44// ClientSocketPools are layered. This defines an interface for higher level
45// socket pools to communicate with lower layer pools.
46class NET_EXPORT LowerLayeredPool {
47 public:
48  virtual ~LowerLayeredPool() {}
49
50  // Returns true if a there is currently a request blocked on the per-pool
51  // (not per-host) max socket limit, either in this pool, or one that it is
52  // layered on top of.
53  virtual bool IsStalled() const = 0;
54
55  // Called to add or remove a higher layer pool on top of |this|.  A higher
56  // layer pool may be added at most once to |this|, and must be removed prior
57  // to destruction of |this|.
58  virtual void AddHigherLayeredPool(HigherLayeredPool* higher_pool) = 0;
59  virtual void RemoveHigherLayeredPool(HigherLayeredPool* higher_pool) = 0;
60};
61
62// A ClientSocketPool is used to restrict the number of sockets open at a time.
63// It also maintains a list of idle persistent sockets.
64//
65class NET_EXPORT ClientSocketPool : public LowerLayeredPool {
66 public:
67  // Subclasses must also have an inner class SocketParams which is
68  // the type for the |params| argument in RequestSocket() and
69  // RequestSockets() below.
70
71  // Requests a connected socket for a group_name.
72  //
73  // There are five possible results from calling this function:
74  // 1) RequestSocket returns OK and initializes |handle| with a reused socket.
75  // 2) RequestSocket returns OK with a newly connected socket.
76  // 3) RequestSocket returns ERR_IO_PENDING.  The handle will be added to a
77  // wait list until a socket is available to reuse or a new socket finishes
78  // connecting.  |priority| will determine the placement into the wait list.
79  // 4) An error occurred early on, so RequestSocket returns an error code.
80  // 5) A recoverable error occurred while setting up the socket.  An error
81  // code is returned, but the |handle| is initialized with the new socket.
82  // The caller must recover from the error before using the connection, or
83  // Disconnect the socket before releasing or resetting the |handle|.
84  // The current recoverable errors are: the errors accepted by
85  // IsCertificateError(err) and PROXY_AUTH_REQUESTED, or
86  // HTTPS_PROXY_TUNNEL_RESPONSE when reported by HttpProxyClientSocketPool.
87  //
88  // If this function returns OK, then |handle| is initialized upon return.
89  // The |handle|'s is_initialized method will return true in this case.  If a
90  // StreamSocket was reused, then ClientSocketPool will call
91  // |handle|->set_reused(true).  In either case, the socket will have been
92  // allocated and will be connected.  A client might want to know whether or
93  // not the socket is reused in order to request a new socket if he encounters
94  // an error with the reused socket.
95  //
96  // If ERR_IO_PENDING is returned, then the callback will be used to notify the
97  // client of completion.
98  //
99  // Profiling information for the request is saved to |net_log| if non-NULL.
100  virtual int RequestSocket(const std::string& group_name,
101                            const void* params,
102                            RequestPriority priority,
103                            ClientSocketHandle* handle,
104                            const CompletionCallback& callback,
105                            const BoundNetLog& net_log) = 0;
106
107  // RequestSockets is used to request that |num_sockets| be connected in the
108  // connection group for |group_name|.  If the connection group already has
109  // |num_sockets| idle sockets / active sockets / currently connecting sockets,
110  // then this function doesn't do anything.  Otherwise, it will start up as
111  // many connections as necessary to reach |num_sockets| total sockets for the
112  // group.  It uses |params| to control how to connect the sockets.   The
113  // ClientSocketPool will assign a priority to the new connections, if any.
114  // This priority will probably be lower than all others, since this method
115  // is intended to make sure ahead of time that |num_sockets| sockets are
116  // available to talk to a host.
117  virtual void RequestSockets(const std::string& group_name,
118                              const void* params,
119                              int num_sockets,
120                              const BoundNetLog& net_log) = 0;
121
122  // Called to cancel a RequestSocket call that returned ERR_IO_PENDING.  The
123  // same handle parameter must be passed to this method as was passed to the
124  // RequestSocket call being cancelled.  The associated CompletionCallback is
125  // not run.  However, for performance, we will let one ConnectJob complete
126  // and go idle.
127  virtual void CancelRequest(const std::string& group_name,
128                             ClientSocketHandle* handle) = 0;
129
130  // Called to release a socket once the socket is no longer needed.  If the
131  // socket still has an established connection, then it will be added to the
132  // set of idle sockets to be used to satisfy future RequestSocket calls.
133  // Otherwise, the StreamSocket is destroyed.  |id| is used to differentiate
134  // between updated versions of the same pool instance.  The pool's id will
135  // change when it flushes, so it can use this |id| to discard sockets with
136  // mismatched ids.
137  virtual void ReleaseSocket(const std::string& group_name,
138                             scoped_ptr<StreamSocket> socket,
139                             int id) = 0;
140
141  // This flushes all state from the ClientSocketPool.  This means that all
142  // idle and connecting sockets are discarded with the given |error|.
143  // Active sockets being held by ClientSocketPool clients will be discarded
144  // when released back to the pool.
145  // Does not flush any pools wrapped by |this|.
146  virtual void FlushWithError(int error) = 0;
147
148  // Called to close any idle connections held by the connection manager.
149  virtual void CloseIdleSockets() = 0;
150
151  // The total number of idle sockets in the pool.
152  virtual int IdleSocketCount() const = 0;
153
154  // The total number of idle sockets in a connection group.
155  virtual int IdleSocketCountInGroup(const std::string& group_name) const = 0;
156
157  // Determine the LoadState of a connecting ClientSocketHandle.
158  virtual LoadState GetLoadState(const std::string& group_name,
159                                 const ClientSocketHandle* handle) const = 0;
160
161  // Retrieves information on the current state of the pool as a
162  // DictionaryValue.  Caller takes possession of the returned value.
163  // If |include_nested_pools| is true, the states of any nested
164  // ClientSocketPools will be included.
165  virtual base::DictionaryValue* GetInfoAsValue(
166      const std::string& name,
167      const std::string& type,
168      bool include_nested_pools) const = 0;
169
170  // Returns the maximum amount of time to wait before retrying a connect.
171  static const int kMaxConnectRetryIntervalMs = 250;
172
173  // The set of histograms specific to this pool.  We can't use the standard
174  // UMA_HISTOGRAM_* macros because they are callsite static.
175  virtual ClientSocketPoolHistograms* histograms() const = 0;
176
177  static base::TimeDelta unused_idle_socket_timeout();
178  static void set_unused_idle_socket_timeout(base::TimeDelta timeout);
179
180  static base::TimeDelta used_idle_socket_timeout();
181  static void set_used_idle_socket_timeout(base::TimeDelta timeout);
182
183 protected:
184  ClientSocketPool();
185  virtual ~ClientSocketPool();
186
187  // Return the connection timeout for this pool.
188  virtual base::TimeDelta ConnectionTimeout() const = 0;
189
190 private:
191  DISALLOW_COPY_AND_ASSIGN(ClientSocketPool);
192};
193
194template <typename PoolType>
195void RequestSocketsForPool(
196    PoolType* pool,
197    const std::string& group_name,
198    const scoped_refptr<typename PoolType::SocketParams>& params,
199    int num_sockets,
200    const BoundNetLog& net_log) {
201  pool->RequestSockets(group_name, &params, num_sockets, net_log);
202}
203
204}  // namespace net
205
206#endif  // NET_SOCKET_CLIENT_SOCKET_POOL_H_
207