1 // Copyright 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.
5 #include "chrome/browser/net/network_stats.h"
8 #include "base/logging.h"
9 #include "base/message_loop/message_loop.h"
10 #include "base/metrics/field_trial.h"
11 #include "base/metrics/histogram.h"
12 #include "base/rand_util.h"
13 #include "base/strings/stringprintf.h"
14 #include "base/time/time.h"
15 #include "chrome/common/chrome_version_info.h"
16 #include "content/public/browser/browser_thread.h"
17 #include "net/base/net_errors.h"
18 #include "net/base/network_change_notifier.h"
19 #include "net/base/test_completion_callback.h"
20 #include "net/dns/single_request_host_resolver.h"
21 #include "net/proxy/proxy_service.h"
22 #include "net/socket/client_socket_factory.h"
23 #include "net/udp/datagram_client_socket.h"
26 using content::BrowserThread
;
28 namespace chrome_browser_net
{
31 uint32
NetworkStats::maximum_tests_
= 8;
33 uint32
NetworkStats::maximum_sequential_packets_
= 21;
35 uint32
NetworkStats::maximum_NAT_packets_
= 2;
37 uint32
NetworkStats::maximum_NAT_idle_seconds_
= 300;
39 bool NetworkStats::start_test_after_connect_
= true;
41 // Specify the possible choices of probe packet sizes.
42 const uint32 kProbePacketBytes
[] = {100, 500, 1200};
43 const uint32 kPacketSizeChoices
= arraysize(kProbePacketBytes
);
45 // List of ports used for probing test.
46 const uint16 kPorts
[] = {443, 80};
48 // Number of first few packets that are recorded in a packet-correlation
49 // histogram, which shows exactly what sequence of packets were received.
50 // We use this to deduce specific packet loss correlation.
51 const uint32 kCorrelatedLossPacketCount
= 6;
53 // This specifies the maximum message (payload) size of one packet.
54 const uint32 kMaxMessageSize
= 1600;
56 // This specifies the maximum udp receiver buffer size.
57 const uint32 kMaxUdpReceiveBufferSize
= 63000;
59 // This specifies the maximum udp receiver buffer size.
60 const uint32 kMaxUdpSendBufferSize
= 4096;
62 // This should match TestType except for the last one.
63 const char* kTestName
[] = {"TokenRequest", "StartPacket", "NonPacedPacket",
64 "PacedPacket", "NATBind", "PacketSizeTest"};
66 // Perform Pacing/Non-pacing test only if at least 2 packets are received
67 // in the StartPacketTest.
68 const uint32 kMinimumReceivedPacketsForPacingTest
= 2;
69 // Perform NAT binding test only if at least 10 packets are received.
70 const uint32 kMinimumReceivedPacketsForNATTest
= 10;
72 // Maximum inter-packet pacing interval in microseconds.
73 const uint32 kMaximumPacingMicros
= 1000000;
74 // Timeout value for getting the token.
75 const uint32 kGetTokenTimeoutSeconds
= 10;
76 // Timeout value for StartPacket and NonPacedPacket if the client does not get
77 // reply. For PacedPacket test, the timeout value is this number plus the total
79 const uint32 kReadDataTimeoutSeconds
= 30;
80 // This is the timeout for NAT without Idle periods.
81 // For NAT test with idle periods, the timeout is the Idle period + this value.
82 const uint32 kReadNATTimeoutSeconds
= 10;
83 // This is the timeout for PACKET_SIZE_TEST.
84 const uint32 kReadPacketSizeTimeoutSeconds
= 10;
85 // This is the maxmium number of packets we would send for PACKET_SIZE_TEST.
86 uint32 kMaximumPacketSizeTestPackets
= 1;
88 // These helper functions are similar to UMA_HISTOGRAM_XXX except that they do
89 // not create a static histogram_pointer.
90 void DynamicHistogramEnumeration(const std::string
& name
,
92 uint32 boundary_value
) {
93 base::HistogramBase
* histogram_pointer
= base::LinearHistogram::FactoryGet(
98 base::HistogramBase::kUmaTargetedHistogramFlag
);
99 histogram_pointer
->Add(sample
);
102 void DynamicHistogramTimes(const std::string
& name
,
103 const base::TimeDelta
& sample
) {
104 base::HistogramBase
* histogram_pointer
= base::Histogram::FactoryTimeGet(
106 base::TimeDelta::FromMilliseconds(1),
107 base::TimeDelta::FromSeconds(30),
109 base::HistogramBase::kUmaTargetedHistogramFlag
);
110 histogram_pointer
->AddTime(sample
);
113 void DynamicHistogramCounts(const std::string
& name
,
117 uint32 bucket_count
) {
118 base::HistogramBase
* histogram_pointer
= base::Histogram::FactoryGet(
119 name
, min
, max
, bucket_count
,
120 base::HistogramBase::kUmaTargetedHistogramFlag
);
121 histogram_pointer
->Add(sample
);
124 NetworkStats::NetworkStats(net::ClientSocketFactory
* socket_factory
)
125 : socket_factory_(socket_factory
),
127 has_proxy_server_(false),
128 probe_packet_bytes_(0),
129 bytes_for_packet_size_test_(0),
130 current_test_index_(0),
131 read_state_(READ_STATE_IDLE
),
132 write_state_(WRITE_STATE_IDLE
),
133 weak_factory_(this) {
137 NetworkStats::~NetworkStats() {}
139 bool NetworkStats::Start(net::HostResolver
* host_resolver
,
140 const net::HostPortPair
& server_host_port_pair
,
141 uint16 histogram_port
,
142 bool has_proxy_server
,
144 uint32 bytes_for_packet_size_test
,
145 const net::CompletionCallback
& finished_callback
) {
146 DCHECK(host_resolver
);
147 histogram_port_
= histogram_port
;
148 has_proxy_server_
= has_proxy_server
;
149 probe_packet_bytes_
= probe_bytes
;
150 bytes_for_packet_size_test_
= bytes_for_packet_size_test
;
151 finished_callback_
= finished_callback
;
152 test_sequence_
.clear();
153 test_sequence_
.push_back(TOKEN_REQUEST
);
157 scoped_ptr
<net::SingleRequestHostResolver
> resolver(
158 new net::SingleRequestHostResolver(host_resolver
));
159 net::HostResolver::RequestInfo
request(server_host_port_pair
);
161 resolver
->Resolve(request
,
162 net::DEFAULT_PRIORITY
,
164 base::Bind(base::IgnoreResult(&NetworkStats::DoConnect
),
165 base::Unretained(this)),
167 if (rv
== net::ERR_IO_PENDING
) {
168 resolver_
.swap(resolver
);
171 return DoConnect(rv
);
174 void NetworkStats::StartOneTest() {
175 if (test_sequence_
[current_test_index_
] == TOKEN_REQUEST
) {
176 DCHECK_EQ(WRITE_STATE_IDLE
, write_state_
);
177 write_buffer_
= NULL
;
184 void NetworkStats::ResetData() {
185 DCHECK_EQ(WRITE_STATE_IDLE
, write_state_
);
186 write_buffer_
= NULL
;
187 packets_received_mask_
.reset();
188 first_arrival_time_
= base::TimeTicks();
189 last_arrival_time_
= base::TimeTicks();
192 packet_rtt_
.resize(maximum_sequential_packets_
);
193 probe_request_time_
= base::TimeTicks();
194 // Note: inter_arrival_time_ should not be reset here because it is used in
198 bool NetworkStats::DoConnect(int result
) {
199 if (result
!= net::OK
) {
200 TestPhaseComplete(RESOLVE_FAILED
, result
);
204 scoped_ptr
<net::DatagramClientSocket
> udp_socket
=
205 socket_factory_
->CreateDatagramClientSocket(
206 net::DatagramSocket::DEFAULT_BIND
,
207 net::RandIntCallback(),
209 net::NetLog::Source());
212 socket_
= udp_socket
.Pass();
214 const net::IPEndPoint
& endpoint
= addresses_
.front();
215 int rv
= socket_
->Connect(endpoint
);
217 TestPhaseComplete(CONNECT_FAILED
, rv
);
221 socket_
->SetSendBufferSize(kMaxUdpSendBufferSize
);
222 socket_
->SetReceiveBufferSize(kMaxUdpReceiveBufferSize
);
223 return ConnectComplete(rv
);
226 bool NetworkStats::ConnectComplete(int result
) {
228 TestPhaseComplete(CONNECT_FAILED
, result
);
232 if (start_test_after_connect_
) {
233 // Reads data for all HelloReply and all subsequent probe tests.
234 if (ReadData() != net::ERR_IO_PENDING
) {
235 TestPhaseComplete(READ_FAILED
, result
);
240 // For unittesting. Only run the callback, do not destroy it.
241 if (!finished_callback_
.is_null())
242 finished_callback_
.Run(result
);
247 void NetworkStats::SendHelloRequest() {
248 StartReadDataTimer(kGetTokenTimeoutSeconds
, current_test_index_
);
249 ProbePacket probe_packet
;
250 probe_message_
.SetPacketHeader(ProbePacket_Type_HELLO_REQUEST
, &probe_packet
);
251 probe_packet
.set_group_id(current_test_index_
);
252 std::string output
= probe_message_
.MakeEncodedPacket(probe_packet
);
254 int result
= SendData(output
);
255 if (result
< 0 && result
!= net::ERR_IO_PENDING
)
256 TestPhaseComplete(WRITE_FAILED
, result
);
259 void NetworkStats::SendProbeRequest() {
261 // Use default timeout except for the NAT bind test.
262 uint32 timeout_seconds
= kReadDataTimeoutSeconds
;
263 uint32 number_packets
= maximum_sequential_packets_
;
264 uint32 probe_bytes
= probe_packet_bytes_
;
265 pacing_interval_
= base::TimeDelta();
266 switch (test_sequence_
[current_test_index_
]) {
267 case START_PACKET_TEST
:
268 case NON_PACED_PACKET_TEST
:
270 case PACED_PACKET_TEST
: {
272 std::min(inter_arrival_time_
,
273 base::TimeDelta::FromMicroseconds(kMaximumPacingMicros
));
274 timeout_seconds
+= pacing_interval_
.InMicroseconds() *
275 (maximum_sequential_packets_
- 1) / 1000000;
278 case NAT_BIND_TEST
: {
279 // Make sure no integer overflow.
280 DCHECK_LE(maximum_NAT_idle_seconds_
, 4000U);
281 int nat_test_idle_seconds
= base::RandInt(1, maximum_NAT_idle_seconds_
);
282 pacing_interval_
= base::TimeDelta::FromSeconds(nat_test_idle_seconds
);
283 timeout_seconds
= nat_test_idle_seconds
+ kReadNATTimeoutSeconds
;
284 number_packets
= maximum_NAT_packets_
;
287 case PACKET_SIZE_TEST
: {
288 number_packets
= kMaximumPacketSizeTestPackets
;
289 probe_bytes
= bytes_for_packet_size_test_
;
290 timeout_seconds
= kReadPacketSizeTimeoutSeconds
;
297 DVLOG(1) << "NetworkStat: Probe pacing " << pacing_interval_
.InMicroseconds()
298 << " microseconds. Time out " << timeout_seconds
<< " seconds";
299 ProbePacket probe_packet
;
300 probe_message_
.GenerateProbeRequest(token_
,
303 pacing_interval_
.InMicroseconds(),
306 std::string output
= probe_message_
.MakeEncodedPacket(probe_packet
);
308 StartReadDataTimer(timeout_seconds
, current_test_index_
);
309 probe_request_time_
= base::TimeTicks::Now();
310 int result
= SendData(output
);
311 if (result
< 0 && result
!= net::ERR_IO_PENDING
)
312 TestPhaseComplete(WRITE_FAILED
, result
);
315 int NetworkStats::ReadData() {
319 if (read_state_
== READ_STATE_READ_PENDING
)
320 return net::ERR_IO_PENDING
;
324 DCHECK(!read_buffer_
.get());
325 read_buffer_
= new net::IOBuffer(kMaxMessageSize
);
330 base::Bind(&NetworkStats::OnReadComplete
, weak_factory_
.GetWeakPtr()));
331 } while (rv
> 0 && !ReadComplete(rv
));
332 if (rv
== net::ERR_IO_PENDING
)
333 read_state_
= READ_STATE_READ_PENDING
;
337 void NetworkStats::OnReadComplete(int result
) {
338 DCHECK_NE(net::ERR_IO_PENDING
, result
);
339 DCHECK_EQ(READ_STATE_READ_PENDING
, read_state_
);
341 read_state_
= READ_STATE_IDLE
;
342 if (!ReadComplete(result
)) {
343 // Called ReadData() via PostDelayedTask() to avoid recursion. Added a delay
344 // of 1ms so that the time-out will fire before we have time to really hog
345 // the CPU too extensively (waiting for the time-out) in case of an infinite
347 base::MessageLoop::current()->PostDelayedTask(
349 base::Bind(base::IgnoreResult(&NetworkStats::ReadData
),
350 weak_factory_
.GetWeakPtr()),
351 base::TimeDelta::FromMilliseconds(1));
355 bool NetworkStats::ReadComplete(int result
) {
356 DCHECK(socket_
.get());
357 DCHECK_NE(net::ERR_IO_PENDING
, result
);
359 // Something is wrong, finish the test.
361 TestPhaseComplete(READ_FAILED
, result
);
365 std::string
encoded_message(read_buffer_
->data(),
366 read_buffer_
->data() + result
);
368 ProbePacket probe_packet
;
369 if (!probe_message_
.ParseInput(encoded_message
, &probe_packet
))
371 // Discard if the packet is for a different test.
372 if (probe_packet
.group_id() != current_test_index_
)
375 // Whether all packets in the current test have been received.
376 bool current_test_complete
= false;
377 switch (probe_packet
.header().type()) {
378 case ProbePacket_Type_HELLO_REPLY
:
379 token_
= probe_packet
.token();
380 if (current_test_index_
== 0)
381 test_sequence_
.push_back(START_PACKET_TEST
);
382 current_test_complete
= true;
384 case ProbePacket_Type_PROBE_REPLY
:
385 current_test_complete
= UpdateReception(probe_packet
);
388 DVLOG(1) << "Received unexpected packet type: "
389 << probe_packet
.header().type();
392 if (!current_test_complete
) {
393 // All packets have not been received for the current test.
396 // All packets are received for the current test.
397 // Read completes if all tests are done.
398 bool all_tests_done
= current_test_index_
>= maximum_tests_
||
399 current_test_index_
+ 1 >= test_sequence_
.size();
400 TestPhaseComplete(SUCCESS
, net::OK
);
401 return all_tests_done
;
404 bool NetworkStats::UpdateReception(const ProbePacket
& probe_packet
) {
405 uint32 packet_index
= probe_packet
.packet_index();
406 if (packet_index
>= packet_rtt_
.size())
408 packets_received_mask_
.set(packet_index
);
409 TestType test_type
= test_sequence_
[current_test_index_
];
410 uint32 received_packets
= packets_received_mask_
.count();
412 // Now() has resolution ~1-15ms. HighResNow() has high resolution but it
413 // is warned not to use it unless necessary.
414 base::TimeTicks current_time
= base::TimeTicks::Now();
415 last_arrival_time_
= current_time
;
416 if (first_arrival_time_
.is_null())
417 first_arrival_time_
= current_time
;
419 // Need to do this after updating the last_arrival_time_ since NAT_BIND_TEST
420 // and PACKET_SIZE_TEST record the SendToLastRecvDelay.
421 if (test_type
== NAT_BIND_TEST
) {
422 return received_packets
>= maximum_NAT_packets_
;
424 if (test_type
== PACKET_SIZE_TEST
) {
425 return received_packets
>= kMaximumPacketSizeTestPackets
;
428 base::TimeDelta rtt
=
429 current_time
- probe_request_time_
-
430 base::TimeDelta::FromMicroseconds(std::max(
431 static_cast<int64
>(0), probe_packet
.server_processing_micros()));
432 base::TimeDelta min_rtt
= base::TimeDelta::FromMicroseconds(1L);
433 packet_rtt_
[packet_index
] = (rtt
>= min_rtt
) ? rtt
: min_rtt
;
435 if (received_packets
< maximum_sequential_packets_
)
437 // All packets in the current test are received.
438 inter_arrival_time_
= (last_arrival_time_
- first_arrival_time_
) /
439 std::max(1U, (received_packets
- 1));
440 if (test_type
== START_PACKET_TEST
) {
441 test_sequence_
.push_back(PACKET_SIZE_TEST
);
442 test_sequence_
.push_back(TOKEN_REQUEST
);
443 // No need to add TOKEN_REQUEST here when all packets are received.
444 test_sequence_
.push_back(base::RandInt(0, 1) ? PACED_PACKET_TEST
445 : NON_PACED_PACKET_TEST
);
446 test_sequence_
.push_back(TOKEN_REQUEST
);
447 test_sequence_
.push_back(NAT_BIND_TEST
);
448 test_sequence_
.push_back(TOKEN_REQUEST
);
453 int NetworkStats::SendData(const std::string
& output
) {
454 if (write_buffer_
.get() || !socket_
.get() ||
455 write_state_
== WRITE_STATE_WRITE_PENDING
) {
456 return net::ERR_UNEXPECTED
;
458 scoped_refptr
<net::StringIOBuffer
> buffer(new net::StringIOBuffer(output
));
459 write_buffer_
= new net::DrainableIOBuffer(buffer
.get(), buffer
->size());
461 int bytes_written
= socket_
->Write(
463 write_buffer_
->BytesRemaining(),
464 base::Bind(&NetworkStats::OnWriteComplete
, weak_factory_
.GetWeakPtr()));
465 if (bytes_written
< 0) {
466 if (bytes_written
== net::ERR_IO_PENDING
)
467 write_state_
= WRITE_STATE_WRITE_PENDING
;
468 return bytes_written
;
470 UpdateSendBuffer(bytes_written
);
474 void NetworkStats::OnWriteComplete(int result
) {
475 DCHECK_NE(net::ERR_IO_PENDING
, result
);
476 DCHECK_EQ(WRITE_STATE_WRITE_PENDING
, write_state_
);
477 write_state_
= WRITE_STATE_IDLE
;
478 if (result
< 0 || !socket_
.get() || write_buffer_
== NULL
) {
479 TestPhaseComplete(WRITE_FAILED
, result
);
482 UpdateSendBuffer(result
);
485 void NetworkStats::UpdateSendBuffer(int bytes_sent
) {
486 write_buffer_
->DidConsume(bytes_sent
);
487 DCHECK_EQ(write_buffer_
->BytesRemaining(), 0);
488 DCHECK_EQ(WRITE_STATE_IDLE
, write_state_
);
489 write_buffer_
= NULL
;
492 void NetworkStats::StartReadDataTimer(uint32 seconds
, uint32 test_index
) {
493 base::MessageLoop::current()->PostDelayedTask(
495 base::Bind(&NetworkStats::OnReadDataTimeout
,
496 weak_factory_
.GetWeakPtr(),
498 base::TimeDelta::FromSeconds(seconds
));
501 void NetworkStats::OnReadDataTimeout(uint32 test_index
) {
502 // If the current_test_index_ has changed since we set the timeout,
503 // the current test has been completed, so do nothing.
504 if (test_index
!= current_test_index_
)
506 // If test_type is TOKEN_REQUEST, it will do nothing but call
507 // TestPhaseComplete().
508 TestType test_type
= test_sequence_
[current_test_index_
];
510 uint32 received_packets
= packets_received_mask_
.count();
511 if (received_packets
>= 2) {
512 inter_arrival_time_
=
513 (last_arrival_time_
- first_arrival_time_
) / (received_packets
- 1);
515 // Add other tests if this is START_PACKET_TEST.
516 if (test_type
== START_PACKET_TEST
) {
517 if (received_packets
>= kMinimumReceivedPacketsForPacingTest
) {
518 test_sequence_
.push_back(TOKEN_REQUEST
);
519 test_sequence_
.push_back(PACKET_SIZE_TEST
);
520 test_sequence_
.push_back(TOKEN_REQUEST
);
521 test_sequence_
.push_back(base::RandInt(0, 1) ? PACED_PACKET_TEST
522 : NON_PACED_PACKET_TEST
);
524 if (received_packets
>= kMinimumReceivedPacketsForNATTest
) {
525 test_sequence_
.push_back(TOKEN_REQUEST
);
526 test_sequence_
.push_back(NAT_BIND_TEST
);
527 test_sequence_
.push_back(TOKEN_REQUEST
);
530 TestPhaseComplete(READ_TIMED_OUT
, net::ERR_FAILED
);
533 void NetworkStats::TestPhaseComplete(Status status
, int result
) {
534 // If there is no valid token, do nothing and delete self.
535 // This includes all connection error, name resolve error, etc.
536 if (write_state_
== WRITE_STATE_WRITE_PENDING
) {
537 UMA_HISTOGRAM_BOOLEAN("NetConnectivity5.TestFailed.WritePending", true);
538 } else if (token_
.timestamp_micros() != 0 &&
539 (status
== SUCCESS
|| status
== READ_TIMED_OUT
)) {
540 TestType current_test
= test_sequence_
[current_test_index_
];
541 DCHECK_LT(current_test
, TEST_TYPE_MAX
);
542 if (current_test
!= TOKEN_REQUEST
) {
543 RecordHistograms(current_test
);
544 } else if (current_test_index_
> 0) {
545 if (test_sequence_
[current_test_index_
- 1] == NAT_BIND_TEST
) {
546 // We record the NATTestReceivedHistograms after the succeeding
548 RecordNATTestReceivedHistograms(status
);
549 } else if (test_sequence_
[current_test_index_
- 1] == PACKET_SIZE_TEST
) {
550 // We record the PacketSizeTestReceivedHistograms after the succeeding
552 RecordPacketSizeTestReceivedHistograms(status
);
556 // Move to the next test.
557 current_test
= GetNextTest();
558 if (current_test_index_
<= maximum_tests_
&& current_test
< TEST_TYPE_MAX
) {
559 DVLOG(1) << "NetworkStat: Start Probe test: " << current_test
;
560 base::MessageLoop::current()->PostTask(
562 base::Bind(&NetworkStats::StartOneTest
, weak_factory_
.GetWeakPtr()));
567 // All tests are done.
568 DoFinishCallback(result
);
570 // Close the socket so that there are no more IO operations.
574 DVLOG(1) << "NetworkStat: schedule delete self at test index "
575 << current_test_index_
;
579 NetworkStats::TestType
NetworkStats::GetNextTest() {
580 ++current_test_index_
;
581 if (current_test_index_
>= test_sequence_
.size())
582 return TEST_TYPE_MAX
;
583 return test_sequence_
[current_test_index_
];
586 void NetworkStats::DoFinishCallback(int result
) {
587 if (!finished_callback_
.is_null()) {
588 net::CompletionCallback callback
= finished_callback_
;
589 finished_callback_
.Reset();
590 callback
.Run(result
);
594 void NetworkStats::RecordHistograms(TestType test_type
) {
596 case START_PACKET_TEST
:
597 case NON_PACED_PACKET_TEST
:
598 case PACED_PACKET_TEST
: {
599 RecordInterArrivalHistograms(test_type
);
600 RecordPacketLossSeriesHistograms(test_type
);
601 RecordPacketsReceivedHistograms(test_type
);
602 // Only record RTT for these packet indices.
603 uint32 rtt_indices
[] = {0, 1, 2, 9, 19};
604 for (uint32 i
= 0; i
< arraysize(rtt_indices
); ++i
) {
605 if (rtt_indices
[i
] < packet_rtt_
.size())
606 RecordRTTHistograms(test_type
, rtt_indices
[i
]);
608 RecordSendToLastRecvDelayHistograms(test_type
);
612 RecordSendToLastRecvDelayHistograms(test_type
);
614 case PACKET_SIZE_TEST
:
615 // No need to record RTT for PacketSizeTest.
618 DVLOG(1) << "Unexpected test type " << test_type
619 << " in RecordHistograms.";
623 void NetworkStats::RecordInterArrivalHistograms(TestType test_type
) {
624 DCHECK_NE(test_type
, PACKET_SIZE_TEST
);
625 std::string histogram_name
=
626 base::StringPrintf("NetConnectivity5.%s.Sent%d.PacketDelay.%d.%dB",
627 kTestName
[test_type
],
628 maximum_sequential_packets_
,
630 probe_packet_bytes_
);
631 // Record the time normalized to 20 packet inter-arrivals.
632 DynamicHistogramTimes(histogram_name
, inter_arrival_time_
* 20);
635 void NetworkStats::RecordPacketsReceivedHistograms(TestType test_type
) {
636 DCHECK_NE(test_type
, PACKET_SIZE_TEST
);
637 const char* test_name
= kTestName
[test_type
];
638 std::string histogram_prefix
= base::StringPrintf(
639 "NetConnectivity5.%s.Sent%d.", test_name
, maximum_sequential_packets_
);
640 std::string histogram_suffix
=
641 base::StringPrintf(".%d.%dB", histogram_port_
, probe_packet_bytes_
);
642 std::string name
= histogram_prefix
+ "GotAPacket" + histogram_suffix
;
643 base::HistogramBase
* histogram_pointer
= base::BooleanHistogram::FactoryGet(
644 name
, base::HistogramBase::kUmaTargetedHistogramFlag
);
645 histogram_pointer
->Add(packets_received_mask_
.any());
647 DynamicHistogramEnumeration(
648 histogram_prefix
+ "PacketsRecv" + histogram_suffix
,
649 packets_received_mask_
.count(),
650 maximum_sequential_packets_
+ 1);
652 if (!packets_received_mask_
.any())
655 base::HistogramBase
* received_nth_packet_histogram
=
656 base::Histogram::FactoryGet(
657 histogram_prefix
+ "RecvNthPacket" + histogram_suffix
,
659 maximum_sequential_packets_
+ 1,
660 maximum_sequential_packets_
+ 2,
661 base::HistogramBase::kUmaTargetedHistogramFlag
);
664 for (size_t j
= 0; j
< maximum_sequential_packets_
; ++j
) {
665 int packet_number
= j
+ 1;
666 if (packets_received_mask_
.test(j
)) {
667 received_nth_packet_histogram
->Add(packet_number
);
670 std::string histogram_name
=
671 base::StringPrintf("%sNumRecvFromFirst%02dPackets%s",
672 histogram_prefix
.c_str(),
674 histogram_suffix
.c_str());
675 DynamicHistogramEnumeration(histogram_name
, count
, packet_number
+ 1);
679 void NetworkStats::RecordNATTestReceivedHistograms(Status status
) {
680 const char* test_name
= kTestName
[NAT_BIND_TEST
];
681 bool test_result
= status
== SUCCESS
;
682 std::string middle_name
= test_result
? "Connectivity.Success"
683 : "Connectivity.Failure";
684 // Record whether the HelloRequest got reply successfully.
685 std::string histogram_name
=
686 base::StringPrintf("NetConnectivity5.%s.Sent%d.%s.%d.%dB",
688 maximum_NAT_packets_
,
691 probe_packet_bytes_
);
692 uint32 bucket_count
= std::min(maximum_NAT_idle_seconds_
+ 2, 50U);
693 DynamicHistogramCounts(histogram_name
,
694 pacing_interval_
.InSeconds(),
696 maximum_NAT_idle_seconds_
+ 1,
699 // Record the NAT bind result only if the HelloRequest successfully got the
700 // token and the first NAT test packet is received.
701 if (!test_result
|| !packets_received_mask_
.test(0))
704 middle_name
= packets_received_mask_
.test(1) ? "Bind.Success"
706 histogram_name
= base::StringPrintf("NetConnectivity5.%s.Sent%d.%s.%d.%dB",
708 maximum_NAT_packets_
,
711 probe_packet_bytes_
);
712 DynamicHistogramCounts(histogram_name
,
713 pacing_interval_
.InSeconds(),
715 maximum_NAT_idle_seconds_
+ 1,
719 void NetworkStats::RecordPacketSizeTestReceivedHistograms(Status status
) {
720 const char* test_name
= kTestName
[PACKET_SIZE_TEST
];
721 bool test_result
= (status
== SUCCESS
&& packets_received_mask_
.test(0));
722 std::string middle_name
= test_result
? "Connectivity.Success"
723 : "Connectivity.Failure";
724 // Record whether the HelloRequest got reply successfully.
725 std::string histogram_name
=
726 base::StringPrintf("NetConnectivity5.%s.%s.%d",
730 base::HistogramBase
* histogram_pointer
= base::LinearHistogram::FactoryGet(
731 histogram_name
, kProbePacketBytes
[kPacketSizeChoices
- 1],
732 ProbeMessage::kMaxProbePacketBytes
, 60,
733 base::HistogramBase::kUmaTargetedHistogramFlag
);
734 histogram_pointer
->Add(bytes_for_packet_size_test_
);
737 void NetworkStats::RecordPacketLossSeriesHistograms(TestType test_type
) {
738 DCHECK_NE(test_type
, PACKET_SIZE_TEST
);
739 const char* test_name
= kTestName
[test_type
];
740 // Build "NetConnectivity5.<TestName>.First6.SeriesRecv.<port>.<probe_size>"
741 // histogram name. Total 3(tests) x 12 histograms.
742 std::string series_acked_histogram_name
=
743 base::StringPrintf("NetConnectivity5.%s.First6.SeriesRecv.%d.%dB",
746 probe_packet_bytes_
);
747 uint32 histogram_boundary
= 1 << kCorrelatedLossPacketCount
;
748 uint32 correlated_packet_mask
=
749 (histogram_boundary
- 1) & packets_received_mask_
.to_ulong();
750 DynamicHistogramEnumeration(
751 series_acked_histogram_name
, correlated_packet_mask
, histogram_boundary
);
753 // If we are running without a proxy, we'll generate an extra histogram with
754 // the ".NoProxy" suffix.
755 if (!has_proxy_server_
) {
756 series_acked_histogram_name
.append(".NoProxy");
757 DynamicHistogramEnumeration(series_acked_histogram_name
,
758 correlated_packet_mask
,
763 void NetworkStats::RecordRTTHistograms(TestType test_type
, uint32 index
) {
764 DCHECK_NE(test_type
, PACKET_SIZE_TEST
);
765 DCHECK_LT(index
, packet_rtt_
.size());
767 if (!packets_received_mask_
.test(index
))
768 return; // Probe packet never received.
770 std::string rtt_histogram_name
= base::StringPrintf(
771 "NetConnectivity5.%s.Sent%d.Success.RTT.Packet%02d.%d.%dB",
772 kTestName
[test_type
],
773 maximum_sequential_packets_
,
776 probe_packet_bytes_
);
777 DynamicHistogramTimes(rtt_histogram_name
, packet_rtt_
[index
]);
780 void NetworkStats::RecordSendToLastRecvDelayHistograms(TestType test_type
) {
781 DCHECK_NE(test_type
, PACKET_SIZE_TEST
);
782 if (packets_received_mask_
.count() < 2)
783 return; // Too few packets are received.
784 uint32 packets_sent
= test_type
== NAT_BIND_TEST
785 ? maximum_NAT_packets_
: maximum_sequential_packets_
;
786 std::string histogram_name
= base::StringPrintf(
787 "NetConnectivity5.%s.Sent%d.SendToLastRecvDelay.%d.%dB",
788 kTestName
[test_type
],
791 probe_packet_bytes_
);
792 base::TimeDelta send_to_last_recv_time
=
793 std::max(last_arrival_time_
- probe_request_time_
-
794 pacing_interval_
* (packets_sent
- 1),
795 base::TimeDelta::FromMilliseconds(0));
796 DynamicHistogramTimes(histogram_name
, send_to_last_recv_time
);
799 // ProxyDetector methods and members.
800 ProxyDetector::ProxyDetector(net::ProxyService
* proxy_service
,
801 const net::HostPortPair
& server_address
,
802 OnResolvedCallback callback
)
803 : proxy_service_(proxy_service
),
804 server_address_(server_address
),
806 has_pending_proxy_resolution_(false) {}
808 ProxyDetector::~ProxyDetector() {
809 CHECK(!has_pending_proxy_resolution_
);
812 void ProxyDetector::StartResolveProxy() {
814 base::StringPrintf("https://%s", server_address_
.ToString().c_str());
817 has_pending_proxy_resolution_
= true;
818 DCHECK(proxy_service_
);
819 int rv
= proxy_service_
->ResolveProxy(
822 base::Bind(&ProxyDetector::OnResolveProxyComplete
,
823 base::Unretained(this)),
826 if (rv
!= net::ERR_IO_PENDING
)
827 OnResolveProxyComplete(rv
);
830 void ProxyDetector::OnResolveProxyComplete(int result
) {
831 has_pending_proxy_resolution_
= false;
832 bool has_proxy_server
=
833 (result
== net::OK
&& proxy_info_
.proxy_server().is_valid() &&
834 !proxy_info_
.proxy_server().is_direct());
836 OnResolvedCallback callback
= callback_
;
837 BrowserThread::PostTask(
838 BrowserThread::IO
, FROM_HERE
, base::Bind(callback
, has_proxy_server
));
840 // TODO(rtenneti): Will we leak if ProxyResolve is cancelled (or proxy
841 // resolution never completes).
845 void CollectNetworkStats(const std::string
& network_stats_server
,
846 IOThread
* io_thread
) {
847 if (network_stats_server
.empty())
850 // If we are not on IO Thread, then post a task to call CollectNetworkStats on
852 if (!BrowserThread::CurrentlyOn(BrowserThread::IO
)) {
853 BrowserThread::PostTask(
856 base::Bind(&CollectNetworkStats
, network_stats_server
, io_thread
));
860 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO
));
862 if (net::NetworkChangeNotifier::IsOffline()) {
866 CR_DEFINE_STATIC_LOCAL(scoped_refptr
<base::FieldTrial
>, trial
, ());
867 static bool collect_stats
= false;
870 // Set up a field trial to collect network stats for UDP.
871 const base::FieldTrial::Probability kDivisor
= 1000;
873 // Enable the connectivity testing for 0.5% of the users in stable channel.
874 base::FieldTrial::Probability probability_per_group
= kDivisor
/ 200;
876 chrome::VersionInfo::Channel channel
= chrome::VersionInfo::GetChannel();
877 if (channel
== chrome::VersionInfo::CHANNEL_CANARY
) {
878 // Enable the connectivity testing for 50% of the users in canary channel.
879 probability_per_group
= kDivisor
/ 2;
880 } else if (channel
== chrome::VersionInfo::CHANNEL_DEV
) {
881 // Enable the connectivity testing for 10% of the users in dev channel.
882 probability_per_group
= kDivisor
/ 10;
883 } else if (channel
== chrome::VersionInfo::CHANNEL_BETA
) {
884 // Enable the connectivity testing for 1% of the users in beta channel.
885 probability_per_group
= kDivisor
/ 100;
888 // After July 31, 2014 builds, it will always be in default group
889 // (disable_network_stats).
890 trial
= base::FieldTrialList::FactoryGetFieldTrial(
891 "NetworkConnectivity", kDivisor
, "disable_network_stats",
892 2014, 7, 31, base::FieldTrial::SESSION_RANDOMIZED
, NULL
);
894 // Add option to collect_stats for NetworkConnectivity.
895 int collect_stats_group
=
896 trial
->AppendGroup("collect_stats", probability_per_group
);
897 if (trial
->group() == collect_stats_group
)
898 collect_stats
= true;
904 // Run test kMaxNumberOfTests times.
905 const size_t kMaxNumberOfTests
= INT_MAX
;
906 static size_t number_of_tests_done
= 0;
907 if (number_of_tests_done
> kMaxNumberOfTests
)
909 ++number_of_tests_done
;
911 net::HostResolver
* host_resolver
= io_thread
->globals()->host_resolver
.get();
912 DCHECK(host_resolver
);
914 uint32 port_index
= base::RandInt(0, arraysize(kPorts
) - 1);
915 uint16 histogram_port
= kPorts
[port_index
];
916 net::HostPortPair
server_address(network_stats_server
, histogram_port
);
918 net::ProxyService
* proxy_service
=
919 io_thread
->globals()->system_proxy_service
.get();
920 DCHECK(proxy_service
);
922 ProxyDetector::OnResolvedCallback callback
= base::Bind(
923 &StartNetworkStatsTest
, host_resolver
, server_address
, histogram_port
);
925 ProxyDetector
* proxy_client
=
926 new ProxyDetector(proxy_service
, server_address
, callback
);
927 proxy_client
->StartResolveProxy();
930 void StartNetworkStatsTest(net::HostResolver
* host_resolver
,
931 const net::HostPortPair
& server_address
,
932 uint16 histogram_port
,
933 bool has_proxy_server
) {
934 int probe_choice
= base::RandInt(0, kPacketSizeChoices
- 1);
936 DCHECK_LE(ProbeMessage::kMaxProbePacketBytes
, kMaxMessageSize
);
937 // Pick a packet size between 1200 and kMaxProbePacketBytes bytes.
938 uint32 bytes_for_packet_size_test
=
939 base::RandInt(kProbePacketBytes
[kPacketSizeChoices
- 1],
940 ProbeMessage::kMaxProbePacketBytes
);
942 // |udp_stats_client| is owned and deleted in the class NetworkStats.
943 NetworkStats
* udp_stats_client
=
944 new NetworkStats(net::ClientSocketFactory::GetDefaultFactory());
945 udp_stats_client
->Start(host_resolver
,
949 kProbePacketBytes
[probe_choice
],
950 bytes_for_packet_size_test
,
951 net::CompletionCallback());
954 } // namespace chrome_browser_net