1c0beca55d290fe0b1c96d78cbbcf94b05c23f5a5Peter Qiu// 2c0beca55d290fe0b1c96d78cbbcf94b05c23f5a5Peter Qiu// Copyright (C) 2012 The Android Open Source Project 3c0beca55d290fe0b1c96d78cbbcf94b05c23f5a5Peter Qiu// 4c0beca55d290fe0b1c96d78cbbcf94b05c23f5a5Peter Qiu// Licensed under the Apache License, Version 2.0 (the "License"); 5c0beca55d290fe0b1c96d78cbbcf94b05c23f5a5Peter Qiu// you may not use this file except in compliance with the License. 6c0beca55d290fe0b1c96d78cbbcf94b05c23f5a5Peter Qiu// You may obtain a copy of the License at 7c0beca55d290fe0b1c96d78cbbcf94b05c23f5a5Peter Qiu// 8c0beca55d290fe0b1c96d78cbbcf94b05c23f5a5Peter Qiu// http://www.apache.org/licenses/LICENSE-2.0 9c0beca55d290fe0b1c96d78cbbcf94b05c23f5a5Peter Qiu// 10c0beca55d290fe0b1c96d78cbbcf94b05c23f5a5Peter Qiu// Unless required by applicable law or agreed to in writing, software 11c0beca55d290fe0b1c96d78cbbcf94b05c23f5a5Peter Qiu// distributed under the License is distributed on an "AS IS" BASIS, 12c0beca55d290fe0b1c96d78cbbcf94b05c23f5a5Peter Qiu// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13c0beca55d290fe0b1c96d78cbbcf94b05c23f5a5Peter Qiu// See the License for the specific language governing permissions and 14c0beca55d290fe0b1c96d78cbbcf94b05c23f5a5Peter Qiu// limitations under the License. 15c0beca55d290fe0b1c96d78cbbcf94b05c23f5a5Peter Qiu// 16e692740c0623d4cb5d92d36214982ee45a03a5dbPaul Stewart 17c45688bb3881f0c2216e6ec0e19ebda0be33e871Ben Chan#ifndef SHILL_PORTAL_DETECTOR_H_ 18c45688bb3881f0c2216e6ec0e19ebda0be33e871Ben Chan#define SHILL_PORTAL_DETECTOR_H_ 19e692740c0623d4cb5d92d36214982ee45a03a5dbPaul Stewart 20cd47732488cd101eaf0d3558dde5a7d4e4fc260bBen Chan#include <memory> 21e692740c0623d4cb5d92d36214982ee45a03a5dbPaul Stewart#include <string> 22e692740c0623d4cb5d92d36214982ee45a03a5dbPaul Stewart#include <vector> 23e692740c0623d4cb5d92d36214982ee45a03a5dbPaul Stewart 243e20a2341d0aeb7681e4ee0f89eae6817ade2b3bEric Shienbrood#include <base/callback.h> 25f582b50dc416de301f3e4a5f1712a93b9ce02e95Paul Stewart#include <base/cancelable_callback.h> 26e692740c0623d4cb5d92d36214982ee45a03a5dbPaul Stewart#include <base/memory/ref_counted.h> 273e20a2341d0aeb7681e4ee0f89eae6817ade2b3bEric Shienbrood#include <base/memory/weak_ptr.h> 28e692740c0623d4cb5d92d36214982ee45a03a5dbPaul Stewart#include <gtest/gtest_prod.h> // for FRIEND_TEST 29e692740c0623d4cb5d92d36214982ee45a03a5dbPaul Stewart 303d49ea435a59436f762c2cc5e750ff27ece0d3c5Rebecca Silberstein#include "shill/connectivity_trial.h" 318d6b59704591ba9fad57751858835dc332dbdd37Peter Qiu#include "shill/net/shill_time.h" 32e692740c0623d4cb5d92d36214982ee45a03a5dbPaul Stewart#include "shill/refptr_types.h" 33e692740c0623d4cb5d92d36214982ee45a03a5dbPaul Stewart 34e692740c0623d4cb5d92d36214982ee45a03a5dbPaul Stewartnamespace shill { 35e692740c0623d4cb5d92d36214982ee45a03a5dbPaul Stewart 36bdb02e664f79f29b3bce9be4ca05c82d8ede697fPaul Stewartclass ByteString; 37e692740c0623d4cb5d92d36214982ee45a03a5dbPaul Stewartclass PortalDetector; 38e692740c0623d4cb5d92d36214982ee45a03a5dbPaul Stewartclass Time; 39e692740c0623d4cb5d92d36214982ee45a03a5dbPaul Stewart 40e692740c0623d4cb5d92d36214982ee45a03a5dbPaul Stewart// The PortalDetector class implements the portal detection 41e692740c0623d4cb5d92d36214982ee45a03a5dbPaul Stewart// facility in shill, which is responsible for checking to see 42e692740c0623d4cb5d92d36214982ee45a03a5dbPaul Stewart// if a connection has "general internet connectivity". 43e692740c0623d4cb5d92d36214982ee45a03a5dbPaul Stewart// 44e692740c0623d4cb5d92d36214982ee45a03a5dbPaul Stewart// This information can be used for ranking one connection 45e692740c0623d4cb5d92d36214982ee45a03a5dbPaul Stewart// against another, or for informing UI and other components 46e692740c0623d4cb5d92d36214982ee45a03a5dbPaul Stewart// outside the connection manager whether the connection seems 47e692740c0623d4cb5d92d36214982ee45a03a5dbPaul Stewart// available for "general use" or if further user action may be 48e692740c0623d4cb5d92d36214982ee45a03a5dbPaul Stewart// necessary (e.g, click through of a WiFi Hotspot's splash 49e692740c0623d4cb5d92d36214982ee45a03a5dbPaul Stewart// page). 50e692740c0623d4cb5d92d36214982ee45a03a5dbPaul Stewart// 513d49ea435a59436f762c2cc5e750ff27ece0d3c5Rebecca Silberstein// This is achieved by using one or more ConnectivityTrial attempts 523d49ea435a59436f762c2cc5e750ff27ece0d3c5Rebecca Silberstein// to access a URL and expecting a specific response. Any result 533d49ea435a59436f762c2cc5e750ff27ece0d3c5Rebecca Silberstein// that deviates from this result (DNS or HTTP errors, as well as 543d49ea435a59436f762c2cc5e750ff27ece0d3c5Rebecca Silberstein// deviations from the expected content) are considered failures. 55e692740c0623d4cb5d92d36214982ee45a03a5dbPaul Stewartclass PortalDetector { 56e692740c0623d4cb5d92d36214982ee45a03a5dbPaul Stewart public: 57e692740c0623d4cb5d92d36214982ee45a03a5dbPaul Stewart struct Result { 5885e050b4923878a57aec1415314d2b39ff233e00Thieu Le Result() 593d49ea435a59436f762c2cc5e750ff27ece0d3c5Rebecca Silberstein : trial_result(ConnectivityTrial::Result()), 603d49ea435a59436f762c2cc5e750ff27ece0d3c5Rebecca Silberstein num_attempts(0), 613d49ea435a59436f762c2cc5e750ff27ece0d3c5Rebecca Silberstein final(false) {} 623d49ea435a59436f762c2cc5e750ff27ece0d3c5Rebecca Silberstein explicit Result(ConnectivityTrial::Result result_in) 633d49ea435a59436f762c2cc5e750ff27ece0d3c5Rebecca Silberstein : trial_result(result_in), 643d49ea435a59436f762c2cc5e750ff27ece0d3c5Rebecca Silberstein num_attempts(0), 653d49ea435a59436f762c2cc5e750ff27ece0d3c5Rebecca Silberstein final(false) {} 663d49ea435a59436f762c2cc5e750ff27ece0d3c5Rebecca Silberstein Result(ConnectivityTrial::Result result_in, 673d49ea435a59436f762c2cc5e750ff27ece0d3c5Rebecca Silberstein int num_attempts_in, 683d49ea435a59436f762c2cc5e750ff27ece0d3c5Rebecca Silberstein int final_in) 693d49ea435a59436f762c2cc5e750ff27ece0d3c5Rebecca Silberstein : trial_result(result_in), 703d49ea435a59436f762c2cc5e750ff27ece0d3c5Rebecca Silberstein num_attempts(num_attempts_in), 713d49ea435a59436f762c2cc5e750ff27ece0d3c5Rebecca Silberstein final(final_in) {} 723d49ea435a59436f762c2cc5e750ff27ece0d3c5Rebecca Silberstein 733d49ea435a59436f762c2cc5e750ff27ece0d3c5Rebecca Silberstein ConnectivityTrial::Result trial_result; 743d49ea435a59436f762c2cc5e750ff27ece0d3c5Rebecca Silberstein 753d49ea435a59436f762c2cc5e750ff27ece0d3c5Rebecca Silberstein // Total number of connectivity trials attempted. 7685e050b4923878a57aec1415314d2b39ff233e00Thieu Le // This includes failure, timeout and successful attempts. 7785e050b4923878a57aec1415314d2b39ff233e00Thieu Le // This only valid when |final| is true. 7885e050b4923878a57aec1415314d2b39ff233e00Thieu Le int num_attempts; 79e692740c0623d4cb5d92d36214982ee45a03a5dbPaul Stewart bool final; 80e692740c0623d4cb5d92d36214982ee45a03a5dbPaul Stewart }; 81e692740c0623d4cb5d92d36214982ee45a03a5dbPaul Stewart 82c681fa0742cabc686ccabaf0fdf6ce12dd7046b2Paul Stewart static const int kDefaultCheckIntervalSeconds; 83f555cf8aac732cbe02913293ac6253629ade9be5Paul Stewart static const char kDefaultCheckPortalList[]; 8485e050b4923878a57aec1415314d2b39ff233e00Thieu Le // Maximum number of times the PortalDetector will attempt a connection. 8585e050b4923878a57aec1415314d2b39ff233e00Thieu Le static const int kMaxRequestAttempts; 86e692740c0623d4cb5d92d36214982ee45a03a5dbPaul Stewart 87e692740c0623d4cb5d92d36214982ee45a03a5dbPaul Stewart PortalDetector(ConnectionRefPtr connection, 881a212a6b98b22ad1d69652bb26a9e94138635476Paul Stewart EventDispatcher* dispatcher, 893d49ea435a59436f762c2cc5e750ff27ece0d3c5Rebecca Silberstein const base::Callback<void(const PortalDetector::Result&)> 903d49ea435a59436f762c2cc5e750ff27ece0d3c5Rebecca Silberstein &callback); 91e692740c0623d4cb5d92d36214982ee45a03a5dbPaul Stewart virtual ~PortalDetector(); 92e692740c0623d4cb5d92d36214982ee45a03a5dbPaul Stewart 93e692740c0623d4cb5d92d36214982ee45a03a5dbPaul Stewart // Start a portal detection test. Returns true if |url_string| correctly 94e692740c0623d4cb5d92d36214982ee45a03a5dbPaul Stewart // parses as a URL. Returns false (and does not start) if the |url_string| 95e692740c0623d4cb5d92d36214982ee45a03a5dbPaul Stewart // fails to parse. 96e692740c0623d4cb5d92d36214982ee45a03a5dbPaul Stewart // 97e692740c0623d4cb5d92d36214982ee45a03a5dbPaul Stewart // As each attempt completes the callback handed to the constructor will 98e692740c0623d4cb5d92d36214982ee45a03a5dbPaul Stewart // be called. The PortalDetector will try up to kMaxRequestAttempts times 99e692740c0623d4cb5d92d36214982ee45a03a5dbPaul Stewart // to successfully retrieve the URL. If the attempt is successful or 100e692740c0623d4cb5d92d36214982ee45a03a5dbPaul Stewart // this is the last attempt, the "final" flag in the Result structure will 101e692740c0623d4cb5d92d36214982ee45a03a5dbPaul Stewart // be true, otherwise it will be false, and the PortalDetector will 102e692740c0623d4cb5d92d36214982ee45a03a5dbPaul Stewart // schedule the next attempt. 1031a212a6b98b22ad1d69652bb26a9e94138635476Paul Stewart virtual bool Start(const std::string& url_string); 1041a212a6b98b22ad1d69652bb26a9e94138635476Paul Stewart virtual bool StartAfterDelay(const std::string& url_string, 105c681fa0742cabc686ccabaf0fdf6ce12dd7046b2Paul Stewart int delay_seconds); 106e692740c0623d4cb5d92d36214982ee45a03a5dbPaul Stewart 107e692740c0623d4cb5d92d36214982ee45a03a5dbPaul Stewart // End the current portal detection process if one exists, and do not call 108e692740c0623d4cb5d92d36214982ee45a03a5dbPaul Stewart // the callback. 109c681fa0742cabc686ccabaf0fdf6ce12dd7046b2Paul Stewart virtual void Stop(); 110c681fa0742cabc686ccabaf0fdf6ce12dd7046b2Paul Stewart 1113d49ea435a59436f762c2cc5e750ff27ece0d3c5Rebecca Silberstein // Returns whether portal request is "in progress": whether the underlying 1123d49ea435a59436f762c2cc5e750ff27ece0d3c5Rebecca Silberstein // ConnectivityTrial is in the progress of making attempts. Returns true if 113c681fa0742cabc686ccabaf0fdf6ce12dd7046b2Paul Stewart // attempts are in progress, false otherwise. Notably, this function 114c681fa0742cabc686ccabaf0fdf6ce12dd7046b2Paul Stewart // returns false during the period of time between calling "Start" or 1153d49ea435a59436f762c2cc5e750ff27ece0d3c5Rebecca Silberstein // "StartAfterDelay" and the actual start of the first attempt. In the case 1163d49ea435a59436f762c2cc5e750ff27ece0d3c5Rebecca Silberstein // where multiple attempts may be tried, IsInProgress will return true after 1173d49ea435a59436f762c2cc5e750ff27ece0d3c5Rebecca Silberstein // the first attempt has actively started testing the connection. 118c681fa0742cabc686ccabaf0fdf6ce12dd7046b2Paul Stewart virtual bool IsInProgress(); 119e692740c0623d4cb5d92d36214982ee45a03a5dbPaul Stewart 120e692740c0623d4cb5d92d36214982ee45a03a5dbPaul Stewart private: 121e692740c0623d4cb5d92d36214982ee45a03a5dbPaul Stewart friend class PortalDetectorTest; 122e692740c0623d4cb5d92d36214982ee45a03a5dbPaul Stewart FRIEND_TEST(PortalDetectorTest, StartAttemptFailed); 1233d49ea435a59436f762c2cc5e750ff27ece0d3c5Rebecca Silberstein FRIEND_TEST(PortalDetectorTest, AdjustStartDelayImmediate); 1243d49ea435a59436f762c2cc5e750ff27ece0d3c5Rebecca Silberstein FRIEND_TEST(PortalDetectorTest, AdjustStartDelayAfterDelay); 125e692740c0623d4cb5d92d36214982ee45a03a5dbPaul Stewart FRIEND_TEST(PortalDetectorTest, AttemptCount); 1266e1dc0ff12ceb0fea899ceb5c0f4798e35d86b71Christopher Wiley FRIEND_TEST(PortalDetectorTest, ReadBadHeadersRetry); 1273d49ea435a59436f762c2cc5e750ff27ece0d3c5Rebecca Silberstein FRIEND_TEST(PortalDetectorTest, ReadBadHeader); 1283d49ea435a59436f762c2cc5e750ff27ece0d3c5Rebecca Silberstein FRIEND_TEST(PortalDetectorTest, RequestTimeout); 1293d49ea435a59436f762c2cc5e750ff27ece0d3c5Rebecca Silberstein FRIEND_TEST(PortalDetectorTest, ReadPartialHeaderTimeout); 1303d49ea435a59436f762c2cc5e750ff27ece0d3c5Rebecca Silberstein FRIEND_TEST(PortalDetectorTest, ReadCompleteHeader); 1313d49ea435a59436f762c2cc5e750ff27ece0d3c5Rebecca Silberstein FRIEND_TEST(PortalDetectorTest, ReadMatchingHeader); 1323d49ea435a59436f762c2cc5e750ff27ece0d3c5Rebecca Silberstein FRIEND_TEST(PortalDetectorTest, InvalidURL); 133e692740c0623d4cb5d92d36214982ee45a03a5dbPaul Stewart 134e692740c0623d4cb5d92d36214982ee45a03a5dbPaul Stewart // Minimum time between attempts to connect to server. 135e692740c0623d4cb5d92d36214982ee45a03a5dbPaul Stewart static const int kMinTimeBetweenAttemptsSeconds; 136e692740c0623d4cb5d92d36214982ee45a03a5dbPaul Stewart // Time to wait for request to complete. 137e692740c0623d4cb5d92d36214982ee45a03a5dbPaul Stewart static const int kRequestTimeoutSeconds; 1386e1dc0ff12ceb0fea899ceb5c0f4798e35d86b71Christopher Wiley // Maximum number of failures in content phase before we stop attempting 1396e1dc0ff12ceb0fea899ceb5c0f4798e35d86b71Christopher Wiley // connections. 1406e1dc0ff12ceb0fea899ceb5c0f4798e35d86b71Christopher Wiley static const int kMaxFailuresInContentPhase; 141e692740c0623d4cb5d92d36214982ee45a03a5dbPaul Stewart 1423d49ea435a59436f762c2cc5e750ff27ece0d3c5Rebecca Silberstein // Internal method to update the start time of the next event. This is used 1433d49ea435a59436f762c2cc5e750ff27ece0d3c5Rebecca Silberstein // to keep attempts spaced by at least kMinTimeBetweenAttemptsSeconds in the 1443d49ea435a59436f762c2cc5e750ff27ece0d3c5Rebecca Silberstein // event of a retry. 1453d49ea435a59436f762c2cc5e750ff27ece0d3c5Rebecca Silberstein void UpdateAttemptTime(int delay_seconds); 1463d49ea435a59436f762c2cc5e750ff27ece0d3c5Rebecca Silberstein 1473d49ea435a59436f762c2cc5e750ff27ece0d3c5Rebecca Silberstein // Internal method used to adjust the start delay in the event of a retry. 1483d49ea435a59436f762c2cc5e750ff27ece0d3c5Rebecca Silberstein // Calculates the elapsed time between the most recent attempt and the point 1493d49ea435a59436f762c2cc5e750ff27ece0d3c5Rebecca Silberstein // the retry is scheduled. Adds an additional delay to meet the 1503d49ea435a59436f762c2cc5e750ff27ece0d3c5Rebecca Silberstein // kMinTimeBetweenAttemptsSeconds requirement. 1513d49ea435a59436f762c2cc5e750ff27ece0d3c5Rebecca Silberstein int AdjustStartDelay(int init_delay_seconds); 1523d49ea435a59436f762c2cc5e750ff27ece0d3c5Rebecca Silberstein 1533d49ea435a59436f762c2cc5e750ff27ece0d3c5Rebecca Silberstein // Callback used by ConnectivityTrial to return |result| after attempting to 1543d49ea435a59436f762c2cc5e750ff27ece0d3c5Rebecca Silberstein // determine connectivity status. 1553d49ea435a59436f762c2cc5e750ff27ece0d3c5Rebecca Silberstein void CompleteAttempt(ConnectivityTrial::Result result); 156e692740c0623d4cb5d92d36214982ee45a03a5dbPaul Stewart 157e692740c0623d4cb5d92d36214982ee45a03a5dbPaul Stewart int attempt_count_; 158e692740c0623d4cb5d92d36214982ee45a03a5dbPaul Stewart struct timeval attempt_start_time_; 159e692740c0623d4cb5d92d36214982ee45a03a5dbPaul Stewart ConnectionRefPtr connection_; 1601a212a6b98b22ad1d69652bb26a9e94138635476Paul Stewart EventDispatcher* dispatcher_; 1613e20a2341d0aeb7681e4ee0f89eae6817ade2b3bEric Shienbrood base::WeakPtrFactory<PortalDetector> weak_ptr_factory_; 1621a212a6b98b22ad1d69652bb26a9e94138635476Paul Stewart base::Callback<void(const Result&)> portal_result_callback_; 1633d49ea435a59436f762c2cc5e750ff27ece0d3c5Rebecca Silberstein base::Callback<void(ConnectivityTrial::Result)> connectivity_trial_callback_; 1641a212a6b98b22ad1d69652bb26a9e94138635476Paul Stewart Time* time_; 1656e1dc0ff12ceb0fea899ceb5c0f4798e35d86b71Christopher Wiley int failures_in_content_phase_; 166cd47732488cd101eaf0d3558dde5a7d4e4fc260bBen Chan std::unique_ptr<ConnectivityTrial> connectivity_trial_; 1673d49ea435a59436f762c2cc5e750ff27ece0d3c5Rebecca Silberstein 168e692740c0623d4cb5d92d36214982ee45a03a5dbPaul Stewart 169e692740c0623d4cb5d92d36214982ee45a03a5dbPaul Stewart DISALLOW_COPY_AND_ASSIGN(PortalDetector); 170e692740c0623d4cb5d92d36214982ee45a03a5dbPaul Stewart}; 171e692740c0623d4cb5d92d36214982ee45a03a5dbPaul Stewart 172e692740c0623d4cb5d92d36214982ee45a03a5dbPaul Stewart} // namespace shill 173e692740c0623d4cb5d92d36214982ee45a03a5dbPaul Stewart 174c45688bb3881f0c2216e6ec0e19ebda0be33e871Ben Chan#endif // SHILL_PORTAL_DETECTOR_H_ 175