OLD | NEW |
---|---|
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 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.h" | 5 #include "chrome/browser/chromeos/net/network_portal_detector.h" |
6 | 6 |
7 #include "base/bind.h" | 7 #include "base/bind.h" |
8 #include "base/command_line.h" | 8 #include "base/command_line.h" |
9 #include "base/logging.h" | 9 #include "base/logging.h" |
10 #include "base/message_loop.h" | 10 #include "base/message_loop.h" |
(...skipping 20 matching lines...) Expand all Loading... | |
31 // Minimum timeout between consecutive portal checks for the same | 31 // Minimum timeout between consecutive portal checks for the same |
32 // network. | 32 // network. |
33 const int kMinTimeBetweenAttemptsSec = 3; | 33 const int kMinTimeBetweenAttemptsSec = 3; |
34 | 34 |
35 // Timeout for a portal check. | 35 // Timeout for a portal check. |
36 const int kRequestTimeoutSec = 10; | 36 const int kRequestTimeoutSec = 10; |
37 | 37 |
38 // Delay before portal detection caused by changes in proxy settings. | 38 // Delay before portal detection caused by changes in proxy settings. |
39 const int kProxyChangeDelayMs = 500; | 39 const int kProxyChangeDelayMs = 500; |
40 | 40 |
41 // Delay between consecutive portal checks for a network in lazy mode. | |
42 // TODO (ygorshenin@): use exponential backoff or normally distributed | |
43 // random variable instead of this. | |
44 const int kLazyCheckIntervalSec = 30; | |
45 | |
41 std::string CaptivePortalStatusString( | 46 std::string CaptivePortalStatusString( |
42 NetworkPortalDetector::CaptivePortalStatus status) { | 47 NetworkPortalDetector::CaptivePortalStatus status) { |
43 switch (status) { | 48 switch (status) { |
44 case NetworkPortalDetector::CAPTIVE_PORTAL_STATUS_UNKNOWN: | 49 case NetworkPortalDetector::CAPTIVE_PORTAL_STATUS_UNKNOWN: |
45 return l10n_util::GetStringUTF8( | 50 return l10n_util::GetStringUTF8( |
46 IDS_CHROMEOS_CAPTIVE_PORTAL_STATUS_UNKNOWN); | 51 IDS_CHROMEOS_CAPTIVE_PORTAL_STATUS_UNKNOWN); |
47 case NetworkPortalDetector::CAPTIVE_PORTAL_STATUS_OFFLINE: | 52 case NetworkPortalDetector::CAPTIVE_PORTAL_STATUS_OFFLINE: |
48 return l10n_util::GetStringUTF8( | 53 return l10n_util::GetStringUTF8( |
49 IDS_CHROMEOS_CAPTIVE_PORTAL_STATUS_OFFLINE); | 54 IDS_CHROMEOS_CAPTIVE_PORTAL_STATUS_OFFLINE); |
50 case NetworkPortalDetector::CAPTIVE_PORTAL_STATUS_ONLINE: | 55 case NetworkPortalDetector::CAPTIVE_PORTAL_STATUS_ONLINE: |
(...skipping 15 matching lines...) Expand all Loading... | |
66 NetworkPortalDetector* g_network_portal_detector = NULL; | 71 NetworkPortalDetector* g_network_portal_detector = NULL; |
67 | 72 |
68 } // namespace | 73 } // namespace |
69 | 74 |
70 NetworkPortalDetector::NetworkPortalDetector( | 75 NetworkPortalDetector::NetworkPortalDetector( |
71 const scoped_refptr<net::URLRequestContextGetter>& request_context) | 76 const scoped_refptr<net::URLRequestContextGetter>& request_context) |
72 : active_connection_state_(STATE_UNKNOWN), | 77 : active_connection_state_(STATE_UNKNOWN), |
73 test_url_(CaptivePortalDetector::kDefaultURL), | 78 test_url_(CaptivePortalDetector::kDefaultURL), |
74 weak_ptr_factory_(this), | 79 weak_ptr_factory_(this), |
75 attempt_count_(0), | 80 attempt_count_(0), |
81 lazy_detection_enabled_(false), | |
82 lazy_check_interval_(base::TimeDelta::FromSeconds(kLazyCheckIntervalSec)), | |
76 min_time_between_attempts_( | 83 min_time_between_attempts_( |
77 base::TimeDelta::FromSeconds(kMinTimeBetweenAttemptsSec)), | 84 base::TimeDelta::FromSeconds(kMinTimeBetweenAttemptsSec)), |
78 request_timeout_(base::TimeDelta::FromSeconds(kRequestTimeoutSec)) { | 85 request_timeout_(base::TimeDelta::FromSeconds(kRequestTimeoutSec)) { |
79 captive_portal_detector_.reset(new CaptivePortalDetector(request_context)); | 86 captive_portal_detector_.reset(new CaptivePortalDetector(request_context)); |
80 | 87 |
81 registrar_.Add(this, | 88 registrar_.Add(this, |
82 chrome::NOTIFICATION_LOGIN_PROXY_CHANGED, | 89 chrome::NOTIFICATION_LOGIN_PROXY_CHANGED, |
83 content::NotificationService::AllSources()); | 90 content::NotificationService::AllSources()); |
84 registrar_.Add(this, | 91 registrar_.Add(this, |
85 chrome::NOTIFICATION_AUTH_SUPPLIED, | 92 chrome::NOTIFICATION_AUTH_SUPPLIED, |
(...skipping 77 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
163 active_service_path_ = active_network->service_path(); | 170 active_service_path_ = active_network->service_path(); |
164 cros->AddNetworkObserver(active_service_path_, this); | 171 cros->AddNetworkObserver(active_service_path_, this); |
165 } | 172 } |
166 | 173 |
167 bool connection_state_changed = | 174 bool connection_state_changed = |
168 (active_connection_state_ != active_network->connection_state()); | 175 (active_connection_state_ != active_network->connection_state()); |
169 active_connection_state_ = active_network->connection_state(); | 176 active_connection_state_ = active_network->connection_state(); |
170 | 177 |
171 if (network_changed || connection_state_changed) { | 178 if (network_changed || connection_state_changed) { |
172 attempt_count_ = 0; | 179 attempt_count_ = 0; |
173 if (IsPortalCheckPending()) { | 180 CancelPortalDetection(); |
174 detection_task_.Cancel(); | |
175 detection_timeout_.Cancel(); | |
176 } else if (IsCheckingForPortal()) { | |
177 captive_portal_detector_->Cancel(); | |
178 } | |
179 state_ = STATE_IDLE; | |
180 } | 181 } |
181 | 182 |
182 if (!IsCheckingForPortal() && !IsPortalCheckPending() && | 183 if (!IsCheckingForPortal() && !IsPortalCheckPending() && |
183 Network::IsConnectedState(active_connection_state_) && | 184 Network::IsConnectedState(active_connection_state_) && |
184 attempt_count_ < kMaxRequestAttempts) { | 185 (attempt_count_ < kMaxRequestAttempts || lazy_detection_enabled_)) { |
185 DCHECK(active_network); | 186 DCHECK(active_network); |
186 | 187 |
187 // Initiate Captive Portal detection if network's captive | 188 // Initiate Captive Portal detection if network's captive |
188 // portal state is unknown (e.g. for freshly created networks), | 189 // portal state is unknown (e.g. for freshly created networks), |
189 // offline or if network connection state was changed. | 190 // offline or if network connection state was changed. |
190 CaptivePortalState state = GetCaptivePortalState(active_network); | 191 CaptivePortalState state = GetCaptivePortalState(active_network); |
191 if (state.status == CAPTIVE_PORTAL_STATUS_UNKNOWN || | 192 if (state.status == CAPTIVE_PORTAL_STATUS_UNKNOWN || |
192 state.status == CAPTIVE_PORTAL_STATUS_OFFLINE || | 193 state.status == CAPTIVE_PORTAL_STATUS_OFFLINE || |
193 (!network_changed && connection_state_changed)) { | 194 (!network_changed && connection_state_changed)) { |
194 DetectCaptivePortal(base::TimeDelta()); | 195 DetectCaptivePortal(base::TimeDelta()); |
195 } | 196 } |
196 } | 197 } |
197 } | 198 } |
198 | 199 |
199 void NetworkPortalDetector::OnNetworkChanged(chromeos::NetworkLibrary* cros, | 200 void NetworkPortalDetector::OnNetworkChanged(chromeos::NetworkLibrary* cros, |
200 const chromeos::Network* network) { | 201 const chromeos::Network* network) { |
201 DCHECK(CalledOnValidThread()); | 202 DCHECK(CalledOnValidThread()); |
202 OnNetworkManagerChanged(cros); | 203 OnNetworkManagerChanged(cros); |
203 } | 204 } |
204 | 205 |
206 void NetworkPortalDetector::EnableLazyDetection() { | |
207 if (lazy_detection_enabled_) | |
208 return; | |
209 VLOG(1) << "Lazy detection mode enabled"; | |
210 lazy_detection_enabled_ = true; | |
211 if (!IsPortalCheckPending() && !IsCheckingForPortal()) | |
212 DetectCaptivePortal(base::TimeDelta()); | |
213 } | |
214 | |
215 void NetworkPortalDetector::DisableLazyDetection() { | |
216 if (!lazy_detection_enabled_) | |
217 return; | |
218 VLOG(1) << "Lazy detection mode disabled"; | |
219 if (attempt_count_ == kMaxRequestAttempts) | |
220 CancelPortalDetection(); | |
221 lazy_detection_enabled_ = false; | |
222 } | |
223 | |
205 // static | 224 // static |
206 NetworkPortalDetector* NetworkPortalDetector::CreateInstance() { | 225 NetworkPortalDetector* NetworkPortalDetector::CreateInstance() { |
207 DCHECK(!g_network_portal_detector); | 226 DCHECK(!g_network_portal_detector); |
208 g_network_portal_detector = new NetworkPortalDetector( | 227 g_network_portal_detector = new NetworkPortalDetector( |
209 g_browser_process->system_request_context()); | 228 g_browser_process->system_request_context()); |
210 return g_network_portal_detector; | 229 return g_network_portal_detector; |
211 } | 230 } |
212 | 231 |
213 // static | 232 // static |
214 NetworkPortalDetector* NetworkPortalDetector::GetInstance() { | 233 NetworkPortalDetector* NetworkPortalDetector::GetInstance() { |
215 if (!g_network_portal_detector) | 234 if (!g_network_portal_detector) |
216 return CreateInstance(); | 235 return CreateInstance(); |
217 return g_network_portal_detector; | 236 return g_network_portal_detector; |
218 } | 237 } |
219 | 238 |
220 // static | 239 // static |
221 bool NetworkPortalDetector::IsEnabled() { | 240 bool NetworkPortalDetector::IsEnabled() { |
222 return !CommandLine::ForCurrentProcess()->HasSwitch( | 241 return !CommandLine::ForCurrentProcess()->HasSwitch( |
223 switches::kDisableChromeCaptivePortalDetector); | 242 switches::kDisableChromeCaptivePortalDetector); |
224 } | 243 } |
225 | 244 |
226 void NetworkPortalDetector::DetectCaptivePortal(const base::TimeDelta& delay) { | 245 void NetworkPortalDetector::DetectCaptivePortal(const base::TimeDelta& delay) { |
227 DCHECK(!IsPortalCheckPending()); | 246 DCHECK(!IsPortalCheckPending()); |
228 DCHECK(!IsCheckingForPortal()); | 247 DCHECK(!IsCheckingForPortal()); |
229 DCHECK(attempt_count_ < kMaxRequestAttempts); | 248 DCHECK(attempt_count_ < kMaxRequestAttempts || lazy_detection_enabled_); |
230 | 249 |
231 detection_task_.Cancel(); | 250 detection_task_.Cancel(); |
232 detection_timeout_.Cancel(); | 251 detection_timeout_.Cancel(); |
233 state_ = STATE_PORTAL_CHECK_PENDING; | 252 state_ = STATE_PORTAL_CHECK_PENDING; |
234 | 253 |
235 next_attempt_delay_ = delay; | 254 next_attempt_delay_ = delay; |
236 if (attempt_count_ > 0) { | 255 if (attempt_count_ > 0) { |
237 base::TimeTicks now = GetCurrentTimeTicks(); | 256 base::TimeTicks now = GetCurrentTimeTicks(); |
238 base::TimeDelta elapsed_time; | 257 base::TimeDelta elapsed_time; |
258 | |
259 base::TimeDelta delay_between_attempts = min_time_between_attempts_; | |
260 if (attempt_count_ == kMaxRequestAttempts) { | |
261 DCHECK(lazy_detection_enabled_); | |
262 delay_between_attempts = lazy_check_interval_; | |
263 } | |
239 if (now > attempt_start_time_) | 264 if (now > attempt_start_time_) |
240 elapsed_time = now - attempt_start_time_; | 265 elapsed_time = now - attempt_start_time_; |
241 if (elapsed_time < min_time_between_attempts_ && | 266 if (elapsed_time < delay_between_attempts && |
242 min_time_between_attempts_ - elapsed_time > next_attempt_delay_) { | 267 delay_between_attempts - elapsed_time > next_attempt_delay_) { |
243 next_attempt_delay_ = min_time_between_attempts_ - elapsed_time; | 268 next_attempt_delay_ = delay_between_attempts - elapsed_time; |
244 } | 269 } |
245 } else { | 270 } else { |
246 detection_start_time_ = GetCurrentTimeTicks(); | 271 detection_start_time_ = GetCurrentTimeTicks(); |
247 } | 272 } |
248 detection_task_.Reset( | 273 detection_task_.Reset( |
249 base::Bind(&NetworkPortalDetector::DetectCaptivePortalTask, | 274 base::Bind(&NetworkPortalDetector::DetectCaptivePortalTask, |
250 weak_ptr_factory_.GetWeakPtr())); | 275 weak_ptr_factory_.GetWeakPtr())); |
251 MessageLoop::current()->PostDelayedTask(FROM_HERE, | 276 MessageLoop::current()->PostDelayedTask(FROM_HERE, |
252 detection_task_.callback(), | 277 detection_task_.callback(), |
253 next_attempt_delay_); | 278 next_attempt_delay_); |
254 } | 279 } |
255 | 280 |
256 void NetworkPortalDetector::DetectCaptivePortalTask() { | 281 void NetworkPortalDetector::DetectCaptivePortalTask() { |
257 DCHECK(IsPortalCheckPending()); | 282 DCHECK(IsPortalCheckPending()); |
258 | 283 |
259 state_ = STATE_CHECKING_FOR_PORTAL; | 284 state_ = STATE_CHECKING_FOR_PORTAL; |
260 | 285 |
261 ++attempt_count_; | |
262 attempt_start_time_ = GetCurrentTimeTicks(); | 286 attempt_start_time_ = GetCurrentTimeTicks(); |
263 | 287 |
264 VLOG(1) << "Portal detection started: network=" << active_network_id_ << ", " | 288 if (attempt_count_ < kMaxRequestAttempts) { |
265 << "attempt=" << attempt_count_ << " of " << kMaxRequestAttempts; | 289 ++attempt_count_; |
290 VLOG(1) << "Portal detection started: " | |
291 << "network=" << active_network_id_ << ", " | |
292 << "attempt=" << attempt_count_ << " of " << kMaxRequestAttempts; | |
293 } else { | |
294 DCHECK(lazy_detection_enabled_); | |
295 VLOG(1) << "Lazy portal detection attempt started"; | |
296 } | |
266 | 297 |
267 captive_portal_detector_->DetectCaptivePortal( | 298 captive_portal_detector_->DetectCaptivePortal( |
268 test_url_, | 299 test_url_, |
269 base::Bind(&NetworkPortalDetector::OnPortalDetectionCompleted, | 300 base::Bind(&NetworkPortalDetector::OnPortalDetectionCompleted, |
270 weak_ptr_factory_.GetWeakPtr())); | 301 weak_ptr_factory_.GetWeakPtr())); |
271 detection_timeout_.Reset( | 302 detection_timeout_.Reset( |
272 base::Bind(&NetworkPortalDetector::PortalDetectionTimeout, | 303 base::Bind(&NetworkPortalDetector::PortalDetectionTimeout, |
273 weak_ptr_factory_.GetWeakPtr())); | 304 weak_ptr_factory_.GetWeakPtr())); |
274 MessageLoop::current()->PostDelayedTask(FROM_HERE, | 305 MessageLoop::current()->PostDelayedTask(FROM_HERE, |
275 detection_timeout_.callback(), | 306 detection_timeout_.callback(), |
276 request_timeout_); | 307 request_timeout_); |
277 } | 308 } |
278 | 309 |
279 void NetworkPortalDetector::PortalDetectionTimeout() { | 310 void NetworkPortalDetector::PortalDetectionTimeout() { |
280 DCHECK(CalledOnValidThread()); | 311 DCHECK(CalledOnValidThread()); |
281 DCHECK(IsCheckingForPortal()); | 312 DCHECK(IsCheckingForPortal()); |
282 | 313 |
283 VLOG(1) << "Portal detection timeout: network=" << active_network_id_; | 314 VLOG(1) << "Portal detection timeout: network=" << active_network_id_; |
284 | 315 |
285 captive_portal_detector_->Cancel(); | 316 captive_portal_detector_->Cancel(); |
286 CaptivePortalDetector::Results results; | 317 CaptivePortalDetector::Results results; |
287 results.result = captive_portal::RESULT_NO_RESPONSE; | 318 results.result = captive_portal::RESULT_NO_RESPONSE; |
288 OnPortalDetectionCompleted(results); | 319 OnPortalDetectionCompleted(results); |
289 } | 320 } |
290 | 321 |
322 void NetworkPortalDetector::CancelPortalDetection() { | |
323 if (IsPortalCheckPending()) { | |
324 detection_task_.Cancel(); | |
Nikita (slow)
2013/02/13 15:12:20
nit: Alignment.
Nikita (slow)
2013/02/13 17:26:31
Done.
| |
325 detection_timeout_.Cancel(); | |
326 } else if (IsCheckingForPortal()) { | |
327 captive_portal_detector_->Cancel(); | |
328 } | |
329 state_ = STATE_IDLE; | |
330 } | |
331 | |
291 void NetworkPortalDetector::OnPortalDetectionCompleted( | 332 void NetworkPortalDetector::OnPortalDetectionCompleted( |
292 const CaptivePortalDetector::Results& results) { | 333 const CaptivePortalDetector::Results& results) { |
293 DCHECK(CalledOnValidThread()); | 334 DCHECK(CalledOnValidThread()); |
294 DCHECK(IsCheckingForPortal()); | 335 DCHECK(IsCheckingForPortal()); |
295 | 336 |
296 VLOG(1) << "Portal detection completed: " | 337 VLOG(1) << "Portal detection completed: " |
297 << "network=" << active_network_id_ << ", " | 338 << "network=" << active_network_id_ << ", " |
298 << "result=" << CaptivePortalDetector::CaptivePortalResultToString( | 339 << "result=" << CaptivePortalDetector::CaptivePortalResultToString( |
299 results.result) << ", " | 340 results.result) << ", " |
300 << "response_code=" << results.response_code; | 341 << "response_code=" << results.response_code; |
301 | 342 |
302 state_ = STATE_IDLE; | 343 state_ = STATE_IDLE; |
303 detection_timeout_.Cancel(); | 344 detection_timeout_.Cancel(); |
304 | 345 |
305 NetworkLibrary* cros = CrosLibrary::Get()->GetNetworkLibrary(); | 346 NetworkLibrary* cros = CrosLibrary::Get()->GetNetworkLibrary(); |
306 const Network* active_network = cros->active_network(); | 347 const Network* active_network = cros->active_network(); |
307 if (!active_network) | 348 if (!active_network) { |
349 TryLazyDetection(); | |
308 return; | 350 return; |
351 } | |
309 | 352 |
310 CaptivePortalState state; | 353 CaptivePortalState state; |
311 state.response_code = results.response_code; | 354 state.response_code = results.response_code; |
312 switch (results.result) { | 355 switch (results.result) { |
313 case captive_portal::RESULT_NO_RESPONSE: | 356 case captive_portal::RESULT_NO_RESPONSE: |
314 if (state.response_code == net::HTTP_PROXY_AUTHENTICATION_REQUIRED) { | 357 if (state.response_code == net::HTTP_PROXY_AUTHENTICATION_REQUIRED) { |
315 state.status = CAPTIVE_PORTAL_STATUS_PROXY_AUTH_REQUIRED; | 358 state.status = CAPTIVE_PORTAL_STATUS_PROXY_AUTH_REQUIRED; |
316 SetCaptivePortalState(active_network, state); | 359 SetCaptivePortalState(active_network, state); |
317 } else if (attempt_count_ >= kMaxRequestAttempts) { | 360 } else if (attempt_count_ >= kMaxRequestAttempts) { |
318 // Take into account shill's detection results. | 361 // Take into account shill's detection results. |
(...skipping 16 matching lines...) Expand all Loading... | |
335 state.status = CAPTIVE_PORTAL_STATUS_ONLINE; | 378 state.status = CAPTIVE_PORTAL_STATUS_ONLINE; |
336 SetCaptivePortalState(active_network, state); | 379 SetCaptivePortalState(active_network, state); |
337 break; | 380 break; |
338 case captive_portal::RESULT_BEHIND_CAPTIVE_PORTAL: | 381 case captive_portal::RESULT_BEHIND_CAPTIVE_PORTAL: |
339 state.status = CAPTIVE_PORTAL_STATUS_PORTAL; | 382 state.status = CAPTIVE_PORTAL_STATUS_PORTAL; |
340 SetCaptivePortalState(active_network, state); | 383 SetCaptivePortalState(active_network, state); |
341 break; | 384 break; |
342 default: | 385 default: |
343 break; | 386 break; |
344 } | 387 } |
388 | |
389 TryLazyDetection(); | |
345 } | 390 } |
391 | |
392 void NetworkPortalDetector::TryLazyDetection() { | |
393 if (!IsPortalCheckPending() && !IsCheckingForPortal() && | |
394 lazy_detection_enabled_) { | |
395 attempt_count_ = kMaxRequestAttempts; | |
396 DetectCaptivePortal(base::TimeDelta()); | |
397 } | |
398 } | |
399 | |
346 void NetworkPortalDetector::Observe( | 400 void NetworkPortalDetector::Observe( |
347 int type, | 401 int type, |
348 const content::NotificationSource& source, | 402 const content::NotificationSource& source, |
349 const content::NotificationDetails& details) { | 403 const content::NotificationDetails& details) { |
350 if (type == chrome::NOTIFICATION_LOGIN_PROXY_CHANGED || | 404 if (type == chrome::NOTIFICATION_LOGIN_PROXY_CHANGED || |
351 type == chrome::NOTIFICATION_AUTH_SUPPLIED || | 405 type == chrome::NOTIFICATION_AUTH_SUPPLIED || |
352 type == chrome::NOTIFICATION_AUTH_CANCELLED) { | 406 type == chrome::NOTIFICATION_AUTH_CANCELLED) { |
353 if (!IsCheckingForPortal() && !IsPortalCheckPending()) { | 407 if (!IsCheckingForPortal() && !IsPortalCheckPending()) { |
354 attempt_count_ = 0; | 408 attempt_count_ = 0; |
355 DetectCaptivePortal( | 409 DetectCaptivePortal( |
(...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
397 } | 451 } |
398 | 452 |
399 base::TimeTicks NetworkPortalDetector::GetCurrentTimeTicks() const { | 453 base::TimeTicks NetworkPortalDetector::GetCurrentTimeTicks() const { |
400 if (time_ticks_for_testing_.is_null()) | 454 if (time_ticks_for_testing_.is_null()) |
401 return base::TimeTicks::Now(); | 455 return base::TimeTicks::Now(); |
402 else | 456 else |
403 return time_ticks_for_testing_; | 457 return time_ticks_for_testing_; |
404 } | 458 } |
405 | 459 |
406 } // namespace chromeos | 460 } // namespace chromeos |
OLD | NEW |