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/profiler/scoped_tracker.h"
10 #include "base/time/time.h"
11 #include "base/values.h"
12 #include "net/base/net_errors.h"
13 #include "net/socket/client_socket_factory.h"
14 #include "net/socket/client_socket_handle.h"
15 #include "net/socket/client_socket_pool_base.h"
16 #include "net/socket/socks5_client_socket.h"
17 #include "net/socket/socks_client_socket.h"
18 #include "net/socket/transport_client_socket_pool.h"
22 SOCKSSocketParams::SOCKSSocketParams(
23 const scoped_refptr
<TransportSocketParams
>& proxy_server
,
25 const HostPortPair
& host_port_pair
)
26 : transport_params_(proxy_server
),
27 destination_(host_port_pair
),
29 if (transport_params_
.get())
30 ignore_limits_
= transport_params_
->ignore_limits();
32 ignore_limits_
= false;
35 SOCKSSocketParams::~SOCKSSocketParams() {}
37 // SOCKSConnectJobs will time out after this many seconds. Note this is on
38 // top of the timeout for the transport socket.
39 static const int kSOCKSConnectJobTimeoutInSeconds
= 30;
41 SOCKSConnectJob::SOCKSConnectJob(
42 const std::string
& group_name
,
43 RequestPriority priority
,
44 const scoped_refptr
<SOCKSSocketParams
>& socks_params
,
45 const base::TimeDelta
& timeout_duration
,
46 TransportClientSocketPool
* transport_pool
,
47 HostResolver
* host_resolver
,
50 : ConnectJob(group_name
, timeout_duration
, priority
, delegate
,
51 BoundNetLog::Make(net_log
, NetLog::SOURCE_CONNECT_JOB
)),
52 socks_params_(socks_params
),
53 transport_pool_(transport_pool
),
54 resolver_(host_resolver
),
55 callback_(base::Bind(&SOCKSConnectJob::OnIOComplete
,
56 base::Unretained(this))) {
59 SOCKSConnectJob::~SOCKSConnectJob() {
60 // We don't worry about cancelling the tcp socket since the destructor in
61 // scoped_ptr<ClientSocketHandle> transport_socket_handle_ will take care of
65 LoadState
SOCKSConnectJob::GetLoadState() const {
66 switch (next_state_
) {
67 case STATE_TRANSPORT_CONNECT
:
68 case STATE_TRANSPORT_CONNECT_COMPLETE
:
69 return transport_socket_handle_
->GetLoadState();
70 case STATE_SOCKS_CONNECT
:
71 case STATE_SOCKS_CONNECT_COMPLETE
:
72 return LOAD_STATE_CONNECTING
;
75 return LOAD_STATE_IDLE
;
79 void SOCKSConnectJob::OnIOComplete(int result
) {
80 // TODO(pkasting): Remove ScopedTracker below once crbug.com/455884 is fixed.
81 tracked_objects::ScopedTracker
tracking_profile(
82 FROM_HERE_WITH_EXPLICIT_FUNCTION("455884 SOCKSConnectJob::OnIOComplete"));
83 int rv
= DoLoop(result
);
84 if (rv
!= ERR_IO_PENDING
)
85 NotifyDelegateOfCompletion(rv
); // Deletes |this|
88 int SOCKSConnectJob::DoLoop(int result
) {
89 DCHECK_NE(next_state_
, STATE_NONE
);
93 State state
= next_state_
;
94 next_state_
= STATE_NONE
;
96 case STATE_TRANSPORT_CONNECT
:
98 rv
= DoTransportConnect();
100 case STATE_TRANSPORT_CONNECT_COMPLETE
:
101 rv
= DoTransportConnectComplete(rv
);
103 case STATE_SOCKS_CONNECT
:
105 rv
= DoSOCKSConnect();
107 case STATE_SOCKS_CONNECT_COMPLETE
:
108 rv
= DoSOCKSConnectComplete(rv
);
111 NOTREACHED() << "bad state";
115 } while (rv
!= ERR_IO_PENDING
&& next_state_
!= STATE_NONE
);
120 int SOCKSConnectJob::DoTransportConnect() {
121 next_state_
= STATE_TRANSPORT_CONNECT_COMPLETE
;
122 transport_socket_handle_
.reset(new ClientSocketHandle());
123 return transport_socket_handle_
->Init(group_name(),
124 socks_params_
->transport_params(),
131 int SOCKSConnectJob::DoTransportConnectComplete(int result
) {
133 return ERR_PROXY_CONNECTION_FAILED
;
135 // Reset the timer to just the length of time allowed for SOCKS handshake
136 // so that a fast TCP connection plus a slow SOCKS failure doesn't take
137 // longer to timeout than it should.
138 ResetTimer(base::TimeDelta::FromSeconds(kSOCKSConnectJobTimeoutInSeconds
));
139 next_state_
= STATE_SOCKS_CONNECT
;
143 int SOCKSConnectJob::DoSOCKSConnect() {
144 next_state_
= STATE_SOCKS_CONNECT_COMPLETE
;
146 // Add a SOCKS connection on top of the tcp socket.
147 if (socks_params_
->is_socks_v5()) {
148 socket_
.reset(new SOCKS5ClientSocket(transport_socket_handle_
.Pass(),
149 socks_params_
->destination()));
151 socket_
.reset(new SOCKSClientSocket(transport_socket_handle_
.Pass(),
152 socks_params_
->destination(),
156 return socket_
->Connect(
157 base::Bind(&SOCKSConnectJob::OnIOComplete
, base::Unretained(this)));
160 int SOCKSConnectJob::DoSOCKSConnectComplete(int result
) {
162 socket_
->Disconnect();
166 SetSocket(socket_
.Pass());
170 int SOCKSConnectJob::ConnectInternal() {
171 next_state_
= STATE_TRANSPORT_CONNECT
;
175 scoped_ptr
<ConnectJob
>
176 SOCKSClientSocketPool::SOCKSConnectJobFactory::NewConnectJob(
177 const std::string
& group_name
,
178 const PoolBase::Request
& request
,
179 ConnectJob::Delegate
* delegate
) const {
180 return scoped_ptr
<ConnectJob
>(new SOCKSConnectJob(group_name
,
191 SOCKSClientSocketPool::SOCKSConnectJobFactory::ConnectionTimeout() const {
192 return transport_pool_
->ConnectionTimeout() +
193 base::TimeDelta::FromSeconds(kSOCKSConnectJobTimeoutInSeconds
);
196 SOCKSClientSocketPool::SOCKSClientSocketPool(
198 int max_sockets_per_group
,
199 HostResolver
* host_resolver
,
200 TransportClientSocketPool
* transport_pool
,
202 : transport_pool_(transport_pool
),
206 max_sockets_per_group
,
207 ClientSocketPool::unused_idle_socket_timeout(),
208 ClientSocketPool::used_idle_socket_timeout(),
209 new SOCKSConnectJobFactory(transport_pool
, host_resolver
, net_log
)) {
210 // We should always have a |transport_pool_| except in unit tests.
212 base_
.AddLowerLayeredPool(transport_pool_
);
215 SOCKSClientSocketPool::~SOCKSClientSocketPool() {
218 int SOCKSClientSocketPool::RequestSocket(
219 const std::string
& group_name
, const void* socket_params
,
220 RequestPriority priority
, ClientSocketHandle
* handle
,
221 const CompletionCallback
& callback
, const BoundNetLog
& net_log
) {
222 const scoped_refptr
<SOCKSSocketParams
>* casted_socket_params
=
223 static_cast<const scoped_refptr
<SOCKSSocketParams
>*>(socket_params
);
225 return base_
.RequestSocket(group_name
, *casted_socket_params
, priority
,
226 handle
, callback
, net_log
);
229 void SOCKSClientSocketPool::RequestSockets(
230 const std::string
& group_name
,
233 const BoundNetLog
& net_log
) {
234 const scoped_refptr
<SOCKSSocketParams
>* casted_params
=
235 static_cast<const scoped_refptr
<SOCKSSocketParams
>*>(params
);
237 base_
.RequestSockets(group_name
, *casted_params
, num_sockets
, net_log
);
240 void SOCKSClientSocketPool::CancelRequest(const std::string
& group_name
,
241 ClientSocketHandle
* handle
) {
242 base_
.CancelRequest(group_name
, handle
);
245 void SOCKSClientSocketPool::ReleaseSocket(const std::string
& group_name
,
246 scoped_ptr
<StreamSocket
> socket
,
248 base_
.ReleaseSocket(group_name
, socket
.Pass(), id
);
251 void SOCKSClientSocketPool::FlushWithError(int error
) {
252 base_
.FlushWithError(error
);
255 void SOCKSClientSocketPool::CloseIdleSockets() {
256 base_
.CloseIdleSockets();
259 int SOCKSClientSocketPool::IdleSocketCount() const {
260 return base_
.idle_socket_count();
263 int SOCKSClientSocketPool::IdleSocketCountInGroup(
264 const std::string
& group_name
) const {
265 return base_
.IdleSocketCountInGroup(group_name
);
268 LoadState
SOCKSClientSocketPool::GetLoadState(
269 const std::string
& group_name
, const ClientSocketHandle
* handle
) const {
270 return base_
.GetLoadState(group_name
, handle
);
273 base::DictionaryValue
* SOCKSClientSocketPool::GetInfoAsValue(
274 const std::string
& name
,
275 const std::string
& type
,
276 bool include_nested_pools
) const {
277 base::DictionaryValue
* dict
= base_
.GetInfoAsValue(name
, type
);
278 if (include_nested_pools
) {
279 base::ListValue
* list
= new base::ListValue();
280 list
->Append(transport_pool_
->GetInfoAsValue("transport_socket_pool",
281 "transport_socket_pool",
283 dict
->Set("nested_pools", list
);
288 base::TimeDelta
SOCKSClientSocketPool::ConnectionTimeout() const {
289 return base_
.ConnectionTimeout();
292 bool SOCKSClientSocketPool::IsStalled() const {
293 return base_
.IsStalled();
296 void SOCKSClientSocketPool::AddHigherLayeredPool(
297 HigherLayeredPool
* higher_pool
) {
298 base_
.AddHigherLayeredPool(higher_pool
);
301 void SOCKSClientSocketPool::RemoveHigherLayeredPool(
302 HigherLayeredPool
* higher_pool
) {
303 base_
.RemoveHigherLayeredPool(higher_pool
);
306 bool SOCKSClientSocketPool::CloseOneIdleConnection() {
307 if (base_
.CloseOneIdleSocket())
309 return base_
.CloseOneIdleConnectionInHigherLayeredPool();