• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
26 using content::BrowserThread;
27 
28 namespace chrome_browser_net {
29 
30 // static
31 uint32 NetworkStats::maximum_tests_ = 8;
32 // static
33 uint32 NetworkStats::maximum_sequential_packets_ = 21;
34 // static
35 uint32 NetworkStats::maximum_NAT_packets_ = 2;
36 // static
37 uint32 NetworkStats::maximum_NAT_idle_seconds_ = 300;
38 // static
39 bool NetworkStats::start_test_after_connect_ = true;
40 
41 // Specify the possible choices of probe packet sizes.
42 const uint32 kProbePacketBytes[] = {100, 500, 1200};
43 const uint32 kPacketSizeChoices = arraysize(kProbePacketBytes);
44 
45 // List of ports used for probing test.
46 const 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.
51 const uint32 kCorrelatedLossPacketCount = 6;
52 
53 // This specifies the maximum message (payload) size of one packet.
54 const uint32 kMaxMessageSize = 1600;
55 
56 // This specifies the maximum udp receiver buffer size.
57 const uint32 kMaxUdpReceiveBufferSize = 63000;
58 
59 // This specifies the maximum udp receiver buffer size.
60 const uint32 kMaxUdpSendBufferSize = 4096;
61 
62 // This should match TestType except for the last one.
63 const 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.
68 const uint32 kMinimumReceivedPacketsForPacingTest = 2;
69 // Perform NAT binding test only if at least 10 packets are received.
70 const uint32 kMinimumReceivedPacketsForNATTest = 10;
71 
72 // Maximum inter-packet pacing interval in microseconds.
73 const uint32 kMaximumPacingMicros = 1000000;
74 // Timeout value for getting the token.
75 const 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.
79 const 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.
82 const uint32 kReadNATTimeoutSeconds = 10;
83 // This is the timeout for PACKET_SIZE_TEST.
84 const uint32 kReadPacketSizeTimeoutSeconds = 10;
85 // This is the maxmium number of packets we would send for PACKET_SIZE_TEST.
86 uint32 kMaximumPacketSizeTestPackets = 1;
87 
88 // These helper functions are similar to UMA_HISTOGRAM_XXX except that they do
89 // not create a static histogram_pointer.
DynamicHistogramEnumeration(const std::string & name,uint32 sample,uint32 boundary_value)90 void 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 
DynamicHistogramTimes(const std::string & name,const base::TimeDelta & sample)102 void 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 
DynamicHistogramCounts(const std::string & name,uint32 sample,uint32 min,uint32 max,uint32 bucket_count)113 void 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 
NetworkStats(net::ClientSocketFactory * socket_factory)124 NetworkStats::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 
~NetworkStats()137 NetworkStats::~NetworkStats() {}
138 
Start(net::HostResolver * host_resolver,const net::HostPortPair & server_host_port_pair,uint16 histogram_port,bool has_proxy_server,uint32 probe_bytes,uint32 bytes_for_packet_size_test,const net::CompletionCallback & finished_callback)139 bool 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 
StartOneTest()174 void 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 
ResetData()184 void 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 
DoConnect(int result)198 bool 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 
ConnectComplete(int result)226 bool 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 
SendHelloRequest()247 void 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 
SendProbeRequest()259 void 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 
ReadData()315 int 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   while (true) {
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     if (rv <= 0)
332       break;
333     if (ReadComplete(rv))
334       return rv;
335   };
336   if (rv == net::ERR_IO_PENDING)
337     read_state_ = READ_STATE_READ_PENDING;
338   return rv;
339 }
340 
OnReadComplete(int result)341 void NetworkStats::OnReadComplete(int result) {
342   DCHECK_NE(net::ERR_IO_PENDING, result);
343   DCHECK_EQ(READ_STATE_READ_PENDING, read_state_);
344 
345   read_state_ = READ_STATE_IDLE;
346   if (!ReadComplete(result)) {
347     // Called ReadData() via PostDelayedTask() to avoid recursion. Added a delay
348     // of 1ms so that the time-out will fire before we have time to really hog
349     // the CPU too extensively (waiting for the time-out) in case of an infinite
350     // loop.
351     base::MessageLoop::current()->PostDelayedTask(
352         FROM_HERE,
353         base::Bind(base::IgnoreResult(&NetworkStats::ReadData),
354                    weak_factory_.GetWeakPtr()),
355         base::TimeDelta::FromMilliseconds(1));
356   }
357 }
358 
ReadComplete(int result)359 bool NetworkStats::ReadComplete(int result) {
360   DCHECK(socket_.get());
361   DCHECK_NE(net::ERR_IO_PENDING, result);
362   if (result < 0) {
363     // Something is wrong, finish the test.
364     read_buffer_ = NULL;
365     TestPhaseComplete(READ_FAILED, result);
366     return true;
367   }
368 
369   std::string encoded_message(read_buffer_->data(),
370                               read_buffer_->data() + result);
371   read_buffer_ = NULL;
372   ProbePacket probe_packet;
373   if (!probe_message_.ParseInput(encoded_message, &probe_packet))
374     return false;
375   // Discard if the packet is for a different test.
376   if (probe_packet.group_id() != current_test_index_)
377     return false;
378 
379   // Whether all packets in the current test have been received.
380   bool current_test_complete = false;
381   switch (probe_packet.header().type()) {
382     case ProbePacket_Type_HELLO_REPLY:
383       token_ = probe_packet.token();
384       if (current_test_index_ == 0)
385         test_sequence_.push_back(START_PACKET_TEST);
386       current_test_complete = true;
387       break;
388     case ProbePacket_Type_PROBE_REPLY:
389       current_test_complete = UpdateReception(probe_packet);
390       break;
391     default:
392       DVLOG(1) << "Received unexpected packet type: "
393                << probe_packet.header().type();
394   }
395 
396   if (!current_test_complete) {
397     // All packets have not been received for the current test.
398     return false;
399   }
400   // All packets are received for the current test.
401   // Read completes if all tests are done (if TestPhaseComplete didn't start
402   // another test).
403   return TestPhaseComplete(SUCCESS, net::OK);
404 }
405 
UpdateReception(const ProbePacket & probe_packet)406 bool NetworkStats::UpdateReception(const ProbePacket& probe_packet) {
407   uint32 packet_index = probe_packet.packet_index();
408   if (packet_index >= packet_rtt_.size())
409     return false;
410   packets_received_mask_.set(packet_index);
411   TestType test_type = test_sequence_[current_test_index_];
412   uint32 received_packets = packets_received_mask_.count();
413 
414   // Now() has resolution ~1-15ms. HighResNow() has high resolution but it
415   // is warned not to use it unless necessary.
416   base::TimeTicks current_time = base::TimeTicks::Now();
417   last_arrival_time_ = current_time;
418   if (first_arrival_time_.is_null())
419     first_arrival_time_ = current_time;
420 
421   // Need to do this after updating the last_arrival_time_ since NAT_BIND_TEST
422   // and PACKET_SIZE_TEST record the SendToLastRecvDelay.
423   if (test_type == NAT_BIND_TEST) {
424     return received_packets >= maximum_NAT_packets_;
425   }
426   if (test_type == PACKET_SIZE_TEST) {
427     return received_packets >= kMaximumPacketSizeTestPackets;
428   }
429 
430   base::TimeDelta rtt =
431       current_time - probe_request_time_ -
432       base::TimeDelta::FromMicroseconds(std::max(
433           static_cast<int64>(0), probe_packet.server_processing_micros()));
434   base::TimeDelta min_rtt = base::TimeDelta::FromMicroseconds(1L);
435   packet_rtt_[packet_index] = (rtt >= min_rtt) ? rtt : min_rtt;
436 
437   if (received_packets < maximum_sequential_packets_)
438     return false;
439   // All packets in the current test are received.
440   inter_arrival_time_ = (last_arrival_time_ - first_arrival_time_) /
441       std::max(1U, (received_packets - 1));
442   if (test_type == START_PACKET_TEST) {
443     test_sequence_.push_back(PACKET_SIZE_TEST);
444     test_sequence_.push_back(TOKEN_REQUEST);
445     // No need to add TOKEN_REQUEST here when all packets are received.
446     test_sequence_.push_back(base::RandInt(0, 1) ? PACED_PACKET_TEST
447                                                  : NON_PACED_PACKET_TEST);
448     test_sequence_.push_back(TOKEN_REQUEST);
449     test_sequence_.push_back(NAT_BIND_TEST);
450     test_sequence_.push_back(TOKEN_REQUEST);
451   }
452   return true;
453 }
454 
SendData(const std::string & output)455 int NetworkStats::SendData(const std::string& output) {
456   if (write_buffer_.get() || !socket_.get() ||
457       write_state_ == WRITE_STATE_WRITE_PENDING) {
458     return net::ERR_UNEXPECTED;
459   }
460   scoped_refptr<net::StringIOBuffer> buffer(new net::StringIOBuffer(output));
461   write_buffer_ = new net::DrainableIOBuffer(buffer.get(), buffer->size());
462 
463   int bytes_written = socket_->Write(
464       write_buffer_.get(),
465       write_buffer_->BytesRemaining(),
466       base::Bind(&NetworkStats::OnWriteComplete, weak_factory_.GetWeakPtr()));
467   if (bytes_written < 0) {
468     if (bytes_written == net::ERR_IO_PENDING)
469       write_state_ = WRITE_STATE_WRITE_PENDING;
470     return bytes_written;
471   }
472   UpdateSendBuffer(bytes_written);
473   return net::OK;
474 }
475 
OnWriteComplete(int result)476 void NetworkStats::OnWriteComplete(int result) {
477   DCHECK_NE(net::ERR_IO_PENDING, result);
478   DCHECK_EQ(WRITE_STATE_WRITE_PENDING, write_state_);
479   write_state_ = WRITE_STATE_IDLE;
480   if (result < 0 || !socket_.get() || write_buffer_ == NULL) {
481     TestPhaseComplete(WRITE_FAILED, result);
482     return;
483   }
484   UpdateSendBuffer(result);
485 }
486 
UpdateSendBuffer(int bytes_sent)487 void NetworkStats::UpdateSendBuffer(int bytes_sent) {
488   write_buffer_->DidConsume(bytes_sent);
489   DCHECK_EQ(write_buffer_->BytesRemaining(), 0);
490   DCHECK_EQ(WRITE_STATE_IDLE, write_state_);
491   write_buffer_ = NULL;
492 }
493 
StartReadDataTimer(uint32 seconds,uint32 test_index)494 void NetworkStats::StartReadDataTimer(uint32 seconds, uint32 test_index) {
495   base::MessageLoop::current()->PostDelayedTask(
496       FROM_HERE,
497       base::Bind(&NetworkStats::OnReadDataTimeout,
498                  weak_factory_.GetWeakPtr(),
499                  test_index),
500       base::TimeDelta::FromSeconds(seconds));
501 }
502 
OnReadDataTimeout(uint32 test_index)503 void NetworkStats::OnReadDataTimeout(uint32 test_index) {
504   // If the current_test_index_ has changed since we set the timeout,
505   // the current test has been completed, so do nothing.
506   if (test_index != current_test_index_)
507     return;
508   // If test_type is TOKEN_REQUEST, it will do nothing but call
509   // TestPhaseComplete().
510   TestType test_type = test_sequence_[current_test_index_];
511 
512   uint32 received_packets = packets_received_mask_.count();
513   if (received_packets >= 2) {
514     inter_arrival_time_ =
515         (last_arrival_time_ - first_arrival_time_) / (received_packets - 1);
516   }
517   // Add other tests if this is START_PACKET_TEST.
518   if (test_type == START_PACKET_TEST) {
519     if (received_packets >= kMinimumReceivedPacketsForPacingTest) {
520       test_sequence_.push_back(TOKEN_REQUEST);
521       test_sequence_.push_back(PACKET_SIZE_TEST);
522       test_sequence_.push_back(TOKEN_REQUEST);
523       test_sequence_.push_back(base::RandInt(0, 1) ? PACED_PACKET_TEST
524                                                    : NON_PACED_PACKET_TEST);
525     }
526     if (received_packets >= kMinimumReceivedPacketsForNATTest) {
527       test_sequence_.push_back(TOKEN_REQUEST);
528       test_sequence_.push_back(NAT_BIND_TEST);
529       test_sequence_.push_back(TOKEN_REQUEST);
530     }
531   }
532   TestPhaseComplete(READ_TIMED_OUT, net::ERR_FAILED);
533 }
534 
TestPhaseComplete(Status status,int result)535 bool NetworkStats::TestPhaseComplete(Status status, int result) {
536   // If there is no valid token, do nothing and delete self.
537   // This includes all connection error, name resolve error, etc.
538   if (write_state_ == WRITE_STATE_WRITE_PENDING) {
539     UMA_HISTOGRAM_BOOLEAN("NetConnectivity5.TestFailed.WritePending", true);
540   } else if (status == SUCCESS || status == READ_TIMED_OUT) {
541     TestType current_test = test_sequence_[current_test_index_];
542     DCHECK_LT(current_test, TEST_TYPE_MAX);
543     if (current_test != TOKEN_REQUEST) {
544       RecordHistograms(current_test);
545     } else if (current_test_index_ > 0) {
546       if (test_sequence_[current_test_index_ - 1] == NAT_BIND_TEST) {
547         // We record the NATTestReceivedHistograms after the succeeding
548         // TokenRequest.
549         RecordNATTestReceivedHistograms(status);
550       } else if (test_sequence_[current_test_index_ - 1] == PACKET_SIZE_TEST) {
551         // We record the PacketSizeTestReceivedHistograms after the succeeding
552         // TokenRequest.
553         RecordPacketSizeTestReceivedHistograms(status);
554       }
555     }
556 
557     // Move to the next test.
558     current_test = GetNextTest();
559     if (current_test_index_ <= maximum_tests_ && current_test < TEST_TYPE_MAX) {
560       DVLOG(1) << "NetworkStat: Start Probe test: " << current_test;
561       base::MessageLoop::current()->PostTask(
562           FROM_HERE,
563           base::Bind(&NetworkStats::StartOneTest, weak_factory_.GetWeakPtr()));
564       return false;
565     }
566   }
567 
568   // All tests are done.
569   DoFinishCallback(result);
570 
571   // Close the socket so that there are no more IO operations.
572   if (socket_.get())
573     socket_->Close();
574 
575   DVLOG(1) << "NetworkStat: schedule delete self at test index "
576            << current_test_index_;
577   delete this;
578   return true;
579 }
580 
GetNextTest()581 NetworkStats::TestType NetworkStats::GetNextTest() {
582   ++current_test_index_;
583   if (current_test_index_ >= test_sequence_.size())
584     return TEST_TYPE_MAX;
585   return test_sequence_[current_test_index_];
586 }
587 
DoFinishCallback(int result)588 void NetworkStats::DoFinishCallback(int result) {
589   if (!finished_callback_.is_null()) {
590     net::CompletionCallback callback = finished_callback_;
591     finished_callback_.Reset();
592     callback.Run(result);
593   }
594 }
595 
RecordHistograms(TestType test_type)596 void NetworkStats::RecordHistograms(TestType test_type) {
597   switch (test_type) {
598     case START_PACKET_TEST:
599     case NON_PACED_PACKET_TEST:
600     case PACED_PACKET_TEST: {
601       RecordInterArrivalHistograms(test_type);
602       RecordPacketLossSeriesHistograms(test_type);
603       RecordPacketsReceivedHistograms(test_type);
604       // Only record RTT for these packet indices.
605       uint32 rtt_indices[] = {0, 1, 2, 9, 19};
606       for (uint32 i = 0; i < arraysize(rtt_indices); ++i) {
607         if (rtt_indices[i] < packet_rtt_.size())
608           RecordRTTHistograms(test_type, rtt_indices[i]);
609       }
610       RecordSendToLastRecvDelayHistograms(test_type);
611       return;
612     }
613     case NAT_BIND_TEST:
614       RecordSendToLastRecvDelayHistograms(test_type);
615       return;
616     case PACKET_SIZE_TEST:
617       // No need to record RTT for PacketSizeTest.
618       return;
619     default:
620       DVLOG(1) << "Unexpected test type " << test_type
621                << " in RecordHistograms.";
622   }
623 }
624 
RecordInterArrivalHistograms(TestType test_type)625 void NetworkStats::RecordInterArrivalHistograms(TestType test_type) {
626   DCHECK_NE(test_type, PACKET_SIZE_TEST);
627   std::string histogram_name =
628       base::StringPrintf("NetConnectivity5.%s.Sent%d.PacketDelay.%d.%dB",
629                          kTestName[test_type],
630                          maximum_sequential_packets_,
631                          histogram_port_,
632                          probe_packet_bytes_);
633   // Record the time normalized to 20 packet inter-arrivals.
634   DynamicHistogramTimes(histogram_name, inter_arrival_time_ * 20);
635 }
636 
RecordPacketsReceivedHistograms(TestType test_type)637 void NetworkStats::RecordPacketsReceivedHistograms(TestType test_type) {
638   DCHECK_NE(test_type, PACKET_SIZE_TEST);
639   const char* test_name = kTestName[test_type];
640   std::string histogram_prefix = base::StringPrintf(
641       "NetConnectivity5.%s.Sent%d.", test_name, maximum_sequential_packets_);
642   std::string histogram_suffix =
643       base::StringPrintf(".%d.%dB", histogram_port_, probe_packet_bytes_);
644   std::string name = histogram_prefix + "GotAPacket" + histogram_suffix;
645   base::HistogramBase* histogram_pointer = base::BooleanHistogram::FactoryGet(
646       name, base::HistogramBase::kUmaTargetedHistogramFlag);
647   histogram_pointer->Add(packets_received_mask_.any());
648 
649   DynamicHistogramEnumeration(
650       histogram_prefix + "PacketsRecv" + histogram_suffix,
651       packets_received_mask_.count(),
652       maximum_sequential_packets_ + 1);
653 
654   if (!packets_received_mask_.any())
655     return;
656 
657   base::HistogramBase* received_nth_packet_histogram =
658       base::Histogram::FactoryGet(
659           histogram_prefix + "RecvNthPacket" + histogram_suffix,
660           1,
661           maximum_sequential_packets_ + 1,
662           maximum_sequential_packets_ + 2,
663           base::HistogramBase::kUmaTargetedHistogramFlag);
664 
665   int count = 0;
666   for (size_t j = 0; j < maximum_sequential_packets_; ++j) {
667     int packet_number = j + 1;
668     if (packets_received_mask_.test(j)) {
669       received_nth_packet_histogram->Add(packet_number);
670       ++count;
671     }
672     std::string histogram_name =
673         base::StringPrintf("%sNumRecvFromFirst%02dPackets%s",
674                            histogram_prefix.c_str(),
675                            packet_number,
676                            histogram_suffix.c_str());
677     DynamicHistogramEnumeration(histogram_name, count, packet_number + 1);
678   }
679 }
680 
RecordNATTestReceivedHistograms(Status status)681 void NetworkStats::RecordNATTestReceivedHistograms(Status status) {
682   const char* test_name = kTestName[NAT_BIND_TEST];
683   bool test_result = status == SUCCESS;
684   std::string middle_name = test_result ? "Connectivity.Success"
685                                         : "Connectivity.Failure";
686   // Record whether the HelloRequest got reply successfully.
687   std::string histogram_name =
688       base::StringPrintf("NetConnectivity5.%s.Sent%d.%s.%d.%dB",
689                          test_name,
690                          maximum_NAT_packets_,
691                          middle_name.c_str(),
692                          histogram_port_,
693                          probe_packet_bytes_);
694   uint32 bucket_count = std::min(maximum_NAT_idle_seconds_ + 2, 50U);
695   DynamicHistogramCounts(histogram_name,
696                          pacing_interval_.InSeconds(),
697                          1,
698                          maximum_NAT_idle_seconds_ + 1,
699                          bucket_count);
700 
701   // Record the NAT bind result only if the HelloRequest successfully got the
702   // token and the first NAT test packet is received.
703   if (!test_result || !packets_received_mask_.test(0))
704     return;
705 
706   middle_name = packets_received_mask_.test(1) ? "Bind.Success"
707                                                : "Bind.Failure";
708   histogram_name = base::StringPrintf("NetConnectivity5.%s.Sent%d.%s.%d.%dB",
709                                       test_name,
710                                       maximum_NAT_packets_,
711                                       middle_name.c_str(),
712                                       histogram_port_,
713                                       probe_packet_bytes_);
714   DynamicHistogramCounts(histogram_name,
715                          pacing_interval_.InSeconds(),
716                          1,
717                          maximum_NAT_idle_seconds_ + 1,
718                          bucket_count);
719 }
720 
RecordPacketSizeTestReceivedHistograms(Status status)721 void NetworkStats::RecordPacketSizeTestReceivedHistograms(Status status) {
722   const char* test_name = kTestName[PACKET_SIZE_TEST];
723   bool test_result = (status == SUCCESS && packets_received_mask_.test(0));
724   std::string middle_name = test_result ? "Connectivity.Success"
725                                         : "Connectivity.Failure";
726   // Record whether the HelloRequest got reply successfully.
727   std::string histogram_name =
728       base::StringPrintf("NetConnectivity5.%s.%s.%d",
729                          test_name,
730                          middle_name.c_str(),
731                          histogram_port_);
732   base::HistogramBase* histogram_pointer = base::LinearHistogram::FactoryGet(
733       histogram_name, kProbePacketBytes[kPacketSizeChoices - 1],
734       ProbeMessage::kMaxProbePacketBytes, 60,
735       base::HistogramBase::kUmaTargetedHistogramFlag);
736   histogram_pointer->Add(bytes_for_packet_size_test_);
737 }
738 
RecordPacketLossSeriesHistograms(TestType test_type)739 void NetworkStats::RecordPacketLossSeriesHistograms(TestType test_type) {
740   DCHECK_NE(test_type, PACKET_SIZE_TEST);
741   const char* test_name = kTestName[test_type];
742   // Build "NetConnectivity5.<TestName>.First6.SeriesRecv.<port>.<probe_size>"
743   // histogram name. Total 3(tests) x 12 histograms.
744   std::string series_acked_histogram_name =
745       base::StringPrintf("NetConnectivity5.%s.First6.SeriesRecv.%d.%dB",
746                          test_name,
747                          histogram_port_,
748                          probe_packet_bytes_);
749   uint32 histogram_boundary = 1 << kCorrelatedLossPacketCount;
750   uint32 correlated_packet_mask =
751       (histogram_boundary - 1) & packets_received_mask_.to_ulong();
752   DynamicHistogramEnumeration(
753       series_acked_histogram_name, correlated_packet_mask, histogram_boundary);
754 
755   // If we are running without a proxy, we'll generate an extra histogram with
756   // the ".NoProxy" suffix.
757   if (!has_proxy_server_) {
758     series_acked_histogram_name.append(".NoProxy");
759     DynamicHistogramEnumeration(series_acked_histogram_name,
760                                 correlated_packet_mask,
761                                 histogram_boundary);
762   }
763 }
764 
RecordRTTHistograms(TestType test_type,uint32 index)765 void NetworkStats::RecordRTTHistograms(TestType test_type, uint32 index) {
766   DCHECK_NE(test_type, PACKET_SIZE_TEST);
767   DCHECK_LT(index, packet_rtt_.size());
768 
769   if (!packets_received_mask_.test(index))
770     return;  // Probe packet never received.
771 
772   std::string rtt_histogram_name = base::StringPrintf(
773       "NetConnectivity5.%s.Sent%d.Success.RTT.Packet%02d.%d.%dB",
774       kTestName[test_type],
775       maximum_sequential_packets_,
776       index + 1,
777       histogram_port_,
778       probe_packet_bytes_);
779   DynamicHistogramTimes(rtt_histogram_name, packet_rtt_[index]);
780 }
781 
RecordSendToLastRecvDelayHistograms(TestType test_type)782 void NetworkStats::RecordSendToLastRecvDelayHistograms(TestType test_type) {
783   DCHECK_NE(test_type, PACKET_SIZE_TEST);
784   if (packets_received_mask_.count() < 2)
785     return;  // Too few packets are received.
786   uint32 packets_sent = test_type == NAT_BIND_TEST
787       ? maximum_NAT_packets_ : maximum_sequential_packets_;
788   std::string histogram_name = base::StringPrintf(
789       "NetConnectivity5.%s.Sent%d.SendToLastRecvDelay.%d.%dB",
790       kTestName[test_type],
791       packets_sent,
792       histogram_port_,
793       probe_packet_bytes_);
794   base::TimeDelta send_to_last_recv_time =
795       std::max(last_arrival_time_ - probe_request_time_ -
796                    pacing_interval_ * (packets_sent - 1),
797                base::TimeDelta::FromMilliseconds(0));
798   DynamicHistogramTimes(histogram_name, send_to_last_recv_time);
799 }
800 
801 // ProxyDetector methods and members.
ProxyDetector(net::ProxyService * proxy_service,const net::HostPortPair & server_address,OnResolvedCallback callback)802 ProxyDetector::ProxyDetector(net::ProxyService* proxy_service,
803                              const net::HostPortPair& server_address,
804                              OnResolvedCallback callback)
805     : proxy_service_(proxy_service),
806       server_address_(server_address),
807       callback_(callback),
808       has_pending_proxy_resolution_(false) {}
809 
~ProxyDetector()810 ProxyDetector::~ProxyDetector() {
811   CHECK(!has_pending_proxy_resolution_);
812 }
813 
StartResolveProxy()814 void ProxyDetector::StartResolveProxy() {
815   std::string url =
816       base::StringPrintf("https://%s", server_address_.ToString().c_str());
817   GURL gurl(url);
818 
819   has_pending_proxy_resolution_ = true;
820   DCHECK(proxy_service_);
821   int rv = proxy_service_->ResolveProxy(
822       gurl,
823       &proxy_info_,
824       base::Bind(&ProxyDetector::OnResolveProxyComplete,
825                  base::Unretained(this)),
826       NULL,
827       net::BoundNetLog());
828   if (rv != net::ERR_IO_PENDING)
829     OnResolveProxyComplete(rv);
830 }
831 
OnResolveProxyComplete(int result)832 void ProxyDetector::OnResolveProxyComplete(int result) {
833   has_pending_proxy_resolution_ = false;
834   bool has_proxy_server =
835       (result == net::OK && proxy_info_.proxy_server().is_valid() &&
836        !proxy_info_.proxy_server().is_direct());
837 
838   OnResolvedCallback callback = callback_;
839   BrowserThread::PostTask(
840       BrowserThread::IO, FROM_HERE, base::Bind(callback, has_proxy_server));
841 
842   // TODO(rtenneti): Will we leak if ProxyResolve is cancelled (or proxy
843   // resolution never completes).
844   delete this;
845 }
846 
CollectNetworkStats(const std::string & network_stats_server,IOThread * io_thread)847 void CollectNetworkStats(const std::string& network_stats_server,
848                          IOThread* io_thread) {
849   if (network_stats_server.empty())
850     return;
851 
852   // If we are not on IO Thread, then post a task to call CollectNetworkStats on
853   // IO Thread.
854   if (!BrowserThread::CurrentlyOn(BrowserThread::IO)) {
855     BrowserThread::PostTask(
856         BrowserThread::IO,
857         FROM_HERE,
858         base::Bind(&CollectNetworkStats, network_stats_server, io_thread));
859     return;
860   }
861 
862   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
863 
864   if (net::NetworkChangeNotifier::IsOffline()) {
865     return;
866   }
867 
868   CR_DEFINE_STATIC_LOCAL(scoped_refptr<base::FieldTrial>, trial, ());
869   static bool collect_stats = false;
870 
871   if (!trial.get()) {
872     // Set up a field trial to collect network stats for UDP.
873     const base::FieldTrial::Probability kDivisor = 1000;
874 
875     // Enable the connectivity testing for 0.5% of the users in stable channel.
876     base::FieldTrial::Probability probability_per_group = kDivisor / 200;
877 
878     chrome::VersionInfo::Channel channel = chrome::VersionInfo::GetChannel();
879     if (channel == chrome::VersionInfo::CHANNEL_CANARY) {
880       // Enable the connectivity testing for 50% of the users in canary channel.
881       probability_per_group = kDivisor / 2;
882     } else if (channel == chrome::VersionInfo::CHANNEL_DEV) {
883       // Enable the connectivity testing for 10% of the users in dev channel.
884       probability_per_group = kDivisor / 10;
885     } else if (channel == chrome::VersionInfo::CHANNEL_BETA) {
886       // Enable the connectivity testing for 1% of the users in beta channel.
887       probability_per_group = kDivisor / 100;
888     }
889 
890     // After July 31, 2014 builds, it will always be in default group
891     // (disable_network_stats).
892     trial = base::FieldTrialList::FactoryGetFieldTrial(
893         "NetworkConnectivity", kDivisor, "disable_network_stats",
894         2014, 7, 31, base::FieldTrial::SESSION_RANDOMIZED, NULL);
895 
896     // Add option to collect_stats for NetworkConnectivity.
897     int collect_stats_group =
898         trial->AppendGroup("collect_stats", probability_per_group);
899     if (trial->group() == collect_stats_group)
900       collect_stats = true;
901   }
902 
903   if (!collect_stats)
904     return;
905 
906   // Run test kMaxNumberOfTests times.
907   const size_t kMaxNumberOfTests = INT_MAX;
908   static size_t number_of_tests_done = 0;
909   if (number_of_tests_done > kMaxNumberOfTests)
910     return;
911   ++number_of_tests_done;
912 
913   net::HostResolver* host_resolver = io_thread->globals()->host_resolver.get();
914   DCHECK(host_resolver);
915 
916   uint32 port_index = base::RandInt(0, arraysize(kPorts) - 1);
917   uint16 histogram_port = kPorts[port_index];
918   net::HostPortPair server_address(network_stats_server, histogram_port);
919 
920   net::ProxyService* proxy_service =
921       io_thread->globals()->system_proxy_service.get();
922   DCHECK(proxy_service);
923 
924   ProxyDetector::OnResolvedCallback callback = base::Bind(
925       &StartNetworkStatsTest, host_resolver, server_address, histogram_port);
926 
927   ProxyDetector* proxy_client =
928       new ProxyDetector(proxy_service, server_address, callback);
929   proxy_client->StartResolveProxy();
930 }
931 
StartNetworkStatsTest(net::HostResolver * host_resolver,const net::HostPortPair & server_address,uint16 histogram_port,bool has_proxy_server)932 void StartNetworkStatsTest(net::HostResolver* host_resolver,
933                            const net::HostPortPair& server_address,
934                            uint16 histogram_port,
935                            bool has_proxy_server) {
936   int probe_choice = base::RandInt(0, kPacketSizeChoices - 1);
937 
938   DCHECK_LE(ProbeMessage::kMaxProbePacketBytes, kMaxMessageSize);
939   // Pick a packet size between 1200 and kMaxProbePacketBytes bytes.
940   uint32 bytes_for_packet_size_test =
941       base::RandInt(kProbePacketBytes[kPacketSizeChoices - 1],
942                     ProbeMessage::kMaxProbePacketBytes);
943 
944   // |udp_stats_client| is owned and deleted in the class NetworkStats.
945   NetworkStats* udp_stats_client =
946       new NetworkStats(net::ClientSocketFactory::GetDefaultFactory());
947   udp_stats_client->Start(host_resolver,
948                           server_address,
949                           histogram_port,
950                           has_proxy_server,
951                           kProbePacketBytes[probe_choice],
952                           bytes_for_packet_size_test,
953                           net::CompletionCallback());
954 }
955 
956 }  // namespace chrome_browser_net
957