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. remote_ips()105 const IPAddressStore* remote_ips() const { return remote_ips_; } 106 virtual bool health_check_in_progress() const; 107 108 protected: 109 // For unit-tests. set_dispatcher(EventDispatcher * dispatcher)110 void set_dispatcher(EventDispatcher* dispatcher) { 111 dispatcher_ = dispatcher; 112 } set_sock_fd(int sock_fd)113 void set_sock_fd(int sock_fd) { sock_fd_ = sock_fd; } num_connection_failures()114 int16_t num_connection_failures() const { return num_connection_failures_; } set_num_connection_failures(int16_t val)115 void set_num_connection_failures(int16_t val) { 116 num_connection_failures_ = val; 117 } num_tx_queue_polling_attempts()118 int16_t num_tx_queue_polling_attempts() const { 119 return num_tx_queue_polling_attempts_; 120 } set_num_tx_queue_polling_attempts(int16_t val)121 void set_num_tx_queue_polling_attempts(int16_t val) { 122 num_tx_queue_polling_attempts_ = val; 123 } num_congested_queue_detected()124 int16_t num_congested_queue_detected() const { 125 return num_congested_queue_detected_; 126 } set_num_congested_queue_detected(int16_t val)127 void set_num_congested_queue_detected(int16_t val) { 128 num_congested_queue_detected_ = val; 129 } num_successful_sends()130 int16_t num_successful_sends() const { return num_successful_sends_; } set_num_successful_sends(int16_t val)131 void set_num_successful_sends(int16_t val) { 132 num_successful_sends_ = val; 133 } set_old_transmit_queue_value(uint64_t val)134 void set_old_transmit_queue_value(uint64_t val) { 135 old_transmit_queue_value_ = val; 136 } health_check_result()137 Result health_check_result() const { return health_check_result_; } tcp_connection()138 AsyncConnection* tcp_connection() const { return tcp_connection_.get(); } connection()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