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"
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"
21 SOCKSSocketParams::SOCKSSocketParams(
22 const scoped_refptr
<TransportSocketParams
>& proxy_server
,
24 const HostPortPair
& host_port_pair
)
25 : transport_params_(proxy_server
),
26 destination_(host_port_pair
),
28 if (transport_params_
.get())
29 ignore_limits_
= transport_params_
->ignore_limits();
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
,
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
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
;
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
);
92 State state
= next_state_
;
93 next_state_
= STATE_NONE
;
95 case STATE_TRANSPORT_CONNECT
:
97 rv
= DoTransportConnect();
99 case STATE_TRANSPORT_CONNECT_COMPLETE
:
100 rv
= DoTransportConnectComplete(rv
);
102 case STATE_SOCKS_CONNECT
:
104 rv
= DoSOCKSConnect();
106 case STATE_SOCKS_CONNECT_COMPLETE
:
107 rv
= DoSOCKSConnectComplete(rv
);
110 NOTREACHED() << "bad state";
114 } while (rv
!= ERR_IO_PENDING
&& next_state_
!= STATE_NONE
);
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(),
130 int SOCKSConnectJob::DoTransportConnectComplete(int result
) {
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
;
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()));
150 socket_
.reset(new SOCKSClientSocket(transport_socket_handle_
.Pass(),
151 socks_params_
->destination(),
155 return socket_
->Connect(
156 base::Bind(&SOCKSConnectJob::OnIOComplete
, base::Unretained(this)));
159 int SOCKSConnectJob::DoSOCKSConnectComplete(int result
) {
161 socket_
->Disconnect();
165 SetSocket(socket_
.Pass());
169 int SOCKSConnectJob::ConnectInternal() {
170 next_state_
= STATE_TRANSPORT_CONNECT
;
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
,
190 SOCKSClientSocketPool::SOCKSConnectJobFactory::ConnectionTimeout() const {
191 return transport_pool_
->ConnectionTimeout() +
192 base::TimeDelta::FromSeconds(kSOCKSConnectJobTimeoutInSeconds
);
195 SOCKSClientSocketPool::SOCKSClientSocketPool(
197 int max_sockets_per_group
,
198 ClientSocketPoolHistograms
* histograms
,
199 HostResolver
* host_resolver
,
200 TransportClientSocketPool
* transport_pool
,
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
,
209 // We should always have a |transport_pool_| except in unit tests.
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
,
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
,
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",
282 dict
->Set("nested_pools", list
);
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())
312 return base_
.CloseOneIdleConnectionInHigherLayeredPool();