OLD | NEW |
1 // Copyright (c) 2013 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2013 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "chrome/browser/chromeos/net/network_portal_detector_impl.h" | 5 #include "chrome/browser/chromeos/net/network_portal_detector_impl.h" |
6 | 6 |
| 7 #include <algorithm> |
| 8 |
7 #include "base/bind.h" | 9 #include "base/bind.h" |
8 #include "base/command_line.h" | 10 #include "base/command_line.h" |
9 #include "base/logging.h" | 11 #include "base/logging.h" |
10 #include "base/message_loop/message_loop.h" | 12 #include "base/message_loop/message_loop.h" |
11 #include "base/metrics/histogram.h" | 13 #include "base/metrics/histogram.h" |
12 #include "chrome/browser/chrome_notification_types.h" | 14 #include "chrome/browser/chrome_notification_types.h" |
13 #include "chromeos/dbus/dbus_thread_manager.h" | 15 #include "chromeos/dbus/dbus_thread_manager.h" |
14 #include "chromeos/dbus/shill_profile_client.h" | 16 #include "chromeos/dbus/shill_profile_client.h" |
15 #include "chromeos/network/network_state.h" | 17 #include "chromeos/network/network_state.h" |
16 #include "chromeos/network/network_state_handler.h" | 18 #include "chromeos/network/network_state_handler.h" |
17 #include "content/public/browser/notification_service.h" | 19 #include "content/public/browser/notification_service.h" |
18 #include "grit/generated_resources.h" | 20 #include "grit/generated_resources.h" |
19 #include "net/http/http_status_code.h" | 21 #include "net/http/http_status_code.h" |
20 #include "third_party/cros_system_api/dbus/service_constants.h" | 22 #include "third_party/cros_system_api/dbus/service_constants.h" |
21 #include "ui/base/l10n/l10n_util.h" | 23 #include "ui/base/l10n/l10n_util.h" |
22 | 24 |
23 using captive_portal::CaptivePortalDetector; | 25 using captive_portal::CaptivePortalDetector; |
24 | 26 |
25 namespace chromeos { | 27 namespace chromeos { |
26 | 28 |
27 namespace { | 29 namespace { |
28 | 30 |
29 // Maximum number of portal detections for the same default network | |
30 // after network change. | |
31 const int kMaxRequestAttempts = 3; | |
32 | |
33 // Minimum timeout between consecutive portal checks for the same | |
34 // network. | |
35 const int kMinTimeBetweenAttemptsSec = 3; | |
36 | |
37 // Delay before portal detection caused by changes in proxy settings. | 31 // Delay before portal detection caused by changes in proxy settings. |
38 const int kProxyChangeDelaySec = 1; | 32 const int kProxyChangeDelaySec = 1; |
39 | 33 |
40 // Delay between consecutive portal checks for a network in lazy mode. | 34 const NetworkState* DefaultNetwork() { |
41 const int kLazyCheckIntervalSec = 5; | 35 return NetworkHandler::Get()->network_state_handler()->DefaultNetwork(); |
| 36 } |
42 | 37 |
43 void RecordDiscrepancyWithShill( | 38 void RecordDiscrepancyWithShill( |
44 const NetworkState* network, | 39 const NetworkState* network, |
45 const NetworkPortalDetector::CaptivePortalStatus status) { | 40 const NetworkPortalDetector::CaptivePortalStatus status) { |
46 if (network->connection_state() == shill::kStateOnline) { | 41 if (network->connection_state() == shill::kStateOnline) { |
47 UMA_HISTOGRAM_ENUMERATION( | 42 UMA_HISTOGRAM_ENUMERATION( |
48 NetworkPortalDetectorImpl::kShillOnlineHistogram, | 43 NetworkPortalDetectorImpl::kShillOnlineHistogram, |
49 status, | 44 status, |
50 NetworkPortalDetector::CAPTIVE_PORTAL_STATUS_COUNT); | 45 NetworkPortalDetector::CAPTIVE_PORTAL_STATUS_COUNT); |
51 } else if (network->connection_state() == shill::kStatePortal) { | 46 } else if (network->connection_state() == shill::kStatePortal) { |
52 UMA_HISTOGRAM_ENUMERATION( | 47 UMA_HISTOGRAM_ENUMERATION( |
53 NetworkPortalDetectorImpl::kShillPortalHistogram, | 48 NetworkPortalDetectorImpl::kShillPortalHistogram, |
54 status, | 49 status, |
55 NetworkPortalDetector::CAPTIVE_PORTAL_STATUS_COUNT); | 50 NetworkPortalDetector::CAPTIVE_PORTAL_STATUS_COUNT); |
56 } else if (network->connection_state() == shill::kStateOffline) { | 51 } else if (network->connection_state() == shill::kStateOffline) { |
57 UMA_HISTOGRAM_ENUMERATION( | 52 UMA_HISTOGRAM_ENUMERATION( |
58 NetworkPortalDetectorImpl::kShillOfflineHistogram, | 53 NetworkPortalDetectorImpl::kShillOfflineHistogram, |
59 status, | 54 status, |
60 NetworkPortalDetector::CAPTIVE_PORTAL_STATUS_COUNT); | 55 NetworkPortalDetector::CAPTIVE_PORTAL_STATUS_COUNT); |
61 } | 56 } |
62 } | 57 } |
63 | 58 |
64 } // namespace | 59 } // namespace |
65 | 60 |
66 //////////////////////////////////////////////////////////////////////////////// | 61 //////////////////////////////////////////////////////////////////////////////// |
67 // NetworkPortalDetectorImpl, public: | 62 // NetworkPortalDetectorImpl, public: |
68 | 63 |
69 const char NetworkPortalDetectorImpl::kDetectionResultHistogram[] = | 64 const char NetworkPortalDetectorImpl::kDetectionResultHistogram[] = |
70 "CaptivePortal.OOBE.DetectionResult"; | 65 "CaptivePortal.OOBE.DetectionResult"; |
71 const char NetworkPortalDetectorImpl::kDetectionDurationHistogram[] = | 66 const char NetworkPortalDetectorImpl::kDetectionDurationHistogram[] = |
72 "CaptivePortal.OOBE.DetectionDuration"; | 67 "CaptivePortal.OOBE.DetectionDuration"; |
73 const char NetworkPortalDetectorImpl::kShillOnlineHistogram[] = | 68 const char NetworkPortalDetectorImpl::kShillOnlineHistogram[] = |
74 "CaptivePortal.OOBE.DiscrepancyWithShill_Online"; | 69 "CaptivePortal.OOBE.DiscrepancyWithShill_Online"; |
75 const char NetworkPortalDetectorImpl::kShillPortalHistogram[] = | 70 const char NetworkPortalDetectorImpl::kShillPortalHistogram[] = |
76 "CaptivePortal.OOBE.DiscrepancyWithShill_RestrictedPool"; | 71 "CaptivePortal.OOBE.DiscrepancyWithShill_RestrictedPool"; |
77 const char NetworkPortalDetectorImpl::kShillOfflineHistogram[] = | 72 const char NetworkPortalDetectorImpl::kShillOfflineHistogram[] = |
78 "CaptivePortal.OOBE.DiscrepancyWithShill_Offline"; | 73 "CaptivePortal.OOBE.DiscrepancyWithShill_Offline"; |
79 | 74 |
80 NetworkPortalDetectorImpl::NetworkPortalDetectorImpl( | 75 NetworkPortalDetectorImpl::NetworkPortalDetectorImpl( |
81 const scoped_refptr<net::URLRequestContextGetter>& request_context) | 76 const scoped_refptr<net::URLRequestContextGetter>& request_context) |
82 : state_(STATE_IDLE), | 77 : state_(STATE_IDLE), |
83 test_url_(CaptivePortalDetector::kDefaultURL), | 78 test_url_(CaptivePortalDetector::kDefaultURL), |
84 enabled_(false), | 79 enabled_(false), |
85 weak_ptr_factory_(this), | 80 weak_factory_(this), |
86 attempt_count_(0), | 81 attempt_count_(0), |
87 lazy_detection_enabled_(false), | 82 strategy_(PortalDetectorStrategy::CreateById( |
88 lazy_check_interval_(base::TimeDelta::FromSeconds(kLazyCheckIntervalSec)), | 83 PortalDetectorStrategy::STRATEGY_ID_LOGIN_SCREEN)) { |
89 min_time_between_attempts_( | |
90 base::TimeDelta::FromSeconds(kMinTimeBetweenAttemptsSec)), | |
91 request_timeout_for_testing_initialized_(false) { | |
92 captive_portal_detector_.reset(new CaptivePortalDetector(request_context)); | 84 captive_portal_detector_.reset(new CaptivePortalDetector(request_context)); |
| 85 strategy_->set_delegate(this); |
93 | 86 |
94 registrar_.Add(this, | 87 registrar_.Add(this, |
95 chrome::NOTIFICATION_LOGIN_PROXY_CHANGED, | 88 chrome::NOTIFICATION_LOGIN_PROXY_CHANGED, |
96 content::NotificationService::AllSources()); | 89 content::NotificationService::AllSources()); |
97 registrar_.Add(this, | 90 registrar_.Add(this, |
98 chrome::NOTIFICATION_AUTH_SUPPLIED, | 91 chrome::NOTIFICATION_AUTH_SUPPLIED, |
99 content::NotificationService::AllSources()); | 92 content::NotificationService::AllSources()); |
100 registrar_.Add(this, | 93 registrar_.Add(this, |
101 chrome::NOTIFICATION_AUTH_CANCELLED, | 94 chrome::NOTIFICATION_AUTH_CANCELLED, |
102 content::NotificationService::AllSources()); | 95 content::NotificationService::AllSources()); |
103 | 96 |
104 NetworkHandler::Get()->network_state_handler()->AddObserver( | 97 NetworkHandler::Get()->network_state_handler()->AddObserver(this, FROM_HERE); |
105 this, FROM_HERE); | |
106 } | 98 } |
107 | 99 |
108 NetworkPortalDetectorImpl::~NetworkPortalDetectorImpl() { | 100 NetworkPortalDetectorImpl::~NetworkPortalDetectorImpl() { |
109 DCHECK(CalledOnValidThread()); | 101 DCHECK(CalledOnValidThread()); |
110 | 102 |
111 detection_task_.Cancel(); | 103 attempt_task_.Cancel(); |
112 detection_timeout_.Cancel(); | 104 attempt_timeout_.Cancel(); |
113 | 105 |
114 captive_portal_detector_->Cancel(); | 106 captive_portal_detector_->Cancel(); |
115 captive_portal_detector_.reset(); | 107 captive_portal_detector_.reset(); |
116 observers_.Clear(); | 108 observers_.Clear(); |
117 if (NetworkHandler::IsInitialized()) { | 109 if (NetworkHandler::IsInitialized()) { |
118 NetworkHandler::Get()->network_state_handler()->RemoveObserver( | 110 NetworkHandler::Get()->network_state_handler()->RemoveObserver(this, |
119 this, FROM_HERE); | 111 FROM_HERE); |
120 } | 112 } |
121 } | 113 } |
122 | 114 |
123 void NetworkPortalDetectorImpl::AddObserver(Observer* observer) { | 115 void NetworkPortalDetectorImpl::AddObserver(Observer* observer) { |
124 DCHECK(CalledOnValidThread()); | 116 DCHECK(CalledOnValidThread()); |
125 if (!observer || observers_.HasObserver(observer)) | 117 if (observer && !observers_.HasObserver(observer)) |
126 return; | 118 observers_.AddObserver(observer); |
127 observers_.AddObserver(observer); | |
128 } | 119 } |
129 | 120 |
130 void NetworkPortalDetectorImpl::AddAndFireObserver(Observer* observer) { | 121 void NetworkPortalDetectorImpl::AddAndFireObserver(Observer* observer) { |
131 DCHECK(CalledOnValidThread()); | 122 DCHECK(CalledOnValidThread()); |
132 if (!observer) | 123 if (!observer) |
133 return; | 124 return; |
134 AddObserver(observer); | 125 AddObserver(observer); |
135 CaptivePortalState portal_state; | 126 CaptivePortalState portal_state; |
136 const NetworkState* network = | 127 const NetworkState* network = DefaultNetwork(); |
137 NetworkHandler::Get()->network_state_handler()->DefaultNetwork(); | |
138 if (network) | 128 if (network) |
139 portal_state = GetCaptivePortalState(network->path()); | 129 portal_state = GetCaptivePortalState(network->path()); |
140 observer->OnPortalDetectionCompleted(network, portal_state); | 130 observer->OnPortalDetectionCompleted(network, portal_state); |
141 } | 131 } |
142 | 132 |
143 void NetworkPortalDetectorImpl::RemoveObserver(Observer* observer) { | 133 void NetworkPortalDetectorImpl::RemoveObserver(Observer* observer) { |
144 DCHECK(CalledOnValidThread()); | 134 DCHECK(CalledOnValidThread()); |
145 if (observer) | 135 if (observer) |
146 observers_.RemoveObserver(observer); | 136 observers_.RemoveObserver(observer); |
147 } | 137 } |
148 | 138 |
149 bool NetworkPortalDetectorImpl::IsEnabled() { | 139 bool NetworkPortalDetectorImpl::IsEnabled() { return enabled_; } |
150 return enabled_; | |
151 } | |
152 | 140 |
153 void NetworkPortalDetectorImpl::Enable(bool start_detection) { | 141 void NetworkPortalDetectorImpl::Enable(bool start_detection) { |
154 DCHECK(CalledOnValidThread()); | 142 DCHECK(CalledOnValidThread()); |
155 if (enabled_) | 143 if (enabled_) |
156 return; | 144 return; |
| 145 |
| 146 DCHECK(is_idle()); |
157 enabled_ = true; | 147 enabled_ = true; |
158 DCHECK(!IsPortalCheckPending()); | 148 |
159 DCHECK(!IsCheckingForPortal()); | 149 const NetworkState* network = DefaultNetwork(); |
160 DCHECK(!lazy_detection_enabled()); | 150 if (!start_detection || !network) |
161 if (!start_detection) | |
162 return; | 151 return; |
163 state_ = STATE_IDLE; | 152 portal_state_map_.erase(network->path()); |
164 attempt_count_ = 0; | 153 StartDetection(); |
165 const NetworkState* default_network = | |
166 NetworkHandler::Get()->network_state_handler()->DefaultNetwork(); | |
167 if (!default_network) | |
168 return; | |
169 portal_state_map_.erase(default_network->path()); | |
170 DCHECK(CanPerformDetection()); | |
171 DetectCaptivePortal(base::TimeDelta()); | |
172 } | 154 } |
173 | 155 |
174 NetworkPortalDetectorImpl::CaptivePortalState | 156 NetworkPortalDetectorImpl::CaptivePortalState |
175 NetworkPortalDetectorImpl::GetCaptivePortalState( | 157 NetworkPortalDetectorImpl::GetCaptivePortalState( |
176 const std::string& service_path) { | 158 const std::string& service_path) { |
177 DCHECK(CalledOnValidThread()); | 159 DCHECK(CalledOnValidThread()); |
178 CaptivePortalStateMap::const_iterator it = | 160 CaptivePortalStateMap::const_iterator it = |
179 portal_state_map_.find(service_path); | 161 portal_state_map_.find(service_path); |
180 if (it == portal_state_map_.end()) | 162 if (it == portal_state_map_.end()) |
181 return CaptivePortalState(); | 163 return CaptivePortalState(); |
182 return it->second; | 164 return it->second; |
183 } | 165 } |
184 | 166 |
185 bool NetworkPortalDetectorImpl::StartDetectionIfIdle() { | 167 bool NetworkPortalDetectorImpl::StartDetectionIfIdle() { |
186 if (IsPortalCheckPending() || IsCheckingForPortal()) | 168 if (!is_idle()) |
187 return false; | 169 return false; |
188 if (!CanPerformDetection()) | 170 StartDetection(); |
189 attempt_count_ = 0; | |
190 DCHECK(CanPerformDetection()); | |
191 DetectCaptivePortal(base::TimeDelta()); | |
192 return true; | 171 return true; |
193 } | 172 } |
194 | 173 |
195 void NetworkPortalDetectorImpl::EnableLazyDetection() { | 174 void NetworkPortalDetectorImpl::EnableErrorScreenStrategy() { |
196 if (lazy_detection_enabled()) | 175 if (strategy_->Id() == PortalDetectorStrategy::STRATEGY_ID_ERROR_SCREEN) |
197 return; | 176 return; |
198 lazy_detection_enabled_ = true; | 177 VLOG(1) << "Error screen detection strategy enabled."; |
199 VLOG(1) << "Lazy detection mode enabled."; | 178 strategy_ = PortalDetectorStrategy::CreateById( |
| 179 PortalDetectorStrategy::STRATEGY_ID_ERROR_SCREEN); |
| 180 strategy_->set_delegate(this); |
200 StartDetectionIfIdle(); | 181 StartDetectionIfIdle(); |
201 } | 182 } |
202 | 183 |
203 void NetworkPortalDetectorImpl::DisableLazyDetection() { | 184 void NetworkPortalDetectorImpl::DisableErrorScreenStrategy() { |
204 if (!lazy_detection_enabled()) | 185 if (strategy_->Id() != PortalDetectorStrategy::STRATEGY_ID_ERROR_SCREEN) |
205 return; | 186 return; |
206 lazy_detection_enabled_ = false; | 187 VLOG(1) << "Error screen detection strategy disabled."; |
207 if (attempt_count_ == kMaxRequestAttempts && IsPortalCheckPending()) | 188 strategy_ = PortalDetectorStrategy::CreateById( |
208 CancelPortalDetection(); | 189 PortalDetectorStrategy::STRATEGY_ID_LOGIN_SCREEN); |
209 VLOG(1) << "Lazy detection mode disabled."; | 190 strategy_->set_delegate(this); |
| 191 StopDetection(); |
210 } | 192 } |
211 | 193 |
212 void NetworkPortalDetectorImpl::DefaultNetworkChanged( | 194 void NetworkPortalDetectorImpl::DefaultNetworkChanged( |
213 const NetworkState* default_network) { | 195 const NetworkState* default_network) { |
214 DCHECK(CalledOnValidThread()); | 196 DCHECK(CalledOnValidThread()); |
215 | 197 |
216 if (!default_network) { | 198 if (!default_network) { |
217 default_network_name_.clear(); | 199 default_network_name_.clear(); |
218 default_network_id_.clear(); | 200 default_network_id_.clear(); |
219 | 201 |
220 CancelPortalDetection(); | 202 StopDetection(); |
221 | 203 |
222 CaptivePortalState state; | 204 CaptivePortalState state; |
223 state.status = CAPTIVE_PORTAL_STATUS_OFFLINE; | 205 state.status = CAPTIVE_PORTAL_STATUS_OFFLINE; |
224 SetCaptivePortalState(NULL, state); | 206 OnDetectionCompleted(NULL, state); |
225 return; | 207 return; |
226 } | 208 } |
227 | 209 |
228 default_network_name_ = default_network->name(); | 210 default_network_name_ = default_network->name(); |
229 default_network_id_ = default_network->guid(); | 211 default_network_id_ = default_network->guid(); |
230 | 212 |
231 bool network_changed = (default_service_path_ != default_network->path()); | 213 bool network_changed = (default_service_path_ != default_network->path()); |
232 default_service_path_ = default_network->path(); | 214 default_service_path_ = default_network->path(); |
233 | 215 |
234 bool connection_state_changed = (default_connection_state_ != | 216 bool connection_state_changed = |
235 default_network->connection_state()); | 217 (default_connection_state_ != default_network->connection_state()); |
236 default_connection_state_ = default_network->connection_state(); | 218 default_connection_state_ = default_network->connection_state(); |
237 | 219 |
238 if (network_changed || connection_state_changed) { | 220 if (network_changed || connection_state_changed) |
239 attempt_count_ = 0; | 221 StopDetection(); |
240 CancelPortalDetection(); | |
241 } | |
242 | 222 |
243 if (CanPerformDetection() && | 223 if (CanPerformAttempt() && |
244 NetworkState::StateIsConnected(default_connection_state_)) { | 224 NetworkState::StateIsConnected(default_connection_state_)) { |
245 // Initiate Captive Portal detection if network's captive | 225 // Initiate Captive Portal detection if network's captive |
246 // portal state is unknown (e.g. for freshly created networks), | 226 // portal state is unknown (e.g. for freshly created networks), |
247 // offline or if network connection state was changed. | 227 // offline or if network connection state was changed. |
248 CaptivePortalState state = GetCaptivePortalState(default_network->path()); | 228 CaptivePortalState state = GetCaptivePortalState(default_network->path()); |
249 if (state.status == CAPTIVE_PORTAL_STATUS_UNKNOWN || | 229 if (state.status == CAPTIVE_PORTAL_STATUS_UNKNOWN || |
250 state.status == CAPTIVE_PORTAL_STATUS_OFFLINE || | 230 state.status == CAPTIVE_PORTAL_STATUS_OFFLINE || |
251 (!network_changed && connection_state_changed)) { | 231 (!network_changed && connection_state_changed)) { |
252 DetectCaptivePortal(base::TimeDelta()); | 232 ScheduleAttempt(base::TimeDelta()); |
253 } | 233 } |
254 } | 234 } |
255 } | 235 } |
256 | 236 |
| 237 int NetworkPortalDetectorImpl::AttemptCount() { return attempt_count_; } |
| 238 |
| 239 base::TimeTicks NetworkPortalDetectorImpl::AttemptStartTime() { |
| 240 return attempt_start_time_; |
| 241 } |
| 242 |
| 243 base::TimeTicks NetworkPortalDetectorImpl::GetCurrentTimeTicks() { |
| 244 if (time_ticks_for_testing_.is_null()) |
| 245 return base::TimeTicks::Now(); |
| 246 return time_ticks_for_testing_; |
| 247 } |
| 248 |
257 //////////////////////////////////////////////////////////////////////////////// | 249 //////////////////////////////////////////////////////////////////////////////// |
258 // NetworkPortalDetectorImpl, private: | 250 // NetworkPortalDetectorImpl, private: |
259 | 251 |
260 bool NetworkPortalDetectorImpl::CanPerformDetection() const { | 252 void NetworkPortalDetectorImpl::StartDetection() { |
261 if (IsPortalCheckPending() || IsCheckingForPortal()) | 253 attempt_count_ = 0; |
262 return false; | 254 DCHECK(CanPerformAttempt()); |
263 return attempt_count_ < kMaxRequestAttempts || lazy_detection_enabled(); | 255 detection_start_time_ = GetCurrentTimeTicks(); |
| 256 ScheduleAttempt(base::TimeDelta()); |
264 } | 257 } |
265 | 258 |
266 void NetworkPortalDetectorImpl::DetectCaptivePortal( | 259 void NetworkPortalDetectorImpl::StopDetection() { |
267 const base::TimeDelta& delay) { | 260 attempt_task_.Cancel(); |
268 DCHECK(CanPerformDetection()); | 261 attempt_timeout_.Cancel(); |
| 262 captive_portal_detector_->Cancel(); |
| 263 state_ = STATE_IDLE; |
| 264 attempt_count_ = 0; |
| 265 } |
| 266 |
| 267 bool NetworkPortalDetectorImpl::CanPerformAttempt() const { |
| 268 return is_idle() && strategy_->CanPerformAttempt(); |
| 269 } |
| 270 |
| 271 void NetworkPortalDetectorImpl::ScheduleAttempt(const base::TimeDelta& delay) { |
| 272 DCHECK(CanPerformAttempt()); |
269 | 273 |
270 if (!IsEnabled()) | 274 if (!IsEnabled()) |
271 return; | 275 return; |
272 | 276 |
273 detection_task_.Cancel(); | 277 attempt_task_.Cancel(); |
274 detection_timeout_.Cancel(); | 278 attempt_timeout_.Cancel(); |
275 state_ = STATE_PORTAL_CHECK_PENDING; | 279 state_ = STATE_PORTAL_CHECK_PENDING; |
276 | 280 |
277 next_attempt_delay_ = delay; | 281 next_attempt_delay_ = std::max(delay, strategy_->GetDelayTillNextAttempt()); |
278 if (attempt_count_ > 0) { | 282 attempt_task_.Reset(base::Bind(&NetworkPortalDetectorImpl::StartAttempt, |
279 base::TimeTicks now = GetCurrentTimeTicks(); | 283 weak_factory_.GetWeakPtr())); |
280 base::TimeDelta elapsed_time; | |
281 | |
282 base::TimeDelta delay_between_attempts = min_time_between_attempts_; | |
283 if (attempt_count_ == kMaxRequestAttempts) { | |
284 DCHECK(lazy_detection_enabled()); | |
285 delay_between_attempts = lazy_check_interval_; | |
286 } | |
287 if (now > attempt_start_time_) | |
288 elapsed_time = now - attempt_start_time_; | |
289 if (elapsed_time < delay_between_attempts && | |
290 delay_between_attempts - elapsed_time > next_attempt_delay_) { | |
291 next_attempt_delay_ = delay_between_attempts - elapsed_time; | |
292 } | |
293 } else { | |
294 detection_start_time_ = GetCurrentTimeTicks(); | |
295 } | |
296 detection_task_.Reset( | |
297 base::Bind(&NetworkPortalDetectorImpl::DetectCaptivePortalTask, | |
298 weak_ptr_factory_.GetWeakPtr())); | |
299 base::MessageLoop::current()->PostDelayedTask( | 284 base::MessageLoop::current()->PostDelayedTask( |
300 FROM_HERE, detection_task_.callback(), next_attempt_delay_); | 285 FROM_HERE, attempt_task_.callback(), next_attempt_delay_); |
301 } | 286 } |
302 | 287 |
303 void NetworkPortalDetectorImpl::DetectCaptivePortalTask() { | 288 void NetworkPortalDetectorImpl::StartAttempt() { |
304 DCHECK(IsPortalCheckPending()); | 289 DCHECK(is_portal_check_pending()); |
305 | 290 |
306 state_ = STATE_CHECKING_FOR_PORTAL; | 291 state_ = STATE_CHECKING_FOR_PORTAL; |
307 attempt_start_time_ = GetCurrentTimeTicks(); | 292 attempt_start_time_ = GetCurrentTimeTicks(); |
308 | 293 |
309 if (attempt_count_ < kMaxRequestAttempts) { | |
310 ++attempt_count_; | |
311 VLOG(1) << "Portal detection started: " | |
312 << "name=" << default_network_name_ << ", " | |
313 << "id=" << default_network_id_ << ", " | |
314 << "attempt=" << attempt_count_ << " of " << kMaxRequestAttempts; | |
315 } else { | |
316 DCHECK(lazy_detection_enabled()); | |
317 VLOG(1) << "Lazy portal detection attempt started"; | |
318 } | |
319 | |
320 captive_portal_detector_->DetectCaptivePortal( | 294 captive_portal_detector_->DetectCaptivePortal( |
321 test_url_, | 295 test_url_, |
322 base::Bind(&NetworkPortalDetectorImpl::OnPortalDetectionCompleted, | 296 base::Bind(&NetworkPortalDetectorImpl::OnAttemptCompleted, |
323 weak_ptr_factory_.GetWeakPtr())); | 297 weak_factory_.GetWeakPtr())); |
324 detection_timeout_.Reset( | 298 attempt_timeout_.Reset( |
325 base::Bind(&NetworkPortalDetectorImpl::PortalDetectionTimeout, | 299 base::Bind(&NetworkPortalDetectorImpl::OnAttemptTimeout, |
326 weak_ptr_factory_.GetWeakPtr())); | 300 weak_factory_.GetWeakPtr())); |
327 base::TimeDelta request_timeout; | |
328 | 301 |
329 // For easier unit testing check for testing state is performed here | |
330 // and not in the GetRequestTimeoutSec(). | |
331 if (request_timeout_for_testing_initialized_) | |
332 request_timeout = request_timeout_for_testing_; | |
333 else | |
334 request_timeout = base::TimeDelta::FromSeconds(GetRequestTimeoutSec()); | |
335 base::MessageLoop::current()->PostDelayedTask( | 302 base::MessageLoop::current()->PostDelayedTask( |
336 FROM_HERE, detection_timeout_.callback(), request_timeout); | 303 FROM_HERE, |
| 304 attempt_timeout_.callback(), |
| 305 strategy_->GetNextAttemptTimeout()); |
337 } | 306 } |
338 | 307 |
339 void NetworkPortalDetectorImpl::PortalDetectionTimeout() { | 308 void NetworkPortalDetectorImpl::OnAttemptTimeout() { |
340 DCHECK(CalledOnValidThread()); | 309 DCHECK(CalledOnValidThread()); |
341 DCHECK(IsCheckingForPortal()); | 310 DCHECK(is_checking_for_portal()); |
342 | 311 |
343 VLOG(1) << "Portal detection timeout: name=" << default_network_name_ << ", " | 312 VLOG(1) << "Portal detection timeout: name=" << default_network_name_ << ", " |
344 << "id=" << default_network_id_; | 313 << "id=" << default_network_id_; |
345 | 314 |
346 captive_portal_detector_->Cancel(); | 315 captive_portal_detector_->Cancel(); |
347 CaptivePortalDetector::Results results; | 316 CaptivePortalDetector::Results results; |
348 results.result = captive_portal::RESULT_NO_RESPONSE; | 317 results.result = captive_portal::RESULT_NO_RESPONSE; |
349 OnPortalDetectionCompleted(results); | 318 OnAttemptCompleted(results); |
350 } | 319 } |
351 | 320 |
352 void NetworkPortalDetectorImpl::CancelPortalDetection() { | 321 void NetworkPortalDetectorImpl::OnAttemptCompleted( |
353 if (IsPortalCheckPending()) | |
354 detection_task_.Cancel(); | |
355 else if (IsCheckingForPortal()) | |
356 captive_portal_detector_->Cancel(); | |
357 detection_timeout_.Cancel(); | |
358 state_ = STATE_IDLE; | |
359 } | |
360 | |
361 void NetworkPortalDetectorImpl::OnPortalDetectionCompleted( | |
362 const CaptivePortalDetector::Results& results) { | 322 const CaptivePortalDetector::Results& results) { |
363 captive_portal::Result result = results.result; | 323 captive_portal::Result result = results.result; |
364 int response_code = results.response_code; | 324 int response_code = results.response_code; |
365 | 325 |
366 DCHECK(CalledOnValidThread()); | 326 DCHECK(CalledOnValidThread()); |
367 DCHECK(IsCheckingForPortal()); | 327 DCHECK(is_checking_for_portal()); |
368 | 328 |
369 VLOG(1) << "Portal detection completed: " | 329 VLOG(1) << "Detection attempt completed: " |
370 << "name=" << default_network_name_ << ", " | 330 << "name=" << default_network_name_ << ", " |
371 << "id=" << default_network_id_ << ", " | 331 << "id=" << default_network_id_ << ", " |
372 << "result=" | 332 << "result=" |
373 << CaptivePortalDetector::CaptivePortalResultToString(results.result) | 333 << CaptivePortalDetector::CaptivePortalResultToString(results.result) |
374 << ", " | 334 << ", " |
375 << "response_code=" << results.response_code; | 335 << "response_code=" << results.response_code; |
376 | 336 |
377 state_ = STATE_IDLE; | 337 state_ = STATE_IDLE; |
378 detection_timeout_.Cancel(); | 338 attempt_timeout_.Cancel(); |
| 339 ++attempt_count_; |
379 | 340 |
380 const NetworkState* default_network = | 341 const NetworkState* network = DefaultNetwork(); |
381 NetworkHandler::Get()->network_state_handler()->DefaultNetwork(); | |
382 | 342 |
383 // If using a fake profile client, also fake being behind a captive portal | 343 // If using a fake profile client, also fake being behind a captive portal |
384 // if the default network is in portal state. | 344 // if the default network is in portal state. |
385 if (result != captive_portal::RESULT_NO_RESPONSE && | 345 if (result != captive_portal::RESULT_NO_RESPONSE && |
386 DBusThreadManager::Get()->GetShillProfileClient()->GetTestInterface() && | 346 DBusThreadManager::Get()->GetShillProfileClient()->GetTestInterface() && |
387 default_network && | 347 network && network->connection_state() == shill::kStatePortal) { |
388 default_network->connection_state() == shill::kStatePortal) { | |
389 result = captive_portal::RESULT_BEHIND_CAPTIVE_PORTAL; | 348 result = captive_portal::RESULT_BEHIND_CAPTIVE_PORTAL; |
390 response_code = 200; | 349 response_code = 200; |
391 } | 350 } |
392 | 351 |
393 CaptivePortalState state; | 352 CaptivePortalState state; |
394 state.response_code = response_code; | 353 state.response_code = response_code; |
395 switch (result) { | 354 switch (result) { |
396 case captive_portal::RESULT_NO_RESPONSE: | 355 case captive_portal::RESULT_NO_RESPONSE: |
397 if (state.response_code == net::HTTP_PROXY_AUTHENTICATION_REQUIRED) { | 356 if (state.response_code == net::HTTP_PROXY_AUTHENTICATION_REQUIRED) { |
398 state.status = CAPTIVE_PORTAL_STATUS_PROXY_AUTH_REQUIRED; | 357 state.status = CAPTIVE_PORTAL_STATUS_PROXY_AUTH_REQUIRED; |
399 SetCaptivePortalState(default_network, state); | 358 } else if (CanPerformAttempt()) { |
400 } else if (attempt_count_ >= kMaxRequestAttempts) { | 359 ScheduleAttempt(results.retry_after_delta); |
401 if (default_network && | 360 return; |
402 (default_network->connection_state() == shill::kStatePortal)) { | 361 } else if (network && |
403 // Take into account shill's detection results. | 362 (network->connection_state() == shill::kStatePortal)) { |
404 state.status = CAPTIVE_PORTAL_STATUS_PORTAL; | 363 // Take into account shill's detection results. |
405 LOG(WARNING) << "Network name=" << default_network->name() << ", " | 364 state.status = CAPTIVE_PORTAL_STATUS_PORTAL; |
406 << "id=" << default_network->guid() << " " | 365 LOG(WARNING) << "Network name=" << network->name() << ", " |
407 << "is marked as " | 366 << "id=" << network->guid() << " " |
408 << CaptivePortalStatusString(state.status) << " " | 367 << "is marked as " |
409 << "despite the fact that CaptivePortalDetector " | 368 << CaptivePortalStatusString(state.status) << " " |
410 << "received no response"; | 369 << "despite the fact that CaptivePortalDetector " |
411 } else { | 370 << "received no response"; |
412 state.status = CAPTIVE_PORTAL_STATUS_OFFLINE; | |
413 } | |
414 SetCaptivePortalState(default_network, state); | |
415 } else { | 371 } else { |
416 DCHECK(CanPerformDetection()); | 372 state.status = CAPTIVE_PORTAL_STATUS_OFFLINE; |
417 DetectCaptivePortal(results.retry_after_delta); | |
418 } | 373 } |
419 break; | 374 break; |
420 case captive_portal::RESULT_INTERNET_CONNECTED: | 375 case captive_portal::RESULT_INTERNET_CONNECTED: |
421 state.status = CAPTIVE_PORTAL_STATUS_ONLINE; | 376 state.status = CAPTIVE_PORTAL_STATUS_ONLINE; |
422 SetCaptivePortalState(default_network, state); | |
423 break; | 377 break; |
424 case captive_portal::RESULT_BEHIND_CAPTIVE_PORTAL: | 378 case captive_portal::RESULT_BEHIND_CAPTIVE_PORTAL: |
425 state.status = CAPTIVE_PORTAL_STATUS_PORTAL; | 379 state.status = CAPTIVE_PORTAL_STATUS_PORTAL; |
426 SetCaptivePortalState(default_network, state); | |
427 break; | 380 break; |
428 default: | 381 default: |
429 break; | 382 break; |
430 } | 383 } |
431 | 384 |
432 TryLazyDetection(); | 385 OnDetectionCompleted(network, state); |
433 } | 386 if (CanPerformAttempt() && strategy_->CanPerformAttemptAfterDetection()) |
434 | 387 ScheduleAttempt(base::TimeDelta()); |
435 void NetworkPortalDetectorImpl::TryLazyDetection() { | |
436 if (lazy_detection_enabled() && CanPerformDetection()) | |
437 DetectCaptivePortal(base::TimeDelta()); | |
438 } | 388 } |
439 | 389 |
440 void NetworkPortalDetectorImpl::Observe( | 390 void NetworkPortalDetectorImpl::Observe( |
441 int type, | 391 int type, |
442 const content::NotificationSource& source, | 392 const content::NotificationSource& source, |
443 const content::NotificationDetails& details) { | 393 const content::NotificationDetails& details) { |
444 if (type == chrome::NOTIFICATION_LOGIN_PROXY_CHANGED || | 394 if (type == chrome::NOTIFICATION_LOGIN_PROXY_CHANGED || |
445 type == chrome::NOTIFICATION_AUTH_SUPPLIED || | 395 type == chrome::NOTIFICATION_AUTH_SUPPLIED || |
446 type == chrome::NOTIFICATION_AUTH_CANCELLED) { | 396 type == chrome::NOTIFICATION_AUTH_CANCELLED) { |
447 VLOG(1) << "Restarting portal detection due to proxy change."; | 397 VLOG(1) << "Restarting portal detection due to proxy change."; |
448 attempt_count_ = 0; | 398 attempt_count_ = 0; |
449 if (IsPortalCheckPending()) | 399 if (is_portal_check_pending()) |
450 return; | 400 return; |
451 CancelPortalDetection(); | 401 StopDetection(); |
452 DCHECK(CanPerformDetection()); | 402 ScheduleAttempt(base::TimeDelta::FromSeconds(kProxyChangeDelaySec)); |
453 DetectCaptivePortal(base::TimeDelta::FromSeconds(kProxyChangeDelaySec)); | |
454 } | 403 } |
455 } | 404 } |
456 | 405 |
457 bool NetworkPortalDetectorImpl::IsPortalCheckPending() const { | 406 void NetworkPortalDetectorImpl::OnDetectionCompleted( |
458 return state_ == STATE_PORTAL_CHECK_PENDING; | |
459 } | |
460 | |
461 bool NetworkPortalDetectorImpl::IsCheckingForPortal() const { | |
462 return state_ == STATE_CHECKING_FOR_PORTAL; | |
463 } | |
464 | |
465 void NetworkPortalDetectorImpl::SetCaptivePortalState( | |
466 const NetworkState* network, | 407 const NetworkState* network, |
467 const CaptivePortalState& state) { | 408 const CaptivePortalState& state) { |
468 if (!network) { | 409 if (!network) { |
469 NotifyPortalDetectionCompleted(network, state); | 410 NotifyDetectionCompleted(network, state); |
470 return; | 411 return; |
471 } | 412 } |
472 | 413 |
473 CaptivePortalStateMap::const_iterator it = | 414 CaptivePortalStateMap::const_iterator it = |
474 portal_state_map_.find(network->path()); | 415 portal_state_map_.find(network->path()); |
475 if (it == portal_state_map_.end() || | 416 if (it == portal_state_map_.end() || it->second.status != state.status || |
476 it->second.status != state.status || | |
477 it->second.response_code != state.response_code) { | 417 it->second.response_code != state.response_code) { |
478 VLOG(1) << "Updating Chrome Captive Portal state: " | 418 VLOG(1) << "Updating Chrome Captive Portal state: " |
479 << "name=" << network->name() << ", " | 419 << "name=" << network->name() << ", " |
480 << "id=" << network->guid() << ", " | 420 << "id=" << network->guid() << ", " |
481 << "status=" << CaptivePortalStatusString(state.status) << ", " | 421 << "status=" << CaptivePortalStatusString(state.status) << ", " |
482 << "response_code=" << state.response_code; | 422 << "response_code=" << state.response_code; |
483 | 423 |
484 // Record detection duration iff detection result differs from the | 424 // Record detection duration iff detection result differs from the |
485 // previous one for this network. The reason is to record all stats | 425 // previous one for this network. The reason is to record all stats |
486 // only when network changes it's state. | 426 // only when network changes it's state. |
487 RecordDetectionStats(network, state.status); | 427 RecordDetectionStats(network, state.status); |
488 | 428 |
489 portal_state_map_[network->path()] = state; | 429 portal_state_map_[network->path()] = state; |
490 } | 430 } |
491 NotifyPortalDetectionCompleted(network, state); | 431 NotifyDetectionCompleted(network, state); |
492 } | 432 } |
493 | 433 |
494 void NetworkPortalDetectorImpl::NotifyPortalDetectionCompleted( | 434 void NetworkPortalDetectorImpl::NotifyDetectionCompleted( |
495 const NetworkState* network, | 435 const NetworkState* network, |
496 const CaptivePortalState& state) { | 436 const CaptivePortalState& state) { |
497 FOR_EACH_OBSERVER(Observer, observers_, | 437 FOR_EACH_OBSERVER( |
498 OnPortalDetectionCompleted(network, state)); | 438 Observer, observers_, OnPortalDetectionCompleted(network, state)); |
499 notification_controller_.OnPortalDetectionCompleted(network, state); | 439 notification_controller_.OnPortalDetectionCompleted(network, state); |
500 } | 440 } |
501 | 441 |
502 base::TimeTicks NetworkPortalDetectorImpl::GetCurrentTimeTicks() const { | 442 bool NetworkPortalDetectorImpl::AttemptTimeoutIsCancelledForTesting() const { |
503 if (time_ticks_for_testing_.is_null()) | 443 return attempt_timeout_.IsCancelled(); |
504 return base::TimeTicks::Now(); | |
505 return time_ticks_for_testing_; | |
506 } | |
507 | |
508 bool NetworkPortalDetectorImpl::DetectionTimeoutIsCancelledForTesting() const { | |
509 return detection_timeout_.IsCancelled(); | |
510 } | |
511 | |
512 int NetworkPortalDetectorImpl::GetRequestTimeoutSec() const { | |
513 DCHECK_LE(0, attempt_count_); | |
514 const NetworkState* network = | |
515 NetworkHandler::Get()->network_state_handler()->DefaultNetwork(); | |
516 if (!network) | |
517 return kBaseRequestTimeoutSec; | |
518 if (lazy_detection_enabled_) | |
519 return kLazyRequestTimeoutSec; | |
520 return attempt_count_ * kBaseRequestTimeoutSec; | |
521 } | 444 } |
522 | 445 |
523 void NetworkPortalDetectorImpl::RecordDetectionStats( | 446 void NetworkPortalDetectorImpl::RecordDetectionStats( |
524 const NetworkState* network, | 447 const NetworkState* network, |
525 CaptivePortalStatus status) { | 448 CaptivePortalStatus status) { |
526 // Don't record stats for offline state. | 449 // Don't record stats for offline state. |
527 if (!network) | 450 if (!network) |
528 return; | 451 return; |
529 | 452 |
530 if (!detection_start_time_.is_null()) { | 453 if (!detection_start_time_.is_null()) { |
(...skipping 25 matching lines...) Expand all Loading... |
556 if (network->connection_state() != shill::kStateOnline) | 479 if (network->connection_state() != shill::kStateOnline) |
557 RecordDiscrepancyWithShill(network, status); | 480 RecordDiscrepancyWithShill(network, status); |
558 break; | 481 break; |
559 case NetworkPortalDetector::CAPTIVE_PORTAL_STATUS_COUNT: | 482 case NetworkPortalDetector::CAPTIVE_PORTAL_STATUS_COUNT: |
560 NOTREACHED(); | 483 NOTREACHED(); |
561 break; | 484 break; |
562 } | 485 } |
563 } | 486 } |
564 | 487 |
565 } // namespace chromeos | 488 } // namespace chromeos |
OLD | NEW |