socks_client_socket_pool.cc revision dfffe33b592d92936093aae70ed06488fc7798ed
1// Copyright (c) 2011 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/time.h" 8#include "base/values.h" 9#include "googleurl/src/gurl.h" 10#include "net/base/net_errors.h" 11#include "net/socket/client_socket_factory.h" 12#include "net/socket/client_socket_handle.h" 13#include "net/socket/client_socket_pool_base.h" 14#include "net/socket/socks5_client_socket.h" 15#include "net/socket/socks_client_socket.h" 16#include "net/socket/transport_client_socket_pool.h" 17 18namespace net { 19 20SOCKSSocketParams::SOCKSSocketParams( 21 const scoped_refptr<TransportSocketParams>& proxy_server, 22 bool socks_v5, 23 const HostPortPair& host_port_pair, 24 RequestPriority priority, 25 const GURL& referrer) 26 : transport_params_(proxy_server), 27 destination_(host_port_pair), 28 socks_v5_(socks_v5) { 29 if (transport_params_) 30 ignore_limits_ = transport_params_->ignore_limits(); 31 else 32 ignore_limits_ = false; 33 // The referrer is used by the DNS prefetch system to correlate resolutions 34 // with the page that triggered them. It doesn't impact the actual addresses 35 // that we resolve to. 36 destination_.set_referrer(referrer); 37 destination_.set_priority(priority); 38} 39 40SOCKSSocketParams::~SOCKSSocketParams() {} 41 42// SOCKSConnectJobs will time out after this many seconds. Note this is on 43// top of the timeout for the transport socket. 44static const int kSOCKSConnectJobTimeoutInSeconds = 30; 45 46SOCKSConnectJob::SOCKSConnectJob( 47 const std::string& group_name, 48 const scoped_refptr<SOCKSSocketParams>& socks_params, 49 const base::TimeDelta& timeout_duration, 50 TransportClientSocketPool* transport_pool, 51 HostResolver* host_resolver, 52 Delegate* delegate, 53 NetLog* net_log) 54 : ConnectJob(group_name, timeout_duration, delegate, 55 BoundNetLog::Make(net_log, NetLog::SOURCE_CONNECT_JOB)), 56 socks_params_(socks_params), 57 transport_pool_(transport_pool), 58 resolver_(host_resolver), 59 ALLOW_THIS_IN_INITIALIZER_LIST( 60 callback_(this, &SOCKSConnectJob::OnIOComplete)) { 61} 62 63SOCKSConnectJob::~SOCKSConnectJob() { 64 // We don't worry about cancelling the tcp socket since the destructor in 65 // scoped_ptr<ClientSocketHandle> transport_socket_handle_ will take care of 66 // it. 67} 68 69LoadState SOCKSConnectJob::GetLoadState() const { 70 switch (next_state_) { 71 case STATE_TRANSPORT_CONNECT: 72 case STATE_TRANSPORT_CONNECT_COMPLETE: 73 return transport_socket_handle_->GetLoadState(); 74 case STATE_SOCKS_CONNECT: 75 case STATE_SOCKS_CONNECT_COMPLETE: 76 return LOAD_STATE_CONNECTING; 77 default: 78 NOTREACHED(); 79 return LOAD_STATE_IDLE; 80 } 81} 82 83void SOCKSConnectJob::OnIOComplete(int result) { 84 int rv = DoLoop(result); 85 if (rv != ERR_IO_PENDING) 86 NotifyDelegateOfCompletion(rv); // Deletes |this| 87} 88 89int SOCKSConnectJob::DoLoop(int result) { 90 DCHECK_NE(next_state_, STATE_NONE); 91 92 int rv = result; 93 do { 94 State state = next_state_; 95 next_state_ = STATE_NONE; 96 switch (state) { 97 case STATE_TRANSPORT_CONNECT: 98 DCHECK_EQ(OK, rv); 99 rv = DoTransportConnect(); 100 break; 101 case STATE_TRANSPORT_CONNECT_COMPLETE: 102 rv = DoTransportConnectComplete(rv); 103 break; 104 case STATE_SOCKS_CONNECT: 105 DCHECK_EQ(OK, rv); 106 rv = DoSOCKSConnect(); 107 break; 108 case STATE_SOCKS_CONNECT_COMPLETE: 109 rv = DoSOCKSConnectComplete(rv); 110 break; 111 default: 112 NOTREACHED() << "bad state"; 113 rv = ERR_FAILED; 114 break; 115 } 116 } while (rv != ERR_IO_PENDING && next_state_ != STATE_NONE); 117 118 return rv; 119} 120 121int SOCKSConnectJob::DoTransportConnect() { 122 next_state_ = STATE_TRANSPORT_CONNECT_COMPLETE; 123 transport_socket_handle_.reset(new ClientSocketHandle()); 124 return transport_socket_handle_->Init(group_name(), 125 socks_params_->transport_params(), 126 socks_params_->destination().priority(), 127 &callback_, 128 transport_pool_, 129 net_log()); 130} 131 132int SOCKSConnectJob::DoTransportConnectComplete(int result) { 133 if (result != OK) 134 return ERR_PROXY_CONNECTION_FAILED; 135 136 // Reset the timer to just the length of time allowed for SOCKS handshake 137 // so that a fast TCP connection plus a slow SOCKS failure doesn't take 138 // longer to timeout than it should. 139 ResetTimer(base::TimeDelta::FromSeconds(kSOCKSConnectJobTimeoutInSeconds)); 140 next_state_ = STATE_SOCKS_CONNECT; 141 return result; 142} 143 144int SOCKSConnectJob::DoSOCKSConnect() { 145 next_state_ = STATE_SOCKS_CONNECT_COMPLETE; 146 147 // Add a SOCKS connection on top of the tcp socket. 148 if (socks_params_->is_socks_v5()) { 149 socket_.reset(new SOCKS5ClientSocket(transport_socket_handle_.release(), 150 socks_params_->destination())); 151 } else { 152 socket_.reset(new SOCKSClientSocket(transport_socket_handle_.release(), 153 socks_params_->destination(), 154 resolver_)); 155 } 156 return socket_->Connect(&callback_ 157#ifdef ANDROID 158 , socks_params_->ignore_limits() 159#endif 160 ); 161} 162 163int SOCKSConnectJob::DoSOCKSConnectComplete(int result) { 164 if (result != OK) { 165 socket_->Disconnect(); 166 return result; 167 } 168 169 set_socket(socket_.release()); 170 return result; 171} 172 173int SOCKSConnectJob::ConnectInternal() { 174 next_state_ = STATE_TRANSPORT_CONNECT; 175 return DoLoop(OK); 176} 177 178ConnectJob* SOCKSClientSocketPool::SOCKSConnectJobFactory::NewConnectJob( 179 const std::string& group_name, 180 const PoolBase::Request& request, 181 ConnectJob::Delegate* delegate) const { 182 return new SOCKSConnectJob(group_name, 183 request.params(), 184 ConnectionTimeout(), 185 transport_pool_, 186 host_resolver_, 187 delegate, 188 net_log_); 189} 190 191base::TimeDelta 192SOCKSClientSocketPool::SOCKSConnectJobFactory::ConnectionTimeout() const { 193 return transport_pool_->ConnectionTimeout() + 194 base::TimeDelta::FromSeconds(kSOCKSConnectJobTimeoutInSeconds); 195} 196 197SOCKSClientSocketPool::SOCKSClientSocketPool( 198 int max_sockets, 199 int max_sockets_per_group, 200 ClientSocketPoolHistograms* histograms, 201 HostResolver* host_resolver, 202 TransportClientSocketPool* transport_pool, 203 NetLog* net_log) 204 : transport_pool_(transport_pool), 205 base_(max_sockets, max_sockets_per_group, histograms, 206 base::TimeDelta::FromSeconds( 207 ClientSocketPool::unused_idle_socket_timeout()), 208 base::TimeDelta::FromSeconds(kUsedIdleSocketTimeout), 209 new SOCKSConnectJobFactory(transport_pool, 210 host_resolver, 211 net_log)) { 212} 213 214SOCKSClientSocketPool::~SOCKSClientSocketPool() {} 215 216int SOCKSClientSocketPool::RequestSocket(const std::string& group_name, 217 const void* socket_params, 218 RequestPriority priority, 219 ClientSocketHandle* handle, 220 CompletionCallback* callback, 221 const BoundNetLog& net_log) { 222 const scoped_refptr<SOCKSSocketParams>* casted_socket_params = 223 static_cast<const scoped_refptr<SOCKSSocketParams>*>(socket_params); 224 225 return base_.RequestSocket(group_name, *casted_socket_params, priority, 226 handle, callback, net_log); 227} 228 229void SOCKSClientSocketPool::RequestSockets( 230 const std::string& group_name, 231 const void* params, 232 int num_sockets, 233 const BoundNetLog& net_log) { 234 const scoped_refptr<SOCKSSocketParams>* casted_params = 235 static_cast<const scoped_refptr<SOCKSSocketParams>*>(params); 236 237 base_.RequestSockets(group_name, *casted_params, num_sockets, net_log); 238} 239 240void SOCKSClientSocketPool::CancelRequest(const std::string& group_name, 241 ClientSocketHandle* handle) { 242 base_.CancelRequest(group_name, handle); 243} 244 245void SOCKSClientSocketPool::ReleaseSocket(const std::string& group_name, 246 ClientSocket* socket, int id) { 247 base_.ReleaseSocket(group_name, socket, id); 248} 249 250void SOCKSClientSocketPool::Flush() { 251 base_.Flush(); 252} 253 254void SOCKSClientSocketPool::CloseIdleSockets() { 255 base_.CloseIdleSockets(); 256} 257 258int SOCKSClientSocketPool::IdleSocketCount() const { 259 return base_.idle_socket_count(); 260} 261 262int SOCKSClientSocketPool::IdleSocketCountInGroup( 263 const std::string& group_name) const { 264 return base_.IdleSocketCountInGroup(group_name); 265} 266 267LoadState SOCKSClientSocketPool::GetLoadState( 268 const std::string& group_name, const ClientSocketHandle* handle) const { 269 return base_.GetLoadState(group_name, handle); 270} 271 272DictionaryValue* SOCKSClientSocketPool::GetInfoAsValue( 273 const std::string& name, 274 const std::string& type, 275 bool include_nested_pools) const { 276 DictionaryValue* dict = base_.GetInfoAsValue(name, type); 277 if (include_nested_pools) { 278 ListValue* list = new 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 287base::TimeDelta SOCKSClientSocketPool::ConnectionTimeout() const { 288 return base_.ConnectionTimeout(); 289} 290 291ClientSocketPoolHistograms* SOCKSClientSocketPool::histograms() const { 292 return base_.histograms(); 293}; 294 295} // namespace net 296