Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(402)

Side by Side Diff: src/net/socket/tcp_client_socket_pool.cc

Issue 7046011: Merge 84251, 85083, 85188, 85375, 77501. (Closed) Base URL: svn://svn.chromium.org/chrome/branches/696/
Patch Set: Created 9 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
1 // Copyright (c) 2010 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2010 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/tcp_client_socket_pool.h" 5 #include "net/socket/tcp_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 TCPSocketParams::TCPSocketParams(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.
29 const int TCPConnectJob::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 TCPSocketParams::TCPSocketParams(
61 const HostPortPair& host_port_pair,
62 RequestPriority priority,
63 const GURL& referrer,
64 bool disable_resolver_cache)
27 : destination_(host_port_pair) { 65 : destination_(host_port_pair) {
28 Initialize(priority, referrer, disable_resolver_cache); 66 Initialize(priority, referrer, disable_resolver_cache);
29 } 67 }
30 68
31 // TODO(willchan): Update all unittests so we don't need this. 69 // TODO(willchan): Update all unittests so we don't need this.
32 TCPSocketParams::TCPSocketParams(const std::string& host, int port, 70 TCPSocketParams::TCPSocketParams(const std::string& host, int port,
33 RequestPriority priority, const GURL& referrer, 71 RequestPriority priority, const GURL& referrer,
34 bool disable_resolver_cache) 72 bool disable_resolver_cache)
35 : destination_(HostPortPair(host, port)) { 73 : destination_(HostPortPair(host, port)) {
36 Initialize(priority, referrer, disable_resolver_cache); 74 Initialize(priority, referrer, disable_resolver_cache);
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after
69 HostResolver* host_resolver, 107 HostResolver* host_resolver,
70 Delegate* delegate, 108 Delegate* delegate,
71 NetLog* net_log) 109 NetLog* net_log)
72 : ConnectJob(group_name, timeout_duration, delegate, 110 : ConnectJob(group_name, timeout_duration, delegate,
73 BoundNetLog::Make(net_log, NetLog::SOURCE_CONNECT_JOB)), 111 BoundNetLog::Make(net_log, NetLog::SOURCE_CONNECT_JOB)),
74 params_(params), 112 params_(params),
75 client_socket_factory_(client_socket_factory), 113 client_socket_factory_(client_socket_factory),
76 ALLOW_THIS_IN_INITIALIZER_LIST( 114 ALLOW_THIS_IN_INITIALIZER_LIST(
77 callback_(this, 115 callback_(this,
78 &TCPConnectJob::OnIOComplete)), 116 &TCPConnectJob::OnIOComplete)),
79 resolver_(host_resolver) {} 117 resolver_(host_resolver),
118 ALLOW_THIS_IN_INITIALIZER_LIST(
119 fallback_callback_(
120 this,
121 &TCPConnectJob::DoIPv6FallbackTCPConnectComplete)) {}
80 122
81 TCPConnectJob::~TCPConnectJob() { 123 TCPConnectJob::~TCPConnectJob() {
82 // We don't worry about cancelling the host resolution and TCP connect, since 124 // We don't worry about cancelling the host resolution and TCP connect, since
83 // ~SingleRequestHostResolver and ~ClientSocket will take care of it. 125 // ~SingleRequestHostResolver and ~ClientSocket will take care of it.
84 } 126 }
85 127
86 LoadState TCPConnectJob::GetLoadState() const { 128 LoadState TCPConnectJob::GetLoadState() const {
87 switch (next_state_) { 129 switch (next_state_) {
88 case STATE_RESOLVE_HOST: 130 case STATE_RESOLVE_HOST:
89 case STATE_RESOLVE_HOST_COMPLETE: 131 case STATE_RESOLVE_HOST_COMPLETE:
90 return LOAD_STATE_RESOLVING_HOST; 132 return LOAD_STATE_RESOLVING_HOST;
91 case STATE_TCP_CONNECT: 133 case STATE_TCP_CONNECT:
92 case STATE_TCP_CONNECT_COMPLETE: 134 case STATE_TCP_CONNECT_COMPLETE:
93 return LOAD_STATE_CONNECTING; 135 return LOAD_STATE_CONNECTING;
94 default: 136 default:
95 NOTREACHED(); 137 NOTREACHED();
96 return LOAD_STATE_IDLE; 138 return LOAD_STATE_IDLE;
97 } 139 }
98 } 140 }
99 141
142 // static
143 void TCPConnectJob::MakeAddrListStartWithIPv4(AddressList* addrlist) {
144 if (addrlist->head()->ai_family != AF_INET6)
145 return;
146 bool has_ipv4 = false;
147 for (const struct addrinfo* ai = addrlist->head(); ai; ai = ai->ai_next) {
148 if (ai->ai_family != AF_INET6) {
149 has_ipv4 = true;
150 break;
151 }
152 }
153 if (!has_ipv4)
154 return;
155
156 struct addrinfo* head = CreateCopyOfAddrinfo(addrlist->head(), true);
157 struct addrinfo* tail = head;
158 while (tail->ai_next)
159 tail = tail->ai_next;
160 char* canonname = head->ai_canonname;
161 head->ai_canonname = NULL;
162 while (head->ai_family == AF_INET6) {
163 tail->ai_next = head;
164 tail = head;
165 head = head->ai_next;
166 tail->ai_next = NULL;
167 }
168 head->ai_canonname = canonname;
169
170 addrlist->Copy(head, true);
171 FreeCopyOfAddrinfo(head);
172 }
173
100 void TCPConnectJob::OnIOComplete(int result) { 174 void TCPConnectJob::OnIOComplete(int result) {
101 int rv = DoLoop(result); 175 int rv = DoLoop(result);
102 if (rv != ERR_IO_PENDING) 176 if (rv != ERR_IO_PENDING)
103 NotifyDelegateOfCompletion(rv); // Deletes |this| 177 NotifyDelegateOfCompletion(rv); // Deletes |this|
104 } 178 }
105 179
106 int TCPConnectJob::DoLoop(int result) { 180 int TCPConnectJob::DoLoop(int result) {
107 DCHECK_NE(next_state_, STATE_NONE); 181 DCHECK_NE(next_state_, STATE_NONE);
108 182
109 int rv = result; 183 int rv = result;
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after
142 } 216 }
143 217
144 int TCPConnectJob::DoResolveHostComplete(int result) { 218 int TCPConnectJob::DoResolveHostComplete(int result) {
145 if (result == OK) 219 if (result == OK)
146 next_state_ = STATE_TCP_CONNECT; 220 next_state_ = STATE_TCP_CONNECT;
147 return result; 221 return result;
148 } 222 }
149 223
150 int TCPConnectJob::DoTCPConnect() { 224 int TCPConnectJob::DoTCPConnect() {
151 next_state_ = STATE_TCP_CONNECT_COMPLETE; 225 next_state_ = STATE_TCP_CONNECT_COMPLETE;
152 set_socket(client_socket_factory_->CreateTCPClientSocket( 226 transport_socket_.reset(client_socket_factory_->CreateTCPClientSocket(
153 addresses_, net_log().net_log(), net_log().source())); 227 addresses_, net_log().net_log(), net_log().source()));
154 connect_start_time_ = base::TimeTicks::Now(); 228 connect_start_time_ = base::TimeTicks::Now();
155 return socket()->Connect(&callback_); 229 int rv = transport_socket_->Connect(&callback_);
230 if (rv == ERR_IO_PENDING &&
231 AddressListStartsWithIPv6AndHasAnIPv4Addr(addresses_)) {
232 fallback_timer_.Start(
233 base::TimeDelta::FromMilliseconds(kIPv6FallbackTimerInMs),
234 this, &TCPConnectJob::DoIPv6FallbackTCPConnect);
235 }
236 return rv;
156 } 237 }
157 238
158 int TCPConnectJob::DoTCPConnectComplete(int result) { 239 int TCPConnectJob::DoTCPConnectComplete(int result) {
159 if (result == OK) { 240 if (result == OK) {
241 bool is_ipv4 = addresses_.head()->ai_family != AF_INET6;
160 DCHECK(connect_start_time_ != base::TimeTicks()); 242 DCHECK(connect_start_time_ != base::TimeTicks());
161 DCHECK(start_time_ != base::TimeTicks()); 243 DCHECK(start_time_ != base::TimeTicks());
162 base::TimeTicks now = base::TimeTicks::Now(); 244 base::TimeTicks now = base::TimeTicks::Now();
163 base::TimeDelta total_duration = now - start_time_; 245 base::TimeDelta total_duration = now - start_time_;
164 UMA_HISTOGRAM_CUSTOM_TIMES( 246 UMA_HISTOGRAM_CUSTOM_TIMES(
165 "Net.DNS_Resolution_And_TCP_Connection_Latency2", 247 "Net.DNS_Resolution_And_TCP_Connection_Latency2",
166 total_duration, 248 total_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);
170 252
171 base::TimeDelta connect_duration = now - connect_start_time_; 253 base::TimeDelta connect_duration = now - connect_start_time_;
172 UMA_HISTOGRAM_CUSTOM_TIMES("Net.TCP_Connection_Latency", 254 UMA_HISTOGRAM_CUSTOM_TIMES("Net.TCP_Connection_Latency",
173 connect_duration, 255 connect_duration,
174 base::TimeDelta::FromMilliseconds(1), 256 base::TimeDelta::FromMilliseconds(1),
175 base::TimeDelta::FromMinutes(10), 257 base::TimeDelta::FromMinutes(10),
176 100); 258 100);
259
260 if (is_ipv4) {
261 UMA_HISTOGRAM_CUSTOM_TIMES("Net.TCP_Connection_Latency_IPv4_No_Race",
262 connect_duration,
263 base::TimeDelta::FromMilliseconds(1),
264 base::TimeDelta::FromMinutes(10),
265 100);
266 } else {
267 if (AddressListOnlyContainsIPv6Addresses(addresses_)) {
268 UMA_HISTOGRAM_CUSTOM_TIMES("Net.TCP_Connection_Latency_IPv6_Solo",
269 connect_duration,
270 base::TimeDelta::FromMilliseconds(1),
271 base::TimeDelta::FromMinutes(10),
272 100);
273 } else {
274 UMA_HISTOGRAM_CUSTOM_TIMES("Net.TCP_Connection_Latency_IPv6_Raceable",
275 connect_duration,
276 base::TimeDelta::FromMilliseconds(1),
277 base::TimeDelta::FromMinutes(10),
278 100);
279 }
280 }
281 set_socket(transport_socket_.release());
282 fallback_timer_.Stop();
177 } else { 283 } else {
178 // Delete the socket on error. 284 // Be a bit paranoid and kill off the fallback members to prevent reuse.
179 set_socket(NULL); 285 fallback_transport_socket_.reset();
286 fallback_addresses_.reset();
180 } 287 }
181 288
182 return result; 289 return result;
183 } 290 }
184 291
292 void TCPConnectJob::DoIPv6FallbackTCPConnect() {
293 // The timer should only fire while we're waiting for the main connect to
294 // succeed.
295 if (next_state_ != STATE_TCP_CONNECT_COMPLETE) {
296 NOTREACHED();
297 return;
298 }
299
300 DCHECK(!fallback_transport_socket_.get());
301 DCHECK(!fallback_addresses_.get());
302
303 fallback_addresses_.reset(new AddressList(addresses_));
304 MakeAddrListStartWithIPv4(fallback_addresses_.get());
305 fallback_transport_socket_.reset(
306 client_socket_factory_->CreateTCPClientSocket(
307 *fallback_addresses_, net_log().net_log(), net_log().source()));
308 fallback_connect_start_time_ = base::TimeTicks::Now();
309 int rv = fallback_transport_socket_->Connect(&fallback_callback_);
310 if (rv != ERR_IO_PENDING)
311 DoIPv6FallbackTCPConnectComplete(rv);
312 }
313
314 void TCPConnectJob::DoIPv6FallbackTCPConnectComplete(int result) {
315 // This should only happen when we're waiting for the main connect to succeed.
316 if (next_state_ != STATE_TCP_CONNECT_COMPLETE) {
317 NOTREACHED();
318 return;
319 }
320
321 DCHECK_NE(ERR_IO_PENDING, result);
322 DCHECK(fallback_transport_socket_.get());
323 DCHECK(fallback_addresses_.get());
324
325 if (result == OK) {
326 DCHECK(fallback_connect_start_time_ != base::TimeTicks());
327 DCHECK(start_time_ != base::TimeTicks());
328 base::TimeTicks now = base::TimeTicks::Now();
329 base::TimeDelta total_duration = now - start_time_;
330 UMA_HISTOGRAM_CUSTOM_TIMES(
331 "Net.DNS_Resolution_And_TCP_Connection_Latency2",
332 total_duration,
333 base::TimeDelta::FromMilliseconds(1),
334 base::TimeDelta::FromMinutes(10),
335 100);
336
337 base::TimeDelta connect_duration = now - fallback_connect_start_time_;
338 UMA_HISTOGRAM_CUSTOM_TIMES("Net.TCP_Connection_Latency",
339 connect_duration,
340 base::TimeDelta::FromMilliseconds(1),
341 base::TimeDelta::FromMinutes(10),
342 100);
343
344 UMA_HISTOGRAM_CUSTOM_TIMES("Net.TCP_Connection_Latency_IPv4_Wins_Race",
345 connect_duration,
346 base::TimeDelta::FromMilliseconds(1),
347 base::TimeDelta::FromMinutes(10),
348 100);
349 set_socket(fallback_transport_socket_.release());
350 next_state_ = STATE_NONE;
351 transport_socket_.reset();
352 } else {
353 // Be a bit paranoid and kill off the fallback members to prevent reuse.
354 fallback_transport_socket_.reset();
355 fallback_addresses_.reset();
356 }
357 NotifyDelegateOfCompletion(result); // Deletes |this|
358 }
359
185 int TCPConnectJob::ConnectInternal() { 360 int TCPConnectJob::ConnectInternal() {
186 next_state_ = STATE_RESOLVE_HOST; 361 next_state_ = STATE_RESOLVE_HOST;
187 start_time_ = base::TimeTicks::Now(); 362 start_time_ = base::TimeTicks::Now();
188 return DoLoop(OK); 363 return DoLoop(OK);
189 } 364 }
190 365
191 ConnectJob* TCPClientSocketPool::TCPConnectJobFactory::NewConnectJob( 366 ConnectJob* TCPClientSocketPool::TCPConnectJobFactory::NewConnectJob(
192 const std::string& group_name, 367 const std::string& group_name,
193 const PoolBase::Request& request, 368 const PoolBase::Request& request,
194 ConnectJob::Delegate* delegate) const { 369 ConnectJob::Delegate* delegate) const {
(...skipping 112 matching lines...) Expand 10 before | Expand all | Expand 10 after
307 482
308 base::TimeDelta TCPClientSocketPool::ConnectionTimeout() const { 483 base::TimeDelta TCPClientSocketPool::ConnectionTimeout() const {
309 return base_.ConnectionTimeout(); 484 return base_.ConnectionTimeout();
310 } 485 }
311 486
312 ClientSocketPoolHistograms* TCPClientSocketPool::histograms() const { 487 ClientSocketPoolHistograms* TCPClientSocketPool::histograms() const {
313 return base_.histograms(); 488 return base_.histograms();
314 } 489 }
315 490
316 } // namespace net 491 } // namespace net
OLDNEW
« no previous file with comments | « src/net/socket/tcp_client_socket_pool.h ('k') | src/net/socket/tcp_client_socket_pool_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698