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_PORTAL_DETECTOR_H_ 18 #define SHILL_PORTAL_DETECTOR_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/connectivity_trial.h" 31 #include "shill/net/shill_time.h" 32 #include "shill/refptr_types.h" 33 34 namespace shill { 35 36 class ByteString; 37 class PortalDetector; 38 class Time; 39 40 // The PortalDetector class implements the portal detection 41 // facility in shill, which is responsible for checking to see 42 // if a connection has "general internet connectivity". 43 // 44 // This information can be used for ranking one connection 45 // against another, or for informing UI and other components 46 // outside the connection manager whether the connection seems 47 // available for "general use" or if further user action may be 48 // necessary (e.g, click through of a WiFi Hotspot's splash 49 // page). 50 // 51 // This is achieved by using one or more ConnectivityTrial attempts 52 // to access a URL and expecting a specific response. Any result 53 // that deviates from this result (DNS or HTTP errors, as well as 54 // deviations from the expected content) are considered failures. 55 class PortalDetector { 56 public: 57 struct Result { ResultResult58 Result() 59 : trial_result(ConnectivityTrial::Result()), 60 num_attempts(0), 61 final(false) {} ResultResult62 explicit Result(ConnectivityTrial::Result result_in) 63 : trial_result(result_in), 64 num_attempts(0), 65 final(false) {} ResultResult66 Result(ConnectivityTrial::Result result_in, 67 int num_attempts_in, 68 int final_in) 69 : trial_result(result_in), 70 num_attempts(num_attempts_in), 71 final(final_in) {} 72 73 ConnectivityTrial::Result trial_result; 74 75 // Total number of connectivity trials attempted. 76 // This includes failure, timeout and successful attempts. 77 // This only valid when |final| is true. 78 int num_attempts; 79 bool final; 80 }; 81 82 static const int kDefaultCheckIntervalSeconds; 83 static const char kDefaultCheckPortalList[]; 84 // Maximum number of times the PortalDetector will attempt a connection. 85 static const int kMaxRequestAttempts; 86 87 PortalDetector(ConnectionRefPtr connection, 88 EventDispatcher* dispatcher, 89 const base::Callback<void(const PortalDetector::Result&)> 90 &callback); 91 virtual ~PortalDetector(); 92 93 // Start a portal detection test. Returns true if |url_string| correctly 94 // parses as a URL. Returns false (and does not start) if the |url_string| 95 // fails to parse. 96 // 97 // As each attempt completes the callback handed to the constructor will 98 // be called. The PortalDetector will try up to kMaxRequestAttempts times 99 // to successfully retrieve the URL. If the attempt is successful or 100 // this is the last attempt, the "final" flag in the Result structure will 101 // be true, otherwise it will be false, and the PortalDetector will 102 // schedule the next attempt. 103 virtual bool Start(const std::string& url_string); 104 virtual bool StartAfterDelay(const std::string& url_string, 105 int delay_seconds); 106 107 // End the current portal detection process if one exists, and do not call 108 // the callback. 109 virtual void Stop(); 110 111 // Returns whether portal request is "in progress": whether the underlying 112 // ConnectivityTrial is in the progress of making attempts. Returns true if 113 // attempts are in progress, false otherwise. Notably, this function 114 // returns false during the period of time between calling "Start" or 115 // "StartAfterDelay" and the actual start of the first attempt. In the case 116 // where multiple attempts may be tried, IsInProgress will return true after 117 // the first attempt has actively started testing the connection. 118 virtual bool IsInProgress(); 119 120 private: 121 friend class PortalDetectorTest; 122 FRIEND_TEST(PortalDetectorTest, StartAttemptFailed); 123 FRIEND_TEST(PortalDetectorTest, AdjustStartDelayImmediate); 124 FRIEND_TEST(PortalDetectorTest, AdjustStartDelayAfterDelay); 125 FRIEND_TEST(PortalDetectorTest, AttemptCount); 126 FRIEND_TEST(PortalDetectorTest, ReadBadHeadersRetry); 127 FRIEND_TEST(PortalDetectorTest, ReadBadHeader); 128 FRIEND_TEST(PortalDetectorTest, RequestTimeout); 129 FRIEND_TEST(PortalDetectorTest, ReadPartialHeaderTimeout); 130 FRIEND_TEST(PortalDetectorTest, ReadCompleteHeader); 131 FRIEND_TEST(PortalDetectorTest, ReadMatchingHeader); 132 FRIEND_TEST(PortalDetectorTest, InvalidURL); 133 134 // Minimum time between attempts to connect to server. 135 static const int kMinTimeBetweenAttemptsSeconds; 136 // Time to wait for request to complete. 137 static const int kRequestTimeoutSeconds; 138 // Maximum number of failures in content phase before we stop attempting 139 // connections. 140 static const int kMaxFailuresInContentPhase; 141 142 // Internal method to update the start time of the next event. This is used 143 // to keep attempts spaced by at least kMinTimeBetweenAttemptsSeconds in the 144 // event of a retry. 145 void UpdateAttemptTime(int delay_seconds); 146 147 // Internal method used to adjust the start delay in the event of a retry. 148 // Calculates the elapsed time between the most recent attempt and the point 149 // the retry is scheduled. Adds an additional delay to meet the 150 // kMinTimeBetweenAttemptsSeconds requirement. 151 int AdjustStartDelay(int init_delay_seconds); 152 153 // Callback used by ConnectivityTrial to return |result| after attempting to 154 // determine connectivity status. 155 void CompleteAttempt(ConnectivityTrial::Result result); 156 157 int attempt_count_; 158 struct timeval attempt_start_time_; 159 ConnectionRefPtr connection_; 160 EventDispatcher* dispatcher_; 161 base::WeakPtrFactory<PortalDetector> weak_ptr_factory_; 162 base::Callback<void(const Result&)> portal_result_callback_; 163 base::Callback<void(ConnectivityTrial::Result)> connectivity_trial_callback_; 164 Time* time_; 165 int failures_in_content_phase_; 166 std::unique_ptr<ConnectivityTrial> connectivity_trial_; 167 168 169 DISALLOW_COPY_AND_ASSIGN(PortalDetector); 170 }; 171 172 } // namespace shill 173 174 #endif // SHILL_PORTAL_DETECTOR_H_ 175