blob: 6119fcb5ed37b93c9916f1f51d31f8f12e20276f [file] [log] [blame]
Paul Stewarte6927402012-01-23 16:11:30 -08001// Copyright (c) 2012 The Chromium OS Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
Ben Chanc45688b2014-07-02 23:50:45 -07005#ifndef SHILL_PORTAL_DETECTOR_H_
6#define SHILL_PORTAL_DETECTOR_H_
Paul Stewarte6927402012-01-23 16:11:30 -08007
Ben Chancd477322014-10-17 14:19:30 -07008#include <memory>
Paul Stewarte6927402012-01-23 16:11:30 -08009#include <string>
10#include <vector>
11
Eric Shienbrood3e20a232012-02-16 11:35:56 -050012#include <base/callback.h>
Paul Stewartf582b502012-04-04 21:39:22 -070013#include <base/cancelable_callback.h>
Paul Stewarte6927402012-01-23 16:11:30 -080014#include <base/memory/ref_counted.h>
Eric Shienbrood3e20a232012-02-16 11:35:56 -050015#include <base/memory/weak_ptr.h>
Paul Stewarte6927402012-01-23 16:11:30 -080016#include <gtest/gtest_prod.h> // for FRIEND_TEST
17
Rebecca Silberstein3d49ea42014-08-21 11:20:50 -070018#include "shill/connectivity_trial.h"
Peter Qiu8d6b5972014-10-28 15:33:34 -070019#include "shill/net/shill_time.h"
Paul Stewarte6927402012-01-23 16:11:30 -080020#include "shill/refptr_types.h"
Paul Stewarte6927402012-01-23 16:11:30 -080021
22namespace shill {
23
Paul Stewartbdb02e62012-02-22 16:24:33 -080024class ByteString;
Paul Stewarte6927402012-01-23 16:11:30 -080025class PortalDetector;
26class Time;
27
28// The PortalDetector class implements the portal detection
29// facility in shill, which is responsible for checking to see
30// if a connection has "general internet connectivity".
31//
32// This information can be used for ranking one connection
33// against another, or for informing UI and other components
34// outside the connection manager whether the connection seems
35// available for "general use" or if further user action may be
36// necessary (e.g, click through of a WiFi Hotspot's splash
37// page).
38//
Rebecca Silberstein3d49ea42014-08-21 11:20:50 -070039// This is achieved by using one or more ConnectivityTrial attempts
40// to access a URL and expecting a specific response. Any result
41// that deviates from this result (DNS or HTTP errors, as well as
42// deviations from the expected content) are considered failures.
Paul Stewarte6927402012-01-23 16:11:30 -080043class PortalDetector {
44 public:
Paul Stewarte6927402012-01-23 16:11:30 -080045 struct Result {
Thieu Le85e050b2012-03-13 15:04:38 -070046 Result()
Rebecca Silberstein3d49ea42014-08-21 11:20:50 -070047 : trial_result(ConnectivityTrial::Result()),
48 num_attempts(0),
49 final(false) {}
50 explicit Result(ConnectivityTrial::Result result_in)
51 : trial_result(result_in),
52 num_attempts(0),
53 final(false) {}
54 Result(ConnectivityTrial::Result result_in,
55 int num_attempts_in,
56 int final_in)
57 : trial_result(result_in),
58 num_attempts(num_attempts_in),
59 final(final_in) {}
60
61 ConnectivityTrial::Result trial_result;
62
63 // Total number of connectivity trials attempted.
Thieu Le85e050b2012-03-13 15:04:38 -070064 // This includes failure, timeout and successful attempts.
65 // This only valid when |final| is true.
66 int num_attempts;
Paul Stewarte6927402012-01-23 16:11:30 -080067 bool final;
68 };
69
Paul Stewartc681fa02012-03-02 19:40:04 -080070 static const int kDefaultCheckIntervalSeconds;
Paul Stewartf555cf82012-03-15 14:42:43 -070071 static const char kDefaultCheckPortalList[];
Thieu Le85e050b2012-03-13 15:04:38 -070072 // Maximum number of times the PortalDetector will attempt a connection.
73 static const int kMaxRequestAttempts;
Paul Stewarte6927402012-01-23 16:11:30 -080074
75 PortalDetector(ConnectionRefPtr connection,
76 EventDispatcher *dispatcher,
Rebecca Silberstein3d49ea42014-08-21 11:20:50 -070077 const base::Callback<void(const PortalDetector::Result&)>
78 &callback);
Paul Stewarte6927402012-01-23 16:11:30 -080079 virtual ~PortalDetector();
80
81 // Start a portal detection test. Returns true if |url_string| correctly
82 // parses as a URL. Returns false (and does not start) if the |url_string|
83 // fails to parse.
84 //
85 // As each attempt completes the callback handed to the constructor will
86 // be called. The PortalDetector will try up to kMaxRequestAttempts times
87 // to successfully retrieve the URL. If the attempt is successful or
88 // this is the last attempt, the "final" flag in the Result structure will
89 // be true, otherwise it will be false, and the PortalDetector will
90 // schedule the next attempt.
Paul Stewartc681fa02012-03-02 19:40:04 -080091 virtual bool Start(const std::string &url_string);
92 virtual bool StartAfterDelay(const std::string &url_string,
93 int delay_seconds);
Paul Stewarte6927402012-01-23 16:11:30 -080094
95 // End the current portal detection process if one exists, and do not call
96 // the callback.
Paul Stewartc681fa02012-03-02 19:40:04 -080097 virtual void Stop();
98
Rebecca Silberstein3d49ea42014-08-21 11:20:50 -070099 // Returns whether portal request is "in progress": whether the underlying
100 // ConnectivityTrial is in the progress of making attempts. Returns true if
Paul Stewartc681fa02012-03-02 19:40:04 -0800101 // attempts are in progress, false otherwise. Notably, this function
102 // returns false during the period of time between calling "Start" or
Rebecca Silberstein3d49ea42014-08-21 11:20:50 -0700103 // "StartAfterDelay" and the actual start of the first attempt. In the case
104 // where multiple attempts may be tried, IsInProgress will return true after
105 // the first attempt has actively started testing the connection.
Paul Stewartc681fa02012-03-02 19:40:04 -0800106 virtual bool IsInProgress();
Paul Stewarte6927402012-01-23 16:11:30 -0800107
Paul Stewarte6927402012-01-23 16:11:30 -0800108 private:
109 friend class PortalDetectorTest;
110 FRIEND_TEST(PortalDetectorTest, StartAttemptFailed);
Rebecca Silberstein3d49ea42014-08-21 11:20:50 -0700111 FRIEND_TEST(PortalDetectorTest, AdjustStartDelayImmediate);
112 FRIEND_TEST(PortalDetectorTest, AdjustStartDelayAfterDelay);
Paul Stewarte6927402012-01-23 16:11:30 -0800113 FRIEND_TEST(PortalDetectorTest, AttemptCount);
Christopher Wiley6e1dc0f2012-10-17 15:38:56 -0700114 FRIEND_TEST(PortalDetectorTest, ReadBadHeadersRetry);
Rebecca Silberstein3d49ea42014-08-21 11:20:50 -0700115 FRIEND_TEST(PortalDetectorTest, ReadBadHeader);
116 FRIEND_TEST(PortalDetectorTest, RequestTimeout);
117 FRIEND_TEST(PortalDetectorTest, ReadPartialHeaderTimeout);
118 FRIEND_TEST(PortalDetectorTest, ReadCompleteHeader);
119 FRIEND_TEST(PortalDetectorTest, ReadMatchingHeader);
120 FRIEND_TEST(PortalDetectorTest, InvalidURL);
Paul Stewarte6927402012-01-23 16:11:30 -0800121
Paul Stewarte6927402012-01-23 16:11:30 -0800122 // Minimum time between attempts to connect to server.
123 static const int kMinTimeBetweenAttemptsSeconds;
124 // Time to wait for request to complete.
125 static const int kRequestTimeoutSeconds;
Christopher Wiley6e1dc0f2012-10-17 15:38:56 -0700126 // Maximum number of failures in content phase before we stop attempting
127 // connections.
128 static const int kMaxFailuresInContentPhase;
Paul Stewarte6927402012-01-23 16:11:30 -0800129
Rebecca Silberstein3d49ea42014-08-21 11:20:50 -0700130 // Internal method to update the start time of the next event. This is used
131 // to keep attempts spaced by at least kMinTimeBetweenAttemptsSeconds in the
132 // event of a retry.
133 void UpdateAttemptTime(int delay_seconds);
134
135 // Internal method used to adjust the start delay in the event of a retry.
136 // Calculates the elapsed time between the most recent attempt and the point
137 // the retry is scheduled. Adds an additional delay to meet the
138 // kMinTimeBetweenAttemptsSeconds requirement.
139 int AdjustStartDelay(int init_delay_seconds);
140
141 // Callback used by ConnectivityTrial to return |result| after attempting to
142 // determine connectivity status.
143 void CompleteAttempt(ConnectivityTrial::Result result);
Paul Stewarte6927402012-01-23 16:11:30 -0800144
145 int attempt_count_;
146 struct timeval attempt_start_time_;
147 ConnectionRefPtr connection_;
148 EventDispatcher *dispatcher_;
Eric Shienbrood3e20a232012-02-16 11:35:56 -0500149 base::WeakPtrFactory<PortalDetector> weak_ptr_factory_;
150 base::Callback<void(const Result &)> portal_result_callback_;
Rebecca Silberstein3d49ea42014-08-21 11:20:50 -0700151 base::Callback<void(ConnectivityTrial::Result)> connectivity_trial_callback_;
Paul Stewarte6927402012-01-23 16:11:30 -0800152 Time *time_;
Christopher Wiley6e1dc0f2012-10-17 15:38:56 -0700153 int failures_in_content_phase_;
Ben Chancd477322014-10-17 14:19:30 -0700154 std::unique_ptr<ConnectivityTrial> connectivity_trial_;
Rebecca Silberstein3d49ea42014-08-21 11:20:50 -0700155
Paul Stewarte6927402012-01-23 16:11:30 -0800156
157 DISALLOW_COPY_AND_ASSIGN(PortalDetector);
158};
159
160} // namespace shill
161
Ben Chanc45688b2014-07-02 23:50:45 -0700162#endif // SHILL_PORTAL_DETECTOR_H_