1. Token CRCs are not handled correctly. This adds the corrected Whispernet binary...
[chromium-blink-merge.git] / chrome / browser / net / network_stats.cc
blob51df4c21bde5e997b6742d511a3b59de17186167
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"
7 #include "base/bind.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/profiler/scoped_tracker.h"
13 #include "base/rand_util.h"
14 #include "base/strings/stringprintf.h"
15 #include "base/time/time.h"
16 #include "chrome/common/chrome_version_info.h"
17 #include "content/public/browser/browser_thread.h"
18 #include "net/base/load_flags.h"
19 #include "net/base/net_errors.h"
20 #include "net/base/network_change_notifier.h"
21 #include "net/base/test_completion_callback.h"
22 #include "net/dns/single_request_host_resolver.h"
23 #include "net/proxy/proxy_service.h"
24 #include "net/socket/client_socket_factory.h"
25 #include "net/udp/datagram_client_socket.h"
26 #include "url/gurl.h"
28 using content::BrowserThread;
30 namespace chrome_browser_net {
32 // static
33 uint32 NetworkStats::maximum_tests_ = 8;
34 // static
35 uint32 NetworkStats::maximum_sequential_packets_ = 21;
36 // static
37 uint32 NetworkStats::maximum_NAT_packets_ = 2;
38 // static
39 uint32 NetworkStats::maximum_NAT_idle_seconds_ = 300;
40 // static
41 bool NetworkStats::start_test_after_connect_ = true;
43 // Specify the possible choices of probe packet sizes.
44 const uint32 kProbePacketBytes[] = {100, 500, 1200};
45 const uint32 kPacketSizeChoices = arraysize(kProbePacketBytes);
47 // List of ports used for probing test.
48 const uint16 kPorts[] = {443, 80};
50 // Number of first few packets that are recorded in a packet-correlation
51 // histogram, which shows exactly what sequence of packets were received.
52 // We use this to deduce specific packet loss correlation.
53 const uint32 kCorrelatedLossPacketCount = 6;
55 // This specifies the maximum message (payload) size of one packet.
56 const uint32 kMaxMessageSize = 1600;
58 // This specifies the maximum udp receiver buffer size.
59 const uint32 kMaxUdpReceiveBufferSize = 63000;
61 // This specifies the maximum udp receiver buffer size.
62 const uint32 kMaxUdpSendBufferSize = 4096;
64 // This should match TestType except for the last one.
65 const char* kTestName[] = {"TokenRequest", "StartPacket", "NonPacedPacket",
66 "PacedPacket", "NATBind", "PacketSizeTest"};
68 // Perform Pacing/Non-pacing test only if at least 2 packets are received
69 // in the StartPacketTest.
70 const uint32 kMinimumReceivedPacketsForPacingTest = 2;
71 // Perform NAT binding test only if at least 10 packets are received.
72 const uint32 kMinimumReceivedPacketsForNATTest = 10;
74 // Maximum inter-packet pacing interval in microseconds.
75 const uint32 kMaximumPacingMicros = 1000000;
76 // Timeout value for getting the token.
77 const uint32 kGetTokenTimeoutSeconds = 10;
78 // Timeout value for StartPacket and NonPacedPacket if the client does not get
79 // reply. For PacedPacket test, the timeout value is this number plus the total
80 // pacing interval.
81 const uint32 kReadDataTimeoutSeconds = 30;
82 // This is the timeout for NAT without Idle periods.
83 // For NAT test with idle periods, the timeout is the Idle period + this value.
84 const uint32 kReadNATTimeoutSeconds = 10;
85 // This is the timeout for PACKET_SIZE_TEST.
86 const uint32 kReadPacketSizeTimeoutSeconds = 10;
87 // This is the maxmium number of packets we would send for PACKET_SIZE_TEST.
88 uint32 kMaximumPacketSizeTestPackets = 1;
90 // These helper functions are similar to UMA_HISTOGRAM_XXX except that they do
91 // not create a static histogram_pointer.
92 void DynamicHistogramEnumeration(const std::string& name,
93 uint32 sample,
94 uint32 boundary_value) {
95 base::HistogramBase* histogram_pointer = base::LinearHistogram::FactoryGet(
96 name,
98 boundary_value,
99 boundary_value + 1,
100 base::HistogramBase::kUmaTargetedHistogramFlag);
101 histogram_pointer->Add(sample);
104 void DynamicHistogramTimes(const std::string& name,
105 const base::TimeDelta& sample) {
106 base::HistogramBase* histogram_pointer = base::Histogram::FactoryTimeGet(
107 name,
108 base::TimeDelta::FromMilliseconds(1),
109 base::TimeDelta::FromSeconds(30),
111 base::HistogramBase::kUmaTargetedHistogramFlag);
112 histogram_pointer->AddTime(sample);
115 void DynamicHistogramCounts(const std::string& name,
116 uint32 sample,
117 uint32 min,
118 uint32 max,
119 uint32 bucket_count) {
120 base::HistogramBase* histogram_pointer = base::Histogram::FactoryGet(
121 name, min, max, bucket_count,
122 base::HistogramBase::kUmaTargetedHistogramFlag);
123 histogram_pointer->Add(sample);
126 NetworkStats::NetworkStats(net::ClientSocketFactory* socket_factory)
127 : socket_factory_(socket_factory),
128 histogram_port_(0),
129 has_proxy_server_(false),
130 probe_packet_bytes_(0),
131 bytes_for_packet_size_test_(0),
132 current_test_index_(0),
133 read_state_(READ_STATE_IDLE),
134 write_state_(WRITE_STATE_IDLE),
135 weak_factory_(this) {
136 ResetData();
139 NetworkStats::~NetworkStats() {}
141 bool NetworkStats::Start(net::HostResolver* host_resolver,
142 const net::HostPortPair& server_host_port_pair,
143 uint16 histogram_port,
144 bool has_proxy_server,
145 uint32 probe_bytes,
146 uint32 bytes_for_packet_size_test,
147 const net::CompletionCallback& finished_callback) {
148 DCHECK(host_resolver);
149 histogram_port_ = histogram_port;
150 has_proxy_server_ = has_proxy_server;
151 probe_packet_bytes_ = probe_bytes;
152 bytes_for_packet_size_test_ = bytes_for_packet_size_test;
153 finished_callback_ = finished_callback;
154 test_sequence_.clear();
155 test_sequence_.push_back(TOKEN_REQUEST);
157 ResetData();
159 scoped_ptr<net::SingleRequestHostResolver> resolver(
160 new net::SingleRequestHostResolver(host_resolver));
161 net::HostResolver::RequestInfo request(server_host_port_pair);
162 int rv =
163 resolver->Resolve(request,
164 net::DEFAULT_PRIORITY,
165 &addresses_,
166 base::Bind(base::IgnoreResult(&NetworkStats::DoConnect),
167 base::Unretained(this)),
168 net::BoundNetLog());
169 if (rv == net::ERR_IO_PENDING) {
170 resolver_.swap(resolver);
171 return true;
173 return DoConnect(rv);
176 void NetworkStats::StartOneTest() {
177 if (test_sequence_[current_test_index_] == TOKEN_REQUEST) {
178 DCHECK_EQ(WRITE_STATE_IDLE, write_state_);
179 write_buffer_ = NULL;
180 SendHelloRequest();
181 } else {
182 SendProbeRequest();
186 void NetworkStats::ResetData() {
187 DCHECK_EQ(WRITE_STATE_IDLE, write_state_);
188 write_buffer_ = NULL;
189 packets_received_mask_.reset();
190 first_arrival_time_ = base::TimeTicks();
191 last_arrival_time_ = base::TimeTicks();
193 packet_rtt_.clear();
194 packet_rtt_.resize(maximum_sequential_packets_);
195 probe_request_time_ = base::TimeTicks();
196 // Note: inter_arrival_time_ should not be reset here because it is used in
197 // subsequent tests.
200 bool NetworkStats::DoConnect(int result) {
201 // TODO(vadimt): Remove ScopedTracker below once crbug.com/436634 is fixed.
202 tracked_objects::ScopedTracker tracking_profile(
203 FROM_HERE_WITH_EXPLICIT_FUNCTION("436634 NetworkStats::DoConnect"));
205 if (result != net::OK) {
206 TestPhaseComplete(RESOLVE_FAILED, result);
207 return false;
210 scoped_ptr<net::DatagramClientSocket> udp_socket =
211 socket_factory_->CreateDatagramClientSocket(
212 net::DatagramSocket::DEFAULT_BIND,
213 net::RandIntCallback(),
214 NULL,
215 net::NetLog::Source());
216 DCHECK(udp_socket);
217 DCHECK(!socket_);
218 socket_ = udp_socket.Pass();
220 const net::IPEndPoint& endpoint = addresses_.front();
221 int rv = socket_->Connect(endpoint);
222 if (rv < 0) {
223 TestPhaseComplete(CONNECT_FAILED, rv);
224 return false;
227 socket_->SetSendBufferSize(kMaxUdpSendBufferSize);
228 socket_->SetReceiveBufferSize(kMaxUdpReceiveBufferSize);
229 return ConnectComplete(rv);
232 bool NetworkStats::ConnectComplete(int result) {
233 if (result < 0) {
234 TestPhaseComplete(CONNECT_FAILED, result);
235 return false;
238 if (start_test_after_connect_) {
239 // Reads data for all HelloReply and all subsequent probe tests.
240 if (ReadData() != net::ERR_IO_PENDING) {
241 TestPhaseComplete(READ_FAILED, result);
242 return false;
244 SendHelloRequest();
245 } else {
246 // For unittesting. Only run the callback, do not destroy it.
247 if (!finished_callback_.is_null())
248 finished_callback_.Run(result);
250 return true;
253 void NetworkStats::SendHelloRequest() {
254 StartReadDataTimer(kGetTokenTimeoutSeconds, current_test_index_);
255 ProbePacket probe_packet;
256 probe_message_.SetPacketHeader(ProbePacket_Type_HELLO_REQUEST, &probe_packet);
257 probe_packet.set_group_id(current_test_index_);
258 std::string output = probe_message_.MakeEncodedPacket(probe_packet);
260 int result = SendData(output);
261 if (result < 0 && result != net::ERR_IO_PENDING)
262 TestPhaseComplete(WRITE_FAILED, result);
265 void NetworkStats::SendProbeRequest() {
266 ResetData();
267 // Use default timeout except for the NAT bind test.
268 uint32 timeout_seconds = kReadDataTimeoutSeconds;
269 uint32 number_packets = maximum_sequential_packets_;
270 uint32 probe_bytes = probe_packet_bytes_;
271 pacing_interval_ = base::TimeDelta();
272 switch (test_sequence_[current_test_index_]) {
273 case START_PACKET_TEST:
274 case NON_PACED_PACKET_TEST:
275 break;
276 case PACED_PACKET_TEST: {
277 pacing_interval_ =
278 std::min(inter_arrival_time_,
279 base::TimeDelta::FromMicroseconds(kMaximumPacingMicros));
280 timeout_seconds += pacing_interval_.InMicroseconds() *
281 (maximum_sequential_packets_ - 1) / 1000000;
282 break;
284 case NAT_BIND_TEST: {
285 // Make sure no integer overflow.
286 DCHECK_LE(maximum_NAT_idle_seconds_, 4000U);
287 int nat_test_idle_seconds = base::RandInt(1, maximum_NAT_idle_seconds_);
288 pacing_interval_ = base::TimeDelta::FromSeconds(nat_test_idle_seconds);
289 timeout_seconds = nat_test_idle_seconds + kReadNATTimeoutSeconds;
290 number_packets = maximum_NAT_packets_;
291 break;
293 case PACKET_SIZE_TEST: {
294 number_packets = kMaximumPacketSizeTestPackets;
295 probe_bytes = bytes_for_packet_size_test_;
296 timeout_seconds = kReadPacketSizeTimeoutSeconds;
297 break;
299 default:
300 NOTREACHED();
301 return;
303 DVLOG(1) << "NetworkStat: Probe pacing " << pacing_interval_.InMicroseconds()
304 << " microseconds. Time out " << timeout_seconds << " seconds";
305 ProbePacket probe_packet;
306 probe_message_.GenerateProbeRequest(token_,
307 current_test_index_,
308 probe_bytes,
309 pacing_interval_.InMicroseconds(),
310 number_packets,
311 &probe_packet);
312 std::string output = probe_message_.MakeEncodedPacket(probe_packet);
314 StartReadDataTimer(timeout_seconds, current_test_index_);
315 probe_request_time_ = base::TimeTicks::Now();
316 int result = SendData(output);
317 if (result < 0 && result != net::ERR_IO_PENDING)
318 TestPhaseComplete(WRITE_FAILED, result);
321 int NetworkStats::ReadData() {
322 if (!socket_.get())
323 return 0;
325 if (read_state_ == READ_STATE_READ_PENDING)
326 return net::ERR_IO_PENDING;
328 int rv = 0;
329 while (true) {
330 DCHECK(!read_buffer_.get());
331 read_buffer_ = new net::IOBuffer(kMaxMessageSize);
333 rv = socket_->Read(
334 read_buffer_.get(),
335 kMaxMessageSize,
336 base::Bind(&NetworkStats::OnReadComplete, weak_factory_.GetWeakPtr()));
337 if (rv <= 0)
338 break;
339 if (ReadComplete(rv))
340 return rv;
342 if (rv == net::ERR_IO_PENDING)
343 read_state_ = READ_STATE_READ_PENDING;
344 return rv;
347 void NetworkStats::OnReadComplete(int result) {
348 DCHECK_NE(net::ERR_IO_PENDING, result);
349 DCHECK_EQ(READ_STATE_READ_PENDING, read_state_);
351 read_state_ = READ_STATE_IDLE;
352 if (!ReadComplete(result)) {
353 // Called ReadData() via PostDelayedTask() to avoid recursion. Added a delay
354 // of 1ms so that the time-out will fire before we have time to really hog
355 // the CPU too extensively (waiting for the time-out) in case of an infinite
356 // loop.
357 base::MessageLoop::current()->PostDelayedTask(
358 FROM_HERE,
359 base::Bind(base::IgnoreResult(&NetworkStats::ReadData),
360 weak_factory_.GetWeakPtr()),
361 base::TimeDelta::FromMilliseconds(1));
365 bool NetworkStats::ReadComplete(int result) {
366 DCHECK(socket_.get());
367 DCHECK_NE(net::ERR_IO_PENDING, result);
368 if (result < 0) {
369 // Something is wrong, finish the test.
370 read_buffer_ = NULL;
371 TestPhaseComplete(READ_FAILED, result);
372 return true;
375 std::string encoded_message(read_buffer_->data(),
376 read_buffer_->data() + result);
377 read_buffer_ = NULL;
378 ProbePacket probe_packet;
379 if (!probe_message_.ParseInput(encoded_message, &probe_packet))
380 return false;
381 // Discard if the packet is for a different test.
382 if (probe_packet.group_id() != current_test_index_)
383 return false;
385 // Whether all packets in the current test have been received.
386 bool current_test_complete = false;
387 switch (probe_packet.header().type()) {
388 case ProbePacket_Type_HELLO_REPLY:
389 token_ = probe_packet.token();
390 if (current_test_index_ == 0)
391 test_sequence_.push_back(START_PACKET_TEST);
392 current_test_complete = true;
393 break;
394 case ProbePacket_Type_PROBE_REPLY:
395 current_test_complete = UpdateReception(probe_packet);
396 break;
397 default:
398 DVLOG(1) << "Received unexpected packet type: "
399 << probe_packet.header().type();
402 if (!current_test_complete) {
403 // All packets have not been received for the current test.
404 return false;
406 // All packets are received for the current test.
407 // Read completes if all tests are done (if TestPhaseComplete didn't start
408 // another test).
409 return TestPhaseComplete(SUCCESS, net::OK);
412 bool NetworkStats::UpdateReception(const ProbePacket& probe_packet) {
413 uint32 packet_index = probe_packet.packet_index();
414 if (packet_index >= packet_rtt_.size())
415 return false;
416 packets_received_mask_.set(packet_index);
417 TestType test_type = test_sequence_[current_test_index_];
418 uint32 received_packets = packets_received_mask_.count();
420 base::TimeTicks current_time = base::TimeTicks::Now();
421 last_arrival_time_ = current_time;
422 if (first_arrival_time_.is_null())
423 first_arrival_time_ = current_time;
425 // Need to do this after updating the last_arrival_time_ since NAT_BIND_TEST
426 // and PACKET_SIZE_TEST record the SendToLastRecvDelay.
427 if (test_type == NAT_BIND_TEST) {
428 return received_packets >= maximum_NAT_packets_;
430 if (test_type == PACKET_SIZE_TEST) {
431 return received_packets >= kMaximumPacketSizeTestPackets;
434 base::TimeDelta rtt =
435 current_time - probe_request_time_ -
436 base::TimeDelta::FromMicroseconds(std::max(
437 static_cast<int64>(0), probe_packet.server_processing_micros()));
438 base::TimeDelta min_rtt = base::TimeDelta::FromMicroseconds(1L);
439 packet_rtt_[packet_index] = (rtt >= min_rtt) ? rtt : min_rtt;
441 if (received_packets < maximum_sequential_packets_)
442 return false;
443 // All packets in the current test are received.
444 inter_arrival_time_ = (last_arrival_time_ - first_arrival_time_) /
445 std::max(1U, (received_packets - 1));
446 if (test_type == START_PACKET_TEST) {
447 test_sequence_.push_back(PACKET_SIZE_TEST);
448 test_sequence_.push_back(TOKEN_REQUEST);
449 // No need to add TOKEN_REQUEST here when all packets are received.
450 test_sequence_.push_back(base::RandInt(0, 1) ? PACED_PACKET_TEST
451 : NON_PACED_PACKET_TEST);
452 test_sequence_.push_back(TOKEN_REQUEST);
453 test_sequence_.push_back(NAT_BIND_TEST);
454 test_sequence_.push_back(TOKEN_REQUEST);
456 return true;
459 int NetworkStats::SendData(const std::string& output) {
460 if (write_buffer_.get() || !socket_.get() ||
461 write_state_ == WRITE_STATE_WRITE_PENDING) {
462 return net::ERR_UNEXPECTED;
464 scoped_refptr<net::StringIOBuffer> buffer(new net::StringIOBuffer(output));
465 write_buffer_ = new net::DrainableIOBuffer(buffer.get(), buffer->size());
467 int bytes_written = socket_->Write(
468 write_buffer_.get(),
469 write_buffer_->BytesRemaining(),
470 base::Bind(&NetworkStats::OnWriteComplete, weak_factory_.GetWeakPtr()));
471 if (bytes_written < 0) {
472 if (bytes_written == net::ERR_IO_PENDING)
473 write_state_ = WRITE_STATE_WRITE_PENDING;
474 return bytes_written;
476 UpdateSendBuffer(bytes_written);
477 return net::OK;
480 void NetworkStats::OnWriteComplete(int result) {
481 DCHECK_NE(net::ERR_IO_PENDING, result);
482 DCHECK_EQ(WRITE_STATE_WRITE_PENDING, write_state_);
483 write_state_ = WRITE_STATE_IDLE;
484 if (result < 0 || !socket_.get() || write_buffer_.get() == NULL) {
485 TestPhaseComplete(WRITE_FAILED, result);
486 return;
488 UpdateSendBuffer(result);
491 void NetworkStats::UpdateSendBuffer(int bytes_sent) {
492 write_buffer_->DidConsume(bytes_sent);
493 DCHECK_EQ(write_buffer_->BytesRemaining(), 0);
494 DCHECK_EQ(WRITE_STATE_IDLE, write_state_);
495 write_buffer_ = NULL;
498 void NetworkStats::StartReadDataTimer(uint32 seconds, uint32 test_index) {
499 base::MessageLoop::current()->PostDelayedTask(
500 FROM_HERE,
501 base::Bind(&NetworkStats::OnReadDataTimeout,
502 weak_factory_.GetWeakPtr(),
503 test_index),
504 base::TimeDelta::FromSeconds(seconds));
507 void NetworkStats::OnReadDataTimeout(uint32 test_index) {
508 // If the current_test_index_ has changed since we set the timeout,
509 // the current test has been completed, so do nothing.
510 if (test_index != current_test_index_)
511 return;
512 // If test_type is TOKEN_REQUEST, it will do nothing but call
513 // TestPhaseComplete().
514 TestType test_type = test_sequence_[current_test_index_];
516 uint32 received_packets = packets_received_mask_.count();
517 if (received_packets >= 2) {
518 inter_arrival_time_ =
519 (last_arrival_time_ - first_arrival_time_) / (received_packets - 1);
521 // Add other tests if this is START_PACKET_TEST.
522 if (test_type == START_PACKET_TEST) {
523 if (received_packets >= kMinimumReceivedPacketsForPacingTest) {
524 test_sequence_.push_back(TOKEN_REQUEST);
525 test_sequence_.push_back(PACKET_SIZE_TEST);
526 test_sequence_.push_back(TOKEN_REQUEST);
527 test_sequence_.push_back(base::RandInt(0, 1) ? PACED_PACKET_TEST
528 : NON_PACED_PACKET_TEST);
530 if (received_packets >= kMinimumReceivedPacketsForNATTest) {
531 test_sequence_.push_back(TOKEN_REQUEST);
532 test_sequence_.push_back(NAT_BIND_TEST);
533 test_sequence_.push_back(TOKEN_REQUEST);
536 TestPhaseComplete(READ_TIMED_OUT, net::ERR_FAILED);
539 bool NetworkStats::TestPhaseComplete(Status status, int result) {
540 // If there is no valid token, do nothing and delete self.
541 // This includes all connection error, name resolve error, etc.
542 if (write_state_ == WRITE_STATE_WRITE_PENDING) {
543 UMA_HISTOGRAM_BOOLEAN("NetConnectivity5.TestFailed.WritePending", true);
544 } else if (status == SUCCESS || status == READ_TIMED_OUT) {
545 TestType current_test = test_sequence_[current_test_index_];
546 DCHECK_LT(current_test, TEST_TYPE_MAX);
547 if (current_test != TOKEN_REQUEST) {
548 RecordHistograms(current_test);
549 } else if (current_test_index_ > 0) {
550 if (test_sequence_[current_test_index_ - 1] == NAT_BIND_TEST) {
551 // We record the NATTestReceivedHistograms after the succeeding
552 // TokenRequest.
553 RecordNATTestReceivedHistograms(status);
554 } else if (test_sequence_[current_test_index_ - 1] == PACKET_SIZE_TEST) {
555 // We record the PacketSizeTestReceivedHistograms after the succeeding
556 // TokenRequest.
557 RecordPacketSizeTestReceivedHistograms(status);
561 // Move to the next test.
562 current_test = GetNextTest();
563 if (current_test_index_ <= maximum_tests_ && current_test < TEST_TYPE_MAX) {
564 DVLOG(1) << "NetworkStat: Start Probe test: " << current_test;
565 base::MessageLoop::current()->PostTask(
566 FROM_HERE,
567 base::Bind(&NetworkStats::StartOneTest, weak_factory_.GetWeakPtr()));
568 return false;
572 // All tests are done.
573 DoFinishCallback(result);
575 // Close the socket so that there are no more IO operations.
576 if (socket_.get())
577 socket_->Close();
579 DVLOG(1) << "NetworkStat: schedule delete self at test index "
580 << current_test_index_;
581 delete this;
582 return true;
585 NetworkStats::TestType NetworkStats::GetNextTest() {
586 ++current_test_index_;
587 if (current_test_index_ >= test_sequence_.size())
588 return TEST_TYPE_MAX;
589 return test_sequence_[current_test_index_];
592 void NetworkStats::DoFinishCallback(int result) {
593 if (!finished_callback_.is_null()) {
594 net::CompletionCallback callback = finished_callback_;
595 finished_callback_.Reset();
596 callback.Run(result);
600 void NetworkStats::RecordHistograms(TestType test_type) {
601 switch (test_type) {
602 case START_PACKET_TEST:
603 case NON_PACED_PACKET_TEST:
604 case PACED_PACKET_TEST: {
605 RecordInterArrivalHistograms(test_type);
606 RecordPacketLossSeriesHistograms(test_type);
607 RecordPacketsReceivedHistograms(test_type);
608 // Only record RTT for these packet indices.
609 uint32 rtt_indices[] = {0, 1, 2, 9, 19};
610 for (uint32 i = 0; i < arraysize(rtt_indices); ++i) {
611 if (rtt_indices[i] < packet_rtt_.size())
612 RecordRTTHistograms(test_type, rtt_indices[i]);
614 RecordSendToLastRecvDelayHistograms(test_type);
615 return;
617 case NAT_BIND_TEST:
618 RecordSendToLastRecvDelayHistograms(test_type);
619 return;
620 case PACKET_SIZE_TEST:
621 // No need to record RTT for PacketSizeTest.
622 return;
623 default:
624 DVLOG(1) << "Unexpected test type " << test_type
625 << " in RecordHistograms.";
629 void NetworkStats::RecordInterArrivalHistograms(TestType test_type) {
630 DCHECK_NE(test_type, PACKET_SIZE_TEST);
631 std::string histogram_name =
632 base::StringPrintf("NetConnectivity5.%s.Sent%d.PacketDelay.%d.%dB",
633 kTestName[test_type],
634 maximum_sequential_packets_,
635 histogram_port_,
636 probe_packet_bytes_);
637 // Record the time normalized to 20 packet inter-arrivals.
638 DynamicHistogramTimes(histogram_name, inter_arrival_time_ * 20);
641 void NetworkStats::RecordPacketsReceivedHistograms(TestType test_type) {
642 DCHECK_NE(test_type, PACKET_SIZE_TEST);
643 const char* test_name = kTestName[test_type];
644 std::string histogram_prefix = base::StringPrintf(
645 "NetConnectivity5.%s.Sent%d.", test_name, maximum_sequential_packets_);
646 std::string histogram_suffix =
647 base::StringPrintf(".%d.%dB", histogram_port_, probe_packet_bytes_);
648 std::string name = histogram_prefix + "GotAPacket" + histogram_suffix;
649 base::HistogramBase* histogram_pointer = base::BooleanHistogram::FactoryGet(
650 name, base::HistogramBase::kUmaTargetedHistogramFlag);
651 histogram_pointer->Add(packets_received_mask_.any());
653 DynamicHistogramEnumeration(
654 histogram_prefix + "PacketsRecv" + histogram_suffix,
655 packets_received_mask_.count(),
656 maximum_sequential_packets_ + 1);
658 if (!packets_received_mask_.any())
659 return;
661 base::HistogramBase* received_nth_packet_histogram =
662 base::Histogram::FactoryGet(
663 histogram_prefix + "RecvNthPacket" + histogram_suffix,
665 maximum_sequential_packets_ + 1,
666 maximum_sequential_packets_ + 2,
667 base::HistogramBase::kUmaTargetedHistogramFlag);
669 int count = 0;
670 for (size_t j = 0; j < maximum_sequential_packets_; ++j) {
671 int packet_number = j + 1;
672 if (packets_received_mask_.test(j)) {
673 received_nth_packet_histogram->Add(packet_number);
674 ++count;
676 std::string histogram_name =
677 base::StringPrintf("%sNumRecvFromFirst%02dPackets%s",
678 histogram_prefix.c_str(),
679 packet_number,
680 histogram_suffix.c_str());
681 DynamicHistogramEnumeration(histogram_name, count, packet_number + 1);
685 void NetworkStats::RecordNATTestReceivedHistograms(Status status) {
686 const char* test_name = kTestName[NAT_BIND_TEST];
687 bool test_result = status == SUCCESS;
688 std::string middle_name = test_result ? "Connectivity.Success"
689 : "Connectivity.Failure";
690 // Record whether the HelloRequest got reply successfully.
691 std::string histogram_name =
692 base::StringPrintf("NetConnectivity5.%s.Sent%d.%s.%d.%dB",
693 test_name,
694 maximum_NAT_packets_,
695 middle_name.c_str(),
696 histogram_port_,
697 probe_packet_bytes_);
698 uint32 bucket_count = std::min(maximum_NAT_idle_seconds_ + 2, 50U);
699 DynamicHistogramCounts(histogram_name,
700 pacing_interval_.InSeconds(),
702 maximum_NAT_idle_seconds_ + 1,
703 bucket_count);
705 // Record the NAT bind result only if the HelloRequest successfully got the
706 // token and the first NAT test packet is received.
707 if (!test_result || !packets_received_mask_.test(0))
708 return;
710 middle_name = packets_received_mask_.test(1) ? "Bind.Success"
711 : "Bind.Failure";
712 histogram_name = base::StringPrintf("NetConnectivity5.%s.Sent%d.%s.%d.%dB",
713 test_name,
714 maximum_NAT_packets_,
715 middle_name.c_str(),
716 histogram_port_,
717 probe_packet_bytes_);
718 DynamicHistogramCounts(histogram_name,
719 pacing_interval_.InSeconds(),
721 maximum_NAT_idle_seconds_ + 1,
722 bucket_count);
725 void NetworkStats::RecordPacketSizeTestReceivedHistograms(Status status) {
726 const char* test_name = kTestName[PACKET_SIZE_TEST];
727 bool test_result = (status == SUCCESS && packets_received_mask_.test(0));
728 std::string middle_name = test_result ? "Connectivity.Success"
729 : "Connectivity.Failure";
730 // Record whether the HelloRequest got reply successfully.
731 std::string histogram_name =
732 base::StringPrintf("NetConnectivity5.%s.%s.%d",
733 test_name,
734 middle_name.c_str(),
735 histogram_port_);
736 base::HistogramBase* histogram_pointer = base::LinearHistogram::FactoryGet(
737 histogram_name, kProbePacketBytes[kPacketSizeChoices - 1],
738 ProbeMessage::kMaxProbePacketBytes, 60,
739 base::HistogramBase::kUmaTargetedHistogramFlag);
740 histogram_pointer->Add(bytes_for_packet_size_test_);
743 void NetworkStats::RecordPacketLossSeriesHistograms(TestType test_type) {
744 DCHECK_NE(test_type, PACKET_SIZE_TEST);
745 const char* test_name = kTestName[test_type];
746 // Build "NetConnectivity5.<TestName>.First6.SeriesRecv.<port>.<probe_size>"
747 // histogram name. Total 3(tests) x 12 histograms.
748 std::string series_acked_histogram_name =
749 base::StringPrintf("NetConnectivity5.%s.First6.SeriesRecv.%d.%dB",
750 test_name,
751 histogram_port_,
752 probe_packet_bytes_);
753 uint32 histogram_boundary = 1 << kCorrelatedLossPacketCount;
754 uint32 correlated_packet_mask =
755 (histogram_boundary - 1) & packets_received_mask_.to_ulong();
756 DynamicHistogramEnumeration(
757 series_acked_histogram_name, correlated_packet_mask, histogram_boundary);
759 // If we are running without a proxy, we'll generate an extra histogram with
760 // the ".NoProxy" suffix.
761 if (!has_proxy_server_) {
762 series_acked_histogram_name.append(".NoProxy");
763 DynamicHistogramEnumeration(series_acked_histogram_name,
764 correlated_packet_mask,
765 histogram_boundary);
769 void NetworkStats::RecordRTTHistograms(TestType test_type, uint32 index) {
770 DCHECK_NE(test_type, PACKET_SIZE_TEST);
771 DCHECK_LT(index, packet_rtt_.size());
773 if (!packets_received_mask_.test(index))
774 return; // Probe packet never received.
776 std::string rtt_histogram_name = base::StringPrintf(
777 "NetConnectivity5.%s.Sent%d.Success.RTT.Packet%02d.%d.%dB",
778 kTestName[test_type],
779 maximum_sequential_packets_,
780 index + 1,
781 histogram_port_,
782 probe_packet_bytes_);
783 DynamicHistogramTimes(rtt_histogram_name, packet_rtt_[index]);
786 void NetworkStats::RecordSendToLastRecvDelayHistograms(TestType test_type) {
787 DCHECK_NE(test_type, PACKET_SIZE_TEST);
788 if (packets_received_mask_.count() < 2)
789 return; // Too few packets are received.
790 uint32 packets_sent = test_type == NAT_BIND_TEST
791 ? maximum_NAT_packets_ : maximum_sequential_packets_;
792 std::string histogram_name = base::StringPrintf(
793 "NetConnectivity5.%s.Sent%d.SendToLastRecvDelay.%d.%dB",
794 kTestName[test_type],
795 packets_sent,
796 histogram_port_,
797 probe_packet_bytes_);
798 base::TimeDelta send_to_last_recv_time =
799 std::max(last_arrival_time_ - probe_request_time_ -
800 pacing_interval_ * (packets_sent - 1),
801 base::TimeDelta::FromMilliseconds(0));
802 DynamicHistogramTimes(histogram_name, send_to_last_recv_time);
805 // ProxyDetector methods and members.
806 ProxyDetector::ProxyDetector(net::ProxyService* proxy_service,
807 const net::HostPortPair& server_address,
808 OnResolvedCallback callback)
809 : proxy_service_(proxy_service),
810 server_address_(server_address),
811 callback_(callback),
812 has_pending_proxy_resolution_(false) {}
814 ProxyDetector::~ProxyDetector() {
815 CHECK(!has_pending_proxy_resolution_);
818 void ProxyDetector::StartResolveProxy() {
819 std::string url =
820 base::StringPrintf("https://%s", server_address_.ToString().c_str());
821 GURL gurl(url);
823 has_pending_proxy_resolution_ = true;
824 DCHECK(proxy_service_);
825 int rv = proxy_service_->ResolveProxy(
826 gurl,
827 net::LOAD_NORMAL,
828 &proxy_info_,
829 base::Bind(&ProxyDetector::OnResolveProxyComplete,
830 base::Unretained(this)),
831 NULL,
832 NULL,
833 net::BoundNetLog());
834 if (rv != net::ERR_IO_PENDING)
835 OnResolveProxyComplete(rv);
838 void ProxyDetector::OnResolveProxyComplete(int result) {
839 has_pending_proxy_resolution_ = false;
840 bool has_proxy_server =
841 (result == net::OK && proxy_info_.proxy_server().is_valid() &&
842 !proxy_info_.proxy_server().is_direct());
844 OnResolvedCallback callback = callback_;
845 BrowserThread::PostTask(
846 BrowserThread::IO, FROM_HERE, base::Bind(callback, has_proxy_server));
848 // TODO(rtenneti): Will we leak if ProxyResolve is cancelled (or proxy
849 // resolution never completes).
850 delete this;
853 void CollectNetworkStats(const std::string& network_stats_server,
854 IOThread* io_thread) {
855 if (network_stats_server.empty())
856 return;
858 // If we are not on IO Thread, then post a task to call CollectNetworkStats on
859 // IO Thread.
860 if (!BrowserThread::CurrentlyOn(BrowserThread::IO)) {
861 BrowserThread::PostTask(
862 BrowserThread::IO,
863 FROM_HERE,
864 base::Bind(&CollectNetworkStats, network_stats_server, io_thread));
865 return;
868 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
870 if (net::NetworkChangeNotifier::IsOffline()) {
871 return;
874 CR_DEFINE_STATIC_LOCAL(scoped_refptr<base::FieldTrial>, trial, ());
875 static bool collect_stats = false;
877 if (!trial.get()) {
878 // Set up a field trial to collect network stats for UDP.
879 const base::FieldTrial::Probability kDivisor = 1000;
881 // Enable the connectivity testing for 0.5% of the users in stable channel.
882 base::FieldTrial::Probability probability_per_group = kDivisor / 200;
884 chrome::VersionInfo::Channel channel = chrome::VersionInfo::GetChannel();
885 if (channel == chrome::VersionInfo::CHANNEL_CANARY) {
886 // Enable the connectivity testing for 50% of the users in canary channel.
887 probability_per_group = kDivisor / 2;
888 } else if (channel == chrome::VersionInfo::CHANNEL_DEV) {
889 // Enable the connectivity testing for 10% of the users in dev channel.
890 probability_per_group = kDivisor / 10;
891 } else if (channel == chrome::VersionInfo::CHANNEL_BETA) {
892 // Enable the connectivity testing for 1% of the users in beta channel.
893 probability_per_group = kDivisor / 100;
896 // After July 31, 2014 builds, it will always be in default group
897 // (disable_network_stats).
898 trial = base::FieldTrialList::FactoryGetFieldTrial(
899 "NetworkConnectivity", kDivisor, "disable_network_stats",
900 2014, 7, 31, base::FieldTrial::SESSION_RANDOMIZED, NULL);
902 // Add option to collect_stats for NetworkConnectivity.
903 int collect_stats_group =
904 trial->AppendGroup("collect_stats", probability_per_group);
905 if (trial->group() == collect_stats_group)
906 collect_stats = true;
909 if (!collect_stats)
910 return;
912 // Run test kMaxNumberOfTests times.
913 const size_t kMaxNumberOfTests = INT_MAX;
914 static size_t number_of_tests_done = 0;
915 if (number_of_tests_done > kMaxNumberOfTests)
916 return;
917 ++number_of_tests_done;
919 net::HostResolver* host_resolver = io_thread->globals()->host_resolver.get();
920 DCHECK(host_resolver);
922 uint32 port_index = base::RandInt(0, arraysize(kPorts) - 1);
923 uint16 histogram_port = kPorts[port_index];
924 net::HostPortPair server_address(network_stats_server, histogram_port);
926 net::ProxyService* proxy_service =
927 io_thread->globals()->system_proxy_service.get();
928 DCHECK(proxy_service);
930 ProxyDetector::OnResolvedCallback callback = base::Bind(
931 &StartNetworkStatsTest, host_resolver, server_address, histogram_port);
933 ProxyDetector* proxy_client =
934 new ProxyDetector(proxy_service, server_address, callback);
935 proxy_client->StartResolveProxy();
938 void StartNetworkStatsTest(net::HostResolver* host_resolver,
939 const net::HostPortPair& server_address,
940 uint16 histogram_port,
941 bool has_proxy_server) {
942 int probe_choice = base::RandInt(0, kPacketSizeChoices - 1);
944 DCHECK_LE(ProbeMessage::kMaxProbePacketBytes, kMaxMessageSize);
945 // Pick a packet size between 1200 and kMaxProbePacketBytes bytes.
946 uint32 bytes_for_packet_size_test =
947 base::RandInt(kProbePacketBytes[kPacketSizeChoices - 1],
948 ProbeMessage::kMaxProbePacketBytes);
950 // |udp_stats_client| is owned and deleted in the class NetworkStats.
951 NetworkStats* udp_stats_client =
952 new NetworkStats(net::ClientSocketFactory::GetDefaultFactory());
953 udp_stats_client->Start(host_resolver,
954 server_address,
955 histogram_port,
956 has_proxy_server,
957 kProbePacketBytes[probe_choice],
958 bytes_for_packet_size_test,
959 net::CompletionCallback());
962 } // namespace chrome_browser_net