• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright (c) 2006-2008 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_HANDLE_H_
6 #define NET_SOCKET_CLIENT_SOCKET_HANDLE_H_
7 
8 #include <string>
9 
10 #include "base/logging.h"
11 #include "base/ref_counted.h"
12 #include "base/scoped_ptr.h"
13 #include "base/time.h"
14 #include "net/base/completion_callback.h"
15 #include "net/base/load_states.h"
16 #include "net/base/net_errors.h"
17 #include "net/base/request_priority.h"
18 #include "net/socket/client_socket.h"
19 #include "net/socket/client_socket_pool.h"
20 
21 namespace net {
22 
23 // A container for a ClientSocket.
24 //
25 // The handle's |group_name| uniquely identifies the origin and type of the
26 // connection.  It is used by the ClientSocketPool to group similar connected
27 // client socket objects.
28 //
29 class ClientSocketHandle {
30  public:
31   typedef enum {
32     UNUSED = 0,   // unused socket that just finished connecting
33     UNUSED_IDLE,  // unused socket that has been idle for awhile
34     REUSED_IDLE,  // previously used socket
35     NUM_TYPES,
36   } SocketReuseType;
37 
38   ClientSocketHandle();
39   ~ClientSocketHandle();
40 
41   // Initializes a ClientSocketHandle object, which involves talking to the
42   // ClientSocketPool to obtain a connected socket, possibly reusing one.  This
43   // method returns either OK or ERR_IO_PENDING.  On ERR_IO_PENDING, |priority|
44   // is used to determine the placement in ClientSocketPool's wait list.
45   //
46   // If this method succeeds, then the socket member will be set to an existing
47   // connected socket if an existing connected socket was available to reuse,
48   // otherwise it will be set to a new connected socket.  Consumers can then
49   // call is_reused() to see if the socket was reused.  If not reusing an
50   // existing socket, ClientSocketPool may need to establish a new
51   // connection using |socket_params|.
52   //
53   // This method returns ERR_IO_PENDING if it cannot complete synchronously, in
54   // which case the consumer will be notified of completion via |callback|.
55   //
56   // Init may be called multiple times.
57   //
58   // Profiling information for the request is saved to |load_log| if non-NULL.
59   //
60   template <typename SocketParams, typename PoolType>
61   int Init(const std::string& group_name,
62            const SocketParams& socket_params,
63            RequestPriority priority,
64            CompletionCallback* callback,
65            PoolType* pool,
66            LoadLog* load_log);
67 
68   // An initialized handle can be reset, which causes it to return to the
69   // un-initialized state.  This releases the underlying socket, which in the
70   // case of a socket that still has an established connection, indicates that
71   // the socket may be kept alive for use by a subsequent ClientSocketHandle.
72   //
73   // NOTE: To prevent the socket from being kept alive, be sure to call its
74   // Disconnect method.  This will result in the ClientSocketPool deleting the
75   // ClientSocket.
76   void Reset();
77 
78   // Used after Init() is called, but before the ClientSocketPool has
79   // initialized the ClientSocketHandle.
80   LoadState GetLoadState() const;
81 
82   // Returns true when Init() has completed successfully.
is_initialized()83   bool is_initialized() const { return socket_ != NULL; }
84 
85   // Returns the time tick when Init() was called.
init_time()86   base::TimeTicks init_time() const { return init_time_; }
87 
88   // Used by ClientSocketPool to initialize the ClientSocketHandle.
set_is_reused(bool is_reused)89   void set_is_reused(bool is_reused) { is_reused_ = is_reused; }
set_socket(ClientSocket * s)90   void set_socket(ClientSocket* s) { socket_.reset(s); }
set_idle_time(base::TimeDelta idle_time)91   void set_idle_time(base::TimeDelta idle_time) { idle_time_ = idle_time; }
92 
93   // These may only be used if is_initialized() is true.
group_name()94   const std::string& group_name() const { return group_name_; }
socket()95   ClientSocket* socket() { return socket_.get(); }
release_socket()96   ClientSocket* release_socket() { return socket_.release(); }
is_reused()97   bool is_reused() const { return is_reused_; }
idle_time()98   base::TimeDelta idle_time() const { return idle_time_; }
reuse_type()99   SocketReuseType reuse_type() const {
100     if (is_reused()) {
101       return REUSED_IDLE;
102     } else if (idle_time() == base::TimeDelta()) {
103       return UNUSED;
104     } else {
105       return UNUSED_IDLE;
106     }
107   }
ShouldResendFailedRequest(int error)108   bool ShouldResendFailedRequest(int error) const {
109     // NOTE: we resend a request only if we reused a keep-alive connection.
110     // This automatically prevents an infinite resend loop because we'll run
111     // out of the cached keep-alive connections eventually.
112     if (  // We used a socket that was never idle.
113         reuse_type() == ClientSocketHandle::UNUSED ||
114         // We used an unused, idle socket and got a error that wasn't a TCP RST.
115         (reuse_type() == ClientSocketHandle::UNUSED_IDLE &&
116          (error != OK && error != ERR_CONNECTION_RESET))) {
117       return false;
118     }
119     return true;
120   }
121 
122  private:
123   // Called on asynchronous completion of an Init() request.
124   void OnIOComplete(int result);
125 
126   // Called on completion (both asynchronous & synchronous) of an Init()
127   // request.
128   void HandleInitCompletion(int result);
129 
130   // Resets the state of the ClientSocketHandle.  |cancel| indicates whether or
131   // not to try to cancel the request with the ClientSocketPool.
132   void ResetInternal(bool cancel);
133 
134   scoped_refptr<ClientSocketPool> pool_;
135   scoped_ptr<ClientSocket> socket_;
136   std::string group_name_;
137   bool is_reused_;
138   CompletionCallbackImpl<ClientSocketHandle> callback_;
139   CompletionCallback* user_callback_;
140   base::TimeDelta idle_time_;
141   base::TimeTicks init_time_;
142 
143   DISALLOW_COPY_AND_ASSIGN(ClientSocketHandle);
144 };
145 
146 // Template function implementation:
147 template <typename SocketParams, typename PoolType>
Init(const std::string & group_name,const SocketParams & socket_params,RequestPriority priority,CompletionCallback * callback,PoolType * pool,LoadLog * load_log)148 int ClientSocketHandle::Init(const std::string& group_name,
149                              const SocketParams& socket_params,
150                              RequestPriority priority,
151                              CompletionCallback* callback,
152                              PoolType* pool,
153                              LoadLog* load_log) {
154   CHECK(!group_name.empty());
155   // Note that this will result in a link error if the SocketParams has not been
156   // registered for the PoolType via REGISTER_SOCKET_PARAMS_FOR_POOL (defined in
157   // client_socket_pool.h).
158   CheckIsValidSocketParamsForPool<PoolType, SocketParams>();
159   ResetInternal(true);
160   pool_ = pool;
161   group_name_ = group_name;
162   init_time_ = base::TimeTicks::Now();
163   int rv = pool_->RequestSocket(
164       group_name, &socket_params, priority, this, &callback_, load_log);
165   if (rv == ERR_IO_PENDING) {
166     user_callback_ = callback;
167   } else {
168     HandleInitCompletion(rv);
169   }
170   return rv;
171 }
172 
173 }  // namespace net
174 
175 #endif  // NET_SOCKET_CLIENT_SOCKET_HANDLE_H_
176