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