blob: 22ace95f42dc8ad0750f45c7b6e2afdb0093d20d [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
8#include <queue>
9
10#include <base/basictypes.h>
11#include <base/callback.h>
12#include <base/memory/scoped_ptr.h>
13#include <base/memory/scoped_vector.h>
14#include <base/memory/weak_ptr.h>
15#include <gtest/gtest_prod.h>
16
17#include "shill/refptr_types.h"
18#include "shill/sockets.h"
19#include "shill/socket_info.h"
20
21namespace shill {
22
23class AsyncConnection;
24class DNSClient;
25class Error;
26class EventDispatcher;
27class IPAddress;
28class SocketInfoReader;
29
30// The ConnectionHealthChecker class implements the facilities to test
31// connectivity status on some connection asynchronously.
32// In particular, the class can distinguish between three states of the
33// connection:
34// -(1)- No connectivity (TCP connection can not be established)
35// -(2)- Partial connectivity (TCP connection can be established, but no data
36// transfer)
37// -(3)- Connectivity OK (TCP connection established, is healthy)
38class ConnectionHealthChecker {
39 public:
40 typedef std::queue<IPAddress> IPAddressQueue;
41
Prathmesh Prabhu5489b7a2013-04-10 13:33:59 -070042 // TODO(pprabhu): Rename kResultElongatedTimeWait to kResultTearDownFailure.
Prathmesh Prabhu40daa012013-04-03 10:35:03 -070043 enum Result {
44 // There was some problem in the setup of ConnctionHealthChecker.
45 // Could not attempt a tcp connection.
46 kResultUnknown,
47 // New health check request made successfully. The result of the health
48 // check is returned asynchronously.
49 kResultInProgress,
50 // Failed to create TCP connection. Condition -(1)-.
51 kResultConnectionFailure,
52 // Failed to destroy TCP connection. Condition -(2)-.
53 kResultElongatedTimeWait,
54 // Failed to send data on TCP connection. Condition -(2)-.
55 kResultCongestedTxQueue,
56 // Condition -(3)-.
57 kResultSuccess
58 };
59
60 ConnectionHealthChecker(ConnectionRefPtr connection,
61 EventDispatcher *dispatcher,
62 const base::Callback<void(Result)> &result_callback);
63 virtual ~ConnectionHealthChecker();
64
65 // A new ConnectionHealthChecker is created with a default URL to attempt the
66 // TCP connection with. Add a URL to try.
Arman Ugurayf84a4242013-04-09 20:01:07 -070067 virtual void AddRemoteURL(const std::string &url_string);
Prathmesh Prabhu40daa012013-04-03 10:35:03 -070068
69 // Name resolution can fail in conditions -(1)- and -(2)-. Add an IP address
70 // to attempt the TCP connection with.
Arman Ugurayf84a4242013-04-09 20:01:07 -070071 virtual void AddRemoteIP(IPAddress ip);
Prathmesh Prabhu40daa012013-04-03 10:35:03 -070072
73 // Start a connection health check. The health check involves one or more
74 // attempts at establishing and using a TCP connection. |result_callback_| is
75 // called with the final result of the check. |result_callback_| will always
76 // be called after a call to Start() unless Stop() is called in the meantime.
77 // |result_callback_| may be called before Start() completes.
78 //
79 // Calling Start() while a health check is in progress is a no-op.
80 virtual void Start();
81
82 // Stop the current health check. No callback is called as a side effect of
83 // this function.
84 //
85 // Calling Stop() on a Stop()ed health check is a no-op.
86 virtual void Stop();
87
Prathmesh Prabhu5489b7a2013-04-10 13:33:59 -070088 static const char *ResultToString(Result result);
89
Prathmesh Prabhu40daa012013-04-03 10:35:03 -070090 // Accessors.
91 const IPAddressQueue &remote_ips() { return remote_ips_; }
92 void set_run_data_test(bool val) { run_data_test_ = val; }
Arman Ugurayf84a4242013-04-09 20:01:07 -070093 virtual bool health_check_in_progress() const {
94 return health_check_in_progress_;
95 }
Prathmesh Prabhu40daa012013-04-03 10:35:03 -070096
97 private:
98 friend class ConnectionHealthCheckerTest;
99 FRIEND_TEST(ConnectionHealthCheckerTest, GetSocketInfo);
100 FRIEND_TEST(ConnectionHealthCheckerTest, SendData);
101 FRIEND_TEST(ConnectionHealthCheckerTest, ShutDown);
102
103 // Time to wait for DNS server.
104 static const int kDNSTimeoutSeconds;
105 // Number of connection attempts before failure per health check request.
106 static const int kMaxConnectionAttempts;
107 static const uint16 kRemotePort;
108
109 // Start a new AsyncConnection with callback set to OnConnectionComplete().
110 void SetupTcpConnection();
111
112 // Callback for AsyncConnection.
113 // Observe the setup connection to test health state
114 void OnConnectionComplete(bool success, int sock_fd);
115
116 // Callback for DnsClient
117 void GetDNSResult(const Error &error, const IPAddress &ip);
118
119 void TryNextIP();
120 Result SendData(int sock_fd);
121 Result ShutDown(int sock_fd);
122 bool GetSocketInfo(int sock_fd, SocketInfo *sock_info);
123
124 ConnectionRefPtr connection_;
125 EventDispatcher *dispatcher_;
126 base::Callback<void(Result)> result_callback_;
127
128 IPAddressQueue remote_ips_;
129 scoped_ptr<SocketInfoReader> socket_info_reader_;
130 scoped_ptr<Sockets> socket_;
131 base::WeakPtrFactory<ConnectionHealthChecker> weak_ptr_factory_;
132 const base::Callback<void(bool, int)> connection_complete_callback_;
133 const base::Callback<void(const Error&, const IPAddress&)>
134 dns_client_callback_;
135 scoped_ptr<AsyncConnection> tcp_connection_;
136 scoped_ptr<DNSClient> dns_client_;
137 // If true, HealthChecker attempts to send a small amount of data over
138 // the network during the test. Otherwise, the inference is based on
139 // the connection open/close behaviour.
140 // Default: true
141 bool run_data_test_;
142 bool health_check_in_progress_;
143 short num_connection_attempts_;
144
145 DISALLOW_COPY_AND_ASSIGN(ConnectionHealthChecker);
146};
147
148} // namespace shill
149
150#endif // SHILL_CONNECTION_HEALTH_CHECKER_H_