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//
16e692740c0623d4cb5d92d36214982ee45a03a5dbPaul Stewart
17c45688bb3881f0c2216e6ec0e19ebda0be33e871Ben Chan#ifndef SHILL_PORTAL_DETECTOR_H_
18c45688bb3881f0c2216e6ec0e19ebda0be33e871Ben Chan#define SHILL_PORTAL_DETECTOR_H_
19e692740c0623d4cb5d92d36214982ee45a03a5dbPaul Stewart
20cd47732488cd101eaf0d3558dde5a7d4e4fc260bBen Chan#include <memory>
21e692740c0623d4cb5d92d36214982ee45a03a5dbPaul Stewart#include <string>
22e692740c0623d4cb5d92d36214982ee45a03a5dbPaul Stewart#include <vector>
23e692740c0623d4cb5d92d36214982ee45a03a5dbPaul Stewart
243e20a2341d0aeb7681e4ee0f89eae6817ade2b3bEric Shienbrood#include <base/callback.h>
25f582b50dc416de301f3e4a5f1712a93b9ce02e95Paul Stewart#include <base/cancelable_callback.h>
26e692740c0623d4cb5d92d36214982ee45a03a5dbPaul Stewart#include <base/memory/ref_counted.h>
273e20a2341d0aeb7681e4ee0f89eae6817ade2b3bEric Shienbrood#include <base/memory/weak_ptr.h>
28e692740c0623d4cb5d92d36214982ee45a03a5dbPaul Stewart#include <gtest/gtest_prod.h>  // for FRIEND_TEST
29e692740c0623d4cb5d92d36214982ee45a03a5dbPaul Stewart
303d49ea435a59436f762c2cc5e750ff27ece0d3c5Rebecca Silberstein#include "shill/connectivity_trial.h"
318d6b59704591ba9fad57751858835dc332dbdd37Peter Qiu#include "shill/net/shill_time.h"
32e692740c0623d4cb5d92d36214982ee45a03a5dbPaul Stewart#include "shill/refptr_types.h"
33e692740c0623d4cb5d92d36214982ee45a03a5dbPaul Stewart
34e692740c0623d4cb5d92d36214982ee45a03a5dbPaul Stewartnamespace shill {
35e692740c0623d4cb5d92d36214982ee45a03a5dbPaul Stewart
36bdb02e664f79f29b3bce9be4ca05c82d8ede697fPaul Stewartclass ByteString;
37e692740c0623d4cb5d92d36214982ee45a03a5dbPaul Stewartclass PortalDetector;
38e692740c0623d4cb5d92d36214982ee45a03a5dbPaul Stewartclass Time;
39e692740c0623d4cb5d92d36214982ee45a03a5dbPaul Stewart
40e692740c0623d4cb5d92d36214982ee45a03a5dbPaul Stewart// The PortalDetector class implements the portal detection
41e692740c0623d4cb5d92d36214982ee45a03a5dbPaul Stewart// facility in shill, which is responsible for checking to see
42e692740c0623d4cb5d92d36214982ee45a03a5dbPaul Stewart// if a connection has "general internet connectivity".
43e692740c0623d4cb5d92d36214982ee45a03a5dbPaul Stewart//
44e692740c0623d4cb5d92d36214982ee45a03a5dbPaul Stewart// This information can be used for ranking one connection
45e692740c0623d4cb5d92d36214982ee45a03a5dbPaul Stewart// against another, or for informing UI and other components
46e692740c0623d4cb5d92d36214982ee45a03a5dbPaul Stewart// outside the connection manager whether the connection seems
47e692740c0623d4cb5d92d36214982ee45a03a5dbPaul Stewart// available for "general use" or if further user action may be
48e692740c0623d4cb5d92d36214982ee45a03a5dbPaul Stewart// necessary (e.g, click through of a WiFi Hotspot's splash
49e692740c0623d4cb5d92d36214982ee45a03a5dbPaul Stewart// page).
50e692740c0623d4cb5d92d36214982ee45a03a5dbPaul Stewart//
513d49ea435a59436f762c2cc5e750ff27ece0d3c5Rebecca Silberstein// This is achieved by using one or more ConnectivityTrial attempts
523d49ea435a59436f762c2cc5e750ff27ece0d3c5Rebecca Silberstein// to access a URL and expecting a specific response.  Any result
533d49ea435a59436f762c2cc5e750ff27ece0d3c5Rebecca Silberstein// that deviates from this result (DNS or HTTP errors, as well as
543d49ea435a59436f762c2cc5e750ff27ece0d3c5Rebecca Silberstein// deviations from the expected content) are considered failures.
55e692740c0623d4cb5d92d36214982ee45a03a5dbPaul Stewartclass PortalDetector {
56e692740c0623d4cb5d92d36214982ee45a03a5dbPaul Stewart public:
57e692740c0623d4cb5d92d36214982ee45a03a5dbPaul Stewart  struct Result {
5885e050b4923878a57aec1415314d2b39ff233e00Thieu Le    Result()
593d49ea435a59436f762c2cc5e750ff27ece0d3c5Rebecca Silberstein        : trial_result(ConnectivityTrial::Result()),
603d49ea435a59436f762c2cc5e750ff27ece0d3c5Rebecca Silberstein          num_attempts(0),
613d49ea435a59436f762c2cc5e750ff27ece0d3c5Rebecca Silberstein          final(false) {}
623d49ea435a59436f762c2cc5e750ff27ece0d3c5Rebecca Silberstein    explicit Result(ConnectivityTrial::Result result_in)
633d49ea435a59436f762c2cc5e750ff27ece0d3c5Rebecca Silberstein        : trial_result(result_in),
643d49ea435a59436f762c2cc5e750ff27ece0d3c5Rebecca Silberstein          num_attempts(0),
653d49ea435a59436f762c2cc5e750ff27ece0d3c5Rebecca Silberstein          final(false) {}
663d49ea435a59436f762c2cc5e750ff27ece0d3c5Rebecca Silberstein    Result(ConnectivityTrial::Result result_in,
673d49ea435a59436f762c2cc5e750ff27ece0d3c5Rebecca Silberstein           int num_attempts_in,
683d49ea435a59436f762c2cc5e750ff27ece0d3c5Rebecca Silberstein           int final_in)
693d49ea435a59436f762c2cc5e750ff27ece0d3c5Rebecca Silberstein        : trial_result(result_in),
703d49ea435a59436f762c2cc5e750ff27ece0d3c5Rebecca Silberstein          num_attempts(num_attempts_in),
713d49ea435a59436f762c2cc5e750ff27ece0d3c5Rebecca Silberstein          final(final_in) {}
723d49ea435a59436f762c2cc5e750ff27ece0d3c5Rebecca Silberstein
733d49ea435a59436f762c2cc5e750ff27ece0d3c5Rebecca Silberstein    ConnectivityTrial::Result trial_result;
743d49ea435a59436f762c2cc5e750ff27ece0d3c5Rebecca Silberstein
753d49ea435a59436f762c2cc5e750ff27ece0d3c5Rebecca Silberstein    // Total number of connectivity trials attempted.
7685e050b4923878a57aec1415314d2b39ff233e00Thieu Le    // This includes failure, timeout and successful attempts.
7785e050b4923878a57aec1415314d2b39ff233e00Thieu Le    // This only valid when |final| is true.
7885e050b4923878a57aec1415314d2b39ff233e00Thieu Le    int num_attempts;
79e692740c0623d4cb5d92d36214982ee45a03a5dbPaul Stewart    bool final;
80e692740c0623d4cb5d92d36214982ee45a03a5dbPaul Stewart  };
81e692740c0623d4cb5d92d36214982ee45a03a5dbPaul Stewart
82c681fa0742cabc686ccabaf0fdf6ce12dd7046b2Paul Stewart  static const int kDefaultCheckIntervalSeconds;
83f555cf8aac732cbe02913293ac6253629ade9be5Paul Stewart  static const char kDefaultCheckPortalList[];
8485e050b4923878a57aec1415314d2b39ff233e00Thieu Le  // Maximum number of times the PortalDetector will attempt a connection.
8585e050b4923878a57aec1415314d2b39ff233e00Thieu Le  static const int kMaxRequestAttempts;
86e692740c0623d4cb5d92d36214982ee45a03a5dbPaul Stewart
87e692740c0623d4cb5d92d36214982ee45a03a5dbPaul Stewart  PortalDetector(ConnectionRefPtr connection,
881a212a6b98b22ad1d69652bb26a9e94138635476Paul Stewart                 EventDispatcher* dispatcher,
893d49ea435a59436f762c2cc5e750ff27ece0d3c5Rebecca Silberstein                 const base::Callback<void(const PortalDetector::Result&)>
903d49ea435a59436f762c2cc5e750ff27ece0d3c5Rebecca Silberstein                     &callback);
91e692740c0623d4cb5d92d36214982ee45a03a5dbPaul Stewart  virtual ~PortalDetector();
92e692740c0623d4cb5d92d36214982ee45a03a5dbPaul Stewart
93e692740c0623d4cb5d92d36214982ee45a03a5dbPaul Stewart  // Start a portal detection test.  Returns true if |url_string| correctly
94e692740c0623d4cb5d92d36214982ee45a03a5dbPaul Stewart  // parses as a URL.  Returns false (and does not start) if the |url_string|
95e692740c0623d4cb5d92d36214982ee45a03a5dbPaul Stewart  // fails to parse.
96e692740c0623d4cb5d92d36214982ee45a03a5dbPaul Stewart  //
97e692740c0623d4cb5d92d36214982ee45a03a5dbPaul Stewart  // As each attempt completes the callback handed to the constructor will
98e692740c0623d4cb5d92d36214982ee45a03a5dbPaul Stewart  // be called.  The PortalDetector will try up to kMaxRequestAttempts times
99e692740c0623d4cb5d92d36214982ee45a03a5dbPaul Stewart  // to successfully retrieve the URL.  If the attempt is successful or
100e692740c0623d4cb5d92d36214982ee45a03a5dbPaul Stewart  // this is the last attempt, the "final" flag in the Result structure will
101e692740c0623d4cb5d92d36214982ee45a03a5dbPaul Stewart  // be true, otherwise it will be false, and the PortalDetector will
102e692740c0623d4cb5d92d36214982ee45a03a5dbPaul Stewart  // schedule the next attempt.
1031a212a6b98b22ad1d69652bb26a9e94138635476Paul Stewart  virtual bool Start(const std::string& url_string);
1041a212a6b98b22ad1d69652bb26a9e94138635476Paul Stewart  virtual bool StartAfterDelay(const std::string& url_string,
105c681fa0742cabc686ccabaf0fdf6ce12dd7046b2Paul Stewart                               int delay_seconds);
106e692740c0623d4cb5d92d36214982ee45a03a5dbPaul Stewart
107e692740c0623d4cb5d92d36214982ee45a03a5dbPaul Stewart  // End the current portal detection process if one exists, and do not call
108e692740c0623d4cb5d92d36214982ee45a03a5dbPaul Stewart  // the callback.
109c681fa0742cabc686ccabaf0fdf6ce12dd7046b2Paul Stewart  virtual void Stop();
110c681fa0742cabc686ccabaf0fdf6ce12dd7046b2Paul Stewart
1113d49ea435a59436f762c2cc5e750ff27ece0d3c5Rebecca Silberstein  // Returns whether portal request is "in progress": whether the underlying
1123d49ea435a59436f762c2cc5e750ff27ece0d3c5Rebecca Silberstein  // ConnectivityTrial is in the progress of making attempts.  Returns true if
113c681fa0742cabc686ccabaf0fdf6ce12dd7046b2Paul Stewart  // attempts are in progress, false otherwise.  Notably, this function
114c681fa0742cabc686ccabaf0fdf6ce12dd7046b2Paul Stewart  // returns false during the period of time between calling "Start" or
1153d49ea435a59436f762c2cc5e750ff27ece0d3c5Rebecca Silberstein  // "StartAfterDelay" and the actual start of the first attempt. In the case
1163d49ea435a59436f762c2cc5e750ff27ece0d3c5Rebecca Silberstein  // where multiple attempts may be tried, IsInProgress will return true after
1173d49ea435a59436f762c2cc5e750ff27ece0d3c5Rebecca Silberstein  // the first attempt has actively started testing the connection.
118c681fa0742cabc686ccabaf0fdf6ce12dd7046b2Paul Stewart  virtual bool IsInProgress();
119e692740c0623d4cb5d92d36214982ee45a03a5dbPaul Stewart
120e692740c0623d4cb5d92d36214982ee45a03a5dbPaul Stewart private:
121e692740c0623d4cb5d92d36214982ee45a03a5dbPaul Stewart  friend class PortalDetectorTest;
122e692740c0623d4cb5d92d36214982ee45a03a5dbPaul Stewart  FRIEND_TEST(PortalDetectorTest, StartAttemptFailed);
1233d49ea435a59436f762c2cc5e750ff27ece0d3c5Rebecca Silberstein  FRIEND_TEST(PortalDetectorTest, AdjustStartDelayImmediate);
1243d49ea435a59436f762c2cc5e750ff27ece0d3c5Rebecca Silberstein  FRIEND_TEST(PortalDetectorTest, AdjustStartDelayAfterDelay);
125e692740c0623d4cb5d92d36214982ee45a03a5dbPaul Stewart  FRIEND_TEST(PortalDetectorTest, AttemptCount);
1266e1dc0ff12ceb0fea899ceb5c0f4798e35d86b71Christopher Wiley  FRIEND_TEST(PortalDetectorTest, ReadBadHeadersRetry);
1273d49ea435a59436f762c2cc5e750ff27ece0d3c5Rebecca Silberstein  FRIEND_TEST(PortalDetectorTest, ReadBadHeader);
1283d49ea435a59436f762c2cc5e750ff27ece0d3c5Rebecca Silberstein  FRIEND_TEST(PortalDetectorTest, RequestTimeout);
1293d49ea435a59436f762c2cc5e750ff27ece0d3c5Rebecca Silberstein  FRIEND_TEST(PortalDetectorTest, ReadPartialHeaderTimeout);
1303d49ea435a59436f762c2cc5e750ff27ece0d3c5Rebecca Silberstein  FRIEND_TEST(PortalDetectorTest, ReadCompleteHeader);
1313d49ea435a59436f762c2cc5e750ff27ece0d3c5Rebecca Silberstein  FRIEND_TEST(PortalDetectorTest, ReadMatchingHeader);
1323d49ea435a59436f762c2cc5e750ff27ece0d3c5Rebecca Silberstein  FRIEND_TEST(PortalDetectorTest, InvalidURL);
133e692740c0623d4cb5d92d36214982ee45a03a5dbPaul Stewart
134e692740c0623d4cb5d92d36214982ee45a03a5dbPaul Stewart  // Minimum time between attempts to connect to server.
135e692740c0623d4cb5d92d36214982ee45a03a5dbPaul Stewart  static const int kMinTimeBetweenAttemptsSeconds;
136e692740c0623d4cb5d92d36214982ee45a03a5dbPaul Stewart  // Time to wait for request to complete.
137e692740c0623d4cb5d92d36214982ee45a03a5dbPaul Stewart  static const int kRequestTimeoutSeconds;
1386e1dc0ff12ceb0fea899ceb5c0f4798e35d86b71Christopher Wiley  // Maximum number of failures in content phase before we stop attempting
1396e1dc0ff12ceb0fea899ceb5c0f4798e35d86b71Christopher Wiley  // connections.
1406e1dc0ff12ceb0fea899ceb5c0f4798e35d86b71Christopher Wiley  static const int kMaxFailuresInContentPhase;
141e692740c0623d4cb5d92d36214982ee45a03a5dbPaul Stewart
1423d49ea435a59436f762c2cc5e750ff27ece0d3c5Rebecca Silberstein  // Internal method to update the start time of the next event.  This is used
1433d49ea435a59436f762c2cc5e750ff27ece0d3c5Rebecca Silberstein  // to keep attempts spaced by at least kMinTimeBetweenAttemptsSeconds in the
1443d49ea435a59436f762c2cc5e750ff27ece0d3c5Rebecca Silberstein  // event of a retry.
1453d49ea435a59436f762c2cc5e750ff27ece0d3c5Rebecca Silberstein  void UpdateAttemptTime(int delay_seconds);
1463d49ea435a59436f762c2cc5e750ff27ece0d3c5Rebecca Silberstein
1473d49ea435a59436f762c2cc5e750ff27ece0d3c5Rebecca Silberstein  // Internal method used to adjust the start delay in the event of a retry.
1483d49ea435a59436f762c2cc5e750ff27ece0d3c5Rebecca Silberstein  // Calculates the elapsed time between the most recent attempt and the point
1493d49ea435a59436f762c2cc5e750ff27ece0d3c5Rebecca Silberstein  // the retry is scheduled.  Adds an additional delay to meet the
1503d49ea435a59436f762c2cc5e750ff27ece0d3c5Rebecca Silberstein  // kMinTimeBetweenAttemptsSeconds requirement.
1513d49ea435a59436f762c2cc5e750ff27ece0d3c5Rebecca Silberstein  int AdjustStartDelay(int init_delay_seconds);
1523d49ea435a59436f762c2cc5e750ff27ece0d3c5Rebecca Silberstein
1533d49ea435a59436f762c2cc5e750ff27ece0d3c5Rebecca Silberstein  // Callback used by ConnectivityTrial to return |result| after attempting to
1543d49ea435a59436f762c2cc5e750ff27ece0d3c5Rebecca Silberstein  // determine connectivity status.
1553d49ea435a59436f762c2cc5e750ff27ece0d3c5Rebecca Silberstein  void CompleteAttempt(ConnectivityTrial::Result result);
156e692740c0623d4cb5d92d36214982ee45a03a5dbPaul Stewart
157e692740c0623d4cb5d92d36214982ee45a03a5dbPaul Stewart  int attempt_count_;
158e692740c0623d4cb5d92d36214982ee45a03a5dbPaul Stewart  struct timeval attempt_start_time_;
159e692740c0623d4cb5d92d36214982ee45a03a5dbPaul Stewart  ConnectionRefPtr connection_;
1601a212a6b98b22ad1d69652bb26a9e94138635476Paul Stewart  EventDispatcher* dispatcher_;
1613e20a2341d0aeb7681e4ee0f89eae6817ade2b3bEric Shienbrood  base::WeakPtrFactory<PortalDetector> weak_ptr_factory_;
1621a212a6b98b22ad1d69652bb26a9e94138635476Paul Stewart  base::Callback<void(const Result&)> portal_result_callback_;
1633d49ea435a59436f762c2cc5e750ff27ece0d3c5Rebecca Silberstein  base::Callback<void(ConnectivityTrial::Result)> connectivity_trial_callback_;
1641a212a6b98b22ad1d69652bb26a9e94138635476Paul Stewart  Time* time_;
1656e1dc0ff12ceb0fea899ceb5c0f4798e35d86b71Christopher Wiley  int failures_in_content_phase_;
166cd47732488cd101eaf0d3558dde5a7d4e4fc260bBen Chan  std::unique_ptr<ConnectivityTrial> connectivity_trial_;
1673d49ea435a59436f762c2cc5e750ff27ece0d3c5Rebecca Silberstein
168e692740c0623d4cb5d92d36214982ee45a03a5dbPaul Stewart
169e692740c0623d4cb5d92d36214982ee45a03a5dbPaul Stewart  DISALLOW_COPY_AND_ASSIGN(PortalDetector);
170e692740c0623d4cb5d92d36214982ee45a03a5dbPaul Stewart};
171e692740c0623d4cb5d92d36214982ee45a03a5dbPaul Stewart
172e692740c0623d4cb5d92d36214982ee45a03a5dbPaul Stewart}  // namespace shill
173e692740c0623d4cb5d92d36214982ee45a03a5dbPaul Stewart
174c45688bb3881f0c2216e6ec0e19ebda0be33e871Ben Chan#endif  // SHILL_PORTAL_DETECTOR_H_
175