blob: 8997af8921831466968dce743359d2b6967bcf9c [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 {
62 Result() : phase(kPhaseUnknown), status(kStatusFailure), final(false) {}
63 Result(Phase phase_in, Status status_in)
64 : phase(phase_in), status(status_in), final(false) {}
65 Result(Phase phase_in, Status status_in, bool final_in)
66 : phase(phase_in), status(status_in), final(final_in) {}
67 Phase phase;
68 Status status;
69 bool final;
70 };
71
Paul Stewartc681fa02012-03-02 19:40:04 -080072 static const int kDefaultCheckIntervalSeconds;
Paul Stewarte6927402012-01-23 16:11:30 -080073 static const char kDefaultURL[];
74 static const char kResponseExpected[];
75
76 PortalDetector(ConnectionRefPtr connection,
77 EventDispatcher *dispatcher,
Eric Shienbrood3e20a232012-02-16 11:35:56 -050078 const base::Callback<void(const Result&)> &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
99 // Returns whether portal request is "in progress": whether the portal
100 // detector is in the progress of making attempts. Returns true if
101 // attempts are in progress, false otherwise. Notably, this function
102 // returns false during the period of time between calling "Start" or
103 // "StartAfterDelay" and the actual start of the first attempt.
104 virtual bool IsInProgress();
Paul Stewarte6927402012-01-23 16:11:30 -0800105
106 static const std::string PhaseToString(Phase phase);
107 static const std::string StatusToString(Status status);
108 static Result GetPortalResultForRequestResult(HTTPRequest::Result result);
109
110 private:
111 friend class PortalDetectorTest;
112 FRIEND_TEST(PortalDetectorTest, StartAttemptFailed);
113 FRIEND_TEST(PortalDetectorTest, StartAttemptRepeated);
Paul Stewartc681fa02012-03-02 19:40:04 -0800114 FRIEND_TEST(PortalDetectorTest, StartAttemptAfterDelay);
Paul Stewarte6927402012-01-23 16:11:30 -0800115 FRIEND_TEST(PortalDetectorTest, AttemptCount);
116
117 // Number of times to attempt connection.
118 static const int kMaxRequestAttempts;
119 // Minimum time between attempts to connect to server.
120 static const int kMinTimeBetweenAttemptsSeconds;
121 // Time to wait for request to complete.
122 static const int kRequestTimeoutSeconds;
123
124 static const char kPhaseConnectionString[];
125 static const char kPhaseDNSString[];
126 static const char kPhaseHTTPString[];
127 static const char kPhaseContentString[];
128 static const char kPhaseUnknownString[];
129
130 static const char kStatusFailureString[];
131 static const char kStatusSuccessString[];
132 static const char kStatusTimeoutString[];
133
134 void CompleteAttempt(Result result);
Paul Stewartbdb02e62012-02-22 16:24:33 -0800135 void RequestReadCallback(const ByteString &response_data);
136 void RequestResultCallback(HTTPRequest::Result result,
137 const ByteString &response_data);
Paul Stewartc681fa02012-03-02 19:40:04 -0800138 void StartAttempt(int init_delay_seconds);
Paul Stewarte6927402012-01-23 16:11:30 -0800139 void StartAttemptTask();
140 void StopAttempt();
141 void TimeoutAttemptTask();
142
143 int attempt_count_;
144 struct timeval attempt_start_time_;
145 ConnectionRefPtr connection_;
146 EventDispatcher *dispatcher_;
Eric Shienbrood3e20a232012-02-16 11:35:56 -0500147 base::WeakPtrFactory<PortalDetector> weak_ptr_factory_;
148 base::Callback<void(const Result &)> portal_result_callback_;
Paul Stewarte6927402012-01-23 16:11:30 -0800149 scoped_ptr<HTTPRequest> request_;
Eric Shienbrood3e20a232012-02-16 11:35:56 -0500150 base::Callback<void(const ByteString &)> request_read_callback_;
151 base::Callback<void(HTTPRequest::Result, const ByteString &)>
Paul Stewartbdb02e62012-02-22 16:24:33 -0800152 request_result_callback_;
Paul Stewarte6927402012-01-23 16:11:30 -0800153 Sockets sockets_;
Paul Stewarte6927402012-01-23 16:11:30 -0800154 Time *time_;
155 HTTPURL url_;
156
157 DISALLOW_COPY_AND_ASSIGN(PortalDetector);
158};
159
160} // namespace shill
161
162#endif // SHILL_PORTAL_DETECTOR_