• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2014 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_WEBSOCKET_TRANSPORT_CLIENT_SOCKET_POOL_H_
6 #define NET_SOCKET_WEBSOCKET_TRANSPORT_CLIENT_SOCKET_POOL_H_
7 
8 #include <list>
9 #include <map>
10 #include <set>
11 #include <string>
12 
13 #include "base/basictypes.h"
14 #include "base/memory/ref_counted.h"
15 #include "base/memory/scoped_ptr.h"
16 #include "base/memory/weak_ptr.h"
17 #include "base/time/time.h"
18 #include "base/timer/timer.h"
19 #include "net/base/net_export.h"
20 #include "net/base/net_log.h"
21 #include "net/socket/client_socket_pool.h"
22 #include "net/socket/client_socket_pool_base.h"
23 #include "net/socket/transport_client_socket_pool.h"
24 
25 namespace net {
26 
27 class ClientSocketFactory;
28 class ClientSocketPoolHistograms;
29 class HostResolver;
30 class NetLog;
31 class WebSocketEndpointLockManager;
32 class WebSocketTransportConnectSubJob;
33 
34 // WebSocketTransportConnectJob handles the host resolution necessary for socket
35 // creation and the TCP connect. WebSocketTransportConnectJob also has fallback
36 // logic for IPv6 connect() timeouts (which may happen due to networks / routers
37 // with broken IPv6 support). Those timeouts take 20s, so rather than make the
38 // user wait 20s for the timeout to fire, we use a fallback timer
39 // (kIPv6FallbackTimerInMs) and start a connect() to an IPv4 address if the
40 // timer fires. Then we race the IPv4 connect(s) against the IPv6 connect(s) and
41 // use the socket that completes successfully first or fails last.
42 class NET_EXPORT_PRIVATE WebSocketTransportConnectJob : public ConnectJob {
43  public:
44   WebSocketTransportConnectJob(
45       const std::string& group_name,
46       RequestPriority priority,
47       const scoped_refptr<TransportSocketParams>& params,
48       base::TimeDelta timeout_duration,
49       const CompletionCallback& callback,
50       ClientSocketFactory* client_socket_factory,
51       HostResolver* host_resolver,
52       ClientSocketHandle* handle,
53       Delegate* delegate,
54       NetLog* pool_net_log,
55       const BoundNetLog& request_net_log);
56   virtual ~WebSocketTransportConnectJob();
57 
58   // Unlike normal socket pools, the WebSocketTransportClientPool uses
59   // early-binding of sockets.
handle()60   ClientSocketHandle* handle() const { return handle_; }
61 
62   // Stash the callback from RequestSocket() here for convenience.
callback()63   const CompletionCallback& callback() const { return callback_; }
64 
request_net_log()65   const BoundNetLog& request_net_log() const { return request_net_log_; }
66 
67   // ConnectJob methods.
68   virtual LoadState GetLoadState() const OVERRIDE;
69 
70  private:
71   friend class WebSocketTransportConnectSubJob;
72   friend class TransportConnectJobHelper;
73   friend class WebSocketEndpointLockManager;
74 
75   // Although it is not strictly necessary, it makes the code simpler if each
76   // subjob knows what type it is.
77   enum SubJobType { SUB_JOB_IPV4, SUB_JOB_IPV6 };
78 
79   int DoResolveHost();
80   int DoResolveHostComplete(int result);
81   int DoTransportConnect();
82   int DoTransportConnectComplete(int result);
83 
84   // Called back from a SubJob when it completes.
85   void OnSubJobComplete(int result, WebSocketTransportConnectSubJob* job);
86 
87   // Called from |fallback_timer_|.
88   void StartIPv4JobAsync();
89 
90   // Begins the host resolution and the TCP connect.  Returns OK on success
91   // and ERR_IO_PENDING if it cannot immediately service the request.
92   // Otherwise, it returns a net error code.
93   virtual int ConnectInternal() OVERRIDE;
94 
95   TransportConnectJobHelper helper_;
96 
97   // The addresses are divided into IPv4 and IPv6, which are performed partially
98   // in parallel. If the list of IPv6 addresses is non-empty, then the IPv6 jobs
99   // go first, followed after |kIPv6FallbackTimerInMs| by the IPv4
100   // addresses. First sub-job to establish a connection wins.
101   scoped_ptr<WebSocketTransportConnectSubJob> ipv4_job_;
102   scoped_ptr<WebSocketTransportConnectSubJob> ipv6_job_;
103 
104   base::OneShotTimer<WebSocketTransportConnectJob> fallback_timer_;
105   TransportConnectJobHelper::ConnectionLatencyHistogram race_result_;
106   ClientSocketHandle* const handle_;
107   CompletionCallback callback_;
108   BoundNetLog request_net_log_;
109 
110   bool had_ipv4_;
111   bool had_ipv6_;
112 
113   DISALLOW_COPY_AND_ASSIGN(WebSocketTransportConnectJob);
114 };
115 
116 class NET_EXPORT_PRIVATE WebSocketTransportClientSocketPool
117     : public TransportClientSocketPool {
118  public:
119   WebSocketTransportClientSocketPool(int max_sockets,
120                                      int max_sockets_per_group,
121                                      ClientSocketPoolHistograms* histograms,
122                                      HostResolver* host_resolver,
123                                      ClientSocketFactory* client_socket_factory,
124                                      NetLog* net_log);
125 
126   virtual ~WebSocketTransportClientSocketPool();
127 
128   // Allow another connection to be started to the IPEndPoint that this |handle|
129   // is connected to. Used when the WebSocket handshake completes successfully.
130   // This only works if the socket is connected, however the caller does not
131   // need to explicitly check for this. Instead, ensure that dead sockets are
132   // returned to ReleaseSocket() in a timely fashion.
133   static void UnlockEndpoint(ClientSocketHandle* handle);
134 
135   // ClientSocketPool implementation.
136   virtual int RequestSocket(const std::string& group_name,
137                             const void* resolve_info,
138                             RequestPriority priority,
139                             ClientSocketHandle* handle,
140                             const CompletionCallback& callback,
141                             const BoundNetLog& net_log) OVERRIDE;
142   virtual void RequestSockets(const std::string& group_name,
143                               const void* params,
144                               int num_sockets,
145                               const BoundNetLog& net_log) OVERRIDE;
146   virtual void CancelRequest(const std::string& group_name,
147                              ClientSocketHandle* handle) OVERRIDE;
148   virtual void ReleaseSocket(const std::string& group_name,
149                              scoped_ptr<StreamSocket> socket,
150                              int id) OVERRIDE;
151   virtual void FlushWithError(int error) OVERRIDE;
152   virtual void CloseIdleSockets() OVERRIDE;
153   virtual int IdleSocketCount() const OVERRIDE;
154   virtual int IdleSocketCountInGroup(
155       const std::string& group_name) const OVERRIDE;
156   virtual LoadState GetLoadState(
157       const std::string& group_name,
158       const ClientSocketHandle* handle) const OVERRIDE;
159   virtual base::DictionaryValue* GetInfoAsValue(
160       const std::string& name,
161       const std::string& type,
162       bool include_nested_pools) const OVERRIDE;
163   virtual base::TimeDelta ConnectionTimeout() const OVERRIDE;
164   virtual ClientSocketPoolHistograms* histograms() const OVERRIDE;
165 
166   // HigherLayeredPool implementation.
167   virtual bool IsStalled() const OVERRIDE;
168 
169  private:
170   class ConnectJobDelegate : public ConnectJob::Delegate {
171    public:
172     explicit ConnectJobDelegate(WebSocketTransportClientSocketPool* owner);
173     virtual ~ConnectJobDelegate();
174 
175     virtual void OnConnectJobComplete(int result, ConnectJob* job) OVERRIDE;
176 
177    private:
178     WebSocketTransportClientSocketPool* owner_;
179 
180     DISALLOW_COPY_AND_ASSIGN(ConnectJobDelegate);
181   };
182 
183   // Store the arguments from a call to RequestSocket() that has stalled so we
184   // can replay it when there are available socket slots.
185   struct StalledRequest {
186     StalledRequest(const scoped_refptr<TransportSocketParams>& params,
187                    RequestPriority priority,
188                    ClientSocketHandle* handle,
189                    const CompletionCallback& callback,
190                    const BoundNetLog& net_log);
191     ~StalledRequest();
192     const scoped_refptr<TransportSocketParams> params;
193     const RequestPriority priority;
194     ClientSocketHandle* const handle;
195     const CompletionCallback callback;
196     const BoundNetLog net_log;
197   };
198   friend class ConnectJobDelegate;
199   typedef std::map<const ClientSocketHandle*, WebSocketTransportConnectJob*>
200       PendingConnectsMap;
201   // This is a list so that we can remove requests from the middle, and also
202   // so that iterators are not invalidated unless the corresponding request is
203   // removed.
204   typedef std::list<StalledRequest> StalledRequestQueue;
205   typedef std::map<const ClientSocketHandle*, StalledRequestQueue::iterator>
206       StalledRequestMap;
207 
208   void OnConnectJobComplete(int result, WebSocketTransportConnectJob* job);
209   void InvokeUserCallbackLater(ClientSocketHandle* handle,
210                                const CompletionCallback& callback,
211                                int rv);
212   void InvokeUserCallback(ClientSocketHandle* handle,
213                           const CompletionCallback& callback,
214                           int rv);
215   bool ReachedMaxSocketsLimit() const;
216   void HandOutSocket(scoped_ptr<StreamSocket> socket,
217                      const LoadTimingInfo::ConnectTiming& connect_timing,
218                      ClientSocketHandle* handle,
219                      const BoundNetLog& net_log);
220   void AddJob(ClientSocketHandle* handle,
221               scoped_ptr<WebSocketTransportConnectJob> connect_job);
222   bool DeleteJob(ClientSocketHandle* handle);
223   const WebSocketTransportConnectJob* LookupConnectJob(
224       const ClientSocketHandle* handle) const;
225   void ActivateStalledRequest();
226   bool DeleteStalledRequest(ClientSocketHandle* handle);
227 
228   ConnectJobDelegate connect_job_delegate_;
229   std::set<const ClientSocketHandle*> pending_callbacks_;
230   PendingConnectsMap pending_connects_;
231   StalledRequestQueue stalled_request_queue_;
232   StalledRequestMap stalled_request_map_;
233   ClientSocketPoolHistograms* const histograms_;
234   NetLog* const pool_net_log_;
235   ClientSocketFactory* const client_socket_factory_;
236   HostResolver* const host_resolver_;
237   const int max_sockets_;
238   int handed_out_socket_count_;
239   bool flushing_;
240 
241   base::WeakPtrFactory<WebSocketTransportClientSocketPool> weak_factory_;
242 
243   DISALLOW_COPY_AND_ASSIGN(WebSocketTransportClientSocketPool);
244 };
245 
246 }  // namespace net
247 
248 #endif  // NET_SOCKET_WEBSOCKET_TRANSPORT_CLIENT_SOCKET_POOL_H_
249