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