1 // 2 // Copyright (C) 2012 The Android Open Source Project 3 // 4 // Licensed under the Apache License, Version 2.0 (the "License"); 5 // you may not use this file except in compliance with the License. 6 // You may obtain a copy of the License at 7 // 8 // http://www.apache.org/licenses/LICENSE-2.0 9 // 10 // Unless required by applicable law or agreed to in writing, software 11 // distributed under the License is distributed on an "AS IS" BASIS, 12 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 // See the License for the specific language governing permissions and 14 // limitations under the License. 15 // 16 17 #ifndef SHILL_CONNECTIVITY_TRIAL_H_ 18 #define SHILL_CONNECTIVITY_TRIAL_H_ 19 20 #include <memory> 21 #include <string> 22 #include <vector> 23 24 #include <base/callback.h> 25 #include <base/cancelable_callback.h> 26 #include <base/memory/ref_counted.h> 27 #include <base/memory/weak_ptr.h> 28 #include <gtest/gtest_prod.h> // for FRIEND_TEST 29 30 #include "shill/http_request.h" 31 #include "shill/http_url.h" 32 #include "shill/net/shill_time.h" 33 #include "shill/net/sockets.h" 34 #include "shill/refptr_types.h" 35 36 namespace shill { 37 38 class ByteString; 39 class EventDispatcher; 40 class Time; 41 42 // The ConnectivityTrial class implements a single portal detection 43 // trial. Each trial checks if a connection has "general internet 44 // connectivity." 45 // 46 // ConnectivityTrial is responsible for managing the callbacks between the 47 // calling class requesting a connectivity trial and the HTTPRequest that is 48 // used to test connectivity. ConnectivityTrial maps between the HTTPRequest 49 // response codes to higher-level connection-oriented status. 50 // 51 // ConnectivityTrial tests the connection by attempting to parse and access a 52 // given URL. Any result that deviates from the expected behavior (DNS or HTTP 53 // errors, as well as retrieved content errors, and timeouts) are considered 54 // failures. 55 56 class ConnectivityTrial { 57 public: 58 enum Phase { 59 kPhaseConnection, 60 kPhaseDNS, 61 kPhaseHTTP, 62 kPhaseContent, 63 kPhaseUnknown 64 }; 65 66 enum Status { 67 kStatusFailure, 68 kStatusSuccess, 69 kStatusTimeout 70 }; 71 72 struct Result { ResultResult73 Result() 74 : phase(kPhaseUnknown), status(kStatusFailure) {} ResultResult75 Result(Phase phase_in, Status status_in) 76 : phase(phase_in), status(status_in) {} 77 Phase phase; 78 Status status; 79 }; 80 81 static const char kDefaultURL[]; 82 static const char kResponseExpected[]; 83 84 ConnectivityTrial(ConnectionRefPtr connection, 85 EventDispatcher* dispatcher, 86 int trial_timeout_seconds, 87 const base::Callback<void(Result)>& trial_callback); 88 virtual ~ConnectivityTrial(); 89 90 // Static method used to map a portal detection phase tp a string. This 91 // includes the phases for connection, DNS, HTTP, returned content and 92 // unknown. 93 static const std::string PhaseToString(Phase phase); 94 95 // Static method to map from the result of a portal detection phase to a 96 // status string. This method supports success, timeout and failure. 97 static const std::string StatusToString(Status status); 98 99 // Static method mapping from HTTPRequest responses to ConntectivityTrial 100 // phases for portal detection. For example, if the HTTPRequest result is 101 // HTTPRequest::kResultDNSFailure, this method returns a 102 // ConnectivityTrial::Result with the phase set to 103 // ConnectivityTrial::kPhaseDNS and the status set to 104 // ConnectivityTrial::kStatusFailure. 105 static Result GetPortalResultForRequestResult(HTTPRequest::Result result); 106 107 // Start a ConnectivityTrial with the supplied URL and starting delay (ms). 108 // Returns trus if |url_string| correctly parses as a URL. Returns false (and 109 // does not start) if the |url_string| fails to parse. 110 // 111 // After a trial completes, the callback supplied in the constructor is 112 // called. 113 virtual bool Start(const std::string& url_string, 114 int start_delay_milliseconds); 115 116 // After a trial completes, the calling class may call Retry on the trial. 117 // This allows the underlying HTTPRequest object to be reused. The URL is not 118 // reparsed and the original URL supplied in the Start command is used. The 119 // |start_delay| is the time (ms) to wait before starting the trial. Retry 120 // returns true if the underlying HTTPRequest is still available. If the 121 // HTTPRequest was reset or never created, Retry will return false. 122 virtual bool Retry(int start_delay_milliseconds); 123 124 // End the current attempt if one is in progress. Will not call the callback 125 // with any intermediate results. 126 // The ConnectivityTrial will cancel any existing scheduled tasks and destroy 127 // the underlying HTTPRequest. 128 virtual void Stop(); 129 130 // Method to return if the connection is being actively tested. 131 virtual bool IsActive(); 132 133 private: 134 friend class PortalDetectorTest; 135 FRIEND_TEST(PortalDetectorTest, StartAttemptFailed); 136 FRIEND_TEST(PortalDetectorTest, StartAttemptRepeated); 137 FRIEND_TEST(PortalDetectorTest, StartAttemptAfterDelay); 138 FRIEND_TEST(PortalDetectorTest, AttemptCount); 139 FRIEND_TEST(PortalDetectorTest, ReadBadHeadersRetry); 140 FRIEND_TEST(PortalDetectorTest, ReadBadHeader); 141 friend class ConnectivityTrialTest; 142 FRIEND_TEST(ConnectivityTrialTest, StartAttemptFailed); 143 FRIEND_TEST(ConnectivityTrialTest, TrialRetry); 144 FRIEND_TEST(ConnectivityTrialTest, ReadBadHeadersRetry); 145 FRIEND_TEST(ConnectivityTrialTest, IsActive); 146 147 // Start a ConnectivityTrial with the supplied delay in ms. 148 void StartTrialAfterDelay(int start_delay_milliseconds); 149 150 // Internal method used to start the actual connectivity trial, called after 151 // the start delay completes. 152 void StartTrialTask(); 153 154 // Callback used to return data read from the HTTPRequest. 155 void RequestReadCallback(const ByteString& response_data); 156 157 // Callback used to return the result of the HTTPRequest. 158 void RequestResultCallback(HTTPRequest::Result result, 159 const ByteString& response_data); 160 161 // Internal method used to clean up state and call the original caller that 162 // created and triggered this ConnectivityTrial. 163 void CompleteTrial(Result result); 164 165 // Internal method used to cancel the timeout timer and stop an active 166 // HTTPRequest. If |reset_request| is true, this method resets the underlying 167 // HTTPRequest object. 168 void CleanupTrial(bool reset_request); 169 170 // Callback used to cancel the underlying HTTPRequest in the event of a 171 // timeout. 172 void TimeoutTrialTask(); 173 174 ConnectionRefPtr connection_; 175 EventDispatcher* dispatcher_; 176 int trial_timeout_seconds_; 177 base::Callback<void(Result)> trial_callback_; 178 base::WeakPtrFactory<ConnectivityTrial> weak_ptr_factory_; 179 base::Callback<void(const ByteString&)> request_read_callback_; 180 base::Callback<void(HTTPRequest::Result, const ByteString&)> 181 request_result_callback_; 182 std::unique_ptr<HTTPRequest> request_; 183 184 Sockets sockets_; 185 HTTPURL url_; 186 base::CancelableClosure trial_; 187 base::CancelableClosure trial_timeout_; 188 bool is_active_; 189 }; 190 191 } // namespace shill 192 193 #endif // SHILL_CONNECTIVITY_TRIAL_H_ 194