Adding instrumentation to locate the source of jankiness.
[chromium-blink-merge.git] / net / socket / socks_client_socket_pool.cc
blobe431227571f517ef16daa383b2ef3f0d0b581b93
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.
5 #include "net/socket/socks_client_socket_pool.h"
7 #include "base/bind.h"
8 #include "base/bind_helpers.h"
9 #include "base/time/time.h"
10 #include "base/values.h"
11 #include "net/base/net_errors.h"
12 #include "net/socket/client_socket_factory.h"
13 #include "net/socket/client_socket_handle.h"
14 #include "net/socket/client_socket_pool_base.h"
15 #include "net/socket/socks5_client_socket.h"
16 #include "net/socket/socks_client_socket.h"
17 #include "net/socket/transport_client_socket_pool.h"
19 namespace net {
21 SOCKSSocketParams::SOCKSSocketParams(
22 const scoped_refptr<TransportSocketParams>& proxy_server,
23 bool socks_v5,
24 const HostPortPair& host_port_pair)
25 : transport_params_(proxy_server),
26 destination_(host_port_pair),
27 socks_v5_(socks_v5) {
28 if (transport_params_.get())
29 ignore_limits_ = transport_params_->ignore_limits();
30 else
31 ignore_limits_ = false;
34 SOCKSSocketParams::~SOCKSSocketParams() {}
36 // SOCKSConnectJobs will time out after this many seconds. Note this is on
37 // top of the timeout for the transport socket.
38 static const int kSOCKSConnectJobTimeoutInSeconds = 30;
40 SOCKSConnectJob::SOCKSConnectJob(
41 const std::string& group_name,
42 RequestPriority priority,
43 const scoped_refptr<SOCKSSocketParams>& socks_params,
44 const base::TimeDelta& timeout_duration,
45 TransportClientSocketPool* transport_pool,
46 HostResolver* host_resolver,
47 Delegate* delegate,
48 NetLog* net_log)
49 : ConnectJob(group_name, timeout_duration, priority, delegate,
50 BoundNetLog::Make(net_log, NetLog::SOURCE_CONNECT_JOB)),
51 socks_params_(socks_params),
52 transport_pool_(transport_pool),
53 resolver_(host_resolver),
54 callback_(base::Bind(&SOCKSConnectJob::OnIOComplete,
55 base::Unretained(this))) {
58 SOCKSConnectJob::~SOCKSConnectJob() {
59 // We don't worry about cancelling the tcp socket since the destructor in
60 // scoped_ptr<ClientSocketHandle> transport_socket_handle_ will take care of
61 // it.
64 LoadState SOCKSConnectJob::GetLoadState() const {
65 switch (next_state_) {
66 case STATE_TRANSPORT_CONNECT:
67 case STATE_TRANSPORT_CONNECT_COMPLETE:
68 return transport_socket_handle_->GetLoadState();
69 case STATE_SOCKS_CONNECT:
70 case STATE_SOCKS_CONNECT_COMPLETE:
71 return LOAD_STATE_CONNECTING;
72 default:
73 NOTREACHED();
74 return LOAD_STATE_IDLE;
78 void SOCKSConnectJob::OnIOComplete(int result) {
79 // TODO(pkasting): Remove ScopedTracker below once crbug.com/455884 is fixed.
80 tracked_objects::ScopedTracker tracking_profile(
81 FROM_HERE_WITH_EXPLICIT_FUNCTION("455884 SOCKSConnectJob::OnIOComplete"));
82 int rv = DoLoop(result);
83 if (rv != ERR_IO_PENDING)
84 NotifyDelegateOfCompletion(rv); // Deletes |this|
87 int SOCKSConnectJob::DoLoop(int result) {
88 DCHECK_NE(next_state_, STATE_NONE);
90 int rv = result;
91 do {
92 State state = next_state_;
93 next_state_ = STATE_NONE;
94 switch (state) {
95 case STATE_TRANSPORT_CONNECT:
96 DCHECK_EQ(OK, rv);
97 rv = DoTransportConnect();
98 break;
99 case STATE_TRANSPORT_CONNECT_COMPLETE:
100 rv = DoTransportConnectComplete(rv);
101 break;
102 case STATE_SOCKS_CONNECT:
103 DCHECK_EQ(OK, rv);
104 rv = DoSOCKSConnect();
105 break;
106 case STATE_SOCKS_CONNECT_COMPLETE:
107 rv = DoSOCKSConnectComplete(rv);
108 break;
109 default:
110 NOTREACHED() << "bad state";
111 rv = ERR_FAILED;
112 break;
114 } while (rv != ERR_IO_PENDING && next_state_ != STATE_NONE);
116 return rv;
119 int SOCKSConnectJob::DoTransportConnect() {
120 next_state_ = STATE_TRANSPORT_CONNECT_COMPLETE;
121 transport_socket_handle_.reset(new ClientSocketHandle());
122 return transport_socket_handle_->Init(group_name(),
123 socks_params_->transport_params(),
124 priority(),
125 callback_,
126 transport_pool_,
127 net_log());
130 int SOCKSConnectJob::DoTransportConnectComplete(int result) {
131 if (result != OK)
132 return ERR_PROXY_CONNECTION_FAILED;
134 // Reset the timer to just the length of time allowed for SOCKS handshake
135 // so that a fast TCP connection plus a slow SOCKS failure doesn't take
136 // longer to timeout than it should.
137 ResetTimer(base::TimeDelta::FromSeconds(kSOCKSConnectJobTimeoutInSeconds));
138 next_state_ = STATE_SOCKS_CONNECT;
139 return result;
142 int SOCKSConnectJob::DoSOCKSConnect() {
143 next_state_ = STATE_SOCKS_CONNECT_COMPLETE;
145 // Add a SOCKS connection on top of the tcp socket.
146 if (socks_params_->is_socks_v5()) {
147 socket_.reset(new SOCKS5ClientSocket(transport_socket_handle_.Pass(),
148 socks_params_->destination()));
149 } else {
150 socket_.reset(new SOCKSClientSocket(transport_socket_handle_.Pass(),
151 socks_params_->destination(),
152 priority(),
153 resolver_));
155 return socket_->Connect(
156 base::Bind(&SOCKSConnectJob::OnIOComplete, base::Unretained(this)));
159 int SOCKSConnectJob::DoSOCKSConnectComplete(int result) {
160 if (result != OK) {
161 socket_->Disconnect();
162 return result;
165 SetSocket(socket_.Pass());
166 return result;
169 int SOCKSConnectJob::ConnectInternal() {
170 next_state_ = STATE_TRANSPORT_CONNECT;
171 return DoLoop(OK);
174 scoped_ptr<ConnectJob>
175 SOCKSClientSocketPool::SOCKSConnectJobFactory::NewConnectJob(
176 const std::string& group_name,
177 const PoolBase::Request& request,
178 ConnectJob::Delegate* delegate) const {
179 return scoped_ptr<ConnectJob>(new SOCKSConnectJob(group_name,
180 request.priority(),
181 request.params(),
182 ConnectionTimeout(),
183 transport_pool_,
184 host_resolver_,
185 delegate,
186 net_log_));
189 base::TimeDelta
190 SOCKSClientSocketPool::SOCKSConnectJobFactory::ConnectionTimeout() const {
191 return transport_pool_->ConnectionTimeout() +
192 base::TimeDelta::FromSeconds(kSOCKSConnectJobTimeoutInSeconds);
195 SOCKSClientSocketPool::SOCKSClientSocketPool(
196 int max_sockets,
197 int max_sockets_per_group,
198 ClientSocketPoolHistograms* histograms,
199 HostResolver* host_resolver,
200 TransportClientSocketPool* transport_pool,
201 NetLog* net_log)
202 : transport_pool_(transport_pool),
203 base_(this, max_sockets, max_sockets_per_group, histograms,
204 ClientSocketPool::unused_idle_socket_timeout(),
205 ClientSocketPool::used_idle_socket_timeout(),
206 new SOCKSConnectJobFactory(transport_pool,
207 host_resolver,
208 net_log)) {
209 // We should always have a |transport_pool_| except in unit tests.
210 if (transport_pool_)
211 base_.AddLowerLayeredPool(transport_pool_);
214 SOCKSClientSocketPool::~SOCKSClientSocketPool() {
217 int SOCKSClientSocketPool::RequestSocket(
218 const std::string& group_name, const void* socket_params,
219 RequestPriority priority, ClientSocketHandle* handle,
220 const CompletionCallback& callback, const BoundNetLog& net_log) {
221 const scoped_refptr<SOCKSSocketParams>* casted_socket_params =
222 static_cast<const scoped_refptr<SOCKSSocketParams>*>(socket_params);
224 return base_.RequestSocket(group_name, *casted_socket_params, priority,
225 handle, callback, net_log);
228 void SOCKSClientSocketPool::RequestSockets(
229 const std::string& group_name,
230 const void* params,
231 int num_sockets,
232 const BoundNetLog& net_log) {
233 const scoped_refptr<SOCKSSocketParams>* casted_params =
234 static_cast<const scoped_refptr<SOCKSSocketParams>*>(params);
236 base_.RequestSockets(group_name, *casted_params, num_sockets, net_log);
239 void SOCKSClientSocketPool::CancelRequest(const std::string& group_name,
240 ClientSocketHandle* handle) {
241 base_.CancelRequest(group_name, handle);
244 void SOCKSClientSocketPool::ReleaseSocket(const std::string& group_name,
245 scoped_ptr<StreamSocket> socket,
246 int id) {
247 base_.ReleaseSocket(group_name, socket.Pass(), id);
250 void SOCKSClientSocketPool::FlushWithError(int error) {
251 base_.FlushWithError(error);
254 void SOCKSClientSocketPool::CloseIdleSockets() {
255 base_.CloseIdleSockets();
258 int SOCKSClientSocketPool::IdleSocketCount() const {
259 return base_.idle_socket_count();
262 int SOCKSClientSocketPool::IdleSocketCountInGroup(
263 const std::string& group_name) const {
264 return base_.IdleSocketCountInGroup(group_name);
267 LoadState SOCKSClientSocketPool::GetLoadState(
268 const std::string& group_name, const ClientSocketHandle* handle) const {
269 return base_.GetLoadState(group_name, handle);
272 base::DictionaryValue* SOCKSClientSocketPool::GetInfoAsValue(
273 const std::string& name,
274 const std::string& type,
275 bool include_nested_pools) const {
276 base::DictionaryValue* dict = base_.GetInfoAsValue(name, type);
277 if (include_nested_pools) {
278 base::ListValue* list = new base::ListValue();
279 list->Append(transport_pool_->GetInfoAsValue("transport_socket_pool",
280 "transport_socket_pool",
281 false));
282 dict->Set("nested_pools", list);
284 return dict;
287 base::TimeDelta SOCKSClientSocketPool::ConnectionTimeout() const {
288 return base_.ConnectionTimeout();
291 ClientSocketPoolHistograms* SOCKSClientSocketPool::histograms() const {
292 return base_.histograms();
295 bool SOCKSClientSocketPool::IsStalled() const {
296 return base_.IsStalled();
299 void SOCKSClientSocketPool::AddHigherLayeredPool(
300 HigherLayeredPool* higher_pool) {
301 base_.AddHigherLayeredPool(higher_pool);
304 void SOCKSClientSocketPool::RemoveHigherLayeredPool(
305 HigherLayeredPool* higher_pool) {
306 base_.RemoveHigherLayeredPool(higher_pool);
309 bool SOCKSClientSocketPool::CloseOneIdleConnection() {
310 if (base_.CloseOneIdleSocket())
311 return true;
312 return base_.CloseOneIdleConnectionInHigherLayeredPool();
315 } // namespace net