blob: 6bc870e720aad11ee606b0a78b87763a1ac0ba2d [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;
30class SocketInfoReader;
31
32// The ConnectionHealthChecker class implements the facilities to test
33// connectivity status on some connection asynchronously.
34// In particular, the class can distinguish between three states of the
35// connection:
36// -(1)- No connectivity (TCP connection can not be established)
37// -(2)- Partial connectivity (TCP connection can be established, but no data
38// transfer)
39// -(3)- Connectivity OK (TCP connection established, is healthy)
40class ConnectionHealthChecker {
41 public:
Prathmesh Prabhu3e452f82013-04-10 16:31:44 -070042 typedef std::vector<IPAddress> IPAddresses;
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,
67 const base::Callback<void(Result)> &result_callback);
68 virtual ~ConnectionHealthChecker();
69
70 // A new ConnectionHealthChecker is created with a default URL to attempt the
71 // TCP connection with. Add a URL to try.
Arman Ugurayf84a4242013-04-09 20:01:07 -070072 virtual void AddRemoteURL(const std::string &url_string);
Prathmesh Prabhu40daa012013-04-03 10:35:03 -070073
74 // Name resolution can fail in conditions -(1)- and -(2)-. Add an IP address
75 // to attempt the TCP connection with.
Arman Ugurayf84a4242013-04-09 20:01:07 -070076 virtual void AddRemoteIP(IPAddress ip);
Prathmesh Prabhu40daa012013-04-03 10:35:03 -070077
78 // Start a connection health check. The health check involves one or more
79 // attempts at establishing and using a TCP connection. |result_callback_| is
80 // called with the final result of the check. |result_callback_| will always
81 // be called after a call to Start() unless Stop() is called in the meantime.
82 // |result_callback_| may be called before Start() completes.
83 //
84 // Calling Start() while a health check is in progress is a no-op.
85 virtual void Start();
86
87 // Stop the current health check. No callback is called as a side effect of
88 // this function.
89 //
90 // Calling Stop() on a Stop()ed health check is a no-op.
91 virtual void Stop();
92
Prathmesh Prabhu5489b7a2013-04-10 13:33:59 -070093 static const char *ResultToString(Result result);
94
Prathmesh Prabhu40daa012013-04-03 10:35:03 -070095 // Accessors.
Prathmesh Prabhu3e452f82013-04-10 16:31:44 -070096 const IPAddresses &remote_ips() const { return remote_ips_; }
Prathmesh Prabhuade9b9a2013-04-22 18:01:19 -070097 virtual bool health_check_in_progress() const;
Prathmesh Prabhu40daa012013-04-03 10:35:03 -070098
Prathmesh Prabhuade9b9a2013-04-22 18:01:19 -070099
100 protected:
101 // For unit-tests.
102 void set_dispatcher(EventDispatcher *dispatcher) {
103 dispatcher_ = dispatcher;
104 }
105 void set_sock_fd(int sock_fd) { sock_fd_ = sock_fd; }
106 short num_connection_failures() const { return num_connection_failures_; }
107 void set_num_connection_failures(short val) {
108 num_connection_failures_ = val;
109 }
110 short num_tx_queue_polling_attempts() const {
111 return num_tx_queue_polling_attempts_;
112 }
113 void set_num_tx_queue_polling_attempts(short val) {
114 num_tx_queue_polling_attempts_ = val;
115 }
116 short num_congested_queue_detected() const {
117 return num_congested_queue_detected_;
118 }
119 void set_num_congested_queue_detected(short val) {
120 num_congested_queue_detected_ = val;
121 }
122 short num_successful_sends() const { return num_successful_sends_; }
123 void set_num_successful_sends(short val) {
124 num_successful_sends_ = val;
125 }
126 void set_old_transmit_queue_value(uint64 val) {
127 old_transmit_queue_value_ = val;
128 }
129 Result health_check_result() const { return health_check_result_; }
Prathmesh Prabhu40daa012013-04-03 10:35:03 -0700130 private:
131 friend class ConnectionHealthCheckerTest;
Prathmesh Prabhu3e452f82013-04-10 16:31:44 -0700132 FRIEND_TEST(ConnectionHealthCheckerTest, GarbageCollectDNSClients);
Prathmesh Prabhu40daa012013-04-03 10:35:03 -0700133 FRIEND_TEST(ConnectionHealthCheckerTest, GetSocketInfo);
Prathmesh Prabhuade9b9a2013-04-22 18:01:19 -0700134 FRIEND_TEST(ConnectionHealthCheckerTest, NextHealthCheckSample);
135 FRIEND_TEST(ConnectionHealthCheckerTest, OnConnectionComplete);
136 FRIEND_TEST(ConnectionHealthCheckerTest, VerifySentData);
Prathmesh Prabhu40daa012013-04-03 10:35:03 -0700137
138 // Time to wait for DNS server.
Prathmesh Prabhu3e452f82013-04-10 16:31:44 -0700139 static const int kDNSTimeoutMilliseconds;
Prathmesh Prabhuade9b9a2013-04-22 18:01:19 -0700140 static const int kInvalidSocket;
141 // After |kMaxFailedConnectionAttempts| failed attempts to connect, give up
142 // health check and return failure.
143 static const int kMaxFailedConnectionAttempts;
144 // After sending a small amount of data, attempt |kMaxSentDataPollingAttempts|
145 // times to see if the data was sent successfully.
146 static const int kMaxSentDataPollingAttempts;
147 // After |kMinCongestedQueueAttempts| to send data indicate a congested tx
148 // queue, finish health check and report a congested queue.
149 static const int kMinCongestedQueueAttempts;
150 // After sending data |kMinSuccessfulAttempts| times succesfully, finish
151 // health check and report a healthy connection.
152 static const int kMinSuccessfulSendAttempts;
Prathmesh Prabhu3e452f82013-04-10 16:31:44 -0700153 // Number of DNS queries to be spawned when a new remote URL is added.
154 static const int kNumDNSQueries;
Prathmesh Prabhuade9b9a2013-04-22 18:01:19 -0700155 // Time to wait before testing successful data transfer / disconnect after
156 // request is made on the device.
157 static const int kTCPStateUpdateWaitMilliseconds;
158
Prathmesh Prabhu40daa012013-04-03 10:35:03 -0700159 static const uint16 kRemotePort;
160
Prathmesh Prabhuade9b9a2013-04-22 18:01:19 -0700161 // Callback for DnsClient
162 void GetDNSResult(const Error &error, const IPAddress &ip);
163 void GarbageCollectDNSClients();
164
Prathmesh Prabhu40daa012013-04-03 10:35:03 -0700165 // Start a new AsyncConnection with callback set to OnConnectionComplete().
Prathmesh Prabhuade9b9a2013-04-22 18:01:19 -0700166 void NextHealthCheckSample();
167 void ReportResult();
Prathmesh Prabhu40daa012013-04-03 10:35:03 -0700168
169 // Callback for AsyncConnection.
170 // Observe the setup connection to test health state
171 void OnConnectionComplete(bool success, int sock_fd);
172
Prathmesh Prabhuade9b9a2013-04-22 18:01:19 -0700173 void VerifySentData();
Prathmesh Prabhu40daa012013-04-03 10:35:03 -0700174 bool GetSocketInfo(int sock_fd, SocketInfo *sock_info);
175
Prathmesh Prabhuade9b9a2013-04-22 18:01:19 -0700176 void SetSocketDescriptor(int sock_fd);
177 void ClearSocketDescriptor();
178
179 // The connection on which the health check is being run.
Prathmesh Prabhu40daa012013-04-03 10:35:03 -0700180 ConnectionRefPtr connection_;
181 EventDispatcher *dispatcher_;
Prathmesh Prabhuade9b9a2013-04-22 18:01:19 -0700182
183 // The client function to call to report the result.
Prathmesh Prabhu40daa012013-04-03 10:35:03 -0700184 base::Callback<void(Result)> result_callback_;
185
Prathmesh Prabhu40daa012013-04-03 10:35:03 -0700186 scoped_ptr<Sockets> socket_;
187 base::WeakPtrFactory<ConnectionHealthChecker> weak_ptr_factory_;
Prathmesh Prabhuade9b9a2013-04-22 18:01:19 -0700188
189 // Set of IPs to create TCP connection with for the health check.
190 IPAddresses remote_ips_;
191 // Callback passed to |tcp_connection_| to report an established TCP
192 // connection.
Prathmesh Prabhu40daa012013-04-03 10:35:03 -0700193 const base::Callback<void(bool, int)> connection_complete_callback_;
Prathmesh Prabhuade9b9a2013-04-22 18:01:19 -0700194 // Active TCP connection during health check.
Prathmesh Prabhu40daa012013-04-03 10:35:03 -0700195 scoped_ptr<AsyncConnection> tcp_connection_;
Prathmesh Prabhuade9b9a2013-04-22 18:01:19 -0700196 const base::Callback<void(void)> report_result_;
197 // Active socket for |tcp_connection_| during an active health check.
198 int sock_fd_;
199 // Interface to read TCP connection information from the system.
200 scoped_ptr<SocketInfoReader> socket_info_reader_;
201
Prathmesh Prabhu3e452f82013-04-10 16:31:44 -0700202 DNSClientFactory *dns_client_factory_;
203 ScopedVector<DNSClient> dns_clients_;
Prathmesh Prabhuade9b9a2013-04-22 18:01:19 -0700204 const base::Callback<void(const Error&, const IPAddress&)>
205 dns_client_callback_;
206
207 // Store the old value of the transmit queue to verify that data sent on the
208 // connection is actually transmitted.
209 uint64 old_transmit_queue_value_;
210 // Callback to post a delayed check on whether data sent on the TCP connection
211 // was successfully transmitted.
212 base::CancelableClosure verify_sent_data_callback_;
213
Prathmesh Prabhu40daa012013-04-03 10:35:03 -0700214 bool health_check_in_progress_;
Prathmesh Prabhuade9b9a2013-04-22 18:01:19 -0700215 // Number of connection failures in currently active health check.
216 short num_connection_failures_;
217 // Number of times we have checked the tx-queue for the current send attempt.
218 short num_tx_queue_polling_attempts_;
219 // Number of out of credit scenarios detected in currentl health check.
220 short num_congested_queue_detected_;
221 // Number of successful send attempts currently active health check.
222 short num_successful_sends_;
223
224 // Temporarily store the result of health check so that |report_result_|
225 // can report it.
226 Result health_check_result_;
Prathmesh Prabhu40daa012013-04-03 10:35:03 -0700227
228 DISALLOW_COPY_AND_ASSIGN(ConnectionHealthChecker);
229};
230
231} // namespace shill
232
233#endif // SHILL_CONNECTION_HEALTH_CHECKER_H_