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