OLD | NEW |
1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "net/socket/transport_client_socket_pool.h" | 5 #include "net/socket/transport_client_socket_pool.h" |
6 | 6 |
7 #include "base/compiler_specific.h" | 7 #include "base/compiler_specific.h" |
8 #include "base/logging.h" | 8 #include "base/logging.h" |
9 #include "base/message_loop.h" | 9 #include "base/message_loop.h" |
10 #include "base/metrics/histogram.h" | 10 #include "base/metrics/histogram.h" |
11 #include "base/string_util.h" | 11 #include "base/string_util.h" |
12 #include "base/time.h" | 12 #include "base/time.h" |
| 13 #include "net/base/ip_endpoint.h" |
13 #include "net/base/net_log.h" | 14 #include "net/base/net_log.h" |
14 #include "net/base/net_errors.h" | 15 #include "net/base/net_errors.h" |
| 16 #include "net/base/sys_addrinfo.h" |
15 #include "net/socket/client_socket_factory.h" | 17 #include "net/socket/client_socket_factory.h" |
16 #include "net/socket/client_socket_handle.h" | 18 #include "net/socket/client_socket_handle.h" |
17 #include "net/socket/client_socket_pool_base.h" | 19 #include "net/socket/client_socket_pool_base.h" |
18 #include "net/socket/tcp_client_socket.h" | 20 #include "net/socket/tcp_client_socket.h" |
19 | 21 |
20 using base::TimeDelta; | 22 using base::TimeDelta; |
21 | 23 |
22 namespace net { | 24 namespace net { |
23 | 25 |
24 TransportSocketParams::TransportSocketParams(const HostPortPair& host_port_pair, | 26 // TODO(willchan): Base this off RTT instead of statically setting it. Note we |
25 RequestPriority priority, const GURL& referrer, | 27 // choose a timeout that is different from the backup connect job timer so they |
26 bool disable_resolver_cache, | 28 // don't synchronize. |
27 bool ignore_limits) | 29 const int TransportConnectJob::kIPv6FallbackTimerInMs = 300; |
| 30 |
| 31 namespace { |
| 32 |
| 33 bool AddressListStartsWithIPv6AndHasAnIPv4Addr(const AddressList& addrlist) { |
| 34 const struct addrinfo* ai = addrlist.head(); |
| 35 if (ai->ai_family != AF_INET6) |
| 36 return false; |
| 37 |
| 38 ai = ai->ai_next; |
| 39 while (ai) { |
| 40 if (ai->ai_family != AF_INET6) |
| 41 return true; |
| 42 ai = ai->ai_next; |
| 43 } |
| 44 |
| 45 return false; |
| 46 } |
| 47 |
| 48 bool AddressListOnlyContainsIPv6Addresses(const AddressList& addrlist) { |
| 49 DCHECK(addrlist.head()); |
| 50 for (const struct addrinfo* ai = addrlist.head(); ai; ai = ai->ai_next) { |
| 51 if (ai->ai_family != AF_INET6) |
| 52 return false; |
| 53 } |
| 54 |
| 55 return true; |
| 56 } |
| 57 |
| 58 } // namespace |
| 59 |
| 60 TransportSocketParams::TransportSocketParams( |
| 61 const HostPortPair& host_port_pair, |
| 62 RequestPriority priority, |
| 63 const GURL& referrer, |
| 64 bool disable_resolver_cache, |
| 65 bool ignore_limits) |
28 : destination_(host_port_pair), ignore_limits_(ignore_limits) { | 66 : destination_(host_port_pair), ignore_limits_(ignore_limits) { |
29 Initialize(priority, referrer, disable_resolver_cache); | 67 Initialize(priority, referrer, disable_resolver_cache); |
30 } | 68 } |
31 | 69 |
32 TransportSocketParams::~TransportSocketParams() {} | 70 TransportSocketParams::~TransportSocketParams() {} |
33 | 71 |
34 void TransportSocketParams::Initialize(RequestPriority priority, | 72 void TransportSocketParams::Initialize(RequestPriority priority, |
35 const GURL& referrer, | 73 const GURL& referrer, |
36 bool disable_resolver_cache) { | 74 bool disable_resolver_cache) { |
37 // The referrer is used by the DNS prefetch system to correlate resolutions | 75 // The referrer is used by the DNS prefetch system to correlate resolutions |
38 // with the page that triggered them. It doesn't impact the actual addresses | 76 // with the page that triggered them. It doesn't impact the actual addresses |
39 // that we resolve to. | 77 // that we resolve to. |
40 destination_.set_referrer(referrer); | 78 destination_.set_referrer(referrer); |
41 destination_.set_priority(priority); | 79 destination_.set_priority(priority); |
42 if (disable_resolver_cache) | 80 if (disable_resolver_cache) |
43 destination_.set_allow_cached_response(false); | 81 destination_.set_allow_cached_response(false); |
44 } | 82 } |
45 | 83 |
46 // TransportConnectJobs will time out after this many seconds. Note this is | 84 // TransportConnectJobs will time out after this many seconds. Note this is |
(...skipping 15 matching lines...) Expand all Loading... |
62 HostResolver* host_resolver, | 100 HostResolver* host_resolver, |
63 Delegate* delegate, | 101 Delegate* delegate, |
64 NetLog* net_log) | 102 NetLog* net_log) |
65 : ConnectJob(group_name, timeout_duration, delegate, | 103 : ConnectJob(group_name, timeout_duration, delegate, |
66 BoundNetLog::Make(net_log, NetLog::SOURCE_CONNECT_JOB)), | 104 BoundNetLog::Make(net_log, NetLog::SOURCE_CONNECT_JOB)), |
67 params_(params), | 105 params_(params), |
68 client_socket_factory_(client_socket_factory), | 106 client_socket_factory_(client_socket_factory), |
69 ALLOW_THIS_IN_INITIALIZER_LIST( | 107 ALLOW_THIS_IN_INITIALIZER_LIST( |
70 callback_(this, | 108 callback_(this, |
71 &TransportConnectJob::OnIOComplete)), | 109 &TransportConnectJob::OnIOComplete)), |
72 resolver_(host_resolver) {} | 110 resolver_(host_resolver), |
| 111 ALLOW_THIS_IN_INITIALIZER_LIST( |
| 112 fallback_callback_( |
| 113 this, |
| 114 &TransportConnectJob::DoIPv6FallbackTransportConnectComplete)) {} |
73 | 115 |
74 TransportConnectJob::~TransportConnectJob() { | 116 TransportConnectJob::~TransportConnectJob() { |
75 // We don't worry about cancelling the host resolution and TCP connect, since | 117 // We don't worry about cancelling the host resolution and TCP connect, since |
76 // ~SingleRequestHostResolver and ~ClientSocket will take care of it. | 118 // ~SingleRequestHostResolver and ~ClientSocket will take care of it. |
77 } | 119 } |
78 | 120 |
79 LoadState TransportConnectJob::GetLoadState() const { | 121 LoadState TransportConnectJob::GetLoadState() const { |
80 switch (next_state_) { | 122 switch (next_state_) { |
81 case STATE_RESOLVE_HOST: | 123 case STATE_RESOLVE_HOST: |
82 case STATE_RESOLVE_HOST_COMPLETE: | 124 case STATE_RESOLVE_HOST_COMPLETE: |
83 return LOAD_STATE_RESOLVING_HOST; | 125 return LOAD_STATE_RESOLVING_HOST; |
84 case STATE_TRANSPORT_CONNECT: | 126 case STATE_TRANSPORT_CONNECT: |
85 case STATE_TRANSPORT_CONNECT_COMPLETE: | 127 case STATE_TRANSPORT_CONNECT_COMPLETE: |
86 return LOAD_STATE_CONNECTING; | 128 return LOAD_STATE_CONNECTING; |
87 default: | 129 default: |
88 NOTREACHED(); | 130 NOTREACHED(); |
89 return LOAD_STATE_IDLE; | 131 return LOAD_STATE_IDLE; |
90 } | 132 } |
91 } | 133 } |
92 | 134 |
| 135 // static |
| 136 void TransportConnectJob::MakeAddrListStartWithIPv4(AddressList* addrlist) { |
| 137 if (addrlist->head()->ai_family != AF_INET6) |
| 138 return; |
| 139 bool has_ipv4 = false; |
| 140 for (const struct addrinfo* ai = addrlist->head(); ai; ai = ai->ai_next) { |
| 141 if (ai->ai_family != AF_INET6) { |
| 142 has_ipv4 = true; |
| 143 break; |
| 144 } |
| 145 } |
| 146 if (!has_ipv4) |
| 147 return; |
| 148 |
| 149 struct addrinfo* head = CreateCopyOfAddrinfo(addrlist->head(), true); |
| 150 struct addrinfo* tail = head; |
| 151 while (tail->ai_next) |
| 152 tail = tail->ai_next; |
| 153 char* canonname = head->ai_canonname; |
| 154 head->ai_canonname = NULL; |
| 155 while (head->ai_family == AF_INET6) { |
| 156 tail->ai_next = head; |
| 157 tail = head; |
| 158 head = head->ai_next; |
| 159 tail->ai_next = NULL; |
| 160 } |
| 161 head->ai_canonname = canonname; |
| 162 |
| 163 addrlist->Copy(head, true); |
| 164 FreeCopyOfAddrinfo(head); |
| 165 } |
| 166 |
93 void TransportConnectJob::OnIOComplete(int result) { | 167 void TransportConnectJob::OnIOComplete(int result) { |
94 int rv = DoLoop(result); | 168 int rv = DoLoop(result); |
95 if (rv != ERR_IO_PENDING) | 169 if (rv != ERR_IO_PENDING) |
96 NotifyDelegateOfCompletion(rv); // Deletes |this| | 170 NotifyDelegateOfCompletion(rv); // Deletes |this| |
97 } | 171 } |
98 | 172 |
99 int TransportConnectJob::DoLoop(int result) { | 173 int TransportConnectJob::DoLoop(int result) { |
100 DCHECK_NE(next_state_, STATE_NONE); | 174 DCHECK_NE(next_state_, STATE_NONE); |
101 | 175 |
102 int rv = result; | 176 int rv = result; |
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
135 } | 209 } |
136 | 210 |
137 int TransportConnectJob::DoResolveHostComplete(int result) { | 211 int TransportConnectJob::DoResolveHostComplete(int result) { |
138 if (result == OK) | 212 if (result == OK) |
139 next_state_ = STATE_TRANSPORT_CONNECT; | 213 next_state_ = STATE_TRANSPORT_CONNECT; |
140 return result; | 214 return result; |
141 } | 215 } |
142 | 216 |
143 int TransportConnectJob::DoTransportConnect() { | 217 int TransportConnectJob::DoTransportConnect() { |
144 next_state_ = STATE_TRANSPORT_CONNECT_COMPLETE; | 218 next_state_ = STATE_TRANSPORT_CONNECT_COMPLETE; |
145 set_socket(client_socket_factory_->CreateTransportClientSocket( | 219 transport_socket_.reset(client_socket_factory_->CreateTransportClientSocket( |
146 addresses_, net_log().net_log(), net_log().source())); | 220 addresses_, net_log().net_log(), net_log().source())); |
147 connect_start_time_ = base::TimeTicks::Now(); | 221 connect_start_time_ = base::TimeTicks::Now(); |
148 return socket()->Connect(&callback_); | 222 int rv = transport_socket_->Connect(&callback_); |
| 223 if (rv == ERR_IO_PENDING && |
| 224 AddressListStartsWithIPv6AndHasAnIPv4Addr(addresses_)) { |
| 225 fallback_timer_.Start( |
| 226 base::TimeDelta::FromMilliseconds(kIPv6FallbackTimerInMs), |
| 227 this, &TransportConnectJob::DoIPv6FallbackTransportConnect); |
| 228 } |
| 229 return rv; |
149 } | 230 } |
150 | 231 |
151 int TransportConnectJob::DoTransportConnectComplete(int result) { | 232 int TransportConnectJob::DoTransportConnectComplete(int result) { |
152 if (result == OK) { | 233 if (result == OK) { |
| 234 bool is_ipv4 = addresses_.head()->ai_family != AF_INET6; |
153 DCHECK(connect_start_time_ != base::TimeTicks()); | 235 DCHECK(connect_start_time_ != base::TimeTicks()); |
154 DCHECK(start_time_ != base::TimeTicks()); | 236 DCHECK(start_time_ != base::TimeTicks()); |
155 base::TimeTicks now = base::TimeTicks::Now(); | 237 base::TimeTicks now = base::TimeTicks::Now(); |
156 base::TimeDelta total_duration = now - start_time_; | 238 base::TimeDelta total_duration = now - start_time_; |
157 UMA_HISTOGRAM_CUSTOM_TIMES( | 239 UMA_HISTOGRAM_CUSTOM_TIMES( |
158 "Net.DNS_Resolution_And_TCP_Connection_Latency2", | 240 "Net.DNS_Resolution_And_TCP_Connection_Latency2", |
159 total_duration, | 241 total_duration, |
160 base::TimeDelta::FromMilliseconds(1), | 242 base::TimeDelta::FromMilliseconds(1), |
161 base::TimeDelta::FromMinutes(10), | 243 base::TimeDelta::FromMinutes(10), |
162 100); | 244 100); |
163 | 245 |
164 base::TimeDelta connect_duration = now - connect_start_time_; | 246 base::TimeDelta connect_duration = now - connect_start_time_; |
165 UMA_HISTOGRAM_CUSTOM_TIMES("Net.TCP_Connection_Latency", | 247 UMA_HISTOGRAM_CUSTOM_TIMES("Net.TCP_Connection_Latency", |
166 connect_duration, | 248 connect_duration, |
167 base::TimeDelta::FromMilliseconds(1), | 249 base::TimeDelta::FromMilliseconds(1), |
168 base::TimeDelta::FromMinutes(10), | 250 base::TimeDelta::FromMinutes(10), |
169 100); | 251 100); |
| 252 |
| 253 if (is_ipv4) { |
| 254 UMA_HISTOGRAM_CUSTOM_TIMES("Net.TCP_Connection_Latency_IPv4_No_Race", |
| 255 connect_duration, |
| 256 base::TimeDelta::FromMilliseconds(1), |
| 257 base::TimeDelta::FromMinutes(10), |
| 258 100); |
| 259 } else { |
| 260 if (AddressListOnlyContainsIPv6Addresses(addresses_)) { |
| 261 UMA_HISTOGRAM_CUSTOM_TIMES("Net.TCP_Connection_Latency_IPv6_Solo", |
| 262 connect_duration, |
| 263 base::TimeDelta::FromMilliseconds(1), |
| 264 base::TimeDelta::FromMinutes(10), |
| 265 100); |
| 266 } else { |
| 267 UMA_HISTOGRAM_CUSTOM_TIMES("Net.TCP_Connection_Latency_IPv6_Raceable", |
| 268 connect_duration, |
| 269 base::TimeDelta::FromMilliseconds(1), |
| 270 base::TimeDelta::FromMinutes(10), |
| 271 100); |
| 272 } |
| 273 } |
| 274 set_socket(transport_socket_.release()); |
| 275 fallback_timer_.Stop(); |
170 } else { | 276 } else { |
171 // Delete the socket on error. | 277 // Be a bit paranoid and kill off the fallback members to prevent reuse. |
172 set_socket(NULL); | 278 fallback_transport_socket_.reset(); |
| 279 fallback_addresses_.reset(); |
173 } | 280 } |
174 | 281 |
175 return result; | 282 return result; |
176 } | 283 } |
177 | 284 |
| 285 void TransportConnectJob::DoIPv6FallbackTransportConnect() { |
| 286 // The timer should only fire while we're waiting for the main connect to |
| 287 // succeed. |
| 288 if (next_state_ != STATE_TRANSPORT_CONNECT_COMPLETE) { |
| 289 NOTREACHED(); |
| 290 return; |
| 291 } |
| 292 |
| 293 DCHECK(!fallback_transport_socket_.get()); |
| 294 DCHECK(!fallback_addresses_.get()); |
| 295 |
| 296 fallback_addresses_.reset(new AddressList(addresses_)); |
| 297 MakeAddrListStartWithIPv4(fallback_addresses_.get()); |
| 298 fallback_transport_socket_.reset( |
| 299 client_socket_factory_->CreateTransportClientSocket( |
| 300 *fallback_addresses_, net_log().net_log(), net_log().source())); |
| 301 fallback_connect_start_time_ = base::TimeTicks::Now(); |
| 302 int rv = fallback_transport_socket_->Connect(&fallback_callback_); |
| 303 if (rv != ERR_IO_PENDING) |
| 304 DoIPv6FallbackTransportConnectComplete(rv); |
| 305 } |
| 306 |
| 307 void TransportConnectJob::DoIPv6FallbackTransportConnectComplete(int result) { |
| 308 // This should only happen when we're waiting for the main connect to succeed. |
| 309 if (next_state_ != STATE_TRANSPORT_CONNECT_COMPLETE) { |
| 310 NOTREACHED(); |
| 311 return; |
| 312 } |
| 313 |
| 314 DCHECK_NE(ERR_IO_PENDING, result); |
| 315 DCHECK(fallback_transport_socket_.get()); |
| 316 DCHECK(fallback_addresses_.get()); |
| 317 |
| 318 if (result == OK) { |
| 319 DCHECK(fallback_connect_start_time_ != base::TimeTicks()); |
| 320 DCHECK(start_time_ != base::TimeTicks()); |
| 321 base::TimeTicks now = base::TimeTicks::Now(); |
| 322 base::TimeDelta total_duration = now - start_time_; |
| 323 UMA_HISTOGRAM_CUSTOM_TIMES( |
| 324 "Net.DNS_Resolution_And_TCP_Connection_Latency2", |
| 325 total_duration, |
| 326 base::TimeDelta::FromMilliseconds(1), |
| 327 base::TimeDelta::FromMinutes(10), |
| 328 100); |
| 329 |
| 330 base::TimeDelta connect_duration = now - fallback_connect_start_time_; |
| 331 UMA_HISTOGRAM_CUSTOM_TIMES("Net.TCP_Connection_Latency", |
| 332 connect_duration, |
| 333 base::TimeDelta::FromMilliseconds(1), |
| 334 base::TimeDelta::FromMinutes(10), |
| 335 100); |
| 336 |
| 337 UMA_HISTOGRAM_CUSTOM_TIMES("Net.TCP_Connection_Latency_IPv4_Wins_Race", |
| 338 connect_duration, |
| 339 base::TimeDelta::FromMilliseconds(1), |
| 340 base::TimeDelta::FromMinutes(10), |
| 341 100); |
| 342 set_socket(fallback_transport_socket_.release()); |
| 343 next_state_ = STATE_NONE; |
| 344 transport_socket_.reset(); |
| 345 } else { |
| 346 // Be a bit paranoid and kill off the fallback members to prevent reuse. |
| 347 fallback_transport_socket_.reset(); |
| 348 fallback_addresses_.reset(); |
| 349 } |
| 350 NotifyDelegateOfCompletion(result); // Deletes |this| |
| 351 } |
| 352 |
178 int TransportConnectJob::ConnectInternal() { | 353 int TransportConnectJob::ConnectInternal() { |
179 next_state_ = STATE_RESOLVE_HOST; | 354 next_state_ = STATE_RESOLVE_HOST; |
180 start_time_ = base::TimeTicks::Now(); | 355 start_time_ = base::TimeTicks::Now(); |
181 return DoLoop(OK); | 356 return DoLoop(OK); |
182 } | 357 } |
183 | 358 |
184 ConnectJob* | 359 ConnectJob* |
185 TransportClientSocketPool::TransportConnectJobFactory::NewConnectJob( | 360 TransportClientSocketPool::TransportConnectJobFactory::NewConnectJob( |
186 const std::string& group_name, | 361 const std::string& group_name, |
187 const PoolBase::Request& request, | 362 const PoolBase::Request& request, |
(...skipping 118 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
306 | 481 |
307 base::TimeDelta TransportClientSocketPool::ConnectionTimeout() const { | 482 base::TimeDelta TransportClientSocketPool::ConnectionTimeout() const { |
308 return base_.ConnectionTimeout(); | 483 return base_.ConnectionTimeout(); |
309 } | 484 } |
310 | 485 |
311 ClientSocketPoolHistograms* TransportClientSocketPool::histograms() const { | 486 ClientSocketPoolHistograms* TransportClientSocketPool::histograms() const { |
312 return base_.histograms(); | 487 return base_.histograms(); |
313 } | 488 } |
314 | 489 |
315 } // namespace net | 490 } // namespace net |
OLD | NEW |