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