Home | History | Annotate | Download | only in socket
      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_TRANSPORT_CLIENT_SOCKET_POOL_H_
      6 #define NET_SOCKET_TRANSPORT_CLIENT_SOCKET_POOL_H_
      7 
      8 #include <string>
      9 
     10 #include "base/basictypes.h"
     11 #include "base/memory/ref_counted.h"
     12 #include "base/memory/scoped_ptr.h"
     13 #include "base/time/time.h"
     14 #include "base/timer/timer.h"
     15 #include "net/base/host_port_pair.h"
     16 #include "net/dns/host_resolver.h"
     17 #include "net/dns/single_request_host_resolver.h"
     18 #include "net/socket/client_socket_pool.h"
     19 #include "net/socket/client_socket_pool_base.h"
     20 #include "net/socket/client_socket_pool_histograms.h"
     21 
     22 namespace net {
     23 
     24 class ClientSocketFactory;
     25 
     26 typedef base::Callback<int(const AddressList&, const BoundNetLog& net_log)>
     27 OnHostResolutionCallback;
     28 
     29 class NET_EXPORT_PRIVATE TransportSocketParams
     30     : public base::RefCounted<TransportSocketParams> {
     31  public:
     32   // CombineConnectAndWrite currently translates to using TCP FastOpen.
     33   // TCP FastOpen should not be used if the first write to the socket may
     34   // be non-idempotent, as the underlying socket could retransmit the data
     35   // on failure of the first transmission.
     36   // NOTE: Currently, COMBINE_CONNECT_AND_WRITE_DESIRED is used if the data in
     37   // the write is known to be idempotent, and COMBINE_CONNECT_AND_WRITE_DEFAULT
     38   // is used as a default for other cases (including non-idempotent writes).
     39   enum CombineConnectAndWritePolicy {
     40     COMBINE_CONNECT_AND_WRITE_DEFAULT,    // Default policy, implemented in
     41                                           // TransportSocketParams constructor.
     42     COMBINE_CONNECT_AND_WRITE_DESIRED,    // Combine if supported by socket.
     43     COMBINE_CONNECT_AND_WRITE_PROHIBITED  // Do not combine.
     44   };
     45 
     46   // |host_resolution_callback| will be invoked after the the hostname is
     47   // resolved.  If |host_resolution_callback| does not return OK, then the
     48   // connection will be aborted with that value. |combine_connect_and_write|
     49   // defines the policy for use of TCP FastOpen on this socket.
     50   TransportSocketParams(
     51       const HostPortPair& host_port_pair,
     52       bool disable_resolver_cache,
     53       bool ignore_limits,
     54       const OnHostResolutionCallback& host_resolution_callback,
     55       CombineConnectAndWritePolicy combine_connect_and_write);
     56 
     57   const HostResolver::RequestInfo& destination() const { return destination_; }
     58   bool ignore_limits() const { return ignore_limits_; }
     59   const OnHostResolutionCallback& host_resolution_callback() const {
     60     return host_resolution_callback_;
     61   }
     62 
     63   CombineConnectAndWritePolicy combine_connect_and_write() const {
     64     return combine_connect_and_write_;
     65   }
     66 
     67  private:
     68   friend class base::RefCounted<TransportSocketParams>;
     69   ~TransportSocketParams();
     70 
     71   HostResolver::RequestInfo destination_;
     72   bool ignore_limits_;
     73   const OnHostResolutionCallback host_resolution_callback_;
     74   CombineConnectAndWritePolicy combine_connect_and_write_;
     75 
     76   DISALLOW_COPY_AND_ASSIGN(TransportSocketParams);
     77 };
     78 
     79 // Common data and logic shared between TransportConnectJob and
     80 // WebSocketTransportConnectJob.
     81 class NET_EXPORT_PRIVATE TransportConnectJobHelper {
     82  public:
     83   enum State {
     84     STATE_RESOLVE_HOST,
     85     STATE_RESOLVE_HOST_COMPLETE,
     86     STATE_TRANSPORT_CONNECT,
     87     STATE_TRANSPORT_CONNECT_COMPLETE,
     88     STATE_NONE,
     89   };
     90 
     91   // For recording the connection time in the appropriate bucket.
     92   enum ConnectionLatencyHistogram {
     93     CONNECTION_LATENCY_UNKNOWN,
     94     CONNECTION_LATENCY_IPV4_WINS_RACE,
     95     CONNECTION_LATENCY_IPV4_NO_RACE,
     96     CONNECTION_LATENCY_IPV6_RACEABLE,
     97     CONNECTION_LATENCY_IPV6_SOLO,
     98   };
     99 
    100   TransportConnectJobHelper(const scoped_refptr<TransportSocketParams>& params,
    101                             ClientSocketFactory* client_socket_factory,
    102                             HostResolver* host_resolver,
    103                             LoadTimingInfo::ConnectTiming* connect_timing);
    104   ~TransportConnectJobHelper();
    105 
    106   ClientSocketFactory* client_socket_factory() {
    107     return client_socket_factory_;
    108   }
    109 
    110   const AddressList& addresses() const { return addresses_; }
    111   State next_state() const { return next_state_; }
    112   void set_next_state(State next_state) { next_state_ = next_state; }
    113   CompletionCallback on_io_complete() const { return on_io_complete_; }
    114   const TransportSocketParams* params() { return params_.get(); }
    115 
    116   int DoResolveHost(RequestPriority priority, const BoundNetLog& net_log);
    117   int DoResolveHostComplete(int result, const BoundNetLog& net_log);
    118 
    119   template <class T>
    120   int DoConnectInternal(T* job);
    121 
    122   template <class T>
    123   void SetOnIOComplete(T* job);
    124 
    125   template <class T>
    126   void OnIOComplete(T* job, int result);
    127 
    128   // Record the histograms Net.DNS_Resolution_And_TCP_Connection_Latency2 and
    129   // Net.TCP_Connection_Latency and return the connect duration.
    130   base::TimeDelta HistogramDuration(ConnectionLatencyHistogram race_result);
    131 
    132   static const int kIPv6FallbackTimerInMs;
    133 
    134  private:
    135   template <class T>
    136   int DoLoop(T* job, int result);
    137 
    138   scoped_refptr<TransportSocketParams> params_;
    139   ClientSocketFactory* const client_socket_factory_;
    140   SingleRequestHostResolver resolver_;
    141   AddressList addresses_;
    142   State next_state_;
    143   CompletionCallback on_io_complete_;
    144   LoadTimingInfo::ConnectTiming* connect_timing_;
    145 
    146   DISALLOW_COPY_AND_ASSIGN(TransportConnectJobHelper);
    147 };
    148 
    149 // TransportConnectJob handles the host resolution necessary for socket creation
    150 // and the transport (likely TCP) connect. TransportConnectJob also has fallback
    151 // logic for IPv6 connect() timeouts (which may happen due to networks / routers
    152 // with broken IPv6 support). Those timeouts take 20s, so rather than make the
    153 // user wait 20s for the timeout to fire, we use a fallback timer
    154 // (kIPv6FallbackTimerInMs) and start a connect() to a IPv4 address if the timer
    155 // fires. Then we race the IPv4 connect() against the IPv6 connect() (which has
    156 // a headstart) and return the one that completes first to the socket pool.
    157 class NET_EXPORT_PRIVATE TransportConnectJob : public ConnectJob {
    158  public:
    159   TransportConnectJob(const std::string& group_name,
    160                       RequestPriority priority,
    161                       const scoped_refptr<TransportSocketParams>& params,
    162                       base::TimeDelta timeout_duration,
    163                       ClientSocketFactory* client_socket_factory,
    164                       HostResolver* host_resolver,
    165                       Delegate* delegate,
    166                       NetLog* net_log);
    167   virtual ~TransportConnectJob();
    168 
    169   // ConnectJob methods.
    170   virtual LoadState GetLoadState() const OVERRIDE;
    171 
    172   // Rolls |addrlist| forward until the first IPv4 address, if any.
    173   // WARNING: this method should only be used to implement the prefer-IPv4 hack.
    174   static void MakeAddressListStartWithIPv4(AddressList* addrlist);
    175 
    176  private:
    177   enum ConnectInterval {
    178     CONNECT_INTERVAL_LE_10MS,
    179     CONNECT_INTERVAL_LE_20MS,
    180     CONNECT_INTERVAL_GT_20MS,
    181   };
    182 
    183   friend class TransportConnectJobHelper;
    184 
    185   int DoResolveHost();
    186   int DoResolveHostComplete(int result);
    187   int DoTransportConnect();
    188   int DoTransportConnectComplete(int result);
    189 
    190   // Not part of the state machine.
    191   void DoIPv6FallbackTransportConnect();
    192   void DoIPv6FallbackTransportConnectComplete(int result);
    193 
    194   // Begins the host resolution and the TCP connect.  Returns OK on success
    195   // and ERR_IO_PENDING if it cannot immediately service the request.
    196   // Otherwise, it returns a net error code.
    197   virtual int ConnectInternal() OVERRIDE;
    198 
    199   TransportConnectJobHelper helper_;
    200 
    201   scoped_ptr<StreamSocket> transport_socket_;
    202 
    203   scoped_ptr<StreamSocket> fallback_transport_socket_;
    204   scoped_ptr<AddressList> fallback_addresses_;
    205   base::TimeTicks fallback_connect_start_time_;
    206   base::OneShotTimer<TransportConnectJob> fallback_timer_;
    207 
    208   // Track the interval between this connect and previous connect.
    209   ConnectInterval interval_between_connects_;
    210 
    211   DISALLOW_COPY_AND_ASSIGN(TransportConnectJob);
    212 };
    213 
    214 class NET_EXPORT_PRIVATE TransportClientSocketPool : public ClientSocketPool {
    215  public:
    216   typedef TransportSocketParams SocketParams;
    217 
    218   TransportClientSocketPool(
    219       int max_sockets,
    220       int max_sockets_per_group,
    221       ClientSocketPoolHistograms* histograms,
    222       HostResolver* host_resolver,
    223       ClientSocketFactory* client_socket_factory,
    224       NetLog* net_log);
    225 
    226   virtual ~TransportClientSocketPool();
    227 
    228   // ClientSocketPool implementation.
    229   virtual int RequestSocket(const std::string& group_name,
    230                             const void* resolve_info,
    231                             RequestPriority priority,
    232                             ClientSocketHandle* handle,
    233                             const CompletionCallback& callback,
    234                             const BoundNetLog& net_log) OVERRIDE;
    235   virtual void RequestSockets(const std::string& group_name,
    236                               const void* params,
    237                               int num_sockets,
    238                               const BoundNetLog& net_log) OVERRIDE;
    239   virtual void CancelRequest(const std::string& group_name,
    240                              ClientSocketHandle* handle) OVERRIDE;
    241   virtual void ReleaseSocket(const std::string& group_name,
    242                              scoped_ptr<StreamSocket> socket,
    243                              int id) OVERRIDE;
    244   virtual void FlushWithError(int error) OVERRIDE;
    245   virtual void CloseIdleSockets() OVERRIDE;
    246   virtual int IdleSocketCount() const OVERRIDE;
    247   virtual int IdleSocketCountInGroup(
    248       const std::string& group_name) const OVERRIDE;
    249   virtual LoadState GetLoadState(
    250       const std::string& group_name,
    251       const ClientSocketHandle* handle) const OVERRIDE;
    252   virtual base::DictionaryValue* GetInfoAsValue(
    253       const std::string& name,
    254       const std::string& type,
    255       bool include_nested_pools) const OVERRIDE;
    256   virtual base::TimeDelta ConnectionTimeout() const OVERRIDE;
    257   virtual ClientSocketPoolHistograms* histograms() const OVERRIDE;
    258 
    259   // HigherLayeredPool implementation.
    260   virtual bool IsStalled() const OVERRIDE;
    261   virtual void AddHigherLayeredPool(HigherLayeredPool* higher_pool) OVERRIDE;
    262   virtual void RemoveHigherLayeredPool(HigherLayeredPool* higher_pool) OVERRIDE;
    263 
    264  protected:
    265   // Methods shared with WebSocketTransportClientSocketPool
    266   void NetLogTcpClientSocketPoolRequestedSocket(
    267       const BoundNetLog& net_log,
    268       const scoped_refptr<TransportSocketParams>* casted_params);
    269 
    270  private:
    271   typedef ClientSocketPoolBase<TransportSocketParams> PoolBase;
    272 
    273   class TransportConnectJobFactory
    274       : public PoolBase::ConnectJobFactory {
    275    public:
    276     TransportConnectJobFactory(ClientSocketFactory* client_socket_factory,
    277                          HostResolver* host_resolver,
    278                          NetLog* net_log)
    279         : client_socket_factory_(client_socket_factory),
    280           host_resolver_(host_resolver),
    281           net_log_(net_log) {}
    282 
    283     virtual ~TransportConnectJobFactory() {}
    284 
    285     // ClientSocketPoolBase::ConnectJobFactory methods.
    286 
    287     virtual scoped_ptr<ConnectJob> NewConnectJob(
    288         const std::string& group_name,
    289         const PoolBase::Request& request,
    290         ConnectJob::Delegate* delegate) const OVERRIDE;
    291 
    292     virtual base::TimeDelta ConnectionTimeout() const OVERRIDE;
    293 
    294    private:
    295     ClientSocketFactory* const client_socket_factory_;
    296     HostResolver* const host_resolver_;
    297     NetLog* net_log_;
    298 
    299     DISALLOW_COPY_AND_ASSIGN(TransportConnectJobFactory);
    300   };
    301 
    302   PoolBase base_;
    303 
    304   DISALLOW_COPY_AND_ASSIGN(TransportClientSocketPool);
    305 };
    306 
    307 template <class T>
    308 int TransportConnectJobHelper::DoConnectInternal(T* job) {
    309   next_state_ = STATE_RESOLVE_HOST;
    310   return this->DoLoop(job, OK);
    311 }
    312 
    313 template <class T>
    314 void TransportConnectJobHelper::SetOnIOComplete(T* job) {
    315   // These usages of base::Unretained() are safe because IO callbacks are
    316   // guaranteed not to be called after the object is destroyed.
    317   on_io_complete_ = base::Bind(&TransportConnectJobHelper::OnIOComplete<T>,
    318                                base::Unretained(this),
    319                                base::Unretained(job));
    320 }
    321 
    322 template <class T>
    323 void TransportConnectJobHelper::OnIOComplete(T* job, int result) {
    324   result = this->DoLoop(job, result);
    325   if (result != ERR_IO_PENDING)
    326     job->NotifyDelegateOfCompletion(result);  // Deletes |job| and |this|
    327 }
    328 
    329 template <class T>
    330 int TransportConnectJobHelper::DoLoop(T* job, int result) {
    331   DCHECK_NE(next_state_, STATE_NONE);
    332 
    333   int rv = result;
    334   do {
    335     State state = next_state_;
    336     next_state_ = STATE_NONE;
    337     switch (state) {
    338       case STATE_RESOLVE_HOST:
    339         DCHECK_EQ(OK, rv);
    340         rv = job->DoResolveHost();
    341         break;
    342       case STATE_RESOLVE_HOST_COMPLETE:
    343         rv = job->DoResolveHostComplete(rv);
    344         break;
    345       case STATE_TRANSPORT_CONNECT:
    346         DCHECK_EQ(OK, rv);
    347         rv = job->DoTransportConnect();
    348         break;
    349       case STATE_TRANSPORT_CONNECT_COMPLETE:
    350         rv = job->DoTransportConnectComplete(rv);
    351         break;
    352       default:
    353         NOTREACHED();
    354         rv = ERR_FAILED;
    355         break;
    356     }
    357   } while (rv != ERR_IO_PENDING && next_state_ != STATE_NONE);
    358 
    359   return rv;
    360 }
    361 
    362 }  // namespace net
    363 
    364 #endif  // NET_SOCKET_TRANSPORT_CLIENT_SOCKET_POOL_H_
    365