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// 163d49ea435a59436f762c2cc5e750ff27ece0d3c5Rebecca Silberstein 173d49ea435a59436f762c2cc5e750ff27ece0d3c5Rebecca Silberstein#ifndef SHILL_CONNECTIVITY_TRIAL_H_ 183d49ea435a59436f762c2cc5e750ff27ece0d3c5Rebecca Silberstein#define SHILL_CONNECTIVITY_TRIAL_H_ 193d49ea435a59436f762c2cc5e750ff27ece0d3c5Rebecca Silberstein 2022f1fbc11b69ee41af8370ec38f1b90577db6c3cBen Chan#include <memory> 213d49ea435a59436f762c2cc5e750ff27ece0d3c5Rebecca Silberstein#include <string> 223d49ea435a59436f762c2cc5e750ff27ece0d3c5Rebecca Silberstein#include <vector> 233d49ea435a59436f762c2cc5e750ff27ece0d3c5Rebecca Silberstein 243d49ea435a59436f762c2cc5e750ff27ece0d3c5Rebecca Silberstein#include <base/callback.h> 253d49ea435a59436f762c2cc5e750ff27ece0d3c5Rebecca Silberstein#include <base/cancelable_callback.h> 263d49ea435a59436f762c2cc5e750ff27ece0d3c5Rebecca Silberstein#include <base/memory/ref_counted.h> 273d49ea435a59436f762c2cc5e750ff27ece0d3c5Rebecca Silberstein#include <base/memory/weak_ptr.h> 283d49ea435a59436f762c2cc5e750ff27ece0d3c5Rebecca Silberstein#include <gtest/gtest_prod.h> // for FRIEND_TEST 293d49ea435a59436f762c2cc5e750ff27ece0d3c5Rebecca Silberstein 303d49ea435a59436f762c2cc5e750ff27ece0d3c5Rebecca Silberstein#include "shill/http_request.h" 313d49ea435a59436f762c2cc5e750ff27ece0d3c5Rebecca Silberstein#include "shill/http_url.h" 328d6b59704591ba9fad57751858835dc332dbdd37Peter Qiu#include "shill/net/shill_time.h" 338d6b59704591ba9fad57751858835dc332dbdd37Peter Qiu#include "shill/net/sockets.h" 343d49ea435a59436f762c2cc5e750ff27ece0d3c5Rebecca Silberstein#include "shill/refptr_types.h" 353d49ea435a59436f762c2cc5e750ff27ece0d3c5Rebecca Silberstein 363d49ea435a59436f762c2cc5e750ff27ece0d3c5Rebecca Silbersteinnamespace shill { 373d49ea435a59436f762c2cc5e750ff27ece0d3c5Rebecca Silberstein 383d49ea435a59436f762c2cc5e750ff27ece0d3c5Rebecca Silbersteinclass ByteString; 393d49ea435a59436f762c2cc5e750ff27ece0d3c5Rebecca Silbersteinclass EventDispatcher; 403d49ea435a59436f762c2cc5e750ff27ece0d3c5Rebecca Silbersteinclass Time; 413d49ea435a59436f762c2cc5e750ff27ece0d3c5Rebecca Silberstein 423d49ea435a59436f762c2cc5e750ff27ece0d3c5Rebecca Silberstein// The ConnectivityTrial class implements a single portal detection 433d49ea435a59436f762c2cc5e750ff27ece0d3c5Rebecca Silberstein// trial. Each trial checks if a connection has "general internet 443d49ea435a59436f762c2cc5e750ff27ece0d3c5Rebecca Silberstein// connectivity." 453d49ea435a59436f762c2cc5e750ff27ece0d3c5Rebecca Silberstein// 463d49ea435a59436f762c2cc5e750ff27ece0d3c5Rebecca Silberstein// ConnectivityTrial is responsible for managing the callbacks between the 473d49ea435a59436f762c2cc5e750ff27ece0d3c5Rebecca Silberstein// calling class requesting a connectivity trial and the HTTPRequest that is 483d49ea435a59436f762c2cc5e750ff27ece0d3c5Rebecca Silberstein// used to test connectivity. ConnectivityTrial maps between the HTTPRequest 493d49ea435a59436f762c2cc5e750ff27ece0d3c5Rebecca Silberstein// response codes to higher-level connection-oriented status. 503d49ea435a59436f762c2cc5e750ff27ece0d3c5Rebecca Silberstein// 513d49ea435a59436f762c2cc5e750ff27ece0d3c5Rebecca Silberstein// ConnectivityTrial tests the connection by attempting to parse and access a 523d49ea435a59436f762c2cc5e750ff27ece0d3c5Rebecca Silberstein// given URL. Any result that deviates from the expected behavior (DNS or HTTP 533d49ea435a59436f762c2cc5e750ff27ece0d3c5Rebecca Silberstein// errors, as well as retrieved content errors, and timeouts) are considered 543d49ea435a59436f762c2cc5e750ff27ece0d3c5Rebecca Silberstein// failures. 553d49ea435a59436f762c2cc5e750ff27ece0d3c5Rebecca Silberstein 563d49ea435a59436f762c2cc5e750ff27ece0d3c5Rebecca Silbersteinclass ConnectivityTrial { 573d49ea435a59436f762c2cc5e750ff27ece0d3c5Rebecca Silberstein public: 583d49ea435a59436f762c2cc5e750ff27ece0d3c5Rebecca Silberstein enum Phase { 593d49ea435a59436f762c2cc5e750ff27ece0d3c5Rebecca Silberstein kPhaseConnection, 603d49ea435a59436f762c2cc5e750ff27ece0d3c5Rebecca Silberstein kPhaseDNS, 613d49ea435a59436f762c2cc5e750ff27ece0d3c5Rebecca Silberstein kPhaseHTTP, 623d49ea435a59436f762c2cc5e750ff27ece0d3c5Rebecca Silberstein kPhaseContent, 633d49ea435a59436f762c2cc5e750ff27ece0d3c5Rebecca Silberstein kPhaseUnknown 643d49ea435a59436f762c2cc5e750ff27ece0d3c5Rebecca Silberstein }; 653d49ea435a59436f762c2cc5e750ff27ece0d3c5Rebecca Silberstein 663d49ea435a59436f762c2cc5e750ff27ece0d3c5Rebecca Silberstein enum Status { 673d49ea435a59436f762c2cc5e750ff27ece0d3c5Rebecca Silberstein kStatusFailure, 683d49ea435a59436f762c2cc5e750ff27ece0d3c5Rebecca Silberstein kStatusSuccess, 693d49ea435a59436f762c2cc5e750ff27ece0d3c5Rebecca Silberstein kStatusTimeout 703d49ea435a59436f762c2cc5e750ff27ece0d3c5Rebecca Silberstein }; 713d49ea435a59436f762c2cc5e750ff27ece0d3c5Rebecca Silberstein 723d49ea435a59436f762c2cc5e750ff27ece0d3c5Rebecca Silberstein struct Result { 733d49ea435a59436f762c2cc5e750ff27ece0d3c5Rebecca Silberstein Result() 743d49ea435a59436f762c2cc5e750ff27ece0d3c5Rebecca Silberstein : phase(kPhaseUnknown), status(kStatusFailure) {} 753d49ea435a59436f762c2cc5e750ff27ece0d3c5Rebecca Silberstein Result(Phase phase_in, Status status_in) 763d49ea435a59436f762c2cc5e750ff27ece0d3c5Rebecca Silberstein : phase(phase_in), status(status_in) {} 773d49ea435a59436f762c2cc5e750ff27ece0d3c5Rebecca Silberstein Phase phase; 783d49ea435a59436f762c2cc5e750ff27ece0d3c5Rebecca Silberstein Status status; 793d49ea435a59436f762c2cc5e750ff27ece0d3c5Rebecca Silberstein }; 803d49ea435a59436f762c2cc5e750ff27ece0d3c5Rebecca Silberstein 813d49ea435a59436f762c2cc5e750ff27ece0d3c5Rebecca Silberstein static const char kDefaultURL[]; 823d49ea435a59436f762c2cc5e750ff27ece0d3c5Rebecca Silberstein static const char kResponseExpected[]; 833d49ea435a59436f762c2cc5e750ff27ece0d3c5Rebecca Silberstein 843d49ea435a59436f762c2cc5e750ff27ece0d3c5Rebecca Silberstein ConnectivityTrial(ConnectionRefPtr connection, 85a794cd60a7339d576ea2eed263a4f0a20fb255afPaul Stewart EventDispatcher* dispatcher, 863d49ea435a59436f762c2cc5e750ff27ece0d3c5Rebecca Silberstein int trial_timeout_seconds, 87a794cd60a7339d576ea2eed263a4f0a20fb255afPaul Stewart const base::Callback<void(Result)>& trial_callback); 883d49ea435a59436f762c2cc5e750ff27ece0d3c5Rebecca Silberstein virtual ~ConnectivityTrial(); 893d49ea435a59436f762c2cc5e750ff27ece0d3c5Rebecca Silberstein 903d49ea435a59436f762c2cc5e750ff27ece0d3c5Rebecca Silberstein // Static method used to map a portal detection phase tp a string. This 913d49ea435a59436f762c2cc5e750ff27ece0d3c5Rebecca Silberstein // includes the phases for connection, DNS, HTTP, returned content and 923d49ea435a59436f762c2cc5e750ff27ece0d3c5Rebecca Silberstein // unknown. 933d49ea435a59436f762c2cc5e750ff27ece0d3c5Rebecca Silberstein static const std::string PhaseToString(Phase phase); 943d49ea435a59436f762c2cc5e750ff27ece0d3c5Rebecca Silberstein 953d49ea435a59436f762c2cc5e750ff27ece0d3c5Rebecca Silberstein // Static method to map from the result of a portal detection phase to a 963d49ea435a59436f762c2cc5e750ff27ece0d3c5Rebecca Silberstein // status string. This method supports success, timeout and failure. 973d49ea435a59436f762c2cc5e750ff27ece0d3c5Rebecca Silberstein static const std::string StatusToString(Status status); 983d49ea435a59436f762c2cc5e750ff27ece0d3c5Rebecca Silberstein 993d49ea435a59436f762c2cc5e750ff27ece0d3c5Rebecca Silberstein // Static method mapping from HTTPRequest responses to ConntectivityTrial 1003d49ea435a59436f762c2cc5e750ff27ece0d3c5Rebecca Silberstein // phases for portal detection. For example, if the HTTPRequest result is 1013d49ea435a59436f762c2cc5e750ff27ece0d3c5Rebecca Silberstein // HTTPRequest::kResultDNSFailure, this method returns a 1023d49ea435a59436f762c2cc5e750ff27ece0d3c5Rebecca Silberstein // ConnectivityTrial::Result with the phase set to 1033d49ea435a59436f762c2cc5e750ff27ece0d3c5Rebecca Silberstein // ConnectivityTrial::kPhaseDNS and the status set to 1043d49ea435a59436f762c2cc5e750ff27ece0d3c5Rebecca Silberstein // ConnectivityTrial::kStatusFailure. 1053d49ea435a59436f762c2cc5e750ff27ece0d3c5Rebecca Silberstein static Result GetPortalResultForRequestResult(HTTPRequest::Result result); 1063d49ea435a59436f762c2cc5e750ff27ece0d3c5Rebecca Silberstein 1073d49ea435a59436f762c2cc5e750ff27ece0d3c5Rebecca Silberstein // Start a ConnectivityTrial with the supplied URL and starting delay (ms). 1083d49ea435a59436f762c2cc5e750ff27ece0d3c5Rebecca Silberstein // Returns trus if |url_string| correctly parses as a URL. Returns false (and 1093d49ea435a59436f762c2cc5e750ff27ece0d3c5Rebecca Silberstein // does not start) if the |url_string| fails to parse. 1103d49ea435a59436f762c2cc5e750ff27ece0d3c5Rebecca Silberstein // 1113d49ea435a59436f762c2cc5e750ff27ece0d3c5Rebecca Silberstein // After a trial completes, the callback supplied in the constructor is 1123d49ea435a59436f762c2cc5e750ff27ece0d3c5Rebecca Silberstein // called. 113a794cd60a7339d576ea2eed263a4f0a20fb255afPaul Stewart virtual bool Start(const std::string& url_string, 1143d49ea435a59436f762c2cc5e750ff27ece0d3c5Rebecca Silberstein int start_delay_milliseconds); 1153d49ea435a59436f762c2cc5e750ff27ece0d3c5Rebecca Silberstein 1163d49ea435a59436f762c2cc5e750ff27ece0d3c5Rebecca Silberstein // After a trial completes, the calling class may call Retry on the trial. 1173d49ea435a59436f762c2cc5e750ff27ece0d3c5Rebecca Silberstein // This allows the underlying HTTPRequest object to be reused. The URL is not 1183d49ea435a59436f762c2cc5e750ff27ece0d3c5Rebecca Silberstein // reparsed and the original URL supplied in the Start command is used. The 1193d49ea435a59436f762c2cc5e750ff27ece0d3c5Rebecca Silberstein // |start_delay| is the time (ms) to wait before starting the trial. Retry 1203d49ea435a59436f762c2cc5e750ff27ece0d3c5Rebecca Silberstein // returns true if the underlying HTTPRequest is still available. If the 1213d49ea435a59436f762c2cc5e750ff27ece0d3c5Rebecca Silberstein // HTTPRequest was reset or never created, Retry will return false. 1223d49ea435a59436f762c2cc5e750ff27ece0d3c5Rebecca Silberstein virtual bool Retry(int start_delay_milliseconds); 1233d49ea435a59436f762c2cc5e750ff27ece0d3c5Rebecca Silberstein 1243d49ea435a59436f762c2cc5e750ff27ece0d3c5Rebecca Silberstein // End the current attempt if one is in progress. Will not call the callback 1253d49ea435a59436f762c2cc5e750ff27ece0d3c5Rebecca Silberstein // with any intermediate results. 1263d49ea435a59436f762c2cc5e750ff27ece0d3c5Rebecca Silberstein // The ConnectivityTrial will cancel any existing scheduled tasks and destroy 1273d49ea435a59436f762c2cc5e750ff27ece0d3c5Rebecca Silberstein // the underlying HTTPRequest. 1283d49ea435a59436f762c2cc5e750ff27ece0d3c5Rebecca Silberstein virtual void Stop(); 1293d49ea435a59436f762c2cc5e750ff27ece0d3c5Rebecca Silberstein 1303d49ea435a59436f762c2cc5e750ff27ece0d3c5Rebecca Silberstein // Method to return if the connection is being actively tested. 1313d49ea435a59436f762c2cc5e750ff27ece0d3c5Rebecca Silberstein virtual bool IsActive(); 1323d49ea435a59436f762c2cc5e750ff27ece0d3c5Rebecca Silberstein 1333d49ea435a59436f762c2cc5e750ff27ece0d3c5Rebecca Silberstein private: 1343d49ea435a59436f762c2cc5e750ff27ece0d3c5Rebecca Silberstein friend class PortalDetectorTest; 1353d49ea435a59436f762c2cc5e750ff27ece0d3c5Rebecca Silberstein FRIEND_TEST(PortalDetectorTest, StartAttemptFailed); 1363d49ea435a59436f762c2cc5e750ff27ece0d3c5Rebecca Silberstein FRIEND_TEST(PortalDetectorTest, StartAttemptRepeated); 1373d49ea435a59436f762c2cc5e750ff27ece0d3c5Rebecca Silberstein FRIEND_TEST(PortalDetectorTest, StartAttemptAfterDelay); 1383d49ea435a59436f762c2cc5e750ff27ece0d3c5Rebecca Silberstein FRIEND_TEST(PortalDetectorTest, AttemptCount); 1393d49ea435a59436f762c2cc5e750ff27ece0d3c5Rebecca Silberstein FRIEND_TEST(PortalDetectorTest, ReadBadHeadersRetry); 1403d49ea435a59436f762c2cc5e750ff27ece0d3c5Rebecca Silberstein FRIEND_TEST(PortalDetectorTest, ReadBadHeader); 1413d49ea435a59436f762c2cc5e750ff27ece0d3c5Rebecca Silberstein friend class ConnectivityTrialTest; 1423d49ea435a59436f762c2cc5e750ff27ece0d3c5Rebecca Silberstein FRIEND_TEST(ConnectivityTrialTest, StartAttemptFailed); 1433d49ea435a59436f762c2cc5e750ff27ece0d3c5Rebecca Silberstein FRIEND_TEST(ConnectivityTrialTest, TrialRetry); 1443d49ea435a59436f762c2cc5e750ff27ece0d3c5Rebecca Silberstein FRIEND_TEST(ConnectivityTrialTest, ReadBadHeadersRetry); 1453d49ea435a59436f762c2cc5e750ff27ece0d3c5Rebecca Silberstein FRIEND_TEST(ConnectivityTrialTest, IsActive); 1463d49ea435a59436f762c2cc5e750ff27ece0d3c5Rebecca Silberstein 1473d49ea435a59436f762c2cc5e750ff27ece0d3c5Rebecca Silberstein // Start a ConnectivityTrial with the supplied delay in ms. 1483d49ea435a59436f762c2cc5e750ff27ece0d3c5Rebecca Silberstein void StartTrialAfterDelay(int start_delay_milliseconds); 1493d49ea435a59436f762c2cc5e750ff27ece0d3c5Rebecca Silberstein 1503d49ea435a59436f762c2cc5e750ff27ece0d3c5Rebecca Silberstein // Internal method used to start the actual connectivity trial, called after 1513d49ea435a59436f762c2cc5e750ff27ece0d3c5Rebecca Silberstein // the start delay completes. 1523d49ea435a59436f762c2cc5e750ff27ece0d3c5Rebecca Silberstein void StartTrialTask(); 1533d49ea435a59436f762c2cc5e750ff27ece0d3c5Rebecca Silberstein 1543d49ea435a59436f762c2cc5e750ff27ece0d3c5Rebecca Silberstein // Callback used to return data read from the HTTPRequest. 155a794cd60a7339d576ea2eed263a4f0a20fb255afPaul Stewart void RequestReadCallback(const ByteString& response_data); 1563d49ea435a59436f762c2cc5e750ff27ece0d3c5Rebecca Silberstein 1573d49ea435a59436f762c2cc5e750ff27ece0d3c5Rebecca Silberstein // Callback used to return the result of the HTTPRequest. 1583d49ea435a59436f762c2cc5e750ff27ece0d3c5Rebecca Silberstein void RequestResultCallback(HTTPRequest::Result result, 159a794cd60a7339d576ea2eed263a4f0a20fb255afPaul Stewart const ByteString& response_data); 1603d49ea435a59436f762c2cc5e750ff27ece0d3c5Rebecca Silberstein 1613d49ea435a59436f762c2cc5e750ff27ece0d3c5Rebecca Silberstein // Internal method used to clean up state and call the original caller that 1623d49ea435a59436f762c2cc5e750ff27ece0d3c5Rebecca Silberstein // created and triggered this ConnectivityTrial. 1633d49ea435a59436f762c2cc5e750ff27ece0d3c5Rebecca Silberstein void CompleteTrial(Result result); 1643d49ea435a59436f762c2cc5e750ff27ece0d3c5Rebecca Silberstein 1653d49ea435a59436f762c2cc5e750ff27ece0d3c5Rebecca Silberstein // Internal method used to cancel the timeout timer and stop an active 1663d49ea435a59436f762c2cc5e750ff27ece0d3c5Rebecca Silberstein // HTTPRequest. If |reset_request| is true, this method resets the underlying 1673d49ea435a59436f762c2cc5e750ff27ece0d3c5Rebecca Silberstein // HTTPRequest object. 1683d49ea435a59436f762c2cc5e750ff27ece0d3c5Rebecca Silberstein void CleanupTrial(bool reset_request); 1693d49ea435a59436f762c2cc5e750ff27ece0d3c5Rebecca Silberstein 1703d49ea435a59436f762c2cc5e750ff27ece0d3c5Rebecca Silberstein // Callback used to cancel the underlying HTTPRequest in the event of a 1713d49ea435a59436f762c2cc5e750ff27ece0d3c5Rebecca Silberstein // timeout. 1723d49ea435a59436f762c2cc5e750ff27ece0d3c5Rebecca Silberstein void TimeoutTrialTask(); 1733d49ea435a59436f762c2cc5e750ff27ece0d3c5Rebecca Silberstein 1743d49ea435a59436f762c2cc5e750ff27ece0d3c5Rebecca Silberstein ConnectionRefPtr connection_; 175a794cd60a7339d576ea2eed263a4f0a20fb255afPaul Stewart EventDispatcher* dispatcher_; 1763d49ea435a59436f762c2cc5e750ff27ece0d3c5Rebecca Silberstein int trial_timeout_seconds_; 1773d49ea435a59436f762c2cc5e750ff27ece0d3c5Rebecca Silberstein base::Callback<void(Result)> trial_callback_; 1783d49ea435a59436f762c2cc5e750ff27ece0d3c5Rebecca Silberstein base::WeakPtrFactory<ConnectivityTrial> weak_ptr_factory_; 179a794cd60a7339d576ea2eed263a4f0a20fb255afPaul Stewart base::Callback<void(const ByteString&)> request_read_callback_; 180a794cd60a7339d576ea2eed263a4f0a20fb255afPaul Stewart base::Callback<void(HTTPRequest::Result, const ByteString&)> 1813d49ea435a59436f762c2cc5e750ff27ece0d3c5Rebecca Silberstein request_result_callback_; 18222f1fbc11b69ee41af8370ec38f1b90577db6c3cBen Chan std::unique_ptr<HTTPRequest> request_; 1833d49ea435a59436f762c2cc5e750ff27ece0d3c5Rebecca Silberstein 1843d49ea435a59436f762c2cc5e750ff27ece0d3c5Rebecca Silberstein Sockets sockets_; 1853d49ea435a59436f762c2cc5e750ff27ece0d3c5Rebecca Silberstein HTTPURL url_; 1863d49ea435a59436f762c2cc5e750ff27ece0d3c5Rebecca Silberstein base::CancelableClosure trial_; 1873d49ea435a59436f762c2cc5e750ff27ece0d3c5Rebecca Silberstein base::CancelableClosure trial_timeout_; 1883d49ea435a59436f762c2cc5e750ff27ece0d3c5Rebecca Silberstein bool is_active_; 1893d49ea435a59436f762c2cc5e750ff27ece0d3c5Rebecca Silberstein}; 1903d49ea435a59436f762c2cc5e750ff27ece0d3c5Rebecca Silberstein 1913d49ea435a59436f762c2cc5e750ff27ece0d3c5Rebecca Silberstein} // namespace shill 1923d49ea435a59436f762c2cc5e750ff27ece0d3c5Rebecca Silberstein 1933d49ea435a59436f762c2cc5e750ff27ece0d3c5Rebecca Silberstein#endif // SHILL_CONNECTIVITY_TRIAL_H_ 194