blob: 20fca7aa4de06a88682a395d14d4cb3948013b55 [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>
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;
Prathmesh Prabhu3e452f82013-04-10 16:31:44 -070025class DNSClientFactory;
Prathmesh Prabhu40daa012013-04-03 10:35:03 -070026class Error;
27class EventDispatcher;
28class IPAddress;
29class SocketInfoReader;
30
31// The ConnectionHealthChecker class implements the facilities to test
32// connectivity status on some connection asynchronously.
33// In particular, the class can distinguish between three states of the
34// connection:
35// -(1)- No connectivity (TCP connection can not be established)
36// -(2)- Partial connectivity (TCP connection can be established, but no data
37// transfer)
38// -(3)- Connectivity OK (TCP connection established, is healthy)
39class ConnectionHealthChecker {
40 public:
Prathmesh Prabhu3e452f82013-04-10 16:31:44 -070041 typedef std::vector<IPAddress> IPAddresses;
Prathmesh Prabhu40daa012013-04-03 10:35:03 -070042
Prathmesh Prabhu5489b7a2013-04-10 13:33:59 -070043 // TODO(pprabhu): Rename kResultElongatedTimeWait to kResultTearDownFailure.
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,
48 // New health check request made successfully. The result of the health
49 // check is returned asynchronously.
50 kResultInProgress,
51 // Failed to create TCP connection. Condition -(1)-.
52 kResultConnectionFailure,
53 // Failed to destroy TCP connection. Condition -(2)-.
54 kResultElongatedTimeWait,
55 // Failed to send data on TCP connection. Condition -(2)-.
56 kResultCongestedTxQueue,
57 // Condition -(3)-.
58 kResultSuccess
59 };
60
61 ConnectionHealthChecker(ConnectionRefPtr connection,
62 EventDispatcher *dispatcher,
63 const base::Callback<void(Result)> &result_callback);
64 virtual ~ConnectionHealthChecker();
65
66 // A new ConnectionHealthChecker is created with a default URL to attempt the
67 // TCP connection with. Add a URL to try.
Arman Ugurayf84a4242013-04-09 20:01:07 -070068 virtual void AddRemoteURL(const std::string &url_string);
Prathmesh Prabhu40daa012013-04-03 10:35:03 -070069
70 // Name resolution can fail in conditions -(1)- and -(2)-. Add an IP address
71 // to attempt the TCP connection with.
Arman Ugurayf84a4242013-04-09 20:01:07 -070072 virtual void AddRemoteIP(IPAddress ip);
Prathmesh Prabhu40daa012013-04-03 10:35:03 -070073
74 // Start a connection health check. The health check involves one or more
75 // attempts at establishing and using a TCP connection. |result_callback_| is
76 // called with the final result of the check. |result_callback_| will always
77 // be called after a call to Start() unless Stop() is called in the meantime.
78 // |result_callback_| may be called before Start() completes.
79 //
80 // Calling Start() while a health check is in progress is a no-op.
81 virtual void Start();
82
83 // Stop the current health check. No callback is called as a side effect of
84 // this function.
85 //
86 // Calling Stop() on a Stop()ed health check is a no-op.
87 virtual void Stop();
88
Prathmesh Prabhu5489b7a2013-04-10 13:33:59 -070089 static const char *ResultToString(Result result);
90
Prathmesh Prabhu40daa012013-04-03 10:35:03 -070091 // Accessors.
Prathmesh Prabhu3e452f82013-04-10 16:31:44 -070092 const IPAddresses &remote_ips() const { return remote_ips_; }
Prathmesh Prabhu40daa012013-04-03 10:35:03 -070093 void set_run_data_test(bool val) { run_data_test_ = val; }
Arman Ugurayf84a4242013-04-09 20:01:07 -070094 virtual bool health_check_in_progress() const {
95 return health_check_in_progress_;
96 }
Prathmesh Prabhu40daa012013-04-03 10:35:03 -070097
98 private:
99 friend class ConnectionHealthCheckerTest;
Prathmesh Prabhu3e452f82013-04-10 16:31:44 -0700100 FRIEND_TEST(ConnectionHealthCheckerTest, GarbageCollectDNSClients);
Prathmesh Prabhu40daa012013-04-03 10:35:03 -0700101 FRIEND_TEST(ConnectionHealthCheckerTest, GetSocketInfo);
102 FRIEND_TEST(ConnectionHealthCheckerTest, SendData);
103 FRIEND_TEST(ConnectionHealthCheckerTest, ShutDown);
104
105 // Time to wait for DNS server.
Prathmesh Prabhu3e452f82013-04-10 16:31:44 -0700106 static const int kDNSTimeoutMilliseconds;
Prathmesh Prabhu40daa012013-04-03 10:35:03 -0700107 // Number of connection attempts before failure per health check request.
108 static const int kMaxConnectionAttempts;
Prathmesh Prabhu3e452f82013-04-10 16:31:44 -0700109 // Number of DNS queries to be spawned when a new remote URL is added.
110 static const int kNumDNSQueries;
Prathmesh Prabhu40daa012013-04-03 10:35:03 -0700111 static const uint16 kRemotePort;
112
113 // Start a new AsyncConnection with callback set to OnConnectionComplete().
114 void SetupTcpConnection();
115
116 // Callback for AsyncConnection.
117 // Observe the setup connection to test health state
118 void OnConnectionComplete(bool success, int sock_fd);
119
120 // Callback for DnsClient
121 void GetDNSResult(const Error &error, const IPAddress &ip);
122
123 void TryNextIP();
124 Result SendData(int sock_fd);
125 Result ShutDown(int sock_fd);
126 bool GetSocketInfo(int sock_fd, SocketInfo *sock_info);
Prathmesh Prabhu3e452f82013-04-10 16:31:44 -0700127 void GarbageCollectDNSClients();
Prathmesh Prabhu40daa012013-04-03 10:35:03 -0700128
129 ConnectionRefPtr connection_;
130 EventDispatcher *dispatcher_;
131 base::Callback<void(Result)> result_callback_;
132
Prathmesh Prabhu3e452f82013-04-10 16:31:44 -0700133 IPAddresses remote_ips_;
Prathmesh Prabhu40daa012013-04-03 10:35:03 -0700134 scoped_ptr<SocketInfoReader> socket_info_reader_;
135 scoped_ptr<Sockets> socket_;
136 base::WeakPtrFactory<ConnectionHealthChecker> weak_ptr_factory_;
137 const base::Callback<void(bool, int)> connection_complete_callback_;
138 const base::Callback<void(const Error&, const IPAddress&)>
139 dns_client_callback_;
140 scoped_ptr<AsyncConnection> tcp_connection_;
Prathmesh Prabhu3e452f82013-04-10 16:31:44 -0700141 DNSClientFactory *dns_client_factory_;
142 ScopedVector<DNSClient> dns_clients_;
Prathmesh Prabhu40daa012013-04-03 10:35:03 -0700143 // If true, HealthChecker attempts to send a small amount of data over
144 // the network during the test. Otherwise, the inference is based on
145 // the connection open/close behaviour.
146 // Default: true
147 bool run_data_test_;
148 bool health_check_in_progress_;
149 short num_connection_attempts_;
150
151 DISALLOW_COPY_AND_ASSIGN(ConnectionHealthChecker);
152};
153
154} // namespace shill
155
156#endif // SHILL_CONNECTION_HEALTH_CHECKER_H_