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(); |
| 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 |