OLD | NEW |
| (Empty) |
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. | |
4 | |
5 #include "net/socket/socks_client_socket_pool.h" | |
6 | |
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" | |
18 | |
19 namespace net { | |
20 | |
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; | |
32 } | |
33 | |
34 SOCKSSocketParams::~SOCKSSocketParams() {} | |
35 | |
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; | |
39 | |
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))) { | |
56 } | |
57 | |
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. | |
62 } | |
63 | |
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; | |
75 } | |
76 } | |
77 | |
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| | |
85 } | |
86 | |
87 int SOCKSConnectJob::DoLoop(int result) { | |
88 DCHECK_NE(next_state_, STATE_NONE); | |
89 | |
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; | |
113 } | |
114 } while (rv != ERR_IO_PENDING && next_state_ != STATE_NONE); | |
115 | |
116 return rv; | |
117 } | |
118 | |
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()); | |
128 } | |
129 | |
130 int SOCKSConnectJob::DoTransportConnectComplete(int result) { | |
131 if (result != OK) | |
132 return ERR_PROXY_CONNECTION_FAILED; | |
133 | |
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; | |
140 } | |
141 | |
142 int SOCKSConnectJob::DoSOCKSConnect() { | |
143 next_state_ = STATE_SOCKS_CONNECT_COMPLETE; | |
144 | |
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_)); | |
154 } | |
155 return socket_->Connect( | |
156 base::Bind(&SOCKSConnectJob::OnIOComplete, base::Unretained(this))); | |
157 } | |
158 | |
159 int SOCKSConnectJob::DoSOCKSConnectComplete(int result) { | |
160 if (result != OK) { | |
161 socket_->Disconnect(); | |
162 return result; | |
163 } | |
164 | |
165 SetSocket(socket_.Pass()); | |
166 return result; | |
167 } | |
168 | |
169 int SOCKSConnectJob::ConnectInternal() { | |
170 next_state_ = STATE_TRANSPORT_CONNECT; | |
171 return DoLoop(OK); | |
172 } | |
173 | |
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_)); | |
187 } | |
188 | |
189 base::TimeDelta | |
190 SOCKSClientSocketPool::SOCKSConnectJobFactory::ConnectionTimeout() const { | |
191 return transport_pool_->ConnectionTimeout() + | |
192 base::TimeDelta::FromSeconds(kSOCKSConnectJobTimeoutInSeconds); | |
193 } | |
194 | |
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_); | |
212 } | |
213 | |
214 SOCKSClientSocketPool::~SOCKSClientSocketPool() { | |
215 } | |
216 | |
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); | |
223 | |
224 return base_.RequestSocket(group_name, *casted_socket_params, priority, | |
225 handle, callback, net_log); | |
226 } | |
227 | |
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); | |
235 | |
236 base_.RequestSockets(group_name, *casted_params, num_sockets, net_log); | |
237 } | |
238 | |
239 void SOCKSClientSocketPool::CancelRequest(const std::string& group_name, | |
240 ClientSocketHandle* handle) { | |
241 base_.CancelRequest(group_name, handle); | |
242 } | |
243 | |
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); | |
248 } | |
249 | |
250 void SOCKSClientSocketPool::FlushWithError(int error) { | |
251 base_.FlushWithError(error); | |
252 } | |
253 | |
254 void SOCKSClientSocketPool::CloseIdleSockets() { | |
255 base_.CloseIdleSockets(); | |
256 } | |
257 | |
258 int SOCKSClientSocketPool::IdleSocketCount() const { | |
259 return base_.idle_socket_count(); | |
260 } | |
261 | |
262 int SOCKSClientSocketPool::IdleSocketCountInGroup( | |
263 const std::string& group_name) const { | |
264 return base_.IdleSocketCountInGroup(group_name); | |
265 } | |
266 | |
267 LoadState SOCKSClientSocketPool::GetLoadState( | |
268 const std::string& group_name, const ClientSocketHandle* handle) const { | |
269 return base_.GetLoadState(group_name, handle); | |
270 } | |
271 | |
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); | |
283 } | |
284 return dict; | |
285 } | |
286 | |
287 base::TimeDelta SOCKSClientSocketPool::ConnectionTimeout() const { | |
288 return base_.ConnectionTimeout(); | |
289 } | |
290 | |
291 ClientSocketPoolHistograms* SOCKSClientSocketPool::histograms() const { | |
292 return base_.histograms(); | |
293 }; | |
294 | |
295 bool SOCKSClientSocketPool::IsStalled() const { | |
296 return base_.IsStalled(); | |
297 } | |
298 | |
299 void SOCKSClientSocketPool::AddHigherLayeredPool( | |
300 HigherLayeredPool* higher_pool) { | |
301 base_.AddHigherLayeredPool(higher_pool); | |
302 } | |
303 | |
304 void SOCKSClientSocketPool::RemoveHigherLayeredPool( | |
305 HigherLayeredPool* higher_pool) { | |
306 base_.RemoveHigherLayeredPool(higher_pool); | |
307 } | |
308 | |
309 bool SOCKSClientSocketPool::CloseOneIdleConnection() { | |
310 if (base_.CloseOneIdleSocket()) | |
311 return true; | |
312 return base_.CloseOneIdleConnectionInHigherLayeredPool(); | |
313 } | |
314 | |
315 } // namespace net | |
OLD | NEW |