OLD | NEW |
(Empty) | |
| 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/sctp_client_socket_pool.h" |
| 6 |
| 7 #include "base/compiler_specific.h" |
| 8 #include "base/logging.h" |
| 9 #include "base/message_loop.h" |
| 10 #include "base/metrics/histogram.h" |
| 11 #include "base/string_util.h" |
| 12 #include "base/time.h" |
| 13 #include "net/base/net_log.h" |
| 14 #include "net/base/net_errors.h" |
| 15 #include "net/socket/client_socket_factory.h" |
| 16 #include "net/socket/client_socket_handle.h" |
| 17 #include "net/socket/client_socket_pool_base.h" |
| 18 #include "net/socket/sctp_client_socket.h" |
| 19 |
| 20 using base::TimeDelta; |
| 21 |
| 22 namespace net { |
| 23 |
| 24 SCTPSocketParams::SCTPSocketParams(const HostPortPair& host_port_pair, |
| 25 RequestPriority priority, |
| 26 const GURL& referrer, |
| 27 bool disable_resolver_cache, |
| 28 bool ignore_limits) |
| 29 : destination_(host_port_pair), ignore_limits_(ignore_limits) { |
| 30 Initialize(priority, referrer, disable_resolver_cache); |
| 31 } |
| 32 |
| 33 SCTPSocketParams::~SCTPSocketParams() {} |
| 34 |
| 35 void SCTPSocketParams::Initialize(RequestPriority priority, |
| 36 const GURL& referrer, |
| 37 bool disable_resolver_cache) { |
| 38 // The referrer is used by the DNS prefetch system to correlate resolutions |
| 39 // with the page that triggered them. It doesn't impact the actual addresses |
| 40 // that we resolve to. |
| 41 destination_.set_referrer(referrer); |
| 42 destination_.set_priority(priority); |
| 43 if (disable_resolver_cache) |
| 44 destination_.set_allow_cached_response(false); |
| 45 } |
| 46 |
| 47 // SCTPConnectJobs will time out after this many seconds. Note this is the |
| 48 // total time, including both host resolution and SCTP connect() times. |
| 49 // |
| 50 // TODO(eroman): The use of this constant needs to be re-evaluated. The time |
| 51 // needed for SCTPClientSocketXXX::Connect() can be arbitrarily long, since |
| 52 // the address list may contain many alternatives, and most of those may |
| 53 // timeout. Even worse, the per-connect timeout threshold varies greatly |
| 54 // between systems (anywhere from 20 seconds to 190 seconds). |
| 55 // See comment #12 at http://crbug.com/23364 for specifics. |
| 56 static const int kSCTPConnectJobTimeoutInSeconds = 240; // 4 minutes. |
| 57 |
| 58 SCTPConnectJob::SCTPConnectJob( |
| 59 const std::string& group_name, |
| 60 const scoped_refptr<SCTPSocketParams>& params, |
| 61 base::TimeDelta timeout_duration, |
| 62 ClientSocketFactory* client_socket_factory, |
| 63 HostResolver* host_resolver, |
| 64 Delegate* delegate, |
| 65 NetLog* net_log) |
| 66 : ConnectJob(group_name, timeout_duration, delegate, |
| 67 BoundNetLog::Make(net_log, NetLog::SOURCE_CONNECT_JOB)), |
| 68 params_(params), |
| 69 client_socket_factory_(client_socket_factory), |
| 70 ALLOW_THIS_IN_INITIALIZER_LIST( |
| 71 callback_(this, |
| 72 &SCTPConnectJob::OnIOComplete)), |
| 73 resolver_(host_resolver) {} |
| 74 |
| 75 SCTPConnectJob::~SCTPConnectJob() { |
| 76 // We don't worry about cancelling the host resolution and SCTP connect, since |
| 77 // ~SingleRequestHostResolver and ~ClientSocket will take care of it. |
| 78 } |
| 79 |
| 80 LoadState SCTPConnectJob::GetLoadState() const { |
| 81 switch (next_state_) { |
| 82 case STATE_RESOLVE_HOST: |
| 83 case STATE_RESOLVE_HOST_COMPLETE: |
| 84 return LOAD_STATE_RESOLVING_HOST; |
| 85 case STATE_SCTP_CONNECT: |
| 86 case STATE_SCTP_CONNECT_COMPLETE: |
| 87 return LOAD_STATE_CONNECTING; |
| 88 default: |
| 89 NOTREACHED(); |
| 90 return LOAD_STATE_IDLE; |
| 91 } |
| 92 } |
| 93 |
| 94 void SCTPConnectJob::OnIOComplete(int result) { |
| 95 int rv = DoLoop(result); |
| 96 if (rv != ERR_IO_PENDING) |
| 97 NotifyDelegateOfCompletion(rv); // Deletes |this| |
| 98 } |
| 99 |
| 100 int SCTPConnectJob::DoLoop(int result) { |
| 101 DCHECK_NE(next_state_, STATE_NONE); |
| 102 |
| 103 int rv = result; |
| 104 do { |
| 105 State state = next_state_; |
| 106 next_state_ = STATE_NONE; |
| 107 switch (state) { |
| 108 case STATE_RESOLVE_HOST: |
| 109 DCHECK_EQ(OK, rv); |
| 110 rv = DoResolveHost(); |
| 111 break; |
| 112 case STATE_RESOLVE_HOST_COMPLETE: |
| 113 rv = DoResolveHostComplete(rv); |
| 114 break; |
| 115 case STATE_SCTP_CONNECT: |
| 116 DCHECK_EQ(OK, rv); |
| 117 rv = DoSCTPConnect(); |
| 118 break; |
| 119 case STATE_SCTP_CONNECT_COMPLETE: |
| 120 rv = DoSCTPConnectComplete(rv); |
| 121 break; |
| 122 default: |
| 123 NOTREACHED(); |
| 124 rv = ERR_FAILED; |
| 125 break; |
| 126 } |
| 127 } while (rv != ERR_IO_PENDING && next_state_ != STATE_NONE); |
| 128 |
| 129 return rv; |
| 130 } |
| 131 |
| 132 int SCTPConnectJob::DoResolveHost() { |
| 133 next_state_ = STATE_RESOLVE_HOST_COMPLETE; |
| 134 return resolver_.Resolve(params_->destination(), &addresses_, &callback_, |
| 135 net_log()); |
| 136 } |
| 137 |
| 138 int SCTPConnectJob::DoResolveHostComplete(int result) { |
| 139 if (result == OK) |
| 140 next_state_ = STATE_SCTP_CONNECT; |
| 141 return result; |
| 142 } |
| 143 |
| 144 int SCTPConnectJob::DoSCTPConnect() { |
| 145 next_state_ = STATE_SCTP_CONNECT_COMPLETE; |
| 146 set_socket(client_socket_factory_->CreateSCTPClientSocket( |
| 147 addresses_, net_log().net_log(), net_log().source())); |
| 148 connect_start_time_ = base::TimeTicks::Now(); |
| 149 return socket()->Connect(&callback_); |
| 150 } |
| 151 |
| 152 int SCTPConnectJob::DoSCTPConnectComplete(int result) { |
| 153 if (result == OK) { |
| 154 DCHECK(connect_start_time_ != base::TimeTicks()); |
| 155 DCHECK(start_time_ != base::TimeTicks()); |
| 156 base::TimeTicks now = base::TimeTicks::Now(); |
| 157 base::TimeDelta total_duration = now - start_time_; |
| 158 UMA_HISTOGRAM_CUSTOM_TIMES( |
| 159 "Net.DNS_Resolution_And_SCTP_Connection_Latency2", |
| 160 total_duration, |
| 161 base::TimeDelta::FromMilliseconds(1), |
| 162 base::TimeDelta::FromMinutes(10), |
| 163 100); |
| 164 |
| 165 base::TimeDelta connect_duration = now - connect_start_time_; |
| 166 UMA_HISTOGRAM_CUSTOM_TIMES("Net.SCTP_Connection_Latency", |
| 167 connect_duration, |
| 168 base::TimeDelta::FromMilliseconds(1), |
| 169 base::TimeDelta::FromMinutes(10), |
| 170 100); |
| 171 } else { |
| 172 // Delete the socket on error. |
| 173 set_socket(NULL); |
| 174 } |
| 175 |
| 176 return result; |
| 177 } |
| 178 |
| 179 int SCTPConnectJob::ConnectInternal() { |
| 180 next_state_ = STATE_RESOLVE_HOST; |
| 181 start_time_ = base::TimeTicks::Now(); |
| 182 return DoLoop(OK); |
| 183 } |
| 184 |
| 185 ConnectJob* SCTPClientSocketPool::SCTPConnectJobFactory::NewConnectJob( |
| 186 const std::string& group_name, |
| 187 const PoolBase::Request& request, |
| 188 ConnectJob::Delegate* delegate) const { |
| 189 return new SCTPConnectJob(group_name, request.params(), ConnectionTimeout(), |
| 190 client_socket_factory_, host_resolver_, delegate, |
| 191 net_log_); |
| 192 } |
| 193 |
| 194 base::TimeDelta |
| 195 SCTPClientSocketPool::SCTPConnectJobFactory::ConnectionTimeout() const { |
| 196 return base::TimeDelta::FromSeconds(kSCTPConnectJobTimeoutInSeconds); |
| 197 } |
| 198 |
| 199 SCTPClientSocketPool::SCTPClientSocketPool( |
| 200 int max_sockets, |
| 201 int max_sockets_per_group, |
| 202 ClientSocketPoolHistograms* histograms, |
| 203 HostResolver* host_resolver, |
| 204 ClientSocketFactory* client_socket_factory, |
| 205 NetLog* net_log) |
| 206 : base_(max_sockets, max_sockets_per_group, histograms, |
| 207 base::TimeDelta::FromSeconds( |
| 208 ClientSocketPool::unused_idle_socket_timeout()), |
| 209 base::TimeDelta::FromSeconds(kUsedIdleSocketTimeout), |
| 210 new SCTPConnectJobFactory(client_socket_factory, |
| 211 host_resolver, net_log)) { |
| 212 base_.EnableConnectBackupJobs(); |
| 213 } |
| 214 |
| 215 SCTPClientSocketPool::~SCTPClientSocketPool() {} |
| 216 |
| 217 int SCTPClientSocketPool::RequestSocket( |
| 218 const std::string& group_name, |
| 219 const void* params, |
| 220 RequestPriority priority, |
| 221 ClientSocketHandle* handle, |
| 222 CompletionCallback* callback, |
| 223 const BoundNetLog& net_log) { |
| 224 const scoped_refptr<SCTPSocketParams>* casted_params = |
| 225 static_cast<const scoped_refptr<SCTPSocketParams>*>(params); |
| 226 |
| 227 if (net_log.IsLoggingAllEvents()) { |
| 228 // TODO(eroman): Split out the host and port parameters. |
| 229 net_log.AddEvent( |
| 230 NetLog::TYPE_SCTP_CLIENT_SOCKET_POOL_REQUESTED_SOCKET, |
| 231 make_scoped_refptr(new NetLogStringParameter( |
| 232 "host_and_port", |
| 233 casted_params->get()->destination().host_port_pair().ToString()))); |
| 234 } |
| 235 |
| 236 return base_.RequestSocket(group_name, *casted_params, priority, handle, |
| 237 callback, net_log); |
| 238 } |
| 239 |
| 240 void SCTPClientSocketPool::RequestSockets( |
| 241 const std::string& group_name, |
| 242 const void* params, |
| 243 int num_sockets, |
| 244 const BoundNetLog& net_log) { |
| 245 const scoped_refptr<SCTPSocketParams>* casted_params = |
| 246 static_cast<const scoped_refptr<SCTPSocketParams>*>(params); |
| 247 |
| 248 if (net_log.IsLoggingAllEvents()) { |
| 249 // TODO(eroman): Split out the host and port parameters. |
| 250 net_log.AddEvent( |
| 251 NetLog::TYPE_SCTP_CLIENT_SOCKET_POOL_REQUESTED_SOCKETS, |
| 252 make_scoped_refptr(new NetLogStringParameter( |
| 253 "host_and_port", |
| 254 casted_params->get()->destination().host_port_pair().ToString()))); |
| 255 } |
| 256 |
| 257 base_.RequestSockets(group_name, *casted_params, num_sockets, net_log); |
| 258 } |
| 259 |
| 260 void SCTPClientSocketPool::CancelRequest( |
| 261 const std::string& group_name, |
| 262 ClientSocketHandle* handle) { |
| 263 base_.CancelRequest(group_name, handle); |
| 264 } |
| 265 |
| 266 void SCTPClientSocketPool::ReleaseSocket( |
| 267 const std::string& group_name, |
| 268 ClientSocket* socket, |
| 269 int id) { |
| 270 base_.ReleaseSocket(group_name, socket, id); |
| 271 } |
| 272 |
| 273 void SCTPClientSocketPool::Flush() { |
| 274 base_.Flush(); |
| 275 } |
| 276 |
| 277 void SCTPClientSocketPool::CloseIdleSockets() { |
| 278 base_.CloseIdleSockets(); |
| 279 } |
| 280 |
| 281 int SCTPClientSocketPool::IdleSocketCount() const { |
| 282 return base_.idle_socket_count(); |
| 283 } |
| 284 |
| 285 int SCTPClientSocketPool::IdleSocketCountInGroup( |
| 286 const std::string& group_name) const { |
| 287 return base_.IdleSocketCountInGroup(group_name); |
| 288 } |
| 289 |
| 290 LoadState SCTPClientSocketPool::GetLoadState( |
| 291 const std::string& group_name, const ClientSocketHandle* handle) const { |
| 292 return base_.GetLoadState(group_name, handle); |
| 293 } |
| 294 |
| 295 DictionaryValue* SCTPClientSocketPool::GetInfoAsValue( |
| 296 const std::string& name, |
| 297 const std::string& type, |
| 298 bool include_nested_pools) const { |
| 299 return base_.GetInfoAsValue(name, type); |
| 300 } |
| 301 |
| 302 base::TimeDelta SCTPClientSocketPool::ConnectionTimeout() const { |
| 303 return base_.ConnectionTimeout(); |
| 304 } |
| 305 |
| 306 ClientSocketPoolHistograms* SCTPClientSocketPool::histograms() const { |
| 307 return base_.histograms(); |
| 308 } |
| 309 |
| 310 } // namespace net |
OLD | NEW |