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
23namespace net {
24class ClientSocketFactory;
25class DatagramClientSocket;
26class HostResolver;
27class SingleRequestHostResolver;
28}
29
30namespace 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
56class NetworkStats {
57 public:
58  enum Status {            // Used in UMA_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. Returns true if a new test wasn't started and it
185  // was self destructed.
186  bool TestPhaseComplete(Status status, int result);
187
188  // This method is called from TestPhaseComplete() and calls
189  // |finished_callback_| callback to indicate that the test has finished.
190  void DoFinishCallback(int result);
191
192  // Update counters/metrics for the given |probe_packet|.
193  // Return true if all packets for the current test are received and
194  // false otherwise.
195  bool UpdateReception(const ProbePacket& probe_packet);
196
197  // Record all histograms for current test phase, which is assumed to be
198  // complete (i.e., we are no longer waiting for packets in this phase).
199  // |test_type| is the current test_type to be recorded. |status| is the
200  // status of the current test.
201  void RecordHistograms(TestType test_type);
202
203  // Collect the following network connectivity stats when
204  // kMaximumSequentialPackets (21) packets are sent from the server.
205  // a) Client received at least one packet.
206  // b) Client received the nth packet.
207  // c) The number of packets received for each subsequence of packets 1...n.
208  void RecordPacketsReceivedHistograms(TestType test_type);
209
210  // Collect the following network connectivity stats for the first
211  // kMaximumCorrelationPackets (6) packets in a test.
212  // Success/failure of each packet, to estimate reachability for users,
213  // and to estimate if there is a probabalistic dependency in packet loss when
214  // kMaximumCorrelationPackets packets are sent consecutively.
215  void RecordPacketLossSeriesHistograms(TestType test_type);
216
217  // Collect the average inter-arrival time (scaled up by 20 times because the
218  // minimum time value in a histogram is 1ms) of a sequence of probing packets.
219  void RecordInterArrivalHistograms(TestType test_type);
220
221  // Collect the RTT for the packet specified by the |index| in the current
222  // test.
223  void RecordRTTHistograms(TestType test_type, uint32 index);
224
225  // Collect whether the second packet in the NAT test is received for the
226  // given idle time.
227  void RecordNATTestReceivedHistograms(Status status);
228
229  // Collect whether we have the requested packet size was received or not in
230  // the PACKET_SIZE_TEST test.
231  void RecordPacketSizeTestReceivedHistograms(Status status);
232
233  // Record the time duration between sending the probe request and receiving
234  // the last probe packet excluding the pacing time requested by the client.
235  // This applies to both NAT bind test and paced/non-paced packet test.
236  void RecordSendToLastRecvDelayHistograms(TestType test_type);
237
238  // Return the next test type (internally increment |current_test_index_|)
239  // in |test_sequence_|;
240  TestType GetNextTest();
241
242  // These static variables are defined so that they can be changed in testing.
243  // Maximum number of tests in one activation of the experiment.
244  static uint32 maximum_tests_;
245  // Maximum number of packets for START/PACED/NON_PACED tests.
246  static uint32 maximum_sequential_packets_;
247  // Maximum number of packets for NAT binding test.
248  static uint32 maximum_NAT_packets_;
249  // Maximum time duration between the two packets for NAT Bind testing.
250  static uint32 maximum_NAT_idle_seconds_;
251  // Whether to start the probe test immediately after connect success.
252  // Used for unittest.
253  static bool start_test_after_connect_;
254
255  // The socket handler for this session.
256  scoped_ptr<net::DatagramClientSocket> socket_;
257
258  net::ClientSocketFactory* socket_factory_;
259
260  // The read buffer used to read data from the socket.
261  scoped_refptr<net::IOBuffer> read_buffer_;
262
263  // The write buffer used to write data to the socket.
264  scoped_refptr<net::DrainableIOBuffer> write_buffer_;
265
266  // Specify the port for which we are testing the network connectivity.
267  uint16 histogram_port_;
268
269  // Specify if there is a proxy server or not.
270  bool has_proxy_server_;
271
272  // HostResolver used to find the IP addresses.
273  scoped_ptr<net::SingleRequestHostResolver> resolver_;
274
275  // Addresses filled out by HostResolver after host resolution is completed.
276  net::AddressList addresses_;
277
278  // Callback to call when test is successefully finished or whenever
279  // there is an error (this will be used by unittests to check the result).
280  net::CompletionCallback finished_callback_;
281
282  // RTTs for each packet.
283  std::vector<base::TimeDelta> packet_rtt_;
284
285  // Time when sending probe_request, used for computing RTT.
286  base::TimeTicks probe_request_time_;
287
288  // Size of the probe packets requested to be sent from servers. We don't use
289  // |probe_packet_bytes_| during PACKET_SIZE_TEST.
290  uint32 probe_packet_bytes_;
291
292  // Size of the packet requested to be sent from servers for PACKET_SIZE_TEST.
293  uint32 bytes_for_packet_size_test_;
294
295  // bitmask indicating which packets are received.
296  std::bitset<21> packets_received_mask_;
297
298  // Arrival time of the first packet in the current test.
299  base::TimeTicks first_arrival_time_;
300  // Arrival time of the most recently received packet in the current test.
301  base::TimeTicks last_arrival_time_;
302  // Average time between two consecutive packets. It is updated when either all
303  // packets are received or timeout happens in the current test.
304  base::TimeDelta inter_arrival_time_;
305  // Target time duration for sending two consecutive packets at the server.
306  // It should be 0 for StartPacket test or NonPacedPacket test. For
307  // PacedPacket test, it is derived from the inter_arrival_time_ in the
308  // previous (StartPacket) test. For NATBind test, it is randomly generated
309  // between 1 second and |maximum_NAT_idle_seconds_| seconds.
310  base::TimeDelta pacing_interval_;
311  // A list of tests that will be performed in sequence.
312  std::vector<TestType> test_sequence_;
313  uint32 current_test_index_;  // Index of the current test.
314
315  ProbeMessage probe_message_;
316
317  // Token received from server for authentication.
318  ProbePacket_Token token_;
319
320  // The state variables to track pending reads/writes.
321  ReadState read_state_;
322  WriteState write_state_;
323
324  // We use this factory to create timeout tasks for socket's ReadData.
325  base::WeakPtrFactory<NetworkStats> weak_factory_;
326
327  DISALLOW_COPY_AND_ASSIGN(NetworkStats);
328};
329
330class ProxyDetector {
331 public:
332  // Used for the callback that is called from |OnResolveProxyComplete|.
333  typedef base::Callback<void(bool)> OnResolvedCallback;
334
335  // Construct a ProxyDetector object that finds out if access to
336  // |server_address| goes through a proxy server or not. Calls the |callback|
337  // after proxy resolution is completed by currying the proxy resolution
338  // status.
339  ProxyDetector(net::ProxyService* proxy_service,
340                const net::HostPortPair& server_address,
341                OnResolvedCallback callback);
342
343  // This method uses |proxy_service_| to resolve the proxy for
344  // |server_address_|.
345  void StartResolveProxy();
346
347 private:
348  // This object is deleted from |OnResolveProxyComplete|.
349  ~ProxyDetector();
350
351  // Call the |callback_| by currying the proxy resolution status.
352  void OnResolveProxyComplete(int result);
353
354  // |proxy_service_| specifies the proxy service that is to be used to find
355  // if access to |server_address_| goes through proxy server or not.
356  net::ProxyService* proxy_service_;
357
358  // |server_address_| specifies the server host and port pair for which we are
359  // trying to see if access to it, goes through proxy or not.
360  net::HostPortPair server_address_;
361
362  // |callback_| will be called after proxy resolution is completed.
363  OnResolvedCallback callback_;
364
365  // |proxy_info_| holds proxy information returned by ResolveProxy.
366  net::ProxyInfo proxy_info_;
367
368  // Indicate if there is a pending a proxy resolution. We use this to assert
369  // that there is no in-progress proxy resolution request.
370  bool has_pending_proxy_resolution_;
371  DISALLOW_COPY_AND_ASSIGN(ProxyDetector);
372};
373
374// This collects the network connectivity stats for UDP protocol for small
375// percentage of users who are participating in the experiment (by enabling
376// "UMA upload"). This method gets called only if UMA upload to the
377// server has succeeded.
378void CollectNetworkStats(const std::string& network_stats_server_url,
379                         IOThread* io_thread);
380
381// This starts a series of tests randomly selected among one of the three
382// choices of probe packet sizes: 100 Bytes, 500 Bytes, 1200 Bytes.
383void StartNetworkStatsTest(net::HostResolver* host_resolver,
384                           const net::HostPortPair& server_address,
385                           uint16 histogram_port,
386                           bool has_proxy_server);
387
388}  // namespace chrome_browser_net
389
390#endif  // CHROME_BROWSER_NET_NETWORK_STATS_H_
391