network_stats.cc revision 868fa2fe829687343ffae624259930155e16dbd8
1// Copyright (c) 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.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/threading/platform_thread.h" 15#include "base/time.h" 16#include "base/tuple.h" 17#include "chrome/common/chrome_version_info.h" 18#include "content/public/browser/browser_thread.h" 19#include "googleurl/src/gurl.h" 20#include "net/base/net_errors.h" 21#include "net/base/net_util.h" 22#include "net/base/network_change_notifier.h" 23#include "net/base/test_completion_callback.h" 24#include "net/proxy/proxy_service.h" 25#include "net/udp/udp_client_socket.h" 26#include "net/udp/udp_server_socket.h" 27 28using content::BrowserThread; 29 30namespace chrome_browser_net { 31 32// This specifies the number of bytes to be sent to the UDP echo servers as part 33// of small packet size test. 34static const uint32 kSmallTestBytesToSend = 100; 35 36// This specifies the number of bytes to be sent to the UDP echo servers as part 37// of medium packet size test. 38static const uint32 kMediumTestBytesToSend = 500; 39 40// This specifies the number of bytes to be sent to the UDP echo servers as part 41// of large packet size test. 42static const uint32 kLargeTestBytesToSend = 1200; 43 44// This specifies starting position of the <version> and length of the 45// <version> in "echo request" and "echo response". 46static const uint32 kVersionNumber = 1; 47static const uint32 kVersionStart = 0; 48static const uint32 kVersionLength = 2; 49static const uint32 kVersionEnd = kVersionStart + kVersionLength; 50 51// This specifies the starting position of the <checksum> and length of the 52// <checksum> in "echo request" and "echo response". Maximum value for the 53// <checksum> is less than (2 ** 31 - 1). 54static const uint32 kChecksumStart = kVersionEnd; 55static const uint32 kChecksumLength = 10; 56static const uint32 kChecksumEnd = kChecksumStart + kChecksumLength; 57 58// This specifies the starting position of the <payload_size> and length of the 59// <payload_size> in "echo request" and "echo response". Maximum number of bytes 60// that can be sent in the <payload> is 9,999,999. 61static const uint32 kPayloadSizeStart = kChecksumEnd; 62static const uint32 kPayloadSizeLength = 7; 63static const uint32 kPayloadSizeEnd = kPayloadSizeStart + kPayloadSizeLength; 64 65// This specifies the starting position of the <key> and length of the <key> in 66// "echo response". 67static const uint32 kKeyStart = kPayloadSizeEnd; 68static const uint32 kKeyLength = 6; 69static const uint32 kKeyEnd = kKeyStart + kKeyLength; 70static const int32 kKeyMinValue = 0; 71static const int32 kKeyMaxValue = 999999; 72 73// This specifies the starting position of the <payload> in "echo request". 74static const uint32 kPayloadStart = kPayloadSizeEnd; 75 76// This specifies the length of the packet_number in the payload. 77static const uint32 kPacketNumberLength = 10; 78 79// This specifies the starting position of the <encoded_payload> in 80// "echo response". 81static const uint32 kEncodedPayloadStart = kKeyEnd; 82 83// HistogramPortSelector and kPorts should be kept in sync. Port 999999 is 84// used by the unit tests. 85static const int32 kPorts[] = {443, 999999}; 86 87// Number of packets that are recorded in a packet-correlation histogram, which 88// shows exactly what sequence of packets were responded to. We use this to 89// deduce specific packet loss correlation. 90static const uint32 kCorrelatedLossPacketCount = 6; 91 92// Maximum number of packets that can be sent to the server. 93static const uint32 kMaximumSequentialPackets = 21; 94 95// This specifies the maximum message (payload) size. 96static const uint32 kMaxMessage = kMaximumSequentialPackets * 2048; 97 98// NetworkStats methods and members. 99NetworkStats::NetworkStats() 100 : read_buffer_(NULL), 101 write_buffer_(NULL), 102 load_size_(0), 103 bytes_to_read_(0), 104 bytes_to_send_(0), 105 has_proxy_server_(false), 106 packets_to_send_(0), 107 packets_sent_(0), 108 packets_received_(0), 109 packets_received_mask_(0), 110 packet_number_(0), 111 base_packet_number_(0), 112 sending_complete_(false), 113 current_test_(START_PACKET_TEST), 114 next_test_(TEST_TYPE_MAX), 115 weak_factory_(this) { 116} 117 118NetworkStats::~NetworkStats() { 119 socket_.reset(); 120} 121 122bool NetworkStats::Start(net::HostResolver* host_resolver, 123 const net::HostPortPair& server_host_port_pair, 124 HistogramPortSelector histogram_port, 125 bool has_proxy_server, 126 uint32 bytes_to_send, 127 uint32 packets_to_send, 128 const net::CompletionCallback& finished_callback) { 129 DCHECK(host_resolver); 130 DCHECK(bytes_to_send); // We should have data to send. 131 DCHECK_LE(packets_to_send, kMaximumSequentialPackets); 132 133 Initialize(bytes_to_send, 134 histogram_port, 135 has_proxy_server, 136 packets_to_send, 137 finished_callback); 138 139 net::HostResolver::RequestInfo request(server_host_port_pair); 140 int rv = host_resolver->Resolve( 141 request, &addresses_, 142 base::Bind(&NetworkStats::OnResolveComplete, 143 base::Unretained(this)), 144 NULL, net::BoundNetLog()); 145 if (rv == net::ERR_IO_PENDING) 146 return true; 147 return DoConnect(rv); 148} 149 150void NetworkStats::RestartPacketTest() { 151 ResetData(); 152 current_test_ = next_test_; 153 next_test_ = TEST_TYPE_MAX; 154 if (!bytes_to_read_) { 155 read_buffer_ = NULL; 156 ReadData(); 157 } 158 SendPacket(); 159} 160 161void NetworkStats::Initialize( 162 uint32 bytes_to_send, 163 HistogramPortSelector histogram_port, 164 bool has_proxy_server, 165 uint32 packets_to_send, 166 const net::CompletionCallback& finished_callback) { 167 DCHECK(bytes_to_send); // We should have data to send. 168 DCHECK(packets_to_send); // We should send at least 1 packet. 169 DCHECK_LE(bytes_to_send, kLargeTestBytesToSend); 170 DCHECK_LE(packets_to_send, 8 * sizeof(packets_received_mask_)); 171 172 load_size_ = bytes_to_send; 173 packets_to_send_ = packets_to_send; 174 histogram_port_ = histogram_port; 175 has_proxy_server_ = has_proxy_server; 176 finished_callback_ = finished_callback; 177 ResetData(); 178 packet_number_ = base::RandInt(1 << 28, INT_MAX); 179} 180 181void NetworkStats::ResetData() { 182 write_buffer_ = NULL; 183 bytes_to_send_ = 0; 184 packet_status_.clear(); 185 packet_status_.resize(packets_to_send_); 186 packets_sent_ = 0; 187 packets_received_ = 0; 188 packets_received_mask_ = 0; 189 sending_complete_ = false; 190} 191 192void NetworkStats::OnResolveComplete(int result) { 193 DoConnect(result); 194} 195 196bool NetworkStats::DoConnect(int result) { 197 if (result != net::OK) { 198 Finish(RESOLVE_FAILED, result); 199 return false; 200 } 201 202 net::UDPClientSocket* udp_socket = 203 new net::UDPClientSocket(net::DatagramSocket::DEFAULT_BIND, 204 net::RandIntCallback(), 205 NULL, 206 net::NetLog::Source()); 207 if (!udp_socket) { 208 Finish(SOCKET_CREATE_FAILED, net::ERR_INVALID_ARGUMENT); 209 return false; 210 } 211 set_socket(udp_socket); 212 213 const net::IPEndPoint& endpoint = addresses().front(); 214 int rv = udp_socket->Connect(endpoint); 215 if (rv < 0) { 216 Finish(CONNECT_FAILED, rv); 217 return false; 218 } 219 220 const int kSocketBufferSize = 2 * packets_to_send_ * 2048; 221 udp_socket->SetSendBufferSize(kSocketBufferSize); 222 udp_socket->SetReceiveBufferSize(kSocketBufferSize); 223 return ConnectComplete(rv); 224} 225 226bool NetworkStats::ConnectComplete(int result) { 227 if (result < 0) { 228 Finish(CONNECT_FAILED, result); 229 return false; 230 } 231 232 ReadData(); 233 SendPacket(); 234 return true; 235} 236 237void NetworkStats::SendPacket() { 238 while (true) { 239 if (bytes_to_send_ == 0u) { 240 if (packets_sent_ >= packets_to_send_) { 241 // Timeout if we don't get response back from echo servers in 30 secs. 242 sending_complete_ = true; 243 const int kReadDataTimeoutMs = 30000; 244 StartReadDataTimer(kReadDataTimeoutMs); 245 break; 246 } 247 248 ++packet_number_; 249 if (packets_sent_ == 0) 250 base_packet_number_ = packet_number_; 251 bytes_to_send_ = SendingPacketSize(); 252 SendNextPacketAfterDelay(); 253 break; 254 } 255 256 int rv = SendData(); 257 if (rv < 0) { 258 if (rv != net::ERR_IO_PENDING) 259 Finish(WRITE_FAILED, rv); 260 break; 261 } 262 DCHECK_EQ(bytes_to_send_, 0u); 263 }; 264} 265 266void NetworkStats::SendNextPacketAfterDelay() { 267 if (current_test_ == PACED_PACKET_TEST) { 268 base::MessageLoop::current()->PostDelayedTask( 269 FROM_HERE, 270 base::Bind(&NetworkStats::SendPacket, weak_factory_.GetWeakPtr()), 271 average_time_); 272 return; 273 } 274 275 base::MessageLoop::current()->PostTask( 276 FROM_HERE, 277 base::Bind(&NetworkStats::SendPacket, weak_factory_.GetWeakPtr())); 278} 279 280bool NetworkStats::ReadComplete(int result) { 281 DCHECK(socket_.get()); 282 DCHECK_NE(net::ERR_IO_PENDING, result); 283 if (result < 0) { 284 Finish(READ_FAILED, result); 285 return true; 286 } 287 288 if (result > 0) { 289 std::string encoded_message; 290 encoded_message.append(read_buffer_->data(), result); 291 if (VerifyBytes(encoded_message) == SUCCESS) { 292 base::TimeTicks now = base::TimeTicks::Now(); 293 if (packets_received_ == 0) 294 packet_1st_byte_read_time_ = now; 295 packet_last_byte_read_time_ = now; 296 297 DCHECK_GE(bytes_to_read_, static_cast<uint32>(result)); 298 if (bytes_to_read_ >= static_cast<uint32>(result)) 299 bytes_to_read_ -= result; 300 ++packets_received_; 301 } 302 } 303 304 read_buffer_ = NULL; 305 306 // No more data to read. 307 if (!bytes_to_read_ || result == 0) { 308 if (!sending_complete_) 309 return false; 310 311 Status status = VerifyPackets(); 312 if (status == SUCCESS) 313 Finish(status, net::OK); 314 else 315 Finish(status, net::ERR_INVALID_RESPONSE); 316 return true; 317 } 318 return false; 319} 320 321void NetworkStats::OnReadComplete(int result) { 322 if (!ReadComplete(result)) { 323 // Called ReadData() via PostDelayedTask() to avoid recursion. Added a delay 324 // of 1ms so that the time-out will fire before we have time to really hog 325 // the CPU too extensively (waiting for the time-out) in case of an infinite 326 // loop. 327 base::MessageLoop::current()->PostDelayedTask( 328 FROM_HERE, 329 base::Bind(&NetworkStats::ReadData, weak_factory_.GetWeakPtr()), 330 base::TimeDelta::FromMilliseconds(1)); 331 } 332} 333 334void NetworkStats::OnWriteComplete(int result) { 335 DCHECK(socket_.get()); 336 DCHECK_NE(net::ERR_IO_PENDING, result); 337 if (result < 0) { 338 Finish(WRITE_FAILED, result); 339 return; 340 } 341 342 DidSendData(result); 343 if (bytes_to_send_) { 344 int rv = SendData(); 345 if (rv < 0) { 346 if (rv != net::ERR_IO_PENDING) 347 Finish(WRITE_FAILED, rv); 348 return; 349 } 350 DCHECK_EQ(rv, net::OK); 351 DCHECK_EQ(bytes_to_send_, 0u); 352 } 353 354 base::MessageLoop::current()->PostTask( 355 FROM_HERE, 356 base::Bind(&NetworkStats::SendPacket, weak_factory_.GetWeakPtr())); 357} 358 359void NetworkStats::ReadData() { 360 int rv; 361 do { 362 if (!socket_.get()) 363 break; 364 365 DCHECK(!read_buffer_.get()); 366 367 // We release the read_buffer_ in the destructor if there is an error. 368 read_buffer_ = new net::IOBuffer(kMaxMessage); 369 370 rv = socket_->Read( 371 read_buffer_.get(), 372 kMaxMessage, 373 base::Bind(&NetworkStats::OnReadComplete, base::Unretained(this))); 374 if (rv == net::ERR_IO_PENDING) 375 break; 376 377 // If we have read all the data then return. 378 if (ReadComplete(rv)) 379 break; 380 } while (rv > 0); 381} 382 383int NetworkStats::SendData() { 384 DCHECK(bytes_to_send_); // We should have data to send. 385 do { 386 if (!write_buffer_.get()) { 387 // Send a new packet. 388 scoped_refptr<net::IOBufferWithSize> buffer( 389 new net::IOBufferWithSize(bytes_to_send_)); 390 GetEchoRequest(buffer.get()); 391 write_buffer_ = new net::DrainableIOBuffer(buffer.get(), bytes_to_send_); 392 393 // As soon as we write, a read could happen. Thus update all the book 394 // keeping data. 395 bytes_to_read_ += ReceivingPacketSize(); 396 ++packets_sent_; 397 if (packets_sent_ >= packets_to_send_) 398 sending_complete_ = true; 399 400 uint32 packet_index = packet_number_ - base_packet_number_; 401 DCHECK_GE(packet_index, 0u); 402 DCHECK_LT(packet_index, packet_status_.size()); 403 packet_status_[packet_index].start_time_ = base::TimeTicks::Now(); 404 } 405 406 if (!socket_.get()) 407 return net::ERR_UNEXPECTED; 408 int rv = socket_->Write( 409 write_buffer_.get(), 410 write_buffer_->BytesRemaining(), 411 base::Bind(&NetworkStats::OnWriteComplete, base::Unretained(this))); 412 if (rv < 0) 413 return rv; 414 DidSendData(rv); 415 } while (bytes_to_send_); 416 return net::OK; 417} 418 419uint32 NetworkStats::SendingPacketSize() const { 420 return kVersionLength + kChecksumLength + kPayloadSizeLength + load_size_; 421} 422 423uint32 NetworkStats::ReceivingPacketSize() const { 424 return kVersionLength + kChecksumLength + kPayloadSizeLength + kKeyLength + 425 load_size_; 426} 427 428void NetworkStats::DidSendData(int bytes_sent) { 429 write_buffer_->DidConsume(bytes_sent); 430 if (!write_buffer_->BytesRemaining()) 431 write_buffer_ = NULL; 432 bytes_to_send_ -= bytes_sent; 433} 434 435void NetworkStats::StartReadDataTimer(int milliseconds) { 436 base::MessageLoop::current()->PostDelayedTask( 437 FROM_HERE, 438 base::Bind(&NetworkStats::OnReadDataTimeout, 439 weak_factory_.GetWeakPtr(), 440 base_packet_number_), 441 base::TimeDelta::FromMilliseconds(milliseconds)); 442} 443 444void NetworkStats::OnReadDataTimeout(uint32 test_base_packet_number) { 445 if (test_base_packet_number != base_packet_number_) 446 return; 447 448 Status status = VerifyPackets(); 449 if (status == SUCCESS) 450 Finish(status, net::OK); 451 else 452 Finish(READ_TIMED_OUT, net::ERR_INVALID_ARGUMENT); 453} 454 455uint32 NetworkStats::GetChecksum(const char* message, uint32 message_length) { 456 // Calculate the <checksum> of the <message>. 457 uint32 sum = 0; 458 for (uint32 i = 0; i < message_length; ++i) 459 sum += message[i]; 460 return sum; 461} 462 463void NetworkStats::Crypt(const char* key, 464 uint32 key_length, 465 const char* data, 466 uint32 data_length, 467 char* encoded_data) { 468 // Decrypt the data by looping through the |data| and XOR each byte with the 469 // |key| to get the decoded byte. Append the decoded byte to the 470 // |encoded_data|. 471 for (uint32 data_index = 0, key_index = 0; 472 data_index < data_length; 473 ++data_index) { 474 char data_byte = data[data_index]; 475 char key_byte = key[key_index]; 476 char encoded_byte = data_byte ^ key_byte; 477 encoded_data[data_index] = encoded_byte; 478 key_index = (key_index + 1) % key_length; 479 } 480} 481 482void NetworkStats::GetEchoRequest(net::IOBufferWithSize* io_buffer) { 483 char* buffer = io_buffer->data(); 484 uint32 buffer_size = static_cast<uint32>(io_buffer->size()); 485 486 // Copy the <version> into the io_buffer starting from the kVersionStart 487 // position. 488 std::string version = base::StringPrintf("%02d", kVersionNumber); 489 DCHECK(kVersionLength == version.length()); 490 DCHECK_GE(buffer_size, kVersionStart + kVersionLength); 491 memcpy(buffer + kVersionStart, version.c_str(), kVersionLength); 492 493 // Copy the packet_number into the payload. 494 std::string packet_number = base::StringPrintf("%010d", packet_number_); 495 DCHECK(kPacketNumberLength == packet_number.length()); 496 DCHECK_GE(buffer_size, kPayloadStart + kPacketNumberLength); 497 memcpy(buffer + kPayloadStart, packet_number.c_str(), kPacketNumberLength); 498 499 // Get the <payload> from the |stream_| and copy it into io_buffer after 500 // packet_number. 501 stream_.Reset(); 502 DCHECK_GE(buffer_size, kPayloadStart + load_size_); 503 stream_.GetBytes(buffer + kPayloadStart + kPacketNumberLength, 504 load_size_ - kPacketNumberLength); 505 506 // Calculate the <checksum> of the <payload>. 507 uint32 sum = GetChecksum(buffer + kPayloadStart, load_size_); 508 509 // Copy the <checksum> into the io_buffer starting from the kChecksumStart 510 // position. 511 std::string checksum = base::StringPrintf("%010d", sum); 512 DCHECK(kChecksumLength == checksum.length()); 513 DCHECK_GE(buffer_size, kChecksumStart + kChecksumLength); 514 memcpy(buffer + kChecksumStart, checksum.c_str(), kChecksumLength); 515 516 // Copy the size of the <payload> into the io_buffer starting from the 517 // kPayloadSizeStart position. 518 std::string payload_size = base::StringPrintf("%07d", load_size_); 519 DCHECK(kPayloadSizeLength == payload_size.length()); 520 DCHECK_GE(buffer_size, kPayloadSizeStart + kPayloadSizeLength); 521 memcpy(buffer + kPayloadSizeStart, payload_size.c_str(), kPayloadSizeLength); 522} 523 524NetworkStats::Status NetworkStats::VerifyPackets() { 525 Status status = SUCCESS; 526 uint32 successful_packets = 0; 527 528 for (uint32 i = 0; i < packet_status_.size(); i++) { 529 if (packets_received_mask_ & (1 << i)) 530 ++successful_packets; 531 } 532 533 if (packets_received_ > packets_to_send_) 534 status = TOO_MANY_PACKETS; 535 536 if (packets_to_send_ > successful_packets) 537 status = SOME_PACKETS_NOT_VERIFIED; 538 539 if (packets_to_send_ == kMaximumSequentialPackets && 540 successful_packets > 1) { 541 base::TimeDelta total_time; 542 if (packet_last_byte_read_time_ > packet_1st_byte_read_time_) { 543 total_time = 544 packet_last_byte_read_time_ - packet_1st_byte_read_time_; 545 } 546 average_time_ = total_time / (successful_packets - 1); 547 std::string histogram_name = base::StringPrintf( 548 "NetConnectivity3.%s.Sent%02d.%d.%dB.PacketDelay", 549 TestName(), 550 kMaximumSequentialPackets, 551 kPorts[histogram_port_], 552 load_size_); 553 base::HistogramBase* histogram = base::Histogram::FactoryTimeGet( 554 histogram_name, base::TimeDelta::FromMilliseconds(1), 555 base::TimeDelta::FromSeconds(30), 50, 556 base::Histogram::kUmaTargetedHistogramFlag); 557 histogram->AddTime(total_time); 558 559 if (current_test_ == START_PACKET_TEST) { 560 int experiment_to_run = base::RandInt(1, 2); 561 if (experiment_to_run == 1) 562 next_test_ = NON_PACED_PACKET_TEST; 563 else 564 next_test_ = PACED_PACKET_TEST; 565 } 566 } 567 568 return status; 569} 570 571NetworkStats::Status NetworkStats::VerifyBytes(const std::string& response) { 572 // If the "echo response" doesn't have enough bytes, then return false. 573 if (response.length() <= kVersionStart) 574 return ZERO_LENGTH_ERROR; 575 if (response.length() <= kChecksumStart) 576 return NO_CHECKSUM_ERROR; 577 if (response.length() <= kPayloadSizeStart) 578 return NO_PAYLOAD_SIZE_ERROR; 579 if (response.length() <= kKeyStart) 580 return NO_KEY_ERROR; 581 if (response.length() <= kEncodedPayloadStart) 582 return NO_PAYLOAD_ERROR; 583 584 // Extract the |key| from the "echo response". 585 std::string key_string = response.substr(kKeyStart, kKeyLength); 586 const char* key = key_string.c_str(); 587 int key_value = atoi(key); 588 if (key_value < kKeyMinValue || key_value > kKeyMaxValue) 589 return INVALID_KEY_ERROR; 590 591 std::string encoded_payload = response.substr(kEncodedPayloadStart); 592 const char* encoded_data = encoded_payload.c_str(); 593 uint32 message_length = encoded_payload.length(); 594 message_length = std::min(message_length, kMaxMessage); 595 if (message_length < load_size_) 596 return TOO_SHORT_PAYLOAD; 597 if (message_length > load_size_) 598 return TOO_LONG_PAYLOAD; 599 600 // Decode/decrypt the |encoded_data| into |decoded_data|. 601 char decoded_data[kMaxMessage + 1]; 602 DCHECK_LE(message_length, kMaxMessage); 603 memset(decoded_data, 0, kMaxMessage + 1); 604 Crypt(key, kKeyLength, encoded_data, message_length, decoded_data); 605 606 // Calculate the <checksum> of the <decoded_data>. 607 uint32 sum = GetChecksum(decoded_data, message_length); 608 // Extract the |checksum| from the "echo response". 609 std::string checksum_string = 610 response.substr(kChecksumStart, kChecksumLength); 611 const char* checksum = checksum_string.c_str(); 612 uint32 checksum_value = atoi(checksum); 613 if (checksum_value != sum) 614 return INVALID_CHECKSUM; 615 616 // Verify the packet_number. 617 char packet_number_data[kPacketNumberLength + 1]; 618 memset(packet_number_data, 0, kPacketNumberLength + 1); 619 memcpy(packet_number_data, decoded_data, kPacketNumberLength); 620 uint32 packet_number_received = atoi(packet_number_data); 621 if (packet_number_received < base_packet_number_) 622 return PREVIOUS_PACKET_NUMBER; 623 uint32 packet_index = packet_number_received - base_packet_number_; 624 if (packet_index >= packets_to_send_) 625 return INVALID_PACKET_NUMBER; 626 627 stream_.Reset(); 628 if (!stream_.VerifyBytes(&decoded_data[kPacketNumberLength], 629 message_length - kPacketNumberLength)) { 630 return PATTERN_CHANGED; 631 } 632 633 if (packets_received_mask_ & (1 << packet_index)) 634 return DUPLICATE_PACKET; 635 636 packets_received_mask_ |= 1 << packet_index; 637 DCHECK_GE(packet_index, 0u); 638 DCHECK_LT(packet_index, packet_status_.size()); 639 packet_status_[packet_index].end_time_ = base::TimeTicks::Now(); 640 return SUCCESS; 641} 642 643void NetworkStats::Finish(Status status, int result) { 644 // Set the base_packet_number_ for the start of next test. Changing the 645 // |base_packet_number_| indicates to OnReadDataTimeout that the Finish has 646 // already been called for the test and that it doesn't need to call Finish 647 // again. 648 base_packet_number_ = packet_number_ + 1; 649 RecordHistograms(PROTOCOL_UDP, status, result); 650 651 if (next_test() == NON_PACED_PACKET_TEST || 652 next_test() == PACED_PACKET_TEST) { 653 base::MessageLoop::current()->PostTask( 654 FROM_HERE, 655 base::Bind(&NetworkStats::RestartPacketTest, 656 weak_factory_.GetWeakPtr())); 657 return; 658 } 659 660 DoFinishCallback(result); 661 662 // Close the socket so that there are no more IO operations. 663 net::UDPClientSocket* udp_socket = 664 static_cast<net::UDPClientSocket*>(socket()); 665 if (udp_socket) 666 udp_socket->Close(); 667 668 delete this; 669} 670 671void NetworkStats::DoFinishCallback(int result) { 672 if (!finished_callback_.is_null()) { 673 net::CompletionCallback callback = finished_callback_; 674 finished_callback_.Reset(); 675 callback.Run(result); 676 } 677} 678 679void NetworkStats::RecordHistograms(const ProtocolValue& protocol, 680 const Status& status, 681 int result) { 682 if (packets_to_send_ != kMaximumSequentialPackets) 683 return; 684 685 std::string load_size_string = base::StringPrintf("%dB", load_size_); 686 687 RecordPacketLossSeriesHistograms(protocol, load_size_string, status, result); 688 689 for (uint32 i = 0; i < 3; i++) 690 RecordRTTHistograms(protocol, load_size_string, i); 691 692 RecordRTTHistograms(protocol, load_size_string, 9); 693 RecordRTTHistograms(protocol, load_size_string, 19); 694 695 RecordAcksReceivedHistograms(load_size_string); 696} 697 698void NetworkStats::RecordAcksReceivedHistograms( 699 const std::string& load_size_string) { 700 DCHECK_EQ(packets_to_send_, kMaximumSequentialPackets); 701 702 const char* test_name = TestName(); 703 bool received_atleast_one_packet = packets_received_mask_ > 0; 704 705 std::string histogram_name = base::StringPrintf( 706 "NetConnectivity3.%s.Sent%02d.GotAnAck.%d.%s", 707 test_name, 708 kMaximumSequentialPackets, 709 kPorts[histogram_port_], 710 load_size_string.c_str()); 711 base::HistogramBase* got_an_ack_histogram = 712 base::BooleanHistogram::FactoryGet( 713 histogram_name, base::HistogramBase::kUmaTargetedHistogramFlag); 714 got_an_ack_histogram->AddBoolean(received_atleast_one_packet); 715 716 histogram_name = base::StringPrintf( 717 "NetConnectivity3.%s.Sent%02d.PacketsSent.%d.%s", 718 test_name, 719 kMaximumSequentialPackets, 720 kPorts[histogram_port_], 721 load_size_string.c_str()); 722 base::HistogramBase* packets_sent_histogram = 723 base::Histogram::FactoryGet( 724 histogram_name, 725 1, kMaximumSequentialPackets, kMaximumSequentialPackets + 1, 726 base::HistogramBase::kUmaTargetedHistogramFlag); 727 packets_sent_histogram->Add(packets_sent_); 728 729 if (!received_atleast_one_packet || packets_sent_ != packets_to_send_) 730 return; 731 732 histogram_name = base::StringPrintf( 733 "NetConnectivity3.%s.Sent%02d.AckReceivedForNthPacket.%02d.%s", 734 test_name, 735 kMaximumSequentialPackets, 736 kPorts[histogram_port_], 737 load_size_string.c_str()); 738 base::HistogramBase* ack_received_for_nth_packet_histogram = 739 base::Histogram::FactoryGet( 740 histogram_name, 741 1, kMaximumSequentialPackets + 1, kMaximumSequentialPackets + 2, 742 base::HistogramBase::kUmaTargetedHistogramFlag); 743 744 int count = 0; 745 for (size_t j = 0; j < packets_to_send_; j++) { 746 int packet_number = j + 1; 747 if (packets_received_mask_ & (1 << j)) { 748 ack_received_for_nth_packet_histogram->Add(packet_number); 749 count++; 750 } 751 if (packet_number < 2) 752 continue; 753 histogram_name = base::StringPrintf( 754 "NetConnectivity3.%s.Sent%02d.AcksReceivedFromFirst%02dPackets.%d.%s", 755 test_name, 756 kMaximumSequentialPackets, 757 packet_number, 758 kPorts[histogram_port_], 759 load_size_string.c_str()); 760 base::HistogramBase* acks_received_count_histogram = 761 base::Histogram::FactoryGet( 762 histogram_name, 1, packet_number, packet_number + 1, 763 base::HistogramBase::kUmaTargetedHistogramFlag); 764 acks_received_count_histogram->Add(count); 765 } 766} 767 768void NetworkStats::RecordPacketLossSeriesHistograms( 769 const ProtocolValue& protocol, 770 const std::string& load_size_string, 771 const Status& status, 772 int result) { 773 DCHECK_GT(packets_to_send_, kCorrelatedLossPacketCount); 774 const char* test_name = TestName(); 775 776 // Build "NetConnectivity3.Send6.SeriesAcked.<port>.<load_size>" histogram 777 // name. Total number of histograms are 5*2. 778 std::string series_acked_histogram_name = base::StringPrintf( 779 "NetConnectivity3.%s.Send6.SeriesAcked.%d.%s", 780 test_name, 781 kPorts[histogram_port_], 782 load_size_string.c_str()); 783 784 uint32 correlated_packet_mask = 785 ((1 << kCorrelatedLossPacketCount) - 1) & packets_received_mask_; 786 787 // If we are running without a proxy, we'll generate 2 distinct histograms in 788 // each case, one will have the ".NoProxy" suffix. 789 size_t histogram_count = has_proxy_server_ ? 1 : 2; 790 for (size_t i = 0; i < histogram_count; i++) { 791 // For packet loss test, just record packet loss data. 792 base::HistogramBase* series_acked_histogram = 793 base::LinearHistogram::FactoryGet( 794 series_acked_histogram_name, 795 1, 796 1 << kCorrelatedLossPacketCount, 797 (1 << kCorrelatedLossPacketCount) + 1, 798 base::HistogramBase::kUmaTargetedHistogramFlag); 799 series_acked_histogram->Add(correlated_packet_mask); 800 series_acked_histogram_name.append(".NoProxy"); 801 } 802} 803 804void NetworkStats::RecordRTTHistograms(const ProtocolValue& protocol, 805 const std::string& load_size_string, 806 uint32 index) { 807 DCHECK_GE(index, 0u); 808 DCHECK_LT(index, packet_status_.size()); 809 810 if (packet_status_[index].end_time_ == base::TimeTicks()) 811 return; // Echo response packet never arrived. 812 813 const char* test_name = TestName(); 814 std::string rtt_histogram_name = base::StringPrintf( 815 "NetConnectivity3.%s.Sent%02d.Success.RTT.Packet%02d.%d.%s", 816 test_name, 817 packets_to_send_, 818 index + 1, 819 kPorts[histogram_port_], 820 load_size_string.c_str()); 821 base::HistogramBase* rtt_histogram = base::Histogram::FactoryTimeGet( 822 rtt_histogram_name, 823 base::TimeDelta::FromMilliseconds(10), 824 base::TimeDelta::FromSeconds(30), 50, 825 base::HistogramBase::kUmaTargetedHistogramFlag); 826 base::TimeDelta duration = 827 packet_status_[index].end_time_ - packet_status_[index].start_time_; 828 rtt_histogram->AddTime(duration); 829} 830 831const char* NetworkStats::TestName() { 832 switch (current_test_) { 833 case START_PACKET_TEST: 834 return "StartPacket"; 835 case NON_PACED_PACKET_TEST: 836 return "NonPacedPacket"; 837 case PACED_PACKET_TEST: 838 return "PacedPacket"; 839 default: 840 NOTREACHED(); 841 return "None"; 842 } 843} 844 845void NetworkStats::set_socket(net::Socket* socket) { 846 DCHECK(socket); 847 DCHECK(!socket_.get()); 848 socket_.reset(socket); 849} 850 851// ProxyDetector methods and members. 852ProxyDetector::ProxyDetector(net::ProxyService* proxy_service, 853 const net::HostPortPair& server_address, 854 OnResolvedCallback callback) 855 : proxy_service_(proxy_service), 856 server_address_(server_address), 857 callback_(callback), 858 has_pending_proxy_resolution_(false) { 859} 860 861ProxyDetector::~ProxyDetector() { 862 CHECK(!has_pending_proxy_resolution_); 863} 864 865void ProxyDetector::StartResolveProxy() { 866 std::string url = 867 base::StringPrintf("https://%s", server_address_.ToString().c_str()); 868 GURL gurl(url); 869 870 has_pending_proxy_resolution_ = true; 871 DCHECK(proxy_service_); 872 int rv = proxy_service_->ResolveProxy( 873 gurl, 874 &proxy_info_, 875 base::Bind(&ProxyDetector::OnResolveProxyComplete, 876 base::Unretained(this)), 877 NULL, 878 net::BoundNetLog()); 879 if (rv != net::ERR_IO_PENDING) 880 OnResolveProxyComplete(rv); 881} 882 883void ProxyDetector::OnResolveProxyComplete(int result) { 884 has_pending_proxy_resolution_ = false; 885 bool has_proxy_server = (result == net::OK && 886 proxy_info_.proxy_server().is_valid() && 887 !proxy_info_.proxy_server().is_direct()); 888 889 OnResolvedCallback callback = callback_; 890 BrowserThread::PostTask( 891 BrowserThread::IO, 892 FROM_HERE, 893 base::Bind(callback, has_proxy_server)); 894 895 // TODO(rtenneti): Will we leak if ProxyResolve is cancelled (or proxy 896 // resolution never completes). 897 delete this; 898} 899 900// static 901void CollectNetworkStats(const std::string& network_stats_server, 902 IOThread* io_thread) { 903 if (network_stats_server.empty()) 904 return; 905 906 // If we are not on IO Thread, then post a task to call CollectNetworkStats on 907 // IO Thread. 908 if (!BrowserThread::CurrentlyOn(BrowserThread::IO)) { 909 BrowserThread::PostTask( 910 BrowserThread::IO, 911 FROM_HERE, 912 base::Bind( 913 &CollectNetworkStats, network_stats_server, io_thread)); 914 return; 915 } 916 917 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 918 919 // Check that there is a network connection. We get called only if UMA upload 920 // to the server has succeeded. 921 DCHECK(!net::NetworkChangeNotifier::IsOffline()); 922 923 CR_DEFINE_STATIC_LOCAL(scoped_refptr<base::FieldTrial>, trial, ()); 924 static bool collect_stats = false; 925 static NetworkStats::HistogramPortSelector histogram_port = 926 NetworkStats::PORT_443; 927 928 if (!trial.get()) { 929 // Set up a field trial to collect network stats for UDP. 930 const base::FieldTrial::Probability kDivisor = 1000; 931 932 // Enable the connectivity testing for 0.5% of the users in stable channel. 933 base::FieldTrial::Probability probability_per_group = 5; 934 935 chrome::VersionInfo::Channel channel = chrome::VersionInfo::GetChannel(); 936 if (channel == chrome::VersionInfo::CHANNEL_CANARY) 937 probability_per_group = kDivisor; 938 else if (channel == chrome::VersionInfo::CHANNEL_DEV) 939 // Enable the connectivity testing for 50% of the users in dev channel. 940 probability_per_group = 500; 941 else if (channel == chrome::VersionInfo::CHANNEL_BETA) 942 // Enable the connectivity testing for 5% of the users in beta channel. 943 probability_per_group = 50; 944 945 // After October 30, 2013 builds, it will always be in default group 946 // (disable_network_stats). 947 trial = base::FieldTrialList::FactoryGetFieldTrial( 948 "NetworkConnectivity", kDivisor, "disable_network_stats", 949 2013, 10, 30, NULL); 950 951 // Add option to collect_stats for NetworkConnectivity. 952 int collect_stats_group = trial->AppendGroup("collect_stats", 953 probability_per_group); 954 if (trial->group() == collect_stats_group) 955 collect_stats = true; 956 } 957 958 if (!collect_stats) 959 return; 960 961 // Run test kMaxNumberOfTests times. 962 const size_t kMaxNumberOfTests = INT_MAX; 963 static size_t number_of_tests_done = 0; 964 if (number_of_tests_done > kMaxNumberOfTests) 965 return; 966 967 ++number_of_tests_done; 968 969 net::HostResolver* host_resolver = io_thread->globals()->host_resolver.get(); 970 DCHECK(host_resolver); 971 972 net::HostPortPair server_address(network_stats_server, 973 kPorts[histogram_port]); 974 975 net::ProxyService* proxy_service = 976 io_thread->globals()->system_proxy_service.get(); 977 DCHECK(proxy_service); 978 979 ProxyDetector::OnResolvedCallback callback = 980 base::Bind(&StartNetworkStatsTest, 981 host_resolver, server_address, histogram_port); 982 983 ProxyDetector* proxy_client = new ProxyDetector( 984 proxy_service, server_address, callback); 985 proxy_client->StartResolveProxy(); 986} 987 988// static 989void StartNetworkStatsTest(net::HostResolver* host_resolver, 990 const net::HostPortPair& server_address, 991 NetworkStats::HistogramPortSelector histogram_port, 992 bool has_proxy_server) { 993 int experiment_to_run = base::RandInt(1, 3); 994 switch (experiment_to_run) { 995 case 1: 996 { 997 NetworkStats* udp_stats_client = new NetworkStats(); 998 udp_stats_client->Start( 999 host_resolver, server_address, histogram_port, has_proxy_server, 1000 kSmallTestBytesToSend, kMaximumSequentialPackets, 1001 net::CompletionCallback()); 1002 } 1003 break; 1004 case 2: 1005 { 1006 NetworkStats* udp_stats_client = new NetworkStats(); 1007 udp_stats_client->Start( 1008 host_resolver, server_address, histogram_port, has_proxy_server, 1009 kMediumTestBytesToSend, kMaximumSequentialPackets, 1010 net::CompletionCallback()); 1011 } 1012 break; 1013 case 3: 1014 { 1015 NetworkStats* udp_stats_client = new NetworkStats(); 1016 udp_stats_client->Start( 1017 host_resolver, server_address, histogram_port, has_proxy_server, 1018 kLargeTestBytesToSend, kMaximumSequentialPackets, 1019 net::CompletionCallback()); 1020 } 1021 break; 1022 } 1023} 1024 1025} // namespace chrome_browser_net 1026