blob: 8aac9dc369019d7e74a731fa72288722312eb952 [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
42 enum Result {
43 // There was some problem in the setup of ConnctionHealthChecker.
44 // Could not attempt a tcp connection.
45 kResultUnknown,
46 // New health check request made successfully. The result of the health
47 // check is returned asynchronously.
48 kResultInProgress,
49 // Failed to create TCP connection. Condition -(1)-.
50 kResultConnectionFailure,
51 // Failed to destroy TCP connection. Condition -(2)-.
52 kResultElongatedTimeWait,
53 // Failed to send data on TCP connection. Condition -(2)-.
54 kResultCongestedTxQueue,
55 // Condition -(3)-.
56 kResultSuccess
57 };
58
59 ConnectionHealthChecker(ConnectionRefPtr connection,
60 EventDispatcher *dispatcher,
61 const base::Callback<void(Result)> &result_callback);
62 virtual ~ConnectionHealthChecker();
63
64 // A new ConnectionHealthChecker is created with a default URL to attempt the
65 // TCP connection with. Add a URL to try.
66 void AddRemoteURL(const std::string &url_string);
67
68 // Name resolution can fail in conditions -(1)- and -(2)-. Add an IP address
69 // to attempt the TCP connection with.
70 void AddRemoteIP(IPAddress ip);
71
72 // Start a connection health check. The health check involves one or more
73 // attempts at establishing and using a TCP connection. |result_callback_| is
74 // called with the final result of the check. |result_callback_| will always
75 // be called after a call to Start() unless Stop() is called in the meantime.
76 // |result_callback_| may be called before Start() completes.
77 //
78 // Calling Start() while a health check is in progress is a no-op.
79 virtual void Start();
80
81 // Stop the current health check. No callback is called as a side effect of
82 // this function.
83 //
84 // Calling Stop() on a Stop()ed health check is a no-op.
85 virtual void Stop();
86
87 // Accessors.
88 const IPAddressQueue &remote_ips() { return remote_ips_; }
89 void set_run_data_test(bool val) { run_data_test_ = val; }
90
91 private:
92 friend class ConnectionHealthCheckerTest;
93 FRIEND_TEST(ConnectionHealthCheckerTest, GetSocketInfo);
94 FRIEND_TEST(ConnectionHealthCheckerTest, SendData);
95 FRIEND_TEST(ConnectionHealthCheckerTest, ShutDown);
96
97 // Time to wait for DNS server.
98 static const int kDNSTimeoutSeconds;
99 // Number of connection attempts before failure per health check request.
100 static const int kMaxConnectionAttempts;
101 static const uint16 kRemotePort;
102
103 // Start a new AsyncConnection with callback set to OnConnectionComplete().
104 void SetupTcpConnection();
105
106 // Callback for AsyncConnection.
107 // Observe the setup connection to test health state
108 void OnConnectionComplete(bool success, int sock_fd);
109
110 // Callback for DnsClient
111 void GetDNSResult(const Error &error, const IPAddress &ip);
112
113 void TryNextIP();
114 Result SendData(int sock_fd);
115 Result ShutDown(int sock_fd);
116 bool GetSocketInfo(int sock_fd, SocketInfo *sock_info);
117
118 ConnectionRefPtr connection_;
119 EventDispatcher *dispatcher_;
120 base::Callback<void(Result)> result_callback_;
121
122 IPAddressQueue remote_ips_;
123 scoped_ptr<SocketInfoReader> socket_info_reader_;
124 scoped_ptr<Sockets> socket_;
125 base::WeakPtrFactory<ConnectionHealthChecker> weak_ptr_factory_;
126 const base::Callback<void(bool, int)> connection_complete_callback_;
127 const base::Callback<void(const Error&, const IPAddress&)>
128 dns_client_callback_;
129 scoped_ptr<AsyncConnection> tcp_connection_;
130 scoped_ptr<DNSClient> dns_client_;
131 // If true, HealthChecker attempts to send a small amount of data over
132 // the network during the test. Otherwise, the inference is based on
133 // the connection open/close behaviour.
134 // Default: true
135 bool run_data_test_;
136 bool health_check_in_progress_;
137 short num_connection_attempts_;
138
139 DISALLOW_COPY_AND_ASSIGN(ConnectionHealthChecker);
140};
141
142} // namespace shill
143
144#endif // SHILL_CONNECTION_HEALTH_CHECKER_H_