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