blob: 3efef0787553a489a57c4fc6d22e2015c3f5785c [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
Prathmesh Prabhu3e452f82013-04-10 16:31:44 -07008#include <vector>
Prathmesh Prabhu40daa012013-04-03 10:35:03 -07009
10#include <base/basictypes.h>
11#include <base/callback.h>
Prathmesh Prabhuade9b9a2013-04-22 18:01:19 -070012#include <base/cancelable_callback.h>
Prathmesh Prabhu40daa012013-04-03 10:35:03 -070013#include <base/memory/scoped_ptr.h>
14#include <base/memory/scoped_vector.h>
15#include <base/memory/weak_ptr.h>
16#include <gtest/gtest_prod.h>
17
18#include "shill/refptr_types.h"
19#include "shill/sockets.h"
20#include "shill/socket_info.h"
21
22namespace shill {
23
24class AsyncConnection;
25class DNSClient;
Prathmesh Prabhu3e452f82013-04-10 16:31:44 -070026class DNSClientFactory;
Prathmesh Prabhu40daa012013-04-03 10:35:03 -070027class Error;
28class EventDispatcher;
29class IPAddress;
Prathmesh Prabhuba99b592013-04-17 15:13:14 -070030class IPAddressStore;
Prathmesh Prabhu40daa012013-04-03 10:35:03 -070031class SocketInfoReader;
32
33// The ConnectionHealthChecker class implements the facilities to test
34// connectivity status on some connection asynchronously.
35// In particular, the class can distinguish between three states of the
36// connection:
37// -(1)- No connectivity (TCP connection can not be established)
38// -(2)- Partial connectivity (TCP connection can be established, but no data
39// transfer)
40// -(3)- Connectivity OK (TCP connection established, is healthy)
41class ConnectionHealthChecker {
42 public:
Prathmesh Prabhu40daa012013-04-03 10:35:03 -070043
44 enum Result {
45 // There was some problem in the setup of ConnctionHealthChecker.
46 // Could not attempt a tcp connection.
47 kResultUnknown,
Prathmesh Prabhuade9b9a2013-04-22 18:01:19 -070048 // TODO(pprabhu) Deprecated. Remove.
49 // crbug.com/234734
Prathmesh Prabhu40daa012013-04-03 10:35:03 -070050 // New health check request made successfully. The result of the health
51 // check is returned asynchronously.
52 kResultInProgress,
53 // Failed to create TCP connection. Condition -(1)-.
54 kResultConnectionFailure,
Prathmesh Prabhuade9b9a2013-04-22 18:01:19 -070055 // TODO(pprabhu) Deprecated. Remove.
56 // crbug.com/234734
Prathmesh Prabhu40daa012013-04-03 10:35:03 -070057 // Failed to destroy TCP connection. Condition -(2)-.
58 kResultElongatedTimeWait,
59 // Failed to send data on TCP connection. Condition -(2)-.
60 kResultCongestedTxQueue,
61 // Condition -(3)-.
62 kResultSuccess
63 };
64
65 ConnectionHealthChecker(ConnectionRefPtr connection,
66 EventDispatcher *dispatcher,
Prathmesh Prabhuba99b592013-04-17 15:13:14 -070067 IPAddressStore *remote_ips,
Prathmesh Prabhu40daa012013-04-03 10:35:03 -070068 const base::Callback<void(Result)> &result_callback);
69 virtual ~ConnectionHealthChecker();
70
71 // A new ConnectionHealthChecker is created with a default URL to attempt the
72 // TCP connection with. Add a URL to try.
Arman Ugurayf84a4242013-04-09 20:01:07 -070073 virtual void AddRemoteURL(const std::string &url_string);
Prathmesh Prabhu40daa012013-04-03 10:35:03 -070074
75 // Name resolution can fail in conditions -(1)- and -(2)-. Add an IP address
76 // to attempt the TCP connection with.
Arman Ugurayf84a4242013-04-09 20:01:07 -070077 virtual void AddRemoteIP(IPAddress ip);
Prathmesh Prabhu40daa012013-04-03 10:35:03 -070078
Prathmesh Prabhuba99b592013-04-17 15:13:14 -070079 // Change the associated Connection on the Device.
80 // This will restart any ongoing health check. Any ongoing DNS query will be
81 // dropped (not restarted).
82 virtual void SetConnection(ConnectionRefPtr connection);
83
Prathmesh Prabhu40daa012013-04-03 10:35:03 -070084 // Start a connection health check. The health check involves one or more
85 // attempts at establishing and using a TCP connection. |result_callback_| is
86 // called with the final result of the check. |result_callback_| will always
87 // be called after a call to Start() unless Stop() is called in the meantime.
88 // |result_callback_| may be called before Start() completes.
89 //
90 // Calling Start() while a health check is in progress is a no-op.
91 virtual void Start();
92
93 // Stop the current health check. No callback is called as a side effect of
94 // this function.
95 //
96 // Calling Stop() on a Stop()ed health check is a no-op.
97 virtual void Stop();
98
Prathmesh Prabhu5489b7a2013-04-10 13:33:59 -070099 static const char *ResultToString(Result result);
100
Prathmesh Prabhu40daa012013-04-03 10:35:03 -0700101 // Accessors.
Prathmesh Prabhuba99b592013-04-17 15:13:14 -0700102 const IPAddressStore *remote_ips() const { return remote_ips_; }
Prathmesh Prabhuade9b9a2013-04-22 18:01:19 -0700103 virtual bool health_check_in_progress() const;
Prathmesh Prabhu40daa012013-04-03 10:35:03 -0700104
Prathmesh Prabhuade9b9a2013-04-22 18:01:19 -0700105 protected:
106 // For unit-tests.
107 void set_dispatcher(EventDispatcher *dispatcher) {
108 dispatcher_ = dispatcher;
109 }
110 void set_sock_fd(int sock_fd) { sock_fd_ = sock_fd; }
111 short num_connection_failures() const { return num_connection_failures_; }
112 void set_num_connection_failures(short val) {
113 num_connection_failures_ = val;
114 }
115 short num_tx_queue_polling_attempts() const {
116 return num_tx_queue_polling_attempts_;
117 }
118 void set_num_tx_queue_polling_attempts(short val) {
119 num_tx_queue_polling_attempts_ = val;
120 }
121 short num_congested_queue_detected() const {
122 return num_congested_queue_detected_;
123 }
124 void set_num_congested_queue_detected(short val) {
125 num_congested_queue_detected_ = val;
126 }
127 short num_successful_sends() const { return num_successful_sends_; }
128 void set_num_successful_sends(short val) {
129 num_successful_sends_ = val;
130 }
131 void set_old_transmit_queue_value(uint64 val) {
132 old_transmit_queue_value_ = val;
133 }
134 Result health_check_result() const { return health_check_result_; }
Prathmesh Prabhuba99b592013-04-17 15:13:14 -0700135 AsyncConnection *tcp_connection() const { return tcp_connection_.get(); }
136 Connection *connection() const { return connection_.get(); }
137
Prathmesh Prabhu40daa012013-04-03 10:35:03 -0700138 private:
139 friend class ConnectionHealthCheckerTest;
Prathmesh Prabhu3e452f82013-04-10 16:31:44 -0700140 FRIEND_TEST(ConnectionHealthCheckerTest, GarbageCollectDNSClients);
Prathmesh Prabhu40daa012013-04-03 10:35:03 -0700141 FRIEND_TEST(ConnectionHealthCheckerTest, GetSocketInfo);
Prathmesh Prabhuade9b9a2013-04-22 18:01:19 -0700142 FRIEND_TEST(ConnectionHealthCheckerTest, NextHealthCheckSample);
143 FRIEND_TEST(ConnectionHealthCheckerTest, OnConnectionComplete);
Prathmesh Prabhuba99b592013-04-17 15:13:14 -0700144 FRIEND_TEST(ConnectionHealthCheckerTest, SetConnection);
Prathmesh Prabhuade9b9a2013-04-22 18:01:19 -0700145 FRIEND_TEST(ConnectionHealthCheckerTest, VerifySentData);
Prathmesh Prabhu40daa012013-04-03 10:35:03 -0700146
Prathmesh Prabhuba99b592013-04-17 15:13:14 -0700147 // List of static IPs for connection health check.
148 static const char *kDefaultRemoteIPPool[];
Prathmesh Prabhu40daa012013-04-03 10:35:03 -0700149 // Time to wait for DNS server.
Prathmesh Prabhu3e452f82013-04-10 16:31:44 -0700150 static const int kDNSTimeoutMilliseconds;
Prathmesh Prabhuade9b9a2013-04-22 18:01:19 -0700151 static const int kInvalidSocket;
152 // After |kMaxFailedConnectionAttempts| failed attempts to connect, give up
153 // health check and return failure.
154 static const int kMaxFailedConnectionAttempts;
155 // After sending a small amount of data, attempt |kMaxSentDataPollingAttempts|
156 // times to see if the data was sent successfully.
157 static const int kMaxSentDataPollingAttempts;
158 // After |kMinCongestedQueueAttempts| to send data indicate a congested tx
159 // queue, finish health check and report a congested queue.
160 static const int kMinCongestedQueueAttempts;
161 // After sending data |kMinSuccessfulAttempts| times succesfully, finish
162 // health check and report a healthy connection.
163 static const int kMinSuccessfulSendAttempts;
Prathmesh Prabhu3e452f82013-04-10 16:31:44 -0700164 // Number of DNS queries to be spawned when a new remote URL is added.
165 static const int kNumDNSQueries;
Prathmesh Prabhuba99b592013-04-17 15:13:14 -0700166 static const uint16 kRemotePort;
Prathmesh Prabhuade9b9a2013-04-22 18:01:19 -0700167 // Time to wait before testing successful data transfer / disconnect after
168 // request is made on the device.
169 static const int kTCPStateUpdateWaitMilliseconds;
170
Prathmesh Prabhuade9b9a2013-04-22 18:01:19 -0700171 // Callback for DnsClient
172 void GetDNSResult(const Error &error, const IPAddress &ip);
173 void GarbageCollectDNSClients();
174
Prathmesh Prabhu40daa012013-04-03 10:35:03 -0700175 // Start a new AsyncConnection with callback set to OnConnectionComplete().
Prathmesh Prabhuade9b9a2013-04-22 18:01:19 -0700176 void NextHealthCheckSample();
177 void ReportResult();
Prathmesh Prabhu40daa012013-04-03 10:35:03 -0700178
179 // Callback for AsyncConnection.
180 // Observe the setup connection to test health state
181 void OnConnectionComplete(bool success, int sock_fd);
182
Prathmesh Prabhuade9b9a2013-04-22 18:01:19 -0700183 void VerifySentData();
Prathmesh Prabhu40daa012013-04-03 10:35:03 -0700184 bool GetSocketInfo(int sock_fd, SocketInfo *sock_info);
185
Prathmesh Prabhuade9b9a2013-04-22 18:01:19 -0700186 void SetSocketDescriptor(int sock_fd);
187 void ClearSocketDescriptor();
188
189 // The connection on which the health check is being run.
Prathmesh Prabhu40daa012013-04-03 10:35:03 -0700190 ConnectionRefPtr connection_;
191 EventDispatcher *dispatcher_;
Prathmesh Prabhuba99b592013-04-17 15:13:14 -0700192 // Set of IPs to create TCP connection with for the health check.
193 IPAddressStore *remote_ips_;
Prathmesh Prabhu40daa012013-04-03 10:35:03 -0700194 base::Callback<void(Result)> result_callback_;
195
Prathmesh Prabhu40daa012013-04-03 10:35:03 -0700196 scoped_ptr<Sockets> socket_;
197 base::WeakPtrFactory<ConnectionHealthChecker> weak_ptr_factory_;
Prathmesh Prabhuade9b9a2013-04-22 18:01:19 -0700198
Prathmesh Prabhuade9b9a2013-04-22 18:01:19 -0700199 // Callback passed to |tcp_connection_| to report an established TCP
200 // connection.
Prathmesh Prabhu40daa012013-04-03 10:35:03 -0700201 const base::Callback<void(bool, int)> connection_complete_callback_;
Prathmesh Prabhuade9b9a2013-04-22 18:01:19 -0700202 // Active TCP connection during health check.
Prathmesh Prabhu40daa012013-04-03 10:35:03 -0700203 scoped_ptr<AsyncConnection> tcp_connection_;
Prathmesh Prabhuade9b9a2013-04-22 18:01:19 -0700204 const base::Callback<void(void)> report_result_;
205 // Active socket for |tcp_connection_| during an active health check.
206 int sock_fd_;
207 // Interface to read TCP connection information from the system.
208 scoped_ptr<SocketInfoReader> socket_info_reader_;
209
Prathmesh Prabhu3e452f82013-04-10 16:31:44 -0700210 DNSClientFactory *dns_client_factory_;
211 ScopedVector<DNSClient> dns_clients_;
Prathmesh Prabhuade9b9a2013-04-22 18:01:19 -0700212 const base::Callback<void(const Error&, const IPAddress&)>
213 dns_client_callback_;
214
215 // Store the old value of the transmit queue to verify that data sent on the
216 // connection is actually transmitted.
217 uint64 old_transmit_queue_value_;
218 // Callback to post a delayed check on whether data sent on the TCP connection
219 // was successfully transmitted.
220 base::CancelableClosure verify_sent_data_callback_;
221
Prathmesh Prabhu40daa012013-04-03 10:35:03 -0700222 bool health_check_in_progress_;
Prathmesh Prabhuade9b9a2013-04-22 18:01:19 -0700223 // Number of connection failures in currently active health check.
224 short num_connection_failures_;
225 // Number of times we have checked the tx-queue for the current send attempt.
226 short num_tx_queue_polling_attempts_;
227 // Number of out of credit scenarios detected in currentl health check.
228 short num_congested_queue_detected_;
229 // Number of successful send attempts currently active health check.
230 short num_successful_sends_;
231
232 // Temporarily store the result of health check so that |report_result_|
233 // can report it.
234 Result health_check_result_;
Prathmesh Prabhu40daa012013-04-03 10:35:03 -0700235
236 DISALLOW_COPY_AND_ASSIGN(ConnectionHealthChecker);
237};
238
239} // namespace shill
240
241#endif // SHILL_CONNECTION_HEALTH_CHECKER_H_