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