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