Home | History | Annotate | Download | only in socket
      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.
     60   ClientSocketHandle* handle() const { return handle_; }
     61 
     62   // Stash the callback from RequestSocket() here for convenience.
     63   const CompletionCallback& callback() const { return callback_; }
     64 
     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