Upstream version 9.38.198.0
[platform/framework/web/crosswalk.git] / src / chrome / browser / net / network_stats.cc
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
27 using content::BrowserThread;
28
29 namespace chrome_browser_net {
30
31 // static
32 uint32 NetworkStats::maximum_tests_ = 8;
33 // static
34 uint32 NetworkStats::maximum_sequential_packets_ = 21;
35 // static
36 uint32 NetworkStats::maximum_NAT_packets_ = 2;
37 // static
38 uint32 NetworkStats::maximum_NAT_idle_seconds_ = 300;
39 // static
40 bool NetworkStats::start_test_after_connect_ = true;
41
42 // Specify the possible choices of probe packet sizes.
43 const uint32 kProbePacketBytes[] = {100, 500, 1200};
44 const uint32 kPacketSizeChoices = arraysize(kProbePacketBytes);
45
46 // List of ports used for probing test.
47 const 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.
52 const uint32 kCorrelatedLossPacketCount = 6;
53
54 // This specifies the maximum message (payload) size of one packet.
55 const uint32 kMaxMessageSize = 1600;
56
57 // This specifies the maximum udp receiver buffer size.
58 const uint32 kMaxUdpReceiveBufferSize = 63000;
59
60 // This specifies the maximum udp receiver buffer size.
61 const uint32 kMaxUdpSendBufferSize = 4096;
62
63 // This should match TestType except for the last one.
64 const 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.
69 const uint32 kMinimumReceivedPacketsForPacingTest = 2;
70 // Perform NAT binding test only if at least 10 packets are received.
71 const uint32 kMinimumReceivedPacketsForNATTest = 10;
72
73 // Maximum inter-packet pacing interval in microseconds.
74 const uint32 kMaximumPacingMicros = 1000000;
75 // Timeout value for getting the token.
76 const 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.
80 const 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.
83 const uint32 kReadNATTimeoutSeconds = 10;
84 // This is the timeout for PACKET_SIZE_TEST.
85 const uint32 kReadPacketSizeTimeoutSeconds = 10;
86 // This is the maxmium number of packets we would send for PACKET_SIZE_TEST.
87 uint32 kMaximumPacketSizeTestPackets = 1;
88
89 // These helper functions are similar to UMA_HISTOGRAM_XXX except that they do
90 // not create a static histogram_pointer.
91 void 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
103 void 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
114 void 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
125 NetworkStats::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
138 NetworkStats::~NetworkStats() {}
139
140 bool 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
175 void 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
185 void 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
199 bool 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
227 bool 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
248 void 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
260 void 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
316 int 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
342 void 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
360 bool 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
407 bool 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
456 int 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
477 void 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_ == NULL) {
482     TestPhaseComplete(WRITE_FAILED, result);
483     return;
484   }
485   UpdateSendBuffer(result);
486 }
487
488 void 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
495 void 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
504 void 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
536 bool 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
582 NetworkStats::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
589 void 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
597 void 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
626 void 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
638 void 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
682 void 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
722 void 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
740 void 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
766 void 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
783 void 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.
803 ProxyDetector::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
811 ProxyDetector::~ProxyDetector() {
812   CHECK(!has_pending_proxy_resolution_);
813 }
814
815 void 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
835 void 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
850 void 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
935 void 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