blob: 494022113006bd992b5b8691188f60587fe2aef3 [file] [log] [blame]
Prathmesh Prabhu40daa012013-04-03 10:35:03 -07001// Copyright (c) 2013 The Chromium OS 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 SHILL_CONNECTION_HEALTH_CHECKER_H_
6#define SHILL_CONNECTION_HEALTH_CHECKER_H_
7
Ben Chan22f1fbc2014-10-17 14:18:07 -07008#include <memory>
Alex Vakulenko8a532292014-06-16 17:18:44 -07009#include <string>
Prathmesh Prabhu3e452f82013-04-10 16:31:44 -070010#include <vector>
Prathmesh Prabhu40daa012013-04-03 10:35:03 -070011
Prathmesh Prabhu40daa012013-04-03 10:35:03 -070012#include <base/callback.h>
Prathmesh Prabhuade9b9a2013-04-22 18:01:19 -070013#include <base/cancelable_callback.h>
Ben Chancc67c522014-09-03 07:19:18 -070014#include <base/macros.h>
Prathmesh Prabhu40daa012013-04-03 10:35:03 -070015#include <base/memory/scoped_vector.h>
16#include <base/memory/weak_ptr.h>
17#include <gtest/gtest_prod.h>
18
Peter Qiu8d6b5972014-10-28 15:33:34 -070019#include "shill/net/sockets.h"
Prathmesh Prabhu40daa012013-04-03 10:35:03 -070020#include "shill/refptr_types.h"
Prathmesh Prabhu40daa012013-04-03 10:35:03 -070021#include "shill/socket_info.h"
22
23namespace shill {
24
25class AsyncConnection;
26class DNSClient;
Prathmesh Prabhu3e452f82013-04-10 16:31:44 -070027class DNSClientFactory;
Prathmesh Prabhu40daa012013-04-03 10:35:03 -070028class Error;
29class EventDispatcher;
30class IPAddress;
Prathmesh Prabhuba99b592013-04-17 15:13:14 -070031class IPAddressStore;
Prathmesh Prabhu40daa012013-04-03 10:35:03 -070032class SocketInfoReader;
33
34// The ConnectionHealthChecker class implements the facilities to test
35// connectivity status on some connection asynchronously.
36// In particular, the class can distinguish between three states of the
37// connection:
38// -(1)- No connectivity (TCP connection can not be established)
39// -(2)- Partial connectivity (TCP connection can be established, but no data
40// transfer)
41// -(3)- Connectivity OK (TCP connection established, is healthy)
42class ConnectionHealthChecker {
43 public:
Prathmesh Prabhu40daa012013-04-03 10:35:03 -070044 enum Result {
45 // There was some problem in the setup of ConnctionHealthChecker.
46 // Could not attempt a tcp connection.
47 kResultUnknown,
Prathmesh Prabhu40daa012013-04-03 10:35:03 -070048 // Failed to create TCP connection. Condition -(1)-.
49 kResultConnectionFailure,
Prathmesh Prabhu40daa012013-04-03 10:35:03 -070050 // Failed to send data on TCP connection. Condition -(2)-.
51 kResultCongestedTxQueue,
52 // Condition -(3)-.
53 kResultSuccess
54 };
55
56 ConnectionHealthChecker(ConnectionRefPtr connection,
57 EventDispatcher *dispatcher,
Prathmesh Prabhuba99b592013-04-17 15:13:14 -070058 IPAddressStore *remote_ips,
Prathmesh Prabhu40daa012013-04-03 10:35:03 -070059 const base::Callback<void(Result)> &result_callback);
60 virtual ~ConnectionHealthChecker();
61
62 // A new ConnectionHealthChecker is created with a default URL to attempt the
63 // TCP connection with. Add a URL to try.
Arman Ugurayf84a4242013-04-09 20:01:07 -070064 virtual void AddRemoteURL(const std::string &url_string);
Prathmesh Prabhu40daa012013-04-03 10:35:03 -070065
66 // Name resolution can fail in conditions -(1)- and -(2)-. Add an IP address
67 // to attempt the TCP connection with.
Arman Ugurayf84a4242013-04-09 20:01:07 -070068 virtual void AddRemoteIP(IPAddress ip);
Prathmesh Prabhu40daa012013-04-03 10:35:03 -070069
Prathmesh Prabhuba99b592013-04-17 15:13:14 -070070 // Change the associated Connection on the Device.
71 // This will restart any ongoing health check. Any ongoing DNS query will be
72 // dropped (not restarted).
73 virtual void SetConnection(ConnectionRefPtr connection);
74
Prathmesh Prabhu40daa012013-04-03 10:35:03 -070075 // Start a connection health check. The health check involves one or more
76 // attempts at establishing and using a TCP connection. |result_callback_| is
77 // called with the final result of the check. |result_callback_| will always
78 // be called after a call to Start() unless Stop() is called in the meantime.
79 // |result_callback_| may be called before Start() completes.
80 //
81 // Calling Start() while a health check is in progress is a no-op.
82 virtual void Start();
83
84 // Stop the current health check. No callback is called as a side effect of
85 // this function.
86 //
87 // Calling Stop() on a Stop()ed health check is a no-op.
88 virtual void Stop();
89
Prathmesh Prabhu5489b7a2013-04-10 13:33:59 -070090 static const char *ResultToString(Result result);
91
Prathmesh Prabhu40daa012013-04-03 10:35:03 -070092 // Accessors.
Prathmesh Prabhuba99b592013-04-17 15:13:14 -070093 const IPAddressStore *remote_ips() const { return remote_ips_; }
Prathmesh Prabhuade9b9a2013-04-22 18:01:19 -070094 virtual bool health_check_in_progress() const;
Prathmesh Prabhu40daa012013-04-03 10:35:03 -070095
Prathmesh Prabhuade9b9a2013-04-22 18:01:19 -070096 protected:
97 // For unit-tests.
98 void set_dispatcher(EventDispatcher *dispatcher) {
99 dispatcher_ = dispatcher;
100 }
101 void set_sock_fd(int sock_fd) { sock_fd_ = sock_fd; }
Alex Vakulenko8a532292014-06-16 17:18:44 -0700102 int16_t num_connection_failures() const { return num_connection_failures_; }
103 void set_num_connection_failures(int16_t val) {
Prathmesh Prabhuade9b9a2013-04-22 18:01:19 -0700104 num_connection_failures_ = val;
105 }
Alex Vakulenko8a532292014-06-16 17:18:44 -0700106 int16_t num_tx_queue_polling_attempts() const {
Prathmesh Prabhuade9b9a2013-04-22 18:01:19 -0700107 return num_tx_queue_polling_attempts_;
108 }
Alex Vakulenko8a532292014-06-16 17:18:44 -0700109 void set_num_tx_queue_polling_attempts(int16_t val) {
Prathmesh Prabhuade9b9a2013-04-22 18:01:19 -0700110 num_tx_queue_polling_attempts_ = val;
111 }
Alex Vakulenko8a532292014-06-16 17:18:44 -0700112 int16_t num_congested_queue_detected() const {
Prathmesh Prabhuade9b9a2013-04-22 18:01:19 -0700113 return num_congested_queue_detected_;
114 }
Alex Vakulenko8a532292014-06-16 17:18:44 -0700115 void set_num_congested_queue_detected(int16_t val) {
Prathmesh Prabhuade9b9a2013-04-22 18:01:19 -0700116 num_congested_queue_detected_ = val;
117 }
Alex Vakulenko8a532292014-06-16 17:18:44 -0700118 int16_t num_successful_sends() const { return num_successful_sends_; }
119 void set_num_successful_sends(int16_t val) {
Prathmesh Prabhuade9b9a2013-04-22 18:01:19 -0700120 num_successful_sends_ = val;
121 }
Ben Chan7fab8972014-08-10 17:14:46 -0700122 void set_old_transmit_queue_value(uint64_t val) {
Prathmesh Prabhuade9b9a2013-04-22 18:01:19 -0700123 old_transmit_queue_value_ = val;
124 }
125 Result health_check_result() const { return health_check_result_; }
Prathmesh Prabhuba99b592013-04-17 15:13:14 -0700126 AsyncConnection *tcp_connection() const { return tcp_connection_.get(); }
127 Connection *connection() const { return connection_.get(); }
128
Prathmesh Prabhu40daa012013-04-03 10:35:03 -0700129 private:
130 friend class ConnectionHealthCheckerTest;
Prathmesh Prabhu3e452f82013-04-10 16:31:44 -0700131 FRIEND_TEST(ConnectionHealthCheckerTest, GarbageCollectDNSClients);
Prathmesh Prabhu40daa012013-04-03 10:35:03 -0700132 FRIEND_TEST(ConnectionHealthCheckerTest, GetSocketInfo);
Prathmesh Prabhuade9b9a2013-04-22 18:01:19 -0700133 FRIEND_TEST(ConnectionHealthCheckerTest, NextHealthCheckSample);
134 FRIEND_TEST(ConnectionHealthCheckerTest, OnConnectionComplete);
Prathmesh Prabhuba99b592013-04-17 15:13:14 -0700135 FRIEND_TEST(ConnectionHealthCheckerTest, SetConnection);
Prathmesh Prabhuade9b9a2013-04-22 18:01:19 -0700136 FRIEND_TEST(ConnectionHealthCheckerTest, VerifySentData);
Prathmesh Prabhu40daa012013-04-03 10:35:03 -0700137
Prathmesh Prabhuba99b592013-04-17 15:13:14 -0700138 // List of static IPs for connection health check.
139 static const char *kDefaultRemoteIPPool[];
Prathmesh Prabhu40daa012013-04-03 10:35:03 -0700140 // Time to wait for DNS server.
Prathmesh Prabhu3e452f82013-04-10 16:31:44 -0700141 static const int kDNSTimeoutMilliseconds;
Prathmesh Prabhuade9b9a2013-04-22 18:01:19 -0700142 static const int kInvalidSocket;
143 // After |kMaxFailedConnectionAttempts| failed attempts to connect, give up
144 // health check and return failure.
145 static const int kMaxFailedConnectionAttempts;
146 // After sending a small amount of data, attempt |kMaxSentDataPollingAttempts|
147 // times to see if the data was sent successfully.
148 static const int kMaxSentDataPollingAttempts;
149 // After |kMinCongestedQueueAttempts| to send data indicate a congested tx
150 // queue, finish health check and report a congested queue.
151 static const int kMinCongestedQueueAttempts;
152 // After sending data |kMinSuccessfulAttempts| times succesfully, finish
153 // health check and report a healthy connection.
154 static const int kMinSuccessfulSendAttempts;
Prathmesh Prabhu3e452f82013-04-10 16:31:44 -0700155 // Number of DNS queries to be spawned when a new remote URL is added.
156 static const int kNumDNSQueries;
Ben Chan7fab8972014-08-10 17:14:46 -0700157 static const uint16_t kRemotePort;
Prathmesh Prabhuade9b9a2013-04-22 18:01:19 -0700158 // Time to wait before testing successful data transfer / disconnect after
159 // request is made on the device.
160 static const int kTCPStateUpdateWaitMilliseconds;
161
Prathmesh Prabhuade9b9a2013-04-22 18:01:19 -0700162 // Callback for DnsClient
163 void GetDNSResult(const Error &error, const IPAddress &ip);
164 void GarbageCollectDNSClients();
165
Prathmesh Prabhu40daa012013-04-03 10:35:03 -0700166 // Start a new AsyncConnection with callback set to OnConnectionComplete().
Prathmesh Prabhuade9b9a2013-04-22 18:01:19 -0700167 void NextHealthCheckSample();
168 void ReportResult();
Prathmesh Prabhu40daa012013-04-03 10:35:03 -0700169
170 // Callback for AsyncConnection.
171 // Observe the setup connection to test health state
172 void OnConnectionComplete(bool success, int sock_fd);
173
Prathmesh Prabhuade9b9a2013-04-22 18:01:19 -0700174 void VerifySentData();
Prathmesh Prabhu40daa012013-04-03 10:35:03 -0700175 bool GetSocketInfo(int sock_fd, SocketInfo *sock_info);
176
Prathmesh Prabhuade9b9a2013-04-22 18:01:19 -0700177 void SetSocketDescriptor(int sock_fd);
178 void ClearSocketDescriptor();
179
180 // The connection on which the health check is being run.
Prathmesh Prabhu40daa012013-04-03 10:35:03 -0700181 ConnectionRefPtr connection_;
182 EventDispatcher *dispatcher_;
Prathmesh Prabhuba99b592013-04-17 15:13:14 -0700183 // Set of IPs to create TCP connection with for the health check.
184 IPAddressStore *remote_ips_;
Prathmesh Prabhu40daa012013-04-03 10:35:03 -0700185 base::Callback<void(Result)> result_callback_;
186
Ben Chan22f1fbc2014-10-17 14:18:07 -0700187 std::unique_ptr<Sockets> socket_;
Prathmesh Prabhu40daa012013-04-03 10:35:03 -0700188 base::WeakPtrFactory<ConnectionHealthChecker> weak_ptr_factory_;
Prathmesh Prabhuade9b9a2013-04-22 18:01:19 -0700189
Prathmesh Prabhuade9b9a2013-04-22 18:01:19 -0700190 // Callback passed to |tcp_connection_| to report an established TCP
191 // connection.
Prathmesh Prabhu40daa012013-04-03 10:35:03 -0700192 const base::Callback<void(bool, int)> connection_complete_callback_;
Prathmesh Prabhuade9b9a2013-04-22 18:01:19 -0700193 // Active TCP connection during health check.
Ben Chan22f1fbc2014-10-17 14:18:07 -0700194 std::unique_ptr<AsyncConnection> tcp_connection_;
Prathmesh Prabhuade9b9a2013-04-22 18:01:19 -0700195 const base::Callback<void(void)> report_result_;
196 // Active socket for |tcp_connection_| during an active health check.
197 int sock_fd_;
198 // Interface to read TCP connection information from the system.
Ben Chan22f1fbc2014-10-17 14:18:07 -0700199 std::unique_ptr<SocketInfoReader> socket_info_reader_;
Prathmesh Prabhuade9b9a2013-04-22 18:01:19 -0700200
Prathmesh Prabhu3e452f82013-04-10 16:31:44 -0700201 DNSClientFactory *dns_client_factory_;
202 ScopedVector<DNSClient> dns_clients_;
Prathmesh Prabhuade9b9a2013-04-22 18:01:19 -0700203 const base::Callback<void(const Error&, const IPAddress&)>
204 dns_client_callback_;
205
206 // Store the old value of the transmit queue to verify that data sent on the
207 // connection is actually transmitted.
Ben Chan7fab8972014-08-10 17:14:46 -0700208 uint64_t old_transmit_queue_value_;
Prathmesh Prabhuade9b9a2013-04-22 18:01:19 -0700209 // Callback to post a delayed check on whether data sent on the TCP connection
210 // was successfully transmitted.
211 base::CancelableClosure verify_sent_data_callback_;
212
Prathmesh Prabhu40daa012013-04-03 10:35:03 -0700213 bool health_check_in_progress_;
Prathmesh Prabhuade9b9a2013-04-22 18:01:19 -0700214 // Number of connection failures in currently active health check.
Alex Vakulenko8a532292014-06-16 17:18:44 -0700215 int16_t num_connection_failures_;
Prathmesh Prabhuade9b9a2013-04-22 18:01:19 -0700216 // Number of times we have checked the tx-queue for the current send attempt.
Alex Vakulenko8a532292014-06-16 17:18:44 -0700217 int16_t num_tx_queue_polling_attempts_;
218 // Number of out of credit scenarios detected in current health check.
219 int16_t num_congested_queue_detected_;
Prathmesh Prabhuade9b9a2013-04-22 18:01:19 -0700220 // Number of successful send attempts currently active health check.
Alex Vakulenko8a532292014-06-16 17:18:44 -0700221 int16_t num_successful_sends_;
Prathmesh Prabhuade9b9a2013-04-22 18:01:19 -0700222
Prathmesh Prabhu81404c62013-05-08 17:04:28 -0700223 // Snooze time while polling for updated /proc/tcpinfo
224 int tcp_state_update_wait_milliseconds_;
225
Prathmesh Prabhuade9b9a2013-04-22 18:01:19 -0700226 // Temporarily store the result of health check so that |report_result_|
227 // can report it.
228 Result health_check_result_;
Prathmesh Prabhu40daa012013-04-03 10:35:03 -0700229
230 DISALLOW_COPY_AND_ASSIGN(ConnectionHealthChecker);
231};
232
233} // namespace shill
234
235#endif // SHILL_CONNECTION_HEALTH_CHECKER_H_