network_stats.cc revision 68043e1e95eeb07d5cae7aca370b26518b0867d6
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. 4 5#include "chrome/browser/net/network_stats.h" 6 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/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" 24#include "url/gurl.h" 25 26using content::BrowserThread; 27 28namespace chrome_browser_net { 29 30// static 31uint32 NetworkStats::maximum_tests_ = 6; 32// static 33uint32 NetworkStats::maximum_sequential_packets_ = 21; 34// static 35uint32 NetworkStats::maximum_NAT_packets_ = 2; 36// static 37uint32 NetworkStats::maximum_NAT_idle_seconds_ = 300; 38// static 39bool NetworkStats::start_test_after_connect_ = true; 40 41// Specify the possible choices of probe packet sizes. 42const uint32 kProbePacketBytes[] = {100, 500, 1200}; 43const uint32 kPacketSizeChoices = arraysize(kProbePacketBytes); 44 45// List of ports used for probing test. 46const uint16 kPorts[] = {443, 80}; 47 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. 51const uint32 kCorrelatedLossPacketCount = 6; 52 53// This specifies the maximum message (payload) size of one packet. 54const uint32 kMaxMessageSize = 1300; 55 56// This specifies the maximum udp receiver buffer size. 57const uint32 kMaxUdpReceiveBufferSize = 63000; 58 59// This specifies the maximum udp receiver buffer size. 60const uint32 kMaxUdpSendBufferSize = 4096; 61 62// This should match TestType except for the last one. 63const char* kTestName[] = {"TokenRequest", "StartPacket", "NonPacedPacket", 64 "PacedPacket", "NATBind"}; 65 66// Perform Pacing/Non-pacing test only if at least 2 packets are received 67// in the StartPacketTest. 68const uint32 kMinimumReceivedPacketsForPacingTest = 2; 69// Perform NAT binding test only if at least 10 packets are received. 70const uint32 kMinimumReceivedPacketsForNATTest = 10; 71 72// Maximum inter-packet pacing interval in microseconds. 73const uint32 kMaximumPacingMicros = 1000000; 74// Timeout value for getting the token. 75const 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 78// pacing interval. 79const 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. 82const uint32 kReadNATTimeoutSeconds = 10; 83 84// These helper functions are similar to UMA_HISTOGRAM_XXX except that they do 85// not create a static histogram_pointer. 86void DynamicHistogramEnumeration(const std::string& name, 87 uint32 sample, 88 uint32 boundary_value) { 89 base::HistogramBase* histogram_pointer = base::LinearHistogram::FactoryGet( 90 name, 91 1, 92 boundary_value, 93 boundary_value + 1, 94 base::HistogramBase::kUmaTargetedHistogramFlag); 95 histogram_pointer->Add(sample); 96} 97 98void DynamicHistogramTimes(const std::string& name, 99 const base::TimeDelta& sample) { 100 base::HistogramBase* histogram_pointer = base::Histogram::FactoryTimeGet( 101 name, 102 base::TimeDelta::FromMilliseconds(1), 103 base::TimeDelta::FromSeconds(30), 104 50, 105 base::HistogramBase::kUmaTargetedHistogramFlag); 106 histogram_pointer->AddTime(sample); 107} 108 109void DynamicHistogramCounts(const std::string& name, 110 uint32 sample, 111 uint32 min, 112 uint32 max, 113 uint32 bucket_count) { 114 base::HistogramBase* histogram_pointer = base::Histogram::FactoryGet( 115 name, min, max, bucket_count, 116 base::HistogramBase::kUmaTargetedHistogramFlag); 117 histogram_pointer->Add(sample); 118} 119 120NetworkStats::NetworkStats(net::ClientSocketFactory* socket_factory) 121 : socket_factory_(socket_factory), 122 histogram_port_(0), 123 has_proxy_server_(false), 124 probe_packet_bytes_(0), 125 current_test_index_(0), 126 weak_factory_(this) { 127 ResetData(); 128} 129 130NetworkStats::~NetworkStats() {} 131 132bool NetworkStats::Start(net::HostResolver* host_resolver, 133 const net::HostPortPair& server_host_port_pair, 134 uint16 histogram_port, 135 bool has_proxy_server, 136 uint32 probe_bytes, 137 const net::CompletionCallback& finished_callback) { 138 CHECK(host_resolver); 139 histogram_port_ = histogram_port; 140 has_proxy_server_ = has_proxy_server; 141 probe_packet_bytes_ = probe_bytes; 142 finished_callback_ = finished_callback; 143 test_sequence_.clear(); 144 test_sequence_.push_back(TOKEN_REQUEST); 145 146 ResetData(); 147 148 scoped_ptr<net::SingleRequestHostResolver> resolver( 149 new net::SingleRequestHostResolver(host_resolver)); 150 net::HostResolver::RequestInfo request(server_host_port_pair); 151 int rv = 152 resolver->Resolve(request, 153 net::DEFAULT_PRIORITY, 154 &addresses_, 155 base::Bind(base::IgnoreResult(&NetworkStats::DoConnect), 156 base::Unretained(this)), 157 net::BoundNetLog()); 158 if (rv == net::ERR_IO_PENDING) { 159 resolver_.swap(resolver); 160 return true; 161 } 162 return DoConnect(rv); 163} 164 165void NetworkStats::StartOneTest() { 166 if (test_sequence_[current_test_index_] == TOKEN_REQUEST) { 167 write_buffer_ = NULL; 168 SendHelloRequest(); 169 } else { 170 SendProbeRequest(); 171 } 172} 173 174void NetworkStats::ResetData() { 175 write_buffer_ = NULL; 176 packets_received_mask_.reset(); 177 first_arrival_time_ = base::TimeTicks(); 178 last_arrival_time_ = base::TimeTicks(); 179 180 packet_rtt_.clear(); 181 packet_rtt_.resize(maximum_sequential_packets_); 182 probe_request_time_ = base::TimeTicks(); 183 // Note: inter_arrival_time_ should not be reset here because it is used in 184 // subsequent tests. 185} 186 187bool NetworkStats::DoConnect(int result) { 188 if (result != net::OK) { 189 TestPhaseComplete(RESOLVE_FAILED, result); 190 return false; 191 } 192 193 scoped_ptr<net::DatagramClientSocket> udp_socket = 194 socket_factory_->CreateDatagramClientSocket( 195 net::DatagramSocket::DEFAULT_BIND, 196 net::RandIntCallback(), 197 NULL, 198 net::NetLog::Source()); 199 CHECK(udp_socket); 200 CHECK(!socket_); 201 socket_ = udp_socket.Pass(); 202 203 const net::IPEndPoint& endpoint = addresses_.front(); 204 int rv = socket_->Connect(endpoint); 205 if (rv < 0) { 206 TestPhaseComplete(CONNECT_FAILED, rv); 207 return false; 208 } 209 210 socket_->SetSendBufferSize(kMaxUdpSendBufferSize); 211 socket_->SetReceiveBufferSize(kMaxUdpReceiveBufferSize); 212 return ConnectComplete(rv); 213} 214 215bool NetworkStats::ConnectComplete(int result) { 216 if (result < 0) { 217 TestPhaseComplete(CONNECT_FAILED, result); 218 return false; 219 } 220 221 if (start_test_after_connect_) { 222 // Reads data for all HelloReply and all subsequent probe tests. 223 if (ReadData() != net::ERR_IO_PENDING) { 224 TestPhaseComplete(READ_FAILED, result); 225 return false; 226 } 227 SendHelloRequest(); 228 } else { 229 // For unittesting. Only run the callback, do not destroy it. 230 if (!finished_callback_.is_null()) 231 finished_callback_.Run(result); 232 } 233 return true; 234} 235 236void NetworkStats::SendHelloRequest() { 237 StartReadDataTimer(kGetTokenTimeoutSeconds, current_test_index_); 238 ProbePacket probe_packet; 239 probe_message_.SetPacketHeader(ProbePacket_Type_HELLO_REQUEST, &probe_packet); 240 probe_packet.set_group_id(current_test_index_); 241 std::string output = probe_message_.MakeEncodedPacket(probe_packet); 242 243 int result = SendData(output); 244 if (result < 0 && result != net::ERR_IO_PENDING) 245 TestPhaseComplete(WRITE_FAILED, result); 246} 247 248void NetworkStats::SendProbeRequest() { 249 ResetData(); 250 // Use default timeout except for the NAT bind test. 251 uint32 timeout_seconds = kReadDataTimeoutSeconds; 252 uint32 number_packets = maximum_sequential_packets_; 253 pacing_interval_ = base::TimeDelta(); 254 switch (test_sequence_[current_test_index_]) { 255 case START_PACKET_TEST: 256 case NON_PACED_PACKET_TEST: 257 break; 258 case PACED_PACKET_TEST: { 259 pacing_interval_ = 260 std::min(inter_arrival_time_, 261 base::TimeDelta::FromMicroseconds(kMaximumPacingMicros)); 262 timeout_seconds += pacing_interval_.InMicroseconds() * 263 (maximum_sequential_packets_ - 1) / 1000000; 264 break; 265 } 266 case NAT_BIND_TEST: { 267 // Make sure no integer overflow. 268 CHECK_LE(maximum_NAT_idle_seconds_, 4000U); 269 int nat_test_idle_seconds = base::RandInt(1, maximum_NAT_idle_seconds_); 270 pacing_interval_ = base::TimeDelta::FromSeconds(nat_test_idle_seconds); 271 timeout_seconds = nat_test_idle_seconds + kReadNATTimeoutSeconds; 272 number_packets = maximum_NAT_packets_; 273 break; 274 } 275 default: 276 NOTREACHED(); 277 return; 278 } 279 DVLOG(1) << "NetworkStat: Probe pacing " << pacing_interval_.InMicroseconds() 280 << " microseconds. Time out " << timeout_seconds << " seconds"; 281 ProbePacket probe_packet; 282 probe_message_.GenerateProbeRequest(token_, 283 current_test_index_, 284 probe_packet_bytes_, 285 pacing_interval_.InMicroseconds(), 286 number_packets, 287 &probe_packet); 288 std::string output = probe_message_.MakeEncodedPacket(probe_packet); 289 290 StartReadDataTimer(timeout_seconds, current_test_index_); 291 probe_request_time_ = base::TimeTicks::Now(); 292 int result = SendData(output); 293 if (result < 0 && result != net::ERR_IO_PENDING) 294 TestPhaseComplete(WRITE_FAILED, result); 295} 296 297int NetworkStats::ReadData() { 298 if (!socket_.get()) 299 return 0; 300 301 int rv = 0; 302 do { 303 CHECK(!read_buffer_.get()); 304 read_buffer_ = new net::IOBuffer(kMaxMessageSize); 305 306 rv = socket_->Read( 307 read_buffer_.get(), 308 kMaxMessageSize, 309 base::Bind(&NetworkStats::OnReadComplete, weak_factory_.GetWeakPtr())); 310 } while (rv > 0 && !ReadComplete(rv)); 311 return rv; 312} 313 314void NetworkStats::OnReadComplete(int result) { 315 if (!ReadComplete(result)) { 316 // Called ReadData() via PostDelayedTask() to avoid recursion. Added a delay 317 // of 1ms so that the time-out will fire before we have time to really hog 318 // the CPU too extensively (waiting for the time-out) in case of an infinite 319 // loop. 320 base::MessageLoop::current()->PostDelayedTask( 321 FROM_HERE, 322 base::Bind(base::IgnoreResult(&NetworkStats::ReadData), 323 weak_factory_.GetWeakPtr()), 324 base::TimeDelta::FromMilliseconds(1)); 325 } 326} 327 328bool NetworkStats::ReadComplete(int result) { 329 CHECK(socket_.get()); 330 CHECK_NE(net::ERR_IO_PENDING, result); 331 if (result < 0) { 332 // Something is wrong, finish the test. 333 read_buffer_ = NULL; 334 TestPhaseComplete(READ_FAILED, result); 335 return true; 336 } 337 338 std::string encoded_message(read_buffer_->data(), 339 read_buffer_->data() + result); 340 read_buffer_ = NULL; 341 ProbePacket probe_packet; 342 if (!probe_message_.ParseInput(encoded_message, &probe_packet)) 343 return false; 344 // Discard if the packet is for a different test. 345 if (probe_packet.group_id() != current_test_index_) 346 return false; 347 348 // Whether all packets in the current test have been received. 349 bool current_test_complete = false; 350 switch (probe_packet.header().type()) { 351 case ProbePacket_Type_HELLO_REPLY: 352 token_ = probe_packet.token(); 353 if (current_test_index_ == 0) 354 test_sequence_.push_back(START_PACKET_TEST); 355 current_test_complete = true; 356 break; 357 case ProbePacket_Type_PROBE_REPLY: 358 current_test_complete = UpdateReception(probe_packet); 359 break; 360 default: 361 DVLOG(1) << "Received unexpected packet type: " 362 << probe_packet.header().type(); 363 } 364 365 if (!current_test_complete) { 366 // All packets have not been received for the current test. 367 return false; 368 } 369 // All packets are received for the current test. 370 // Read completes if all tests are done. 371 bool all_tests_done = current_test_index_ >= maximum_tests_ || 372 current_test_index_ + 1 >= test_sequence_.size(); 373 TestPhaseComplete(SUCCESS, net::OK); 374 return all_tests_done; 375} 376 377bool NetworkStats::UpdateReception(const ProbePacket& probe_packet) { 378 uint32 packet_index = probe_packet.packet_index(); 379 if (packet_index >= packet_rtt_.size()) 380 return false; 381 packets_received_mask_.set(packet_index); 382 TestType test_type = test_sequence_[current_test_index_]; 383 uint32 received_packets = packets_received_mask_.count(); 384 385 // Now() has resolution ~1-15ms. HighResNow() has high resolution but it 386 // is warned not to use it unless necessary. 387 base::TimeTicks current_time = base::TimeTicks::Now(); 388 last_arrival_time_ = current_time; 389 if (first_arrival_time_.is_null()) 390 first_arrival_time_ = current_time; 391 392 // Need to do this after updating the last_arrival_time_ since NAT_BIND_TEST 393 // records the SendToLastRecvDelay. 394 if (test_type == NAT_BIND_TEST) { 395 return received_packets >= maximum_NAT_packets_; 396 } 397 398 base::TimeDelta rtt = 399 current_time - probe_request_time_ - 400 base::TimeDelta::FromMicroseconds(std::max( 401 static_cast<int64>(0), probe_packet.server_processing_micros())); 402 base::TimeDelta min_rtt = base::TimeDelta::FromMicroseconds(1L); 403 packet_rtt_[packet_index] = (rtt >= min_rtt) ? rtt : min_rtt; 404 405 if (received_packets < maximum_sequential_packets_) 406 return false; 407 // All packets in the current test are received. 408 inter_arrival_time_ = (last_arrival_time_ - first_arrival_time_) / 409 std::max(1U, (received_packets - 1)); 410 if (test_type == START_PACKET_TEST) { 411 // No need to add TOKEN_REQUEST here when all packets are received. 412 test_sequence_.push_back(base::RandInt(0, 1) ? PACED_PACKET_TEST 413 : NON_PACED_PACKET_TEST); 414 test_sequence_.push_back(TOKEN_REQUEST); 415 test_sequence_.push_back(NAT_BIND_TEST); 416 test_sequence_.push_back(TOKEN_REQUEST); 417 } 418 return true; 419} 420 421int NetworkStats::SendData(const std::string& output) { 422 if (write_buffer_.get() || !socket_.get()) 423 return net::ERR_UNEXPECTED; 424 scoped_refptr<net::StringIOBuffer> buffer(new net::StringIOBuffer(output)); 425 write_buffer_ = new net::DrainableIOBuffer(buffer.get(), buffer->size()); 426 427 int bytes_written = socket_->Write( 428 write_buffer_.get(), 429 write_buffer_->BytesRemaining(), 430 base::Bind(&NetworkStats::OnWriteComplete, weak_factory_.GetWeakPtr())); 431 if (bytes_written < 0) 432 return bytes_written; 433 UpdateSendBuffer(bytes_written); 434 return net::OK; 435} 436 437void NetworkStats::OnWriteComplete(int result) { 438 CHECK(socket_.get()); 439 CHECK_NE(net::ERR_IO_PENDING, result); 440 if (result < 0) { 441 TestPhaseComplete(WRITE_FAILED, result); 442 return; 443 } 444 UpdateSendBuffer(result); 445} 446 447void NetworkStats::UpdateSendBuffer(int bytes_sent) { 448 write_buffer_->DidConsume(bytes_sent); 449 CHECK_EQ(write_buffer_->BytesRemaining(), 0); 450 write_buffer_ = NULL; 451} 452 453void NetworkStats::StartReadDataTimer(uint32 seconds, uint32 test_index) { 454 base::MessageLoop::current()->PostDelayedTask( 455 FROM_HERE, 456 base::Bind(&NetworkStats::OnReadDataTimeout, 457 weak_factory_.GetWeakPtr(), 458 test_index), 459 base::TimeDelta::FromSeconds(seconds)); 460} 461 462void NetworkStats::OnReadDataTimeout(uint32 test_index) { 463 // If the current_test_index_ has changed since we set the timeout, 464 // the current test has been completed, so do nothing. 465 if (test_index != current_test_index_) 466 return; 467 // If test_type is TOKEN_REQUEST, it will do nothing but call 468 // TestPhaseComplete(). 469 TestType test_type = test_sequence_[current_test_index_]; 470 471 uint32 received_packets = packets_received_mask_.count(); 472 if (received_packets >= 2) { 473 inter_arrival_time_ = 474 (last_arrival_time_ - first_arrival_time_) / (received_packets - 1); 475 } 476 // Add other tests if this is START_PACKET_TEST. 477 if (test_type == START_PACKET_TEST) { 478 if (received_packets >= kMinimumReceivedPacketsForPacingTest) { 479 test_sequence_.push_back(TOKEN_REQUEST); 480 test_sequence_.push_back(base::RandInt(0, 1) ? PACED_PACKET_TEST 481 : NON_PACED_PACKET_TEST); 482 } 483 if (received_packets >= kMinimumReceivedPacketsForNATTest) { 484 test_sequence_.push_back(TOKEN_REQUEST); 485 test_sequence_.push_back(NAT_BIND_TEST); 486 test_sequence_.push_back(TOKEN_REQUEST); 487 } 488 } 489 TestPhaseComplete(READ_TIMED_OUT, net::ERR_FAILED); 490} 491 492void NetworkStats::TestPhaseComplete(Status status, int result) { 493 // If there is no valid token, do nothing and delete self. 494 // This includes all connection error, name resolve error, etc. 495 if (token_.timestamp_micros() != 0 && 496 (status == SUCCESS || status == READ_TIMED_OUT)) { 497 TestType current_test = test_sequence_[current_test_index_]; 498 CHECK_LT(current_test, TEST_TYPE_MAX); 499 if (current_test != TOKEN_REQUEST) 500 RecordHistograms(current_test); 501 else if (current_test_index_ > 0 && 502 test_sequence_[current_test_index_ - 1] == NAT_BIND_TEST) { 503 // We record the NATTestReceivedHistograms after the succeeding 504 // TokenRequest. 505 RecordNATTestReceivedHistograms(status); 506 } 507 508 // Move to the next test. 509 current_test = GetNextTest(); 510 if (current_test_index_ <= maximum_tests_ && current_test < TEST_TYPE_MAX) { 511 DVLOG(1) << "NetworkStat: Start Probe test: " << current_test; 512 base::MessageLoop::current()->PostTask( 513 FROM_HERE, 514 base::Bind(&NetworkStats::StartOneTest, weak_factory_.GetWeakPtr())); 515 return; 516 } 517 } 518 519 // All tests are done. 520 DoFinishCallback(result); 521 522 // Close the socket so that there are no more IO operations. 523 if (socket_.get()) 524 socket_->Close(); 525 526 DVLOG(1) << "NetworkStat: schedule delete self at test index " 527 << current_test_index_; 528 delete this; 529} 530 531NetworkStats::TestType NetworkStats::GetNextTest() { 532 ++current_test_index_; 533 if (current_test_index_ >= test_sequence_.size()) 534 return TEST_TYPE_MAX; 535 return test_sequence_[current_test_index_]; 536} 537 538void NetworkStats::DoFinishCallback(int result) { 539 if (!finished_callback_.is_null()) { 540 net::CompletionCallback callback = finished_callback_; 541 finished_callback_.Reset(); 542 callback.Run(result); 543 } 544} 545 546void NetworkStats::RecordHistograms(TestType test_type) { 547 switch (test_type) { 548 case START_PACKET_TEST: 549 case NON_PACED_PACKET_TEST: 550 case PACED_PACKET_TEST: { 551 RecordInterArrivalHistograms(test_type); 552 RecordPacketLossSeriesHistograms(test_type); 553 RecordPacketsReceivedHistograms(test_type); 554 // Only record RTT for these packet indices. 555 uint32 rtt_indices[] = {0, 1, 2, 9, 19}; 556 for (uint32 i = 0; i < arraysize(rtt_indices); ++i) { 557 if (rtt_indices[i] < packet_rtt_.size()) 558 RecordRTTHistograms(test_type, rtt_indices[i]); 559 } 560 RecordSendToLastRecvDelayHistograms(test_type); 561 return; 562 } 563 case NAT_BIND_TEST: 564 RecordSendToLastRecvDelayHistograms(test_type); 565 return; 566 default: 567 DVLOG(1) << "Unexpected test type " << test_type 568 << " in RecordHistograms."; 569 } 570} 571 572void NetworkStats::RecordInterArrivalHistograms(TestType test_type) { 573 std::string histogram_name = 574 base::StringPrintf("NetConnectivity4.%s.Sent%d.PacketDelay.%d.%dB", 575 kTestName[test_type], 576 maximum_sequential_packets_, 577 histogram_port_, 578 probe_packet_bytes_); 579 // Record the time normalized to 20 packet inter-arrivals. 580 DynamicHistogramTimes(histogram_name, inter_arrival_time_ * 20); 581} 582 583void NetworkStats::RecordPacketsReceivedHistograms(TestType test_type) { 584 const char* test_name = kTestName[test_type]; 585 std::string histogram_prefix = base::StringPrintf( 586 "NetConnectivity4.%s.Sent%d.", test_name, maximum_sequential_packets_); 587 std::string histogram_suffix = 588 base::StringPrintf(".%d.%dB", histogram_port_, probe_packet_bytes_); 589 std::string name = histogram_prefix + "GotAPacket" + histogram_suffix; 590 base::HistogramBase* histogram_pointer = base::BooleanHistogram::FactoryGet( 591 name, base::HistogramBase::kUmaTargetedHistogramFlag); 592 histogram_pointer->Add(packets_received_mask_.any()); 593 594 DynamicHistogramEnumeration( 595 histogram_prefix + "PacketsRecv" + histogram_suffix, 596 packets_received_mask_.count(), 597 maximum_sequential_packets_ + 1); 598 599 if (!packets_received_mask_.any()) 600 return; 601 602 base::HistogramBase* received_nth_packet_histogram = 603 base::Histogram::FactoryGet( 604 histogram_prefix + "RecvNthPacket" + histogram_suffix, 605 1, 606 maximum_sequential_packets_ + 1, 607 maximum_sequential_packets_ + 2, 608 base::HistogramBase::kUmaTargetedHistogramFlag); 609 610 int count = 0; 611 for (size_t j = 0; j < maximum_sequential_packets_; ++j) { 612 int packet_number = j + 1; 613 if (packets_received_mask_.test(j)) { 614 received_nth_packet_histogram->Add(packet_number); 615 ++count; 616 } 617 std::string histogram_name = 618 base::StringPrintf("%sNumRecvFromFirst%02dPackets%s", 619 histogram_prefix.c_str(), 620 packet_number, 621 histogram_suffix.c_str()); 622 DynamicHistogramEnumeration(histogram_name, count, packet_number + 1); 623 } 624} 625 626void NetworkStats::RecordNATTestReceivedHistograms(Status status) { 627 const char* test_name = kTestName[NAT_BIND_TEST]; 628 bool test_result = status == SUCCESS; 629 std::string middle_name = test_result ? "Connectivity.Success" 630 : "Connectivity.Failure"; 631 // Record whether the HelloRequest got reply successfully. 632 std::string histogram_name = 633 base::StringPrintf("NetConnectivity4.%s.Sent%d.%s.%d.%dB", 634 test_name, 635 maximum_NAT_packets_, 636 middle_name.c_str(), 637 histogram_port_, 638 probe_packet_bytes_); 639 uint32 bucket_count = std::min(maximum_NAT_idle_seconds_ + 2, 50U); 640 DynamicHistogramCounts(histogram_name, 641 pacing_interval_.InSeconds(), 642 1, 643 maximum_NAT_idle_seconds_ + 1, 644 bucket_count); 645 646 // Record the NAT bind result only if the HelloRequest successfully got the 647 // token and the first NAT test packet is received. 648 if (!test_result || !packets_received_mask_.test(0)) 649 return; 650 651 middle_name = packets_received_mask_.test(1) ? "Bind.Success" 652 : "Bind.Failure"; 653 histogram_name = base::StringPrintf("NetConnectivity4.%s.Sent%d.%s.%d.%dB", 654 test_name, 655 maximum_NAT_packets_, 656 middle_name.c_str(), 657 histogram_port_, 658 probe_packet_bytes_); 659 DynamicHistogramCounts(histogram_name, 660 pacing_interval_.InSeconds(), 661 1, 662 maximum_NAT_idle_seconds_ + 1, 663 bucket_count); 664} 665 666void NetworkStats::RecordPacketLossSeriesHistograms(TestType test_type) { 667 const char* test_name = kTestName[test_type]; 668 // Build "NetConnectivity4.<TestName>.First6.SeriesRecv.<port>.<probe_size>" 669 // histogram name. Total 3(tests) x 12 histograms. 670 std::string series_acked_histogram_name = 671 base::StringPrintf("NetConnectivity4.%s.First6.SeriesRecv.%d.%dB", 672 test_name, 673 histogram_port_, 674 probe_packet_bytes_); 675 uint32 histogram_boundary = 1 << kCorrelatedLossPacketCount; 676 uint32 correlated_packet_mask = 677 (histogram_boundary - 1) & packets_received_mask_.to_ulong(); 678 DynamicHistogramEnumeration( 679 series_acked_histogram_name, correlated_packet_mask, histogram_boundary); 680 681 // If we are running without a proxy, we'll generate an extra histogram with 682 // the ".NoProxy" suffix. 683 if (!has_proxy_server_) { 684 series_acked_histogram_name.append(".NoProxy"); 685 DynamicHistogramEnumeration(series_acked_histogram_name, 686 correlated_packet_mask, 687 histogram_boundary); 688 } 689} 690 691void NetworkStats::RecordRTTHistograms(TestType test_type, uint32 index) { 692 CHECK_LT(index, packet_rtt_.size()); 693 694 if (!packets_received_mask_.test(index)) 695 return; // Probe packet never received. 696 697 std::string rtt_histogram_name = base::StringPrintf( 698 "NetConnectivity4.%s.Sent%d.Success.RTT.Packet%02d.%d.%dB", 699 kTestName[test_type], 700 maximum_sequential_packets_, 701 index + 1, 702 histogram_port_, 703 probe_packet_bytes_); 704 DynamicHistogramTimes(rtt_histogram_name, packet_rtt_[index]); 705} 706 707void NetworkStats::RecordSendToLastRecvDelayHistograms(TestType test_type) { 708 if (packets_received_mask_.count() < 2) 709 return; // Too few packets are received. 710 uint32 packets_sent = test_type == NAT_BIND_TEST 711 ? maximum_NAT_packets_ : maximum_sequential_packets_; 712 std::string histogram_name = base::StringPrintf( 713 "NetConnectivity4.%s.Sent%d.SendToLastRecvDelay.%d.%dB", 714 kTestName[test_type], 715 packets_sent, 716 histogram_port_, 717 probe_packet_bytes_); 718 base::TimeDelta send_to_last_recv_time = 719 std::max(last_arrival_time_ - probe_request_time_ - 720 pacing_interval_ * (packets_sent - 1), 721 base::TimeDelta::FromMilliseconds(0)); 722 DynamicHistogramTimes(histogram_name, send_to_last_recv_time); 723} 724 725// ProxyDetector methods and members. 726ProxyDetector::ProxyDetector(net::ProxyService* proxy_service, 727 const net::HostPortPair& server_address, 728 OnResolvedCallback callback) 729 : proxy_service_(proxy_service), 730 server_address_(server_address), 731 callback_(callback), 732 has_pending_proxy_resolution_(false) {} 733 734ProxyDetector::~ProxyDetector() { 735 CHECK(!has_pending_proxy_resolution_); 736} 737 738void ProxyDetector::StartResolveProxy() { 739 std::string url = 740 base::StringPrintf("https://%s", server_address_.ToString().c_str()); 741 GURL gurl(url); 742 743 has_pending_proxy_resolution_ = true; 744 CHECK(proxy_service_); 745 int rv = proxy_service_->ResolveProxy( 746 gurl, 747 &proxy_info_, 748 base::Bind(&ProxyDetector::OnResolveProxyComplete, 749 base::Unretained(this)), 750 NULL, 751 net::BoundNetLog()); 752 if (rv != net::ERR_IO_PENDING) 753 OnResolveProxyComplete(rv); 754} 755 756void ProxyDetector::OnResolveProxyComplete(int result) { 757 has_pending_proxy_resolution_ = false; 758 bool has_proxy_server = 759 (result == net::OK && proxy_info_.proxy_server().is_valid() && 760 !proxy_info_.proxy_server().is_direct()); 761 762 OnResolvedCallback callback = callback_; 763 BrowserThread::PostTask( 764 BrowserThread::IO, FROM_HERE, base::Bind(callback, has_proxy_server)); 765 766 // TODO(rtenneti): Will we leak if ProxyResolve is cancelled (or proxy 767 // resolution never completes). 768 delete this; 769} 770 771void CollectNetworkStats(const std::string& network_stats_server, 772 IOThread* io_thread) { 773 if (network_stats_server.empty()) 774 return; 775 776 // If we are not on IO Thread, then post a task to call CollectNetworkStats on 777 // IO Thread. 778 if (!BrowserThread::CurrentlyOn(BrowserThread::IO)) { 779 BrowserThread::PostTask( 780 BrowserThread::IO, 781 FROM_HERE, 782 base::Bind(&CollectNetworkStats, network_stats_server, io_thread)); 783 return; 784 } 785 786 CHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 787 788 // Check that there is a network connection. We get called only if UMA upload 789 // to the server has succeeded. 790 CHECK(!net::NetworkChangeNotifier::IsOffline()); 791 792 CR_DEFINE_STATIC_LOCAL(scoped_refptr<base::FieldTrial>, trial, ()); 793 static bool collect_stats = false; 794 795 if (!trial.get()) { 796 // Set up a field trial to collect network stats for UDP. 797 const base::FieldTrial::Probability kDivisor = 1000; 798 799 // Enable the connectivity testing for 0.5% of the users in stable channel. 800 base::FieldTrial::Probability probability_per_group = kDivisor / 200; 801 802 chrome::VersionInfo::Channel channel = chrome::VersionInfo::GetChannel(); 803 if (channel == chrome::VersionInfo::CHANNEL_CANARY) { 804 // Enable the connectivity testing for 20% of the users in canary channel. 805 probability_per_group = kDivisor / 5; 806 } else if (channel == chrome::VersionInfo::CHANNEL_DEV) { 807 // Enable the connectivity testing for 10% of the users in dev channel. 808 probability_per_group = kDivisor / 10; 809 } else if (channel == chrome::VersionInfo::CHANNEL_BETA) { 810 // Enable the connectivity testing for 1% of the users in beta channel. 811 probability_per_group = kDivisor / 100; 812 } 813 814 // After July 31, 2014 builds, it will always be in default group 815 // (disable_network_stats). 816 trial = base::FieldTrialList::FactoryGetFieldTrial( 817 "NetworkConnectivity", kDivisor, "disable_network_stats", 818 2014, 7, 31, base::FieldTrial::SESSION_RANDOMIZED, NULL); 819 820 // Add option to collect_stats for NetworkConnectivity. 821 int collect_stats_group = 822 trial->AppendGroup("collect_stats", probability_per_group); 823 if (trial->group() == collect_stats_group) 824 collect_stats = true; 825 } 826 827 if (!collect_stats) 828 return; 829 830 // Run test kMaxNumberOfTests times. 831 const size_t kMaxNumberOfTests = INT_MAX; 832 static size_t number_of_tests_done = 0; 833 if (number_of_tests_done > kMaxNumberOfTests) 834 return; 835 ++number_of_tests_done; 836 837 net::HostResolver* host_resolver = io_thread->globals()->host_resolver.get(); 838 CHECK(host_resolver); 839 840 uint32 port_index = base::RandInt(0, arraysize(kPorts) - 1); 841 uint16 histogram_port = kPorts[port_index]; 842 net::HostPortPair server_address(network_stats_server, histogram_port); 843 844 net::ProxyService* proxy_service = 845 io_thread->globals()->system_proxy_service.get(); 846 CHECK(proxy_service); 847 848 ProxyDetector::OnResolvedCallback callback = base::Bind( 849 &StartNetworkStatsTest, host_resolver, server_address, histogram_port); 850 851 ProxyDetector* proxy_client = 852 new ProxyDetector(proxy_service, server_address, callback); 853 proxy_client->StartResolveProxy(); 854} 855 856void StartNetworkStatsTest(net::HostResolver* host_resolver, 857 const net::HostPortPair& server_address, 858 uint16 histogram_port, 859 bool has_proxy_server) { 860 int probe_choice = base::RandInt(0, kPacketSizeChoices - 1); 861 862 // |udp_stats_client| is owned and deleted in the class NetworkStats. 863 NetworkStats* udp_stats_client = 864 new NetworkStats(net::ClientSocketFactory::GetDefaultFactory()); 865 udp_stats_client->Start(host_resolver, 866 server_address, 867 histogram_port, 868 has_proxy_server, 869 kProbePacketBytes[probe_choice], 870 net::CompletionCallback()); 871} 872 873} // namespace chrome_browser_net 874