blob: 2bc381da3c4bd0d628b32514071f0dd7b18b9a36 [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 Stewarte6927402012-01-23 16:11:30 -080012#include <base/memory/ref_counted.h>
13#include <base/memory/scoped_ptr.h>
Eric Shienbrood3e20a232012-02-16 11:35:56 -050014#include <base/memory/weak_ptr.h>
Paul Stewarte6927402012-01-23 16:11:30 -080015#include <gtest/gtest_prod.h> // for FRIEND_TEST
16
17#include "shill/http_request.h"
18#include "shill/http_url.h"
19#include "shill/refptr_types.h"
20#include "shill/shill_time.h"
21#include "shill/sockets.h"
22
23namespace shill {
24
Paul Stewartbdb02e62012-02-22 16:24:33 -080025class ByteString;
Paul Stewarte6927402012-01-23 16:11:30 -080026class EventDispatcher;
27class PortalDetector;
28class Time;
29
30// The PortalDetector class implements the portal detection
31// facility in shill, which is responsible for checking to see
32// if a connection has "general internet connectivity".
33//
34// This information can be used for ranking one connection
35// against another, or for informing UI and other components
36// outside the connection manager whether the connection seems
37// available for "general use" or if further user action may be
38// necessary (e.g, click through of a WiFi Hotspot's splash
39// page).
40//
41// This is achieved by trying to access a URL and expecting a
42// specific response. Any result that deviates from this result
43// (DNS or HTTP errors, as well as deviations from the expected
44// content) are considered failures.
45class PortalDetector {
46 public:
47 enum Phase {
48 kPhaseConnection,
49 kPhaseDNS,
50 kPhaseHTTP,
51 kPhaseContent,
52 kPhaseUnknown
53 };
54
55 enum Status {
56 kStatusFailure,
57 kStatusSuccess,
58 kStatusTimeout
59 };
60
61 struct Result {
Thieu Le85e050b2012-03-13 15:04:38 -070062 Result()
63 : phase(kPhaseUnknown), status(kStatusFailure),
64 num_attempts(0), final(false) {}
Paul Stewarte6927402012-01-23 16:11:30 -080065 Result(Phase phase_in, Status status_in)
Thieu Le85e050b2012-03-13 15:04:38 -070066 : phase(phase_in), status(status_in),
67 num_attempts(0), final(false) {}
68 Result(Phase phase_in, Status status_in, int num_attempts_in, bool final_in)
69 : phase(phase_in), status(status_in),
70 num_attempts(num_attempts_in), final(final_in) {}
Paul Stewarte6927402012-01-23 16:11:30 -080071 Phase phase;
72 Status status;
Thieu Le85e050b2012-03-13 15:04:38 -070073 // Total number of portal detections attempted.
74 // This includes failure, timeout and successful attempts.
75 // This only valid when |final| is true.
76 int num_attempts;
Paul Stewarte6927402012-01-23 16:11:30 -080077 bool final;
78 };
79
Paul Stewartc681fa02012-03-02 19:40:04 -080080 static const int kDefaultCheckIntervalSeconds;
Paul Stewartf555cf82012-03-15 14:42:43 -070081 static const char kDefaultCheckPortalList[];
Paul Stewarte6927402012-01-23 16:11:30 -080082 static const char kDefaultURL[];
83 static const char kResponseExpected[];
Thieu Le85e050b2012-03-13 15:04:38 -070084 // Maximum number of times the PortalDetector will attempt a connection.
85 static const int kMaxRequestAttempts;
Paul Stewarte6927402012-01-23 16:11:30 -080086
87 PortalDetector(ConnectionRefPtr connection,
88 EventDispatcher *dispatcher,
Eric Shienbrood3e20a232012-02-16 11:35:56 -050089 const base::Callback<void(const Result&)> &callback);
Paul Stewarte6927402012-01-23 16:11:30 -080090 virtual ~PortalDetector();
91
92 // Start a portal detection test. Returns true if |url_string| correctly
93 // parses as a URL. Returns false (and does not start) if the |url_string|
94 // fails to parse.
95 //
96 // As each attempt completes the callback handed to the constructor will
97 // be called. The PortalDetector will try up to kMaxRequestAttempts times
98 // to successfully retrieve the URL. If the attempt is successful or
99 // this is the last attempt, the "final" flag in the Result structure will
100 // be true, otherwise it will be false, and the PortalDetector will
101 // schedule the next attempt.
Paul Stewartc681fa02012-03-02 19:40:04 -0800102 virtual bool Start(const std::string &url_string);
103 virtual bool StartAfterDelay(const std::string &url_string,
104 int delay_seconds);
Paul Stewarte6927402012-01-23 16:11:30 -0800105
106 // End the current portal detection process if one exists, and do not call
107 // the callback.
Paul Stewartc681fa02012-03-02 19:40:04 -0800108 virtual void Stop();
109
110 // Returns whether portal request is "in progress": whether the portal
111 // detector is in the progress of making attempts. Returns true if
112 // attempts are in progress, false otherwise. Notably, this function
113 // returns false during the period of time between calling "Start" or
114 // "StartAfterDelay" and the actual start of the first attempt.
115 virtual bool IsInProgress();
Paul Stewarte6927402012-01-23 16:11:30 -0800116
117 static const std::string PhaseToString(Phase phase);
118 static const std::string StatusToString(Status status);
119 static Result GetPortalResultForRequestResult(HTTPRequest::Result result);
120
121 private:
122 friend class PortalDetectorTest;
123 FRIEND_TEST(PortalDetectorTest, StartAttemptFailed);
124 FRIEND_TEST(PortalDetectorTest, StartAttemptRepeated);
Paul Stewartc681fa02012-03-02 19:40:04 -0800125 FRIEND_TEST(PortalDetectorTest, StartAttemptAfterDelay);
Paul Stewarte6927402012-01-23 16:11:30 -0800126 FRIEND_TEST(PortalDetectorTest, AttemptCount);
127
Paul Stewarte6927402012-01-23 16:11:30 -0800128 // Minimum time between attempts to connect to server.
129 static const int kMinTimeBetweenAttemptsSeconds;
130 // Time to wait for request to complete.
131 static const int kRequestTimeoutSeconds;
132
133 static const char kPhaseConnectionString[];
134 static const char kPhaseDNSString[];
135 static const char kPhaseHTTPString[];
136 static const char kPhaseContentString[];
137 static const char kPhaseUnknownString[];
138
139 static const char kStatusFailureString[];
140 static const char kStatusSuccessString[];
141 static const char kStatusTimeoutString[];
142
143 void CompleteAttempt(Result result);
Paul Stewartbdb02e62012-02-22 16:24:33 -0800144 void RequestReadCallback(const ByteString &response_data);
145 void RequestResultCallback(HTTPRequest::Result result,
146 const ByteString &response_data);
Paul Stewartc681fa02012-03-02 19:40:04 -0800147 void StartAttempt(int init_delay_seconds);
Paul Stewarte6927402012-01-23 16:11:30 -0800148 void StartAttemptTask();
149 void StopAttempt();
150 void TimeoutAttemptTask();
151
152 int attempt_count_;
153 struct timeval attempt_start_time_;
154 ConnectionRefPtr connection_;
155 EventDispatcher *dispatcher_;
Eric Shienbrood3e20a232012-02-16 11:35:56 -0500156 base::WeakPtrFactory<PortalDetector> weak_ptr_factory_;
157 base::Callback<void(const Result &)> portal_result_callback_;
Paul Stewarte6927402012-01-23 16:11:30 -0800158 scoped_ptr<HTTPRequest> request_;
Eric Shienbrood3e20a232012-02-16 11:35:56 -0500159 base::Callback<void(const ByteString &)> request_read_callback_;
160 base::Callback<void(HTTPRequest::Result, const ByteString &)>
Paul Stewartbdb02e62012-02-22 16:24:33 -0800161 request_result_callback_;
Paul Stewarte6927402012-01-23 16:11:30 -0800162 Sockets sockets_;
Paul Stewarte6927402012-01-23 16:11:30 -0800163 Time *time_;
164 HTTPURL url_;
165
166 DISALLOW_COPY_AND_ASSIGN(PortalDetector);
167};
168
169} // namespace shill
170
171#endif // SHILL_PORTAL_DETECTOR_