| 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 |