• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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