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