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