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