• 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 #ifndef CHROME_BROWSER_NET_NETWORK_STATS_H_
6 #define CHROME_BROWSER_NET_NETWORK_STATS_H_
7 
8 #include <bitset>
9 #include <string>
10 #include <vector>
11 
12 #include "base/memory/scoped_ptr.h"
13 #include "base/metrics/histogram.h"
14 #include "base/time/time.h"
15 #include "chrome/browser/io_thread.h"
16 #include "chrome/browser/net/probe_message.h"
17 #include "net/base/address_list.h"
18 #include "net/base/completion_callback.h"
19 #include "net/base/host_port_pair.h"
20 #include "net/base/io_buffer.h"
21 #include "net/proxy/proxy_info.h"
22 
23 namespace net {
24 class ClientSocketFactory;
25 class DatagramClientSocket;
26 class HostResolver;
27 class SingleRequestHostResolver;
28 }
29 
30 namespace chrome_browser_net {
31 
32 // This class is used for live experiment of network connectivity (for UDP)
33 // metrics. A small percentage of users participate in this experiment. All
34 // users (who are in the experiment) must have enabled "UMA upload".
35 // In the experiments, clients request the server to send some probing packets,
36 // collect some stats, and send back the results via UMA reports.
37 //
38 // This class collects the following stats from users who have opted in.
39 // a) RTT.
40 // b) packet inter-arrival time.
41 // c) packet losses for correlation and FEC experiments.
42 // d) packet losses for NAT binding test after idling for a certain period.
43 //
44 // There are three tests in one experiment. Right before each test, a
45 // HelloRequest is sent to get an updated token.
46 // 1. |START_PACKET_TEST|: 21 packets are sent from the server to the client
47 //    without pacing.
48 // 2. |PACED_PACKET_TEST| or |NON_PACED_PACKET_TEST|: After the first test,
49 //    21 packets are sent from the server to the client with or without pacing.
50 //    If pacing, the pacing rate is computed from the first test.
51 // 3. |NAT_BIND_TEST|: 2 packets are sent from the server to the client with
52 //    a randomly generated delay of 1~300 seconds.
53 // At the end of these tests, we send another HelloRequest to test whether
54 // the network is still connected and has not changed (e.g. from Wifi to 3g).
55 
56 class NetworkStats {
57  public:
58   enum Status {            // Used in HISTOGRAM_ENUMERATION.
59     SUCCESS,               // Successfully received bytes from the server.
60     SOCKET_CREATE_FAILED,  // Socket creation failed.
61     RESOLVE_FAILED,        // Host resolution failed.
62     CONNECT_FAILED,        // Connection to the server failed.
63     WRITE_FAILED,          // Sending a message to the server failed.
64     READ_TIMED_OUT,        // Reading the reply from the server timed out.
65     READ_FAILED,           // Reading the reply from the server failed.
66     STATUS_MAX,            // Bounding value.
67   };
68 
69   enum ReadState {         // Used to track if |socket_| has a pending read.
70     READ_STATE_IDLE,
71     READ_STATE_READ_PENDING,
72   };
73 
74   enum WriteState {        // Used to track if |socket_| has a pending write.
75     WRITE_STATE_IDLE,
76     WRITE_STATE_WRITE_PENDING,
77   };
78 
79   // |TestType| specifies the possible tests we may run
80   // (except for the first and the last serving as boundaries).
81   enum TestType {
82     // The first one is for requesting token, not a probe test. Put it here
83     // because we use it as a symbol for sending the HelloRequest packet to
84     // acquire the token.
85     TOKEN_REQUEST,
86     START_PACKET_TEST,      // First packet loss test (no pacing).
87     NON_PACED_PACKET_TEST,  // Packet loss test with no pacing.
88     PACED_PACKET_TEST,      // Packet loss test with pacing.
89     // Test whether NAT binding expires after some idle period.
90     NAT_BIND_TEST,
91     PACKET_SIZE_TEST,
92     TEST_TYPE_MAX,
93   };
94 
95   // Pointer |socket_factory| is NOT deleted by this class.
96   explicit NetworkStats(net::ClientSocketFactory* socket_factory);
97   // NetworkStats is deleted in TestPhaseComplete() when all tests are done.
98   ~NetworkStats();
99 
100   // Start the client and connect to |server|.
101   // A client will request a token and then perform several tests.
102   // When the client finishes all tests, or when an error occurs causing the
103   // client to stop, |TestPhaseComplete| will be called with a net status code.
104   // |TestPhaseComplete| will collect histogram stats.
105   // Return true if successful in starting the client.
106   bool Start(net::HostResolver* host_resolver,
107              const net::HostPortPair& server,
108              uint16 histogram_port,
109              bool has_proxy_server,
110              uint32 probe_bytes,
111              uint32 bytes_for_packet_size_test,
112              const net::CompletionCallback& callback);
113 
114  private:
115   friend class NetworkStatsTest;
116 
117   // Start the test specified by the current_test_index_. It also resets all
118   // the book keeping data, before starting the new test.
119   void StartOneTest();
120 
121   // Reset all the counters and the collected stats.
122   void ResetData();
123 
124   // Callback that is called when host resolution is completed.
125   void OnResolveComplete(int result);
126 
127   // Called after host is resolved. Creates UDPClientSocket and connects to the
128   // server. If successfully connected, then calls ConnectComplete() to start
129   // the network connectivity tests. Returns |false| if there is any error.
130   bool DoConnect(int result);
131 
132   // This method is called after socket connection is completed. It will start
133   // the process of sending packets to |server| by calling SendHelloPacket().
134   // Return false if connection is not established (result is less than 0).
135   bool ConnectComplete(int result);
136 
137   // Send a HelloRequest packet which asks for a token from the server. If
138   // a token is received, it will will add |START_PACKET_TEST| to the test
139   // queue.
140   void SendHelloRequest();
141 
142   // Send a ProbeRequest packet which requests the server to send a set
143   // of Probing packets.
144   void SendProbeRequest();
145 
146   // Read and process the data. Called from OnReadComplete() or ReadData().
147   // This function calls TestPhaseComplete() if there is a significant network
148   // error or if all packets in the current test are received.
149   // Return true if TestPhaseComplete() is called otherwise return false.
150   bool ReadComplete(int result);
151 
152   // Callbacks when an internal IO (Read or Write) is completed.
153   void OnReadComplete(int result);
154   void OnWriteComplete(int result);
155 
156   // Read data from server until an error or IO blocking occurs or reading is
157   // complete. Return the result value from socket reading and 0 if |socket_|
158   // is Null.
159   int ReadData();
160 
161   // Send data contained in |str| to server.
162   // Return a negative value if IO blocking occurs or there is an error.
163   // Otherwise return net::OK.
164   int SendData(const std::string& str);
165 
166   // Update the send buffer (telling it that |bytes_sent| has been sent).
167   // And reset |write_buffer_|.
168   void UpdateSendBuffer(int bytes_sent);
169 
170   // Start a timer (with value |milliseconds|) for responses from the probe
171   // servers.  |test_index| is the index of the test at vector |test_sequence_|
172   // and it is used as a parameter of the timer callback.
173   void StartReadDataTimer(uint32 milliseconds, uint32 test_index);
174 
175   // Called when the StartReadDataTimer fires. |test_index| specifies
176   // the index of the test. If |current_test_index_| has changed to a
177   // different value, it indicates |test_index| has completed, then
178   // this method is a no-op.
179   void OnReadDataTimeout(uint32 test_index);
180 
181   // Collect network connectivity stats. This is called when all the data from
182   // server is read or when there is a failure during connect/read/write. It
183   // will either start the next phase of the test, or it will self destruct
184   // at the end of this method.
185   void TestPhaseComplete(Status status, int result);
186 
187   // This method is called from TestPhaseComplete() and calls
188   // |finished_callback_| callback to indicate that the test has finished.
189   void DoFinishCallback(int result);
190 
191   // Update counters/metrics for the given |probe_packet|.
192   // Return true if all packets for the current test are received and
193   // false otherwise.
194   bool UpdateReception(const ProbePacket& probe_packet);
195 
196   // Record all histograms for current test phase, which is assumed to be
197   // complete (i.e., we are no longer waiting for packets in this phase).
198   // |test_type| is the current test_type to be recorded. |status| is the
199   // status of the current test.
200   void RecordHistograms(TestType test_type);
201 
202   // Collect the following network connectivity stats when
203   // kMaximumSequentialPackets (21) packets are sent from the server.
204   // a) Client received at least one packet.
205   // b) Client received the nth packet.
206   // c) The number of packets received for each subsequence of packets 1...n.
207   void RecordPacketsReceivedHistograms(TestType test_type);
208 
209   // Collect the following network connectivity stats for the first
210   // kMaximumCorrelationPackets (6) packets in a test.
211   // Success/failure of each packet, to estimate reachability for users,
212   // and to estimate if there is a probabalistic dependency in packet loss when
213   // kMaximumCorrelationPackets packets are sent consecutively.
214   void RecordPacketLossSeriesHistograms(TestType test_type);
215 
216   // Collect the average inter-arrival time (scaled up by 20 times because the
217   // minimum time value in a histogram is 1ms) of a sequence of probing packets.
218   void RecordInterArrivalHistograms(TestType test_type);
219 
220   // Collect the RTT for the packet specified by the |index| in the current
221   // test.
222   void RecordRTTHistograms(TestType test_type, uint32 index);
223 
224   // Collect whether the second packet in the NAT test is received for the
225   // given idle time.
226   void RecordNATTestReceivedHistograms(Status status);
227 
228   // Collect whether we have the requested packet size was received or not in
229   // the PACKET_SIZE_TEST test.
230   void RecordPacketSizeTestReceivedHistograms(Status status);
231 
232   // Record the time duration between sending the probe request and receiving
233   // the last probe packet excluding the pacing time requested by the client.
234   // This applies to both NAT bind test and paced/non-paced packet test.
235   void RecordSendToLastRecvDelayHistograms(TestType test_type);
236 
237   // Return the next test type (internally increment |current_test_index_|)
238   // in |test_sequence_|;
239   TestType GetNextTest();
240 
241   // These static variables are defined so that they can be changed in testing.
242   // Maximum number of tests in one activation of the experiment.
243   static uint32 maximum_tests_;
244   // Maximum number of packets for START/PACED/NON_PACED tests.
245   static uint32 maximum_sequential_packets_;
246   // Maximum number of packets for NAT binding test.
247   static uint32 maximum_NAT_packets_;
248   // Maximum time duration between the two packets for NAT Bind testing.
249   static uint32 maximum_NAT_idle_seconds_;
250   // Whether to start the probe test immediately after connect success.
251   // Used for unittest.
252   static bool start_test_after_connect_;
253 
254   // The socket handler for this session.
255   scoped_ptr<net::DatagramClientSocket> socket_;
256 
257   net::ClientSocketFactory* socket_factory_;
258 
259   // The read buffer used to read data from the socket.
260   scoped_refptr<net::IOBuffer> read_buffer_;
261 
262   // The write buffer used to write data to the socket.
263   scoped_refptr<net::DrainableIOBuffer> write_buffer_;
264 
265   // Specify the port for which we are testing the network connectivity.
266   uint16 histogram_port_;
267 
268   // Specify if there is a proxy server or not.
269   bool has_proxy_server_;
270 
271   // HostResolver used to find the IP addresses.
272   scoped_ptr<net::SingleRequestHostResolver> resolver_;
273 
274   // Addresses filled out by HostResolver after host resolution is completed.
275   net::AddressList addresses_;
276 
277   // Callback to call when test is successefully finished or whenever
278   // there is an error (this will be used by unittests to check the result).
279   net::CompletionCallback finished_callback_;
280 
281   // RTTs for each packet.
282   std::vector<base::TimeDelta> packet_rtt_;
283 
284   // Time when sending probe_request, used for computing RTT.
285   base::TimeTicks probe_request_time_;
286 
287   // Size of the probe packets requested to be sent from servers. We don't use
288   // |probe_packet_bytes_| during PACKET_SIZE_TEST.
289   uint32 probe_packet_bytes_;
290 
291   // Size of the packet requested to be sent from servers for PACKET_SIZE_TEST.
292   uint32 bytes_for_packet_size_test_;
293 
294   // bitmask indicating which packets are received.
295   std::bitset<21> packets_received_mask_;
296 
297   // Arrival time of the first packet in the current test.
298   base::TimeTicks first_arrival_time_;
299   // Arrival time of the most recently received packet in the current test.
300   base::TimeTicks last_arrival_time_;
301   // Average time between two consecutive packets. It is updated when either all
302   // packets are received or timeout happens in the current test.
303   base::TimeDelta inter_arrival_time_;
304   // Target time duration for sending two consecutive packets at the server.
305   // It should be 0 for StartPacket test or NonPacedPacket test. For
306   // PacedPacket test, it is derived from the inter_arrival_time_ in the
307   // previous (StartPacket) test. For NATBind test, it is randomly generated
308   // between 1 second and |maximum_NAT_idle_seconds_| seconds.
309   base::TimeDelta pacing_interval_;
310   // A list of tests that will be performed in sequence.
311   std::vector<TestType> test_sequence_;
312   uint32 current_test_index_;  // Index of the current test.
313 
314   ProbeMessage probe_message_;
315 
316   // Token received from server for authentication.
317   ProbePacket_Token token_;
318 
319   // The state variables to track pending reads/writes.
320   ReadState read_state_;
321   WriteState write_state_;
322 
323   // We use this factory to create timeout tasks for socket's ReadData.
324   base::WeakPtrFactory<NetworkStats> weak_factory_;
325 
326   DISALLOW_COPY_AND_ASSIGN(NetworkStats);
327 };
328 
329 class ProxyDetector {
330  public:
331   // Used for the callback that is called from |OnResolveProxyComplete|.
332   typedef base::Callback<void(bool)> OnResolvedCallback;
333 
334   // Construct a ProxyDetector object that finds out if access to
335   // |server_address| goes through a proxy server or not. Calls the |callback|
336   // after proxy resolution is completed by currying the proxy resolution
337   // status.
338   ProxyDetector(net::ProxyService* proxy_service,
339                 const net::HostPortPair& server_address,
340                 OnResolvedCallback callback);
341 
342   // This method uses |proxy_service_| to resolve the proxy for
343   // |server_address_|.
344   void StartResolveProxy();
345 
346  private:
347   // This object is deleted from |OnResolveProxyComplete|.
348   ~ProxyDetector();
349 
350   // Call the |callback_| by currying the proxy resolution status.
351   void OnResolveProxyComplete(int result);
352 
353   // |proxy_service_| specifies the proxy service that is to be used to find
354   // if access to |server_address_| goes through proxy server or not.
355   net::ProxyService* proxy_service_;
356 
357   // |server_address_| specifies the server host and port pair for which we are
358   // trying to see if access to it, goes through proxy or not.
359   net::HostPortPair server_address_;
360 
361   // |callback_| will be called after proxy resolution is completed.
362   OnResolvedCallback callback_;
363 
364   // |proxy_info_| holds proxy information returned by ResolveProxy.
365   net::ProxyInfo proxy_info_;
366 
367   // Indicate if there is a pending a proxy resolution. We use this to assert
368   // that there is no in-progress proxy resolution request.
369   bool has_pending_proxy_resolution_;
370   DISALLOW_COPY_AND_ASSIGN(ProxyDetector);
371 };
372 
373 // This collects the network connectivity stats for UDP protocol for small
374 // percentage of users who are participating in the experiment (by enabling
375 // "UMA upload"). This method gets called only if UMA upload to the
376 // server has succeeded.
377 void CollectNetworkStats(const std::string& network_stats_server_url,
378                          IOThread* io_thread);
379 
380 // This starts a series of tests randomly selected among one of the three
381 // choices of probe packet sizes: 100 Bytes, 500 Bytes, 1200 Bytes.
382 void StartNetworkStatsTest(net::HostResolver* host_resolver,
383                            const net::HostPortPair& server_address,
384                            uint16 histogram_port,
385                            bool has_proxy_server);
386 
387 }  // namespace chrome_browser_net
388 
389 #endif  // CHROME_BROWSER_NET_NETWORK_STATS_H_
390