blob: 802e49c943eeecb46e88ce26678077764f4a858e [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
5#ifndef SHILL_PORTAL_DETECTOR_
6#define SHILL_PORTAL_DETECTOR_
7
8#include <string>
9#include <vector>
10
Eric Shienbrood3e20a232012-02-16 11:35:56 -050011#include <base/callback.h>
Paul Stewartf582b502012-04-04 21:39:22 -070012#include <base/cancelable_callback.h>
Paul Stewarte6927402012-01-23 16:11:30 -080013#include <base/memory/ref_counted.h>
14#include <base/memory/scoped_ptr.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
18#include "shill/http_request.h"
19#include "shill/http_url.h"
20#include "shill/refptr_types.h"
21#include "shill/shill_time.h"
22#include "shill/sockets.h"
23
24namespace shill {
25
Paul Stewartbdb02e62012-02-22 16:24:33 -080026class ByteString;
Paul Stewarte6927402012-01-23 16:11:30 -080027class EventDispatcher;
28class PortalDetector;
29class Time;
30
31// The PortalDetector class implements the portal detection
32// facility in shill, which is responsible for checking to see
33// if a connection has "general internet connectivity".
34//
35// This information can be used for ranking one connection
36// against another, or for informing UI and other components
37// outside the connection manager whether the connection seems
38// available for "general use" or if further user action may be
39// necessary (e.g, click through of a WiFi Hotspot's splash
40// page).
41//
42// This is achieved by trying to access a URL and expecting a
43// specific response. Any result that deviates from this result
44// (DNS or HTTP errors, as well as deviations from the expected
45// content) are considered failures.
46class PortalDetector {
47 public:
48 enum Phase {
49 kPhaseConnection,
50 kPhaseDNS,
51 kPhaseHTTP,
52 kPhaseContent,
53 kPhaseUnknown
54 };
55
56 enum Status {
57 kStatusFailure,
58 kStatusSuccess,
59 kStatusTimeout
60 };
61
62 struct Result {
Thieu Le85e050b2012-03-13 15:04:38 -070063 Result()
64 : phase(kPhaseUnknown), status(kStatusFailure),
65 num_attempts(0), final(false) {}
Paul Stewarte6927402012-01-23 16:11:30 -080066 Result(Phase phase_in, Status status_in)
Thieu Le85e050b2012-03-13 15:04:38 -070067 : phase(phase_in), status(status_in),
68 num_attempts(0), final(false) {}
69 Result(Phase phase_in, Status status_in, int num_attempts_in, bool final_in)
70 : phase(phase_in), status(status_in),
71 num_attempts(num_attempts_in), final(final_in) {}
Paul Stewarte6927402012-01-23 16:11:30 -080072 Phase phase;
73 Status status;
Thieu Le85e050b2012-03-13 15:04:38 -070074 // Total number of portal detections attempted.
75 // This includes failure, timeout and successful attempts.
76 // This only valid when |final| is true.
77 int num_attempts;
Paul Stewarte6927402012-01-23 16:11:30 -080078 bool final;
79 };
80
Paul Stewartc681fa02012-03-02 19:40:04 -080081 static const int kDefaultCheckIntervalSeconds;
Paul Stewartf555cf82012-03-15 14:42:43 -070082 static const char kDefaultCheckPortalList[];
Paul Stewarte6927402012-01-23 16:11:30 -080083 static const char kDefaultURL[];
84 static const char kResponseExpected[];
Thieu Le85e050b2012-03-13 15:04:38 -070085 // Maximum number of times the PortalDetector will attempt a connection.
86 static const int kMaxRequestAttempts;
Paul Stewarte6927402012-01-23 16:11:30 -080087
88 PortalDetector(ConnectionRefPtr connection,
89 EventDispatcher *dispatcher,
Eric Shienbrood3e20a232012-02-16 11:35:56 -050090 const base::Callback<void(const Result&)> &callback);
Paul Stewarte6927402012-01-23 16:11:30 -080091 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.
Paul Stewartc681fa02012-03-02 19:40:04 -0800103 virtual bool Start(const std::string &url_string);
104 virtual bool StartAfterDelay(const std::string &url_string,
105 int delay_seconds);
Paul Stewarte6927402012-01-23 16:11:30 -0800106
107 // End the current portal detection process if one exists, and do not call
108 // the callback.
Paul Stewartc681fa02012-03-02 19:40:04 -0800109 virtual void Stop();
110
111 // Returns whether portal request is "in progress": whether the portal
112 // detector 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.
116 virtual bool IsInProgress();
Paul Stewarte6927402012-01-23 16:11:30 -0800117
118 static const std::string PhaseToString(Phase phase);
119 static const std::string StatusToString(Status status);
120 static Result GetPortalResultForRequestResult(HTTPRequest::Result result);
121
122 private:
123 friend class PortalDetectorTest;
124 FRIEND_TEST(PortalDetectorTest, StartAttemptFailed);
125 FRIEND_TEST(PortalDetectorTest, StartAttemptRepeated);
Paul Stewartc681fa02012-03-02 19:40:04 -0800126 FRIEND_TEST(PortalDetectorTest, StartAttemptAfterDelay);
Paul Stewarte6927402012-01-23 16:11:30 -0800127 FRIEND_TEST(PortalDetectorTest, AttemptCount);
128
Paul Stewarte6927402012-01-23 16:11:30 -0800129 // Minimum time between attempts to connect to server.
130 static const int kMinTimeBetweenAttemptsSeconds;
131 // Time to wait for request to complete.
132 static const int kRequestTimeoutSeconds;
133
134 static const char kPhaseConnectionString[];
135 static const char kPhaseDNSString[];
136 static const char kPhaseHTTPString[];
137 static const char kPhaseContentString[];
138 static const char kPhaseUnknownString[];
139
140 static const char kStatusFailureString[];
141 static const char kStatusSuccessString[];
142 static const char kStatusTimeoutString[];
143
144 void CompleteAttempt(Result result);
Paul Stewartbdb02e62012-02-22 16:24:33 -0800145 void RequestReadCallback(const ByteString &response_data);
146 void RequestResultCallback(HTTPRequest::Result result,
147 const ByteString &response_data);
Paul Stewartc681fa02012-03-02 19:40:04 -0800148 void StartAttempt(int init_delay_seconds);
Paul Stewarte6927402012-01-23 16:11:30 -0800149 void StartAttemptTask();
150 void StopAttempt();
151 void TimeoutAttemptTask();
152
153 int attempt_count_;
154 struct timeval attempt_start_time_;
155 ConnectionRefPtr connection_;
156 EventDispatcher *dispatcher_;
Eric Shienbrood3e20a232012-02-16 11:35:56 -0500157 base::WeakPtrFactory<PortalDetector> weak_ptr_factory_;
Paul Stewartf582b502012-04-04 21:39:22 -0700158 base::CancelableClosure attempt_timeout_;
159 base::CancelableClosure start_attempt_;
Eric Shienbrood3e20a232012-02-16 11:35:56 -0500160 base::Callback<void(const Result &)> portal_result_callback_;
Paul Stewarte6927402012-01-23 16:11:30 -0800161 scoped_ptr<HTTPRequest> request_;
Eric Shienbrood3e20a232012-02-16 11:35:56 -0500162 base::Callback<void(const ByteString &)> request_read_callback_;
163 base::Callback<void(HTTPRequest::Result, const ByteString &)>
Paul Stewartbdb02e62012-02-22 16:24:33 -0800164 request_result_callback_;
Paul Stewarte6927402012-01-23 16:11:30 -0800165 Sockets sockets_;
Paul Stewarte6927402012-01-23 16:11:30 -0800166 Time *time_;
167 HTTPURL url_;
168
169 DISALLOW_COPY_AND_ASSIGN(PortalDetector);
170};
171
172} // namespace shill
173
174#endif // SHILL_PORTAL_DETECTOR_