blob: e11b7a48db5b6f8e8ed21823d2afdd718a473c8d [file] [log] [blame]
[email protected]e34400c32012-01-24 02:49:331// Copyright (c) 2012 The Chromium Authors. All rights reserved.
[email protected]a796bcec2010-03-22 17:17:262// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "net/socket/socks_client_socket_pool.h"
6
[email protected]6ecf2b92011-12-15 01:14:527#include "base/bind.h"
8#include "base/bind_helpers.h"
[email protected]f002abb2013-06-28 02:30:219#include "base/time/time.h"
[email protected]ba00b492010-09-08 14:53:3810#include "base/values.h"
[email protected]a796bcec2010-03-22 17:17:2611#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"
[email protected]ab739042011-04-07 15:22:2817#include "net/socket/transport_client_socket_pool.h"
[email protected]a796bcec2010-03-22 17:17:2618
19namespace net {
20
[email protected]df4b4ef2010-07-12 18:25:2121SOCKSSocketParams::SOCKSSocketParams(
[email protected]ab739042011-04-07 15:22:2822 const scoped_refptr<TransportSocketParams>& proxy_server,
[email protected]df4b4ef2010-07-12 18:25:2123 bool socks_v5,
[email protected]3f6007ab2013-08-22 19:45:3924 const HostPortPair& host_port_pair)
[email protected]ab739042011-04-07 15:22:2825 : transport_params_(proxy_server),
[email protected]5109c1952013-08-20 18:44:1026 destination_(host_port_pair),
[email protected]df4b4ef2010-07-12 18:25:2127 socks_v5_(socks_v5) {
[email protected]90499482013-06-01 00:39:5028 if (transport_params_.get())
[email protected]ab739042011-04-07 15:22:2829 ignore_limits_ = transport_params_->ignore_limits();
[email protected]5acdce12011-03-30 13:00:2030 else
31 ignore_limits_ = false;
[email protected]df4b4ef2010-07-12 18:25:2132}
33
34SOCKSSocketParams::~SOCKSSocketParams() {}
35
[email protected]a796bcec2010-03-22 17:17:2636// SOCKSConnectJobs will time out after this many seconds. Note this is on
37// top of the timeout for the transport socket.
38static const int kSOCKSConnectJobTimeoutInSeconds = 30;
39
40SOCKSConnectJob::SOCKSConnectJob(
41 const std::string& group_name,
[email protected]3f6007ab2013-08-22 19:45:3942 RequestPriority priority,
[email protected]df4b4ef2010-07-12 18:25:2143 const scoped_refptr<SOCKSSocketParams>& socks_params,
[email protected]a796bcec2010-03-22 17:17:2644 const base::TimeDelta& timeout_duration,
[email protected]ab739042011-04-07 15:22:2845 TransportClientSocketPool* transport_pool,
[email protected]73c45322010-10-01 23:57:5446 HostResolver* host_resolver,
[email protected]a796bcec2010-03-22 17:17:2647 Delegate* delegate,
[email protected]06650c52010-06-03 00:49:1748 NetLog* net_log)
[email protected]3f6007ab2013-08-22 19:45:3949 : ConnectJob(group_name, timeout_duration, priority, delegate,
[email protected]06650c52010-06-03 00:49:1750 BoundNetLog::Make(net_log, NetLog::SOURCE_CONNECT_JOB)),
[email protected]a796bcec2010-03-22 17:17:2651 socks_params_(socks_params),
[email protected]ab739042011-04-07 15:22:2852 transport_pool_(transport_pool),
[email protected]a796bcec2010-03-22 17:17:2653 resolver_(host_resolver),
[email protected]aa249b52013-04-30 01:04:3254 callback_(base::Bind(&SOCKSConnectJob::OnIOComplete,
55 base::Unretained(this))) {
[email protected]06650c52010-06-03 00:49:1756}
[email protected]a796bcec2010-03-22 17:17:2657
58SOCKSConnectJob::~SOCKSConnectJob() {
59 // We don't worry about cancelling the tcp socket since the destructor in
[email protected]ab739042011-04-07 15:22:2860 // scoped_ptr<ClientSocketHandle> transport_socket_handle_ will take care of
61 // it.
[email protected]a796bcec2010-03-22 17:17:2662}
63
64LoadState SOCKSConnectJob::GetLoadState() const {
65 switch (next_state_) {
[email protected]ab739042011-04-07 15:22:2866 case STATE_TRANSPORT_CONNECT:
67 case STATE_TRANSPORT_CONNECT_COMPLETE:
68 return transport_socket_handle_->GetLoadState();
[email protected]81854c42010-09-22 03:39:3669 case STATE_SOCKS_CONNECT:
70 case STATE_SOCKS_CONNECT_COMPLETE:
[email protected]a796bcec2010-03-22 17:17:2671 return LOAD_STATE_CONNECTING;
72 default:
73 NOTREACHED();
74 return LOAD_STATE_IDLE;
75 }
76}
77
[email protected]a796bcec2010-03-22 17:17:2678void SOCKSConnectJob::OnIOComplete(int result) {
79 int rv = DoLoop(result);
80 if (rv != ERR_IO_PENDING)
81 NotifyDelegateOfCompletion(rv); // Deletes |this|
82}
83
84int SOCKSConnectJob::DoLoop(int result) {
[email protected]81854c42010-09-22 03:39:3685 DCHECK_NE(next_state_, STATE_NONE);
[email protected]a796bcec2010-03-22 17:17:2686
87 int rv = result;
88 do {
89 State state = next_state_;
[email protected]81854c42010-09-22 03:39:3690 next_state_ = STATE_NONE;
[email protected]a796bcec2010-03-22 17:17:2691 switch (state) {
[email protected]ab739042011-04-07 15:22:2892 case STATE_TRANSPORT_CONNECT:
[email protected]a796bcec2010-03-22 17:17:2693 DCHECK_EQ(OK, rv);
[email protected]ab739042011-04-07 15:22:2894 rv = DoTransportConnect();
[email protected]a796bcec2010-03-22 17:17:2695 break;
[email protected]ab739042011-04-07 15:22:2896 case STATE_TRANSPORT_CONNECT_COMPLETE:
97 rv = DoTransportConnectComplete(rv);
[email protected]a796bcec2010-03-22 17:17:2698 break;
[email protected]81854c42010-09-22 03:39:3699 case STATE_SOCKS_CONNECT:
[email protected]a796bcec2010-03-22 17:17:26100 DCHECK_EQ(OK, rv);
101 rv = DoSOCKSConnect();
102 break;
[email protected]81854c42010-09-22 03:39:36103 case STATE_SOCKS_CONNECT_COMPLETE:
[email protected]a796bcec2010-03-22 17:17:26104 rv = DoSOCKSConnectComplete(rv);
105 break;
106 default:
107 NOTREACHED() << "bad state";
108 rv = ERR_FAILED;
109 break;
110 }
[email protected]81854c42010-09-22 03:39:36111 } while (rv != ERR_IO_PENDING && next_state_ != STATE_NONE);
[email protected]a796bcec2010-03-22 17:17:26112
113 return rv;
114}
115
[email protected]ab739042011-04-07 15:22:28116int SOCKSConnectJob::DoTransportConnect() {
117 next_state_ = STATE_TRANSPORT_CONNECT_COMPLETE;
118 transport_socket_handle_.reset(new ClientSocketHandle());
[email protected]5109c1952013-08-20 18:44:10119 return transport_socket_handle_->Init(group_name(),
120 socks_params_->transport_params(),
[email protected]3f6007ab2013-08-22 19:45:39121 priority(),
[email protected]5109c1952013-08-20 18:44:10122 callback_,
123 transport_pool_,
124 net_log());
[email protected]a796bcec2010-03-22 17:17:26125}
126
[email protected]ab739042011-04-07 15:22:28127int SOCKSConnectJob::DoTransportConnectComplete(int result) {
[email protected]a796bcec2010-03-22 17:17:26128 if (result != OK)
[email protected]f7fccee2010-09-16 20:53:01129 return ERR_PROXY_CONNECTION_FAILED;
[email protected]a796bcec2010-03-22 17:17:26130
131 // Reset the timer to just the length of time allowed for SOCKS handshake
132 // so that a fast TCP connection plus a slow SOCKS failure doesn't take
133 // longer to timeout than it should.
134 ResetTimer(base::TimeDelta::FromSeconds(kSOCKSConnectJobTimeoutInSeconds));
[email protected]81854c42010-09-22 03:39:36135 next_state_ = STATE_SOCKS_CONNECT;
[email protected]a796bcec2010-03-22 17:17:26136 return result;
137}
138
139int SOCKSConnectJob::DoSOCKSConnect() {
[email protected]81854c42010-09-22 03:39:36140 next_state_ = STATE_SOCKS_CONNECT_COMPLETE;
[email protected]a796bcec2010-03-22 17:17:26141
142 // Add a SOCKS connection on top of the tcp socket.
[email protected]df4b4ef2010-07-12 18:25:21143 if (socks_params_->is_socks_v5()) {
[email protected]18ccfdb2013-08-15 00:13:44144 socket_.reset(new SOCKS5ClientSocket(transport_socket_handle_.Pass(),
[email protected]df4b4ef2010-07-12 18:25:21145 socks_params_->destination()));
[email protected]a796bcec2010-03-22 17:17:26146 } else {
[email protected]18ccfdb2013-08-15 00:13:44147 socket_.reset(new SOCKSClientSocket(transport_socket_handle_.Pass(),
[email protected]df4b4ef2010-07-12 18:25:21148 socks_params_->destination(),
[email protected]3f6007ab2013-08-22 19:45:39149 priority(),
[email protected]a796bcec2010-03-22 17:17:26150 resolver_));
151 }
[email protected]83039bb2011-12-09 18:43:55152 return socket_->Connect(
153 base::Bind(&SOCKSConnectJob::OnIOComplete, base::Unretained(this)));
[email protected]a796bcec2010-03-22 17:17:26154}
155
156int SOCKSConnectJob::DoSOCKSConnectComplete(int result) {
157 if (result != OK) {
158 socket_->Disconnect();
159 return result;
160 }
161
[email protected]18ccfdb2013-08-15 00:13:44162 SetSocket(socket_.Pass());
[email protected]a796bcec2010-03-22 17:17:26163 return result;
164}
165
[email protected]ad74a592011-01-21 18:40:55166int SOCKSConnectJob::ConnectInternal() {
[email protected]ab739042011-04-07 15:22:28167 next_state_ = STATE_TRANSPORT_CONNECT;
[email protected]ad74a592011-01-21 18:40:55168 return DoLoop(OK);
169}
170
[email protected]18ccfdb2013-08-15 00:13:44171scoped_ptr<ConnectJob>
172SOCKSClientSocketPool::SOCKSConnectJobFactory::NewConnectJob(
[email protected]a796bcec2010-03-22 17:17:26173 const std::string& group_name,
174 const PoolBase::Request& request,
[email protected]06650c52010-06-03 00:49:17175 ConnectJob::Delegate* delegate) const {
[email protected]18ccfdb2013-08-15 00:13:44176 return scoped_ptr<ConnectJob>(new SOCKSConnectJob(group_name,
[email protected]3f6007ab2013-08-22 19:45:39177 request.priority(),
[email protected]18ccfdb2013-08-15 00:13:44178 request.params(),
179 ConnectionTimeout(),
180 transport_pool_,
181 host_resolver_,
182 delegate,
183 net_log_));
[email protected]a796bcec2010-03-22 17:17:26184}
185
186base::TimeDelta
187SOCKSClientSocketPool::SOCKSConnectJobFactory::ConnectionTimeout() const {
[email protected]ab739042011-04-07 15:22:28188 return transport_pool_->ConnectionTimeout() +
[email protected]a796bcec2010-03-22 17:17:26189 base::TimeDelta::FromSeconds(kSOCKSConnectJobTimeoutInSeconds);
190}
191
192SOCKSClientSocketPool::SOCKSClientSocketPool(
193 int max_sockets,
194 int max_sockets_per_group,
[email protected]2431756e2010-09-29 20:26:13195 ClientSocketPoolHistograms* histograms,
[email protected]73c45322010-10-01 23:57:54196 HostResolver* host_resolver,
[email protected]ab739042011-04-07 15:22:28197 TransportClientSocketPool* transport_pool,
[email protected]06650c52010-06-03 00:49:17198 NetLog* net_log)
[email protected]ab739042011-04-07 15:22:28199 : transport_pool_(transport_pool),
[email protected]043b68c82013-08-22 23:41:52200 base_(this, max_sockets, max_sockets_per_group, histograms,
[email protected]82b8c962011-10-12 09:17:30201 ClientSocketPool::unused_idle_socket_timeout(),
202 ClientSocketPool::used_idle_socket_timeout(),
[email protected]ab739042011-04-07 15:22:28203 new SOCKSConnectJobFactory(transport_pool,
204 host_resolver,
205 net_log)) {
[email protected]51fdc7c2012-04-10 19:19:48206 // We should always have a |transport_pool_| except in unit tests.
207 if (transport_pool_)
[email protected]043b68c82013-08-22 23:41:52208 base_.AddLowerLayeredPool(transport_pool_);
[email protected]66761b952010-06-25 21:30:38209}
[email protected]a796bcec2010-03-22 17:17:26210
[email protected]51fdc7c2012-04-10 19:19:48211SOCKSClientSocketPool::~SOCKSClientSocketPool() {
[email protected]51fdc7c2012-04-10 19:19:48212}
[email protected]a796bcec2010-03-22 17:17:26213
[email protected]49639fa2011-12-20 23:22:41214int SOCKSClientSocketPool::RequestSocket(
215 const std::string& group_name, const void* socket_params,
216 RequestPriority priority, ClientSocketHandle* handle,
217 const CompletionCallback& callback, const BoundNetLog& net_log) {
[email protected]df4b4ef2010-07-12 18:25:21218 const scoped_refptr<SOCKSSocketParams>* casted_socket_params =
219 static_cast<const scoped_refptr<SOCKSSocketParams>*>(socket_params);
[email protected]a796bcec2010-03-22 17:17:26220
221 return base_.RequestSocket(group_name, *casted_socket_params, priority,
222 handle, callback, net_log);
223}
224
[email protected]2c2bef152010-10-13 00:55:03225void SOCKSClientSocketPool::RequestSockets(
226 const std::string& group_name,
227 const void* params,
228 int num_sockets,
229 const BoundNetLog& net_log) {
230 const scoped_refptr<SOCKSSocketParams>* casted_params =
231 static_cast<const scoped_refptr<SOCKSSocketParams>*>(params);
232
233 base_.RequestSockets(group_name, *casted_params, num_sockets, net_log);
234}
235
[email protected]df4b4ef2010-07-12 18:25:21236void SOCKSClientSocketPool::CancelRequest(const std::string& group_name,
[email protected]05ea9ff2010-07-15 19:08:21237 ClientSocketHandle* handle) {
[email protected]a796bcec2010-03-22 17:17:26238 base_.CancelRequest(group_name, handle);
239}
240
[email protected]df4b4ef2010-07-12 18:25:21241void SOCKSClientSocketPool::ReleaseSocket(const std::string& group_name,
[email protected]18ccfdb2013-08-15 00:13:44242 scoped_ptr<StreamSocket> socket,
243 int id) {
244 base_.ReleaseSocket(group_name, socket.Pass(), id);
[email protected]a7e38572010-06-07 18:22:24245}
246
[email protected]7af985a2012-12-14 22:40:42247void SOCKSClientSocketPool::FlushWithError(int error) {
248 base_.FlushWithError(error);
[email protected]a796bcec2010-03-22 17:17:26249}
250
[email protected]a796bcec2010-03-22 17:17:26251void SOCKSClientSocketPool::CloseIdleSockets() {
252 base_.CloseIdleSockets();
253}
254
[email protected]7cf40912010-12-09 18:25:03255int SOCKSClientSocketPool::IdleSocketCount() const {
256 return base_.idle_socket_count();
257}
258
[email protected]a796bcec2010-03-22 17:17:26259int SOCKSClientSocketPool::IdleSocketCountInGroup(
260 const std::string& group_name) const {
261 return base_.IdleSocketCountInGroup(group_name);
262}
263
264LoadState SOCKSClientSocketPool::GetLoadState(
265 const std::string& group_name, const ClientSocketHandle* handle) const {
266 return base_.GetLoadState(group_name, handle);
267}
268
[email protected]ea5ef4c2013-06-13 22:50:27269base::DictionaryValue* SOCKSClientSocketPool::GetInfoAsValue(
[email protected]ba00b492010-09-08 14:53:38270 const std::string& name,
271 const std::string& type,
272 bool include_nested_pools) const {
[email protected]ea5ef4c2013-06-13 22:50:27273 base::DictionaryValue* dict = base_.GetInfoAsValue(name, type);
[email protected]ba00b492010-09-08 14:53:38274 if (include_nested_pools) {
[email protected]ea5ef4c2013-06-13 22:50:27275 base::ListValue* list = new base::ListValue();
[email protected]ab739042011-04-07 15:22:28276 list->Append(transport_pool_->GetInfoAsValue("transport_socket_pool",
277 "transport_socket_pool",
278 false));
[email protected]ba00b492010-09-08 14:53:38279 dict->Set("nested_pools", list);
280 }
281 return dict;
282}
283
[email protected]7cf40912010-12-09 18:25:03284base::TimeDelta SOCKSClientSocketPool::ConnectionTimeout() const {
285 return base_.ConnectionTimeout();
286}
287
288ClientSocketPoolHistograms* SOCKSClientSocketPool::histograms() const {
289 return base_.histograms();
290};
291
[email protected]043b68c82013-08-22 23:41:52292bool SOCKSClientSocketPool::IsStalled() const {
293 return base_.IsStalled();
294}
295
296void SOCKSClientSocketPool::AddHigherLayeredPool(
297 HigherLayeredPool* higher_pool) {
298 base_.AddHigherLayeredPool(higher_pool);
299}
300
301void SOCKSClientSocketPool::RemoveHigherLayeredPool(
302 HigherLayeredPool* higher_pool) {
303 base_.RemoveHigherLayeredPool(higher_pool);
304}
305
[email protected]51fdc7c2012-04-10 19:19:48306bool SOCKSClientSocketPool::CloseOneIdleConnection() {
307 if (base_.CloseOneIdleSocket())
308 return true;
[email protected]043b68c82013-08-22 23:41:52309 return base_.CloseOneIdleConnectionInHigherLayeredPool();
[email protected]51fdc7c2012-04-10 19:19:48310}
311
[email protected]a796bcec2010-03-22 17:17:26312} // namespace net