Home | History | Annotate | Download | only in shill
      1 //
      2 // Copyright (C) 2013 The Android Open Source Project
      3 //
      4 // Licensed under the Apache License, Version 2.0 (the "License");
      5 // you may not use this file except in compliance with the License.
      6 // You may obtain a copy of the License at
      7 //
      8 //      http://www.apache.org/licenses/LICENSE-2.0
      9 //
     10 // Unless required by applicable law or agreed to in writing, software
     11 // distributed under the License is distributed on an "AS IS" BASIS,
     12 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13 // See the License for the specific language governing permissions and
     14 // limitations under the License.
     15 //
     16 
     17 #ifndef SHILL_CONNECTION_HEALTH_CHECKER_H_
     18 #define SHILL_CONNECTION_HEALTH_CHECKER_H_
     19 
     20 #include <memory>
     21 #include <string>
     22 #include <vector>
     23 
     24 #include <base/callback.h>
     25 #include <base/cancelable_callback.h>
     26 #include <base/macros.h>
     27 #include <base/memory/scoped_vector.h>
     28 #include <base/memory/weak_ptr.h>
     29 #include <gtest/gtest_prod.h>
     30 
     31 #include "shill/net/sockets.h"
     32 #include "shill/refptr_types.h"
     33 #include "shill/socket_info.h"
     34 
     35 namespace shill {
     36 
     37 class AsyncConnection;
     38 class DNSClient;
     39 class DNSClientFactory;
     40 class Error;
     41 class EventDispatcher;
     42 class IPAddress;
     43 class IPAddressStore;
     44 class SocketInfoReader;
     45 
     46 // The ConnectionHealthChecker class implements the facilities to test
     47 // connectivity status on some connection asynchronously.
     48 // In particular, the class can distinguish between three states of the
     49 // connection:
     50 //   -(1)- No connectivity (TCP connection can not be established)
     51 //   -(2)- Partial connectivity (TCP connection can be established, but no data
     52 //         transfer)
     53 //   -(3)- Connectivity OK (TCP connection established, is healthy)
     54 class ConnectionHealthChecker {
     55  public:
     56   enum Result {
     57     // There was some problem in the setup of ConnctionHealthChecker.
     58     // Could not attempt a tcp connection.
     59     kResultUnknown,
     60     // Failed to create TCP connection. Condition -(1)-.
     61     kResultConnectionFailure,
     62     // Failed to send data on TCP connection. Condition -(2)-.
     63     kResultCongestedTxQueue,
     64     // Condition -(3)-.
     65     kResultSuccess
     66   };
     67 
     68   ConnectionHealthChecker(ConnectionRefPtr connection,
     69                           EventDispatcher* dispatcher,
     70                           IPAddressStore* remote_ips,
     71                           const base::Callback<void(Result)>& result_callback);
     72   virtual ~ConnectionHealthChecker();
     73 
     74   // A new ConnectionHealthChecker is created with a default URL to attempt the
     75   // TCP connection with. Add a URL to try.
     76   virtual void AddRemoteURL(const std::string& url_string);
     77 
     78   // Name resolution can fail in conditions -(1)- and -(2)-. Add an IP address
     79   // to attempt the TCP connection with.
     80   virtual void AddRemoteIP(IPAddress ip);
     81 
     82   // Change the associated Connection on the Device.
     83   // This will restart any ongoing health check. Any ongoing DNS query will be
     84   // dropped (not restarted).
     85   virtual void SetConnection(ConnectionRefPtr connection);
     86 
     87   // Start a connection health check. The health check involves one or more
     88   // attempts at establishing and using a TCP connection. |result_callback_| is
     89   // called with the final result of the check. |result_callback_| will always
     90   // be called after a call to Start() unless Stop() is called in the meantime.
     91   // |result_callback_| may be called before Start() completes.
     92   //
     93   // Calling Start() while a health check is in progress is a no-op.
     94   virtual void Start();
     95 
     96   // Stop the current health check. No callback is called as a side effect of
     97   // this function.
     98   //
     99   // Calling Stop() on a Stop()ed health check is a no-op.
    100   virtual void Stop();
    101 
    102   static const char* ResultToString(Result result);
    103 
    104   // Accessors.
    105   const IPAddressStore* remote_ips() const { return remote_ips_; }
    106   virtual bool health_check_in_progress() const;
    107 
    108  protected:
    109   // For unit-tests.
    110   void set_dispatcher(EventDispatcher* dispatcher) {
    111     dispatcher_ = dispatcher;
    112   }
    113   void set_sock_fd(int sock_fd) { sock_fd_ = sock_fd; }
    114   int16_t num_connection_failures() const { return num_connection_failures_; }
    115   void set_num_connection_failures(int16_t val) {
    116     num_connection_failures_ = val;
    117   }
    118   int16_t num_tx_queue_polling_attempts() const {
    119     return num_tx_queue_polling_attempts_;
    120   }
    121   void set_num_tx_queue_polling_attempts(int16_t val) {
    122     num_tx_queue_polling_attempts_ = val;
    123   }
    124   int16_t num_congested_queue_detected() const {
    125     return num_congested_queue_detected_;
    126   }
    127   void set_num_congested_queue_detected(int16_t val) {
    128     num_congested_queue_detected_ = val;
    129   }
    130   int16_t num_successful_sends() const { return num_successful_sends_; }
    131   void set_num_successful_sends(int16_t val) {
    132     num_successful_sends_ = val;
    133   }
    134   void set_old_transmit_queue_value(uint64_t val) {
    135     old_transmit_queue_value_ = val;
    136   }
    137   Result health_check_result() const { return health_check_result_; }
    138   AsyncConnection* tcp_connection() const { return tcp_connection_.get(); }
    139   Connection* connection() const { return connection_.get(); }
    140 
    141  private:
    142   friend class ConnectionHealthCheckerTest;
    143   FRIEND_TEST(ConnectionHealthCheckerTest, GarbageCollectDNSClients);
    144   FRIEND_TEST(ConnectionHealthCheckerTest, GetSocketInfo);
    145   FRIEND_TEST(ConnectionHealthCheckerTest, NextHealthCheckSample);
    146   FRIEND_TEST(ConnectionHealthCheckerTest, OnConnectionComplete);
    147   FRIEND_TEST(ConnectionHealthCheckerTest, SetConnection);
    148   FRIEND_TEST(ConnectionHealthCheckerTest, VerifySentData);
    149 
    150   // List of static IPs for connection health check.
    151   static const char* kDefaultRemoteIPPool[];
    152   // Time to wait for DNS server.
    153   static const int kDNSTimeoutMilliseconds;
    154   static const int kInvalidSocket;
    155   // After |kMaxFailedConnectionAttempts| failed attempts to connect, give up
    156   // health check and return failure.
    157   static const int kMaxFailedConnectionAttempts;
    158   // After sending a small amount of data, attempt |kMaxSentDataPollingAttempts|
    159   // times to see if the data was sent successfully.
    160   static const int kMaxSentDataPollingAttempts;
    161   // After |kMinCongestedQueueAttempts| to send data indicate a congested tx
    162   // queue, finish health check and report a congested queue.
    163   static const int kMinCongestedQueueAttempts;
    164   // After sending data |kMinSuccessfulAttempts| times succesfully, finish
    165   // health check and report a healthy connection.
    166   static const int kMinSuccessfulSendAttempts;
    167   // Number of DNS queries to be spawned when a new remote URL is added.
    168   static const int kNumDNSQueries;
    169   static const uint16_t kRemotePort;
    170   // Time to wait before testing successful data transfer / disconnect after
    171   // request is made on the device.
    172   static const int kTCPStateUpdateWaitMilliseconds;
    173 
    174   // Callback for DnsClient
    175   void GetDNSResult(const Error& error, const IPAddress& ip);
    176   void GarbageCollectDNSClients();
    177 
    178   // Start a new AsyncConnection with callback set to OnConnectionComplete().
    179   void NextHealthCheckSample();
    180   void ReportResult();
    181 
    182   // Callback for AsyncConnection.
    183   // Observe the setup connection to test health state
    184   void OnConnectionComplete(bool success, int sock_fd);
    185 
    186   void VerifySentData();
    187   bool GetSocketInfo(int sock_fd, SocketInfo* sock_info);
    188 
    189   void SetSocketDescriptor(int sock_fd);
    190   void ClearSocketDescriptor();
    191 
    192   // The connection on which the health check is being run.
    193   ConnectionRefPtr connection_;
    194   EventDispatcher* dispatcher_;
    195   // Set of IPs to create TCP connection with for the health check.
    196   IPAddressStore* remote_ips_;
    197   base::Callback<void(Result)> result_callback_;
    198 
    199   std::unique_ptr<Sockets> socket_;
    200   base::WeakPtrFactory<ConnectionHealthChecker> weak_ptr_factory_;
    201 
    202   // Callback passed to |tcp_connection_| to report an established TCP
    203   // connection.
    204   const base::Callback<void(bool, int)> connection_complete_callback_;
    205   // Active TCP connection during health check.
    206   std::unique_ptr<AsyncConnection> tcp_connection_;
    207   const base::Callback<void(void)> report_result_;
    208   // Active socket for |tcp_connection_| during an active health check.
    209   int sock_fd_;
    210   // Interface to read TCP connection information from the system.
    211   std::unique_ptr<SocketInfoReader> socket_info_reader_;
    212 
    213   DNSClientFactory* dns_client_factory_;
    214   ScopedVector<DNSClient> dns_clients_;
    215   const base::Callback<void(const Error&, const IPAddress&)>
    216       dns_client_callback_;
    217 
    218   // Store the old value of the transmit queue to verify that data sent on the
    219   // connection is actually transmitted.
    220   uint64_t old_transmit_queue_value_;
    221   // Callback to post a delayed check on whether data sent on the TCP connection
    222   // was successfully transmitted.
    223   base::CancelableClosure verify_sent_data_callback_;
    224 
    225   bool health_check_in_progress_;
    226   // Number of connection failures in currently active health check.
    227   int16_t num_connection_failures_;
    228   // Number of times we have checked the tx-queue for the current send attempt.
    229   int16_t num_tx_queue_polling_attempts_;
    230   // Number of out of credit scenarios detected in current health check.
    231   int16_t num_congested_queue_detected_;
    232   // Number of successful send attempts currently active health check.
    233   int16_t num_successful_sends_;
    234 
    235   // Snooze time while polling for updated /proc/tcpinfo
    236   int tcp_state_update_wait_milliseconds_;
    237 
    238   // Temporarily store the result of health check so that |report_result_|
    239   // can report it.
    240   Result health_check_result_;
    241 
    242   DISALLOW_COPY_AND_ASSIGN(ConnectionHealthChecker);
    243 };
    244 
    245 }  // namespace shill
    246 
    247 #endif  // SHILL_CONNECTION_HEALTH_CHECKER_H_
    248