| 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 login_screen_strategy_(this), |
| 87 lazy_detection_enabled_(false), | 82 error_screen_strategy_(this), |
| 88 lazy_check_interval_(base::TimeDelta::FromSeconds(kLazyCheckIntervalSec)), | 83 strategy_(&login_screen_strategy_) { |
| 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)); |
| 93 | 85 |
| 94 registrar_.Add(this, | 86 registrar_.Add(this, |
| 95 chrome::NOTIFICATION_LOGIN_PROXY_CHANGED, | 87 chrome::NOTIFICATION_LOGIN_PROXY_CHANGED, |
| 96 content::NotificationService::AllSources()); | 88 content::NotificationService::AllSources()); |
| 97 registrar_.Add(this, | 89 registrar_.Add(this, |
| 98 chrome::NOTIFICATION_AUTH_SUPPLIED, | 90 chrome::NOTIFICATION_AUTH_SUPPLIED, |
| 99 content::NotificationService::AllSources()); | 91 content::NotificationService::AllSources()); |
| 100 registrar_.Add(this, | 92 registrar_.Add(this, |
| 101 chrome::NOTIFICATION_AUTH_CANCELLED, | 93 chrome::NOTIFICATION_AUTH_CANCELLED, |
| 102 content::NotificationService::AllSources()); | 94 content::NotificationService::AllSources()); |
| 103 | 95 |
| 104 NetworkHandler::Get()->network_state_handler()->AddObserver( | 96 NetworkHandler::Get()->network_state_handler()->AddObserver(this, FROM_HERE); |
| 105 this, FROM_HERE); | |
| 106 } | 97 } |
| 107 | 98 |
| 108 NetworkPortalDetectorImpl::~NetworkPortalDetectorImpl() { | 99 NetworkPortalDetectorImpl::~NetworkPortalDetectorImpl() { |
| 109 DCHECK(CalledOnValidThread()); | 100 DCHECK(CalledOnValidThread()); |
| 110 | 101 |
| 111 detection_task_.Cancel(); | 102 attempt_task_.Cancel(); |
| 112 detection_timeout_.Cancel(); | 103 attempt_timeout_.Cancel(); |
| 113 | 104 |
| 114 captive_portal_detector_->Cancel(); | 105 captive_portal_detector_->Cancel(); |
| 115 captive_portal_detector_.reset(); | 106 captive_portal_detector_.reset(); |
| 116 observers_.Clear(); | 107 observers_.Clear(); |
| 117 if (NetworkHandler::IsInitialized()) { | 108 if (NetworkHandler::IsInitialized()) { |
| 118 NetworkHandler::Get()->network_state_handler()->RemoveObserver( | 109 NetworkHandler::Get()->network_state_handler()->RemoveObserver(this, |
| 119 this, FROM_HERE); | 110 FROM_HERE); |
| 120 } | 111 } |
| 121 } | 112 } |
| 122 | 113 |
| 123 void NetworkPortalDetectorImpl::AddObserver(Observer* observer) { | 114 void NetworkPortalDetectorImpl::AddObserver(Observer* observer) { |
| 124 DCHECK(CalledOnValidThread()); | 115 DCHECK(CalledOnValidThread()); |
| 125 if (!observer || observers_.HasObserver(observer)) | 116 if (observer && !observers_.HasObserver(observer)) |
| 126 return; | 117 observers_.AddObserver(observer); |
| 127 observers_.AddObserver(observer); | |
| 128 } | 118 } |
| 129 | 119 |
| 130 void NetworkPortalDetectorImpl::AddAndFireObserver(Observer* observer) { | 120 void NetworkPortalDetectorImpl::AddAndFireObserver(Observer* observer) { |
| 131 DCHECK(CalledOnValidThread()); | 121 DCHECK(CalledOnValidThread()); |
| 132 if (!observer) | 122 if (!observer) |
| 133 return; | 123 return; |
| 134 AddObserver(observer); | 124 AddObserver(observer); |
| 135 CaptivePortalState portal_state; | 125 CaptivePortalState portal_state; |
| 136 const NetworkState* network = | 126 const NetworkState* network = DefaultNetwork(); |
| 137 NetworkHandler::Get()->network_state_handler()->DefaultNetwork(); | |
| 138 if (network) | 127 if (network) |
| 139 portal_state = GetCaptivePortalState(network->path()); | 128 portal_state = GetCaptivePortalState(network->path()); |
| 140 observer->OnPortalDetectionCompleted(network, portal_state); | 129 observer->OnPortalDetectionCompleted(network, portal_state); |
| 141 } | 130 } |
| 142 | 131 |
| 143 void NetworkPortalDetectorImpl::RemoveObserver(Observer* observer) { | 132 void NetworkPortalDetectorImpl::RemoveObserver(Observer* observer) { |
| 144 DCHECK(CalledOnValidThread()); | 133 DCHECK(CalledOnValidThread()); |
| 145 if (observer) | 134 if (observer) |
| 146 observers_.RemoveObserver(observer); | 135 observers_.RemoveObserver(observer); |
| 147 } | 136 } |
| 148 | 137 |
| 149 bool NetworkPortalDetectorImpl::IsEnabled() { | 138 bool NetworkPortalDetectorImpl::IsEnabled() { return enabled_; } |
| 150 return enabled_; | |
| 151 } | |
| 152 | 139 |
| 153 void NetworkPortalDetectorImpl::Enable(bool start_detection) { | 140 void NetworkPortalDetectorImpl::Enable(bool start_detection) { |
| 154 DCHECK(CalledOnValidThread()); | 141 DCHECK(CalledOnValidThread()); |
| 155 if (enabled_) | 142 if (enabled_) |
| 156 return; | 143 return; |
| 144 |
| 145 DCHECK(is_idle()); |
| 157 enabled_ = true; | 146 enabled_ = true; |
| 158 DCHECK(!IsPortalCheckPending()); | 147 |
| 159 DCHECK(!IsCheckingForPortal()); | 148 const NetworkState* network = DefaultNetwork(); |
| 160 DCHECK(!lazy_detection_enabled()); | 149 if (!start_detection || !network) |
| 161 if (!start_detection) | |
| 162 return; | 150 return; |
| 163 state_ = STATE_IDLE; | 151 portal_state_map_.erase(network->path()); |
| 164 attempt_count_ = 0; | 152 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 } | 153 } |
| 173 | 154 |
| 174 NetworkPortalDetectorImpl::CaptivePortalState | 155 NetworkPortalDetectorImpl::CaptivePortalState |
| 175 NetworkPortalDetectorImpl::GetCaptivePortalState( | 156 NetworkPortalDetectorImpl::GetCaptivePortalState( |
| 176 const std::string& service_path) { | 157 const std::string& service_path) { |
| 177 DCHECK(CalledOnValidThread()); | 158 DCHECK(CalledOnValidThread()); |
| 178 CaptivePortalStateMap::const_iterator it = | 159 CaptivePortalStateMap::const_iterator it = |
| 179 portal_state_map_.find(service_path); | 160 portal_state_map_.find(service_path); |
| 180 if (it == portal_state_map_.end()) | 161 if (it == portal_state_map_.end()) |
| 181 return CaptivePortalState(); | 162 return CaptivePortalState(); |
| 182 return it->second; | 163 return it->second; |
| 183 } | 164 } |
| 184 | 165 |
| 185 bool NetworkPortalDetectorImpl::StartDetectionIfIdle() { | 166 bool NetworkPortalDetectorImpl::StartDetectionIfIdle() { |
| 186 if (IsPortalCheckPending() || IsCheckingForPortal()) | 167 if (!is_idle()) |
| 187 return false; | 168 return false; |
| 188 if (!CanPerformDetection()) | 169 StartDetection(); |
| 189 attempt_count_ = 0; | |
| 190 DCHECK(CanPerformDetection()); | |
| 191 DetectCaptivePortal(base::TimeDelta()); | |
| 192 return true; | 170 return true; |
| 193 } | 171 } |
| 194 | 172 |
| 195 void NetworkPortalDetectorImpl::EnableLazyDetection() { | 173 void NetworkPortalDetectorImpl::EnableErrorScreenStrategy() { |
| 196 if (lazy_detection_enabled()) | 174 if (strategy_ == &error_screen_strategy_) |
| 197 return; | 175 return; |
| 198 lazy_detection_enabled_ = true; | 176 VLOG(1) << "Error screen detection strategy enabled."; |
| 199 VLOG(1) << "Lazy detection mode enabled."; | 177 strategy_ = &error_screen_strategy_; |
| 178 strategy_->Reset(); |
| 200 StartDetectionIfIdle(); | 179 StartDetectionIfIdle(); |
| 201 } | 180 } |
| 202 | 181 |
| 203 void NetworkPortalDetectorImpl::DisableLazyDetection() { | 182 void NetworkPortalDetectorImpl::DisableErrorScreenStrategy() { |
| 204 if (!lazy_detection_enabled()) | 183 if (strategy_ != &error_screen_strategy_) |
| 205 return; | 184 return; |
| 206 lazy_detection_enabled_ = false; | 185 VLOG(1) << "Error screen detection strategy disabled."; |
| 207 if (attempt_count_ == kMaxRequestAttempts && IsPortalCheckPending()) | 186 strategy_ = &login_screen_strategy_; |
| 208 CancelPortalDetection(); | 187 strategy_->Reset(); |
| 209 VLOG(1) << "Lazy detection mode disabled."; | 188 CancelDetection(); |
| 210 } | 189 } |
| 211 | 190 |
| 212 void NetworkPortalDetectorImpl::DefaultNetworkChanged( | 191 void NetworkPortalDetectorImpl::DefaultNetworkChanged( |
| 213 const NetworkState* default_network) { | 192 const NetworkState* default_network) { |
| 214 DCHECK(CalledOnValidThread()); | 193 DCHECK(CalledOnValidThread()); |
| 215 | 194 |
| 216 if (!default_network) { | 195 if (!default_network) { |
| 217 default_network_name_.clear(); | 196 default_network_name_.clear(); |
| 218 default_network_id_.clear(); | 197 default_network_id_.clear(); |
| 219 | 198 |
| 220 CancelPortalDetection(); | 199 CancelDetection(); |
| 221 | 200 |
| 222 CaptivePortalState state; | 201 CaptivePortalState state; |
| 223 state.status = CAPTIVE_PORTAL_STATUS_OFFLINE; | 202 state.status = CAPTIVE_PORTAL_STATUS_OFFLINE; |
| 224 SetCaptivePortalState(NULL, state); | 203 OnDetectionCompleted(NULL, state); |
| 225 return; | 204 return; |
| 226 } | 205 } |
| 227 | 206 |
| 228 default_network_name_ = default_network->name(); | 207 default_network_name_ = default_network->name(); |
| 229 default_network_id_ = default_network->guid(); | 208 default_network_id_ = default_network->guid(); |
| 230 | 209 |
| 231 bool network_changed = (default_service_path_ != default_network->path()); | 210 bool network_changed = (default_service_path_ != default_network->path()); |
| 232 default_service_path_ = default_network->path(); | 211 default_service_path_ = default_network->path(); |
| 233 | 212 |
| 234 bool connection_state_changed = (default_connection_state_ != | 213 bool connection_state_changed = |
| 235 default_network->connection_state()); | 214 (default_connection_state_ != default_network->connection_state()); |
| 236 default_connection_state_ = default_network->connection_state(); | 215 default_connection_state_ = default_network->connection_state(); |
| 237 | 216 |
| 238 if (network_changed || connection_state_changed) { | 217 if (network_changed || connection_state_changed) |
| 239 attempt_count_ = 0; | 218 CancelDetection(); |
| 240 CancelPortalDetection(); | |
| 241 } | |
| 242 | 219 |
| 243 if (CanPerformDetection() && | 220 if (CanPerformAttempt() && |
| 244 NetworkState::StateIsConnected(default_connection_state_)) { | 221 NetworkState::StateIsConnected(default_connection_state_)) { |
| 245 // Initiate Captive Portal detection if network's captive | 222 // Initiate Captive Portal detection if network's captive |
| 246 // portal state is unknown (e.g. for freshly created networks), | 223 // portal state is unknown (e.g. for freshly created networks), |
| 247 // offline or if network connection state was changed. | 224 // offline or if network connection state was changed. |
| 248 CaptivePortalState state = GetCaptivePortalState(default_network->path()); | 225 CaptivePortalState state = GetCaptivePortalState(default_network->path()); |
| 249 if (state.status == CAPTIVE_PORTAL_STATUS_UNKNOWN || | 226 if (state.status == CAPTIVE_PORTAL_STATUS_UNKNOWN || |
| 250 state.status == CAPTIVE_PORTAL_STATUS_OFFLINE || | 227 state.status == CAPTIVE_PORTAL_STATUS_OFFLINE || |
| 251 (!network_changed && connection_state_changed)) { | 228 (!network_changed && connection_state_changed)) { |
| 252 DetectCaptivePortal(base::TimeDelta()); | 229 ScheduleAttempt(base::TimeDelta()); |
| 253 } | 230 } |
| 254 } | 231 } |
| 255 } | 232 } |
| 256 | 233 |
| 234 base::TimeTicks NetworkPortalDetectorImpl::GetCurrentTimeTicks() { |
| 235 if (time_ticks_for_testing_.is_null()) |
| 236 return base::TimeTicks::Now(); |
| 237 return time_ticks_for_testing_; |
| 238 } |
| 239 |
| 257 //////////////////////////////////////////////////////////////////////////////// | 240 //////////////////////////////////////////////////////////////////////////////// |
| 258 // NetworkPortalDetectorImpl, private: | 241 // NetworkPortalDetectorImpl, private: |
| 259 | 242 |
| 260 bool NetworkPortalDetectorImpl::CanPerformDetection() const { | 243 void NetworkPortalDetectorImpl::StartDetection() { |
| 261 if (IsPortalCheckPending() || IsCheckingForPortal()) | 244 strategy_->Reset(); |
| 262 return false; | 245 DCHECK(CanPerformAttempt()); |
| 263 return attempt_count_ < kMaxRequestAttempts || lazy_detection_enabled(); | 246 detection_start_time_ = GetCurrentTimeTicks(); |
| 247 ScheduleAttempt(base::TimeDelta()); |
| 264 } | 248 } |
| 265 | 249 |
| 266 void NetworkPortalDetectorImpl::DetectCaptivePortal( | 250 void NetworkPortalDetectorImpl::CancelDetection() { |
| 267 const base::TimeDelta& delay) { | 251 attempt_task_.Cancel(); |
| 268 DCHECK(CanPerformDetection()); | 252 attempt_timeout_.Cancel(); |
| 253 captive_portal_detector_->Cancel(); |
| 254 state_ = STATE_IDLE; |
| 255 strategy_->Reset(); |
| 256 } |
| 257 |
| 258 bool NetworkPortalDetectorImpl::CanPerformAttempt() const { |
| 259 return is_idle() && strategy_->CanPerformAttempt(); |
| 260 } |
| 261 |
| 262 void NetworkPortalDetectorImpl::ScheduleAttempt(const base::TimeDelta& delay) { |
| 263 DCHECK(CanPerformAttempt()); |
| 269 | 264 |
| 270 if (!IsEnabled()) | 265 if (!IsEnabled()) |
| 271 return; | 266 return; |
| 272 | 267 |
| 273 detection_task_.Cancel(); | 268 attempt_task_.Cancel(); |
| 274 detection_timeout_.Cancel(); | 269 attempt_timeout_.Cancel(); |
| 275 state_ = STATE_PORTAL_CHECK_PENDING; | 270 state_ = STATE_PORTAL_CHECK_PENDING; |
| 276 | 271 |
| 277 next_attempt_delay_ = delay; | 272 next_attempt_delay_ = |
| 278 if (attempt_count_ > 0) { | 273 std::max(delay, strategy_->GetDelayBeforeCurrentAttempt()); |
| 279 base::TimeTicks now = GetCurrentTimeTicks(); | 274 attempt_task_.Reset(base::Bind(&NetworkPortalDetectorImpl::StartAttempt, |
| 280 base::TimeDelta elapsed_time; | 275 weak_factory_.GetWeakPtr())); |
| 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( | 276 base::MessageLoop::current()->PostDelayedTask( |
| 300 FROM_HERE, detection_task_.callback(), next_attempt_delay_); | 277 FROM_HERE, attempt_task_.callback(), next_attempt_delay_); |
| 301 } | 278 } |
| 302 | 279 |
| 303 void NetworkPortalDetectorImpl::DetectCaptivePortalTask() { | 280 void NetworkPortalDetectorImpl::StartAttempt() { |
| 304 DCHECK(IsPortalCheckPending()); | 281 DCHECK(is_portal_check_pending()); |
| 305 | 282 |
| 306 state_ = STATE_CHECKING_FOR_PORTAL; | 283 state_ = STATE_CHECKING_FOR_PORTAL; |
| 307 attempt_start_time_ = GetCurrentTimeTicks(); | |
| 308 | |
| 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 | 284 |
| 320 captive_portal_detector_->DetectCaptivePortal( | 285 captive_portal_detector_->DetectCaptivePortal( |
| 321 test_url_, | 286 test_url_, |
| 322 base::Bind(&NetworkPortalDetectorImpl::OnPortalDetectionCompleted, | 287 base::Bind(&NetworkPortalDetectorImpl::OnAttemptCompleted, |
| 323 weak_ptr_factory_.GetWeakPtr())); | 288 weak_factory_.GetWeakPtr())); |
| 324 detection_timeout_.Reset( | 289 attempt_timeout_.Reset( |
| 325 base::Bind(&NetworkPortalDetectorImpl::PortalDetectionTimeout, | 290 base::Bind(&NetworkPortalDetectorImpl::OnAttemptTimeout, |
| 326 weak_ptr_factory_.GetWeakPtr())); | 291 weak_factory_.GetWeakPtr())); |
| 327 base::TimeDelta request_timeout; | |
| 328 | 292 |
| 329 // For easier unit testing check for testing state is performed here | 293 strategy_->OnAttemptStarted(); |
| 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( | 294 base::MessageLoop::current()->PostDelayedTask( |
| 336 FROM_HERE, detection_timeout_.callback(), request_timeout); | 295 FROM_HERE, |
| 296 attempt_timeout_.callback(), |
| 297 strategy_->GetCurrentAttemptTimeout()); |
| 337 } | 298 } |
| 338 | 299 |
| 339 void NetworkPortalDetectorImpl::PortalDetectionTimeout() { | 300 void NetworkPortalDetectorImpl::OnAttemptTimeout() { |
| 340 DCHECK(CalledOnValidThread()); | 301 DCHECK(CalledOnValidThread()); |
| 341 DCHECK(IsCheckingForPortal()); | 302 DCHECK(is_checking_for_portal()); |
| 342 | 303 |
| 343 VLOG(1) << "Portal detection timeout: name=" << default_network_name_ << ", " | 304 VLOG(1) << "Portal detection timeout: name=" << default_network_name_ << ", " |
| 344 << "id=" << default_network_id_; | 305 << "id=" << default_network_id_; |
| 345 | 306 |
| 346 captive_portal_detector_->Cancel(); | 307 captive_portal_detector_->Cancel(); |
| 347 CaptivePortalDetector::Results results; | 308 CaptivePortalDetector::Results results; |
| 348 results.result = captive_portal::RESULT_NO_RESPONSE; | 309 results.result = captive_portal::RESULT_NO_RESPONSE; |
| 349 OnPortalDetectionCompleted(results); | 310 OnAttemptCompleted(results); |
| 350 } | 311 } |
| 351 | 312 |
| 352 void NetworkPortalDetectorImpl::CancelPortalDetection() { | 313 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) { | 314 const CaptivePortalDetector::Results& results) { |
| 363 captive_portal::Result result = results.result; | 315 captive_portal::Result result = results.result; |
| 364 int response_code = results.response_code; | 316 int response_code = results.response_code; |
| 365 | 317 |
| 366 DCHECK(CalledOnValidThread()); | 318 DCHECK(CalledOnValidThread()); |
| 367 DCHECK(IsCheckingForPortal()); | 319 DCHECK(is_checking_for_portal()); |
| 368 | 320 |
| 369 VLOG(1) << "Portal detection completed: " | 321 VLOG(1) << "Detection attempt completed: " |
| 370 << "name=" << default_network_name_ << ", " | 322 << "name=" << default_network_name_ << ", " |
| 371 << "id=" << default_network_id_ << ", " | 323 << "id=" << default_network_id_ << ", " |
| 372 << "result=" | 324 << "result=" |
| 373 << CaptivePortalDetector::CaptivePortalResultToString(results.result) | 325 << CaptivePortalDetector::CaptivePortalResultToString(results.result) |
| 374 << ", " | 326 << ", " |
| 375 << "response_code=" << results.response_code; | 327 << "response_code=" << results.response_code; |
| 376 | 328 |
| 377 state_ = STATE_IDLE; | 329 state_ = STATE_IDLE; |
| 378 detection_timeout_.Cancel(); | 330 attempt_timeout_.Cancel(); |
| 379 | 331 |
| 380 const NetworkState* default_network = | 332 const NetworkState* network = DefaultNetwork(); |
| 381 NetworkHandler::Get()->network_state_handler()->DefaultNetwork(); | |
| 382 | 333 |
| 383 // If using a fake profile client, also fake being behind a captive portal | 334 // If using a fake profile client, also fake being behind a captive portal |
| 384 // if the default network is in portal state. | 335 // if the default network is in portal state. |
| 385 if (result != captive_portal::RESULT_NO_RESPONSE && | 336 if (result != captive_portal::RESULT_NO_RESPONSE && |
| 386 DBusThreadManager::Get()->GetShillProfileClient()->GetTestInterface() && | 337 DBusThreadManager::Get()->GetShillProfileClient()->GetTestInterface() && |
| 387 default_network && | 338 network && network->connection_state() == shill::kStatePortal) { |
| 388 default_network->connection_state() == shill::kStatePortal) { | |
| 389 result = captive_portal::RESULT_BEHIND_CAPTIVE_PORTAL; | 339 result = captive_portal::RESULT_BEHIND_CAPTIVE_PORTAL; |
| 390 response_code = 200; | 340 response_code = 200; |
| 391 } | 341 } |
| 392 | 342 |
| 393 CaptivePortalState state; | 343 CaptivePortalState state; |
| 394 state.response_code = response_code; | 344 state.response_code = response_code; |
| 395 switch (result) { | 345 switch (result) { |
| 396 case captive_portal::RESULT_NO_RESPONSE: | 346 case captive_portal::RESULT_NO_RESPONSE: |
| 397 if (state.response_code == net::HTTP_PROXY_AUTHENTICATION_REQUIRED) { | 347 if (state.response_code == net::HTTP_PROXY_AUTHENTICATION_REQUIRED) { |
| 398 state.status = CAPTIVE_PORTAL_STATUS_PROXY_AUTH_REQUIRED; | 348 state.status = CAPTIVE_PORTAL_STATUS_PROXY_AUTH_REQUIRED; |
| 399 SetCaptivePortalState(default_network, state); | 349 } else if (CanPerformAttempt()) { |
| 400 } else if (attempt_count_ >= kMaxRequestAttempts) { | 350 ScheduleAttempt(results.retry_after_delta); |
| 401 if (default_network && | 351 return; |
| 402 (default_network->connection_state() == shill::kStatePortal)) { | 352 } else if (network && |
| 403 // Take into account shill's detection results. | 353 (network->connection_state() == shill::kStatePortal)) { |
| 404 state.status = CAPTIVE_PORTAL_STATUS_PORTAL; | 354 // Take into account shill's detection results. |
| 405 LOG(WARNING) << "Network name=" << default_network->name() << ", " | 355 state.status = CAPTIVE_PORTAL_STATUS_PORTAL; |
| 406 << "id=" << default_network->guid() << " " | 356 LOG(WARNING) << "Network name=" << network->name() << ", " |
| 407 << "is marked as " | 357 << "id=" << network->guid() << " " |
| 408 << CaptivePortalStatusString(state.status) << " " | 358 << "is marked as " |
| 409 << "despite the fact that CaptivePortalDetector " | 359 << CaptivePortalStatusString(state.status) << " " |
| 410 << "received no response"; | 360 << "despite the fact that CaptivePortalDetector " |
| 411 } else { | 361 << "received no response"; |
| 412 state.status = CAPTIVE_PORTAL_STATUS_OFFLINE; | |
| 413 } | |
| 414 SetCaptivePortalState(default_network, state); | |
| 415 } else { | 362 } else { |
| 416 DCHECK(CanPerformDetection()); | 363 state.status = CAPTIVE_PORTAL_STATUS_OFFLINE; |
| 417 DetectCaptivePortal(results.retry_after_delta); | |
| 418 } | 364 } |
| 419 break; | 365 break; |
| 420 case captive_portal::RESULT_INTERNET_CONNECTED: | 366 case captive_portal::RESULT_INTERNET_CONNECTED: |
| 421 state.status = CAPTIVE_PORTAL_STATUS_ONLINE; | 367 state.status = CAPTIVE_PORTAL_STATUS_ONLINE; |
| 422 SetCaptivePortalState(default_network, state); | |
| 423 break; | 368 break; |
| 424 case captive_portal::RESULT_BEHIND_CAPTIVE_PORTAL: | 369 case captive_portal::RESULT_BEHIND_CAPTIVE_PORTAL: |
| 425 state.status = CAPTIVE_PORTAL_STATUS_PORTAL; | 370 state.status = CAPTIVE_PORTAL_STATUS_PORTAL; |
| 426 SetCaptivePortalState(default_network, state); | |
| 427 break; | 371 break; |
| 428 default: | 372 default: |
| 429 break; | 373 break; |
| 430 } | 374 } |
| 431 | 375 |
| 432 TryLazyDetection(); | 376 OnDetectionCompleted(network, state); |
| 433 } | 377 if (CanPerformAttempt()) |
| 434 | 378 ScheduleAttempt(base::TimeDelta()); |
| 435 void NetworkPortalDetectorImpl::TryLazyDetection() { | |
| 436 if (lazy_detection_enabled() && CanPerformDetection()) | |
| 437 DetectCaptivePortal(base::TimeDelta()); | |
| 438 } | 379 } |
| 439 | 380 |
| 440 void NetworkPortalDetectorImpl::Observe( | 381 void NetworkPortalDetectorImpl::Observe( |
| 441 int type, | 382 int type, |
| 442 const content::NotificationSource& source, | 383 const content::NotificationSource& source, |
| 443 const content::NotificationDetails& details) { | 384 const content::NotificationDetails& details) { |
| 444 if (type == chrome::NOTIFICATION_LOGIN_PROXY_CHANGED || | 385 if (type == chrome::NOTIFICATION_LOGIN_PROXY_CHANGED || |
| 445 type == chrome::NOTIFICATION_AUTH_SUPPLIED || | 386 type == chrome::NOTIFICATION_AUTH_SUPPLIED || |
| 446 type == chrome::NOTIFICATION_AUTH_CANCELLED) { | 387 type == chrome::NOTIFICATION_AUTH_CANCELLED) { |
| 447 VLOG(1) << "Restarting portal detection due to proxy change."; | 388 VLOG(1) << "Restarting portal detection due to proxy change."; |
| 448 attempt_count_ = 0; | 389 strategy_->Reset(); |
| 449 if (IsPortalCheckPending()) | 390 if (is_portal_check_pending()) |
| 450 return; | 391 return; |
| 451 CancelPortalDetection(); | 392 CancelDetection(); |
| 452 DCHECK(CanPerformDetection()); | 393 ScheduleAttempt(base::TimeDelta::FromSeconds(kProxyChangeDelaySec)); |
| 453 DetectCaptivePortal(base::TimeDelta::FromSeconds(kProxyChangeDelaySec)); | |
| 454 } | 394 } |
| 455 } | 395 } |
| 456 | 396 |
| 457 bool NetworkPortalDetectorImpl::IsPortalCheckPending() const { | 397 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, | 398 const NetworkState* network, |
| 467 const CaptivePortalState& state) { | 399 const CaptivePortalState& state) { |
| 400 strategy_->OnDetectionCompleted(); |
| 401 |
| 468 if (!network) { | 402 if (!network) { |
| 469 NotifyPortalDetectionCompleted(network, state); | 403 NotifyDetectionCompleted(network, state); |
| 470 return; | 404 return; |
| 471 } | 405 } |
| 472 | 406 |
| 473 CaptivePortalStateMap::const_iterator it = | 407 CaptivePortalStateMap::const_iterator it = |
| 474 portal_state_map_.find(network->path()); | 408 portal_state_map_.find(network->path()); |
| 475 if (it == portal_state_map_.end() || | 409 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) { | 410 it->second.response_code != state.response_code) { |
| 478 VLOG(1) << "Updating Chrome Captive Portal state: " | 411 VLOG(1) << "Updating Chrome Captive Portal state: " |
| 479 << "name=" << network->name() << ", " | 412 << "name=" << network->name() << ", " |
| 480 << "id=" << network->guid() << ", " | 413 << "id=" << network->guid() << ", " |
| 481 << "status=" << CaptivePortalStatusString(state.status) << ", " | 414 << "status=" << CaptivePortalStatusString(state.status) << ", " |
| 482 << "response_code=" << state.response_code; | 415 << "response_code=" << state.response_code; |
| 483 | 416 |
| 484 // Record detection duration iff detection result differs from the | 417 // Record detection duration iff detection result differs from the |
| 485 // previous one for this network. The reason is to record all stats | 418 // previous one for this network. The reason is to record all stats |
| 486 // only when network changes it's state. | 419 // only when network changes it's state. |
| 487 RecordDetectionStats(network, state.status); | 420 RecordDetectionStats(network, state.status); |
| 488 | 421 |
| 489 portal_state_map_[network->path()] = state; | 422 portal_state_map_[network->path()] = state; |
| 490 } | 423 } |
| 491 NotifyPortalDetectionCompleted(network, state); | 424 NotifyDetectionCompleted(network, state); |
| 492 } | 425 } |
| 493 | 426 |
| 494 void NetworkPortalDetectorImpl::NotifyPortalDetectionCompleted( | 427 void NetworkPortalDetectorImpl::NotifyDetectionCompleted( |
| 495 const NetworkState* network, | 428 const NetworkState* network, |
| 496 const CaptivePortalState& state) { | 429 const CaptivePortalState& state) { |
| 497 FOR_EACH_OBSERVER(Observer, observers_, | 430 FOR_EACH_OBSERVER( |
| 498 OnPortalDetectionCompleted(network, state)); | 431 Observer, observers_, OnPortalDetectionCompleted(network, state)); |
| 499 notification_controller_.OnPortalDetectionCompleted(network, state); | 432 notification_controller_.OnPortalDetectionCompleted(network, state); |
| 500 } | 433 } |
| 501 | 434 |
| 502 base::TimeTicks NetworkPortalDetectorImpl::GetCurrentTimeTicks() const { | 435 bool NetworkPortalDetectorImpl::AttemptTimeoutIsCancelledForTesting() const { |
| 503 if (time_ticks_for_testing_.is_null()) | 436 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 } | 437 } |
| 522 | 438 |
| 523 void NetworkPortalDetectorImpl::RecordDetectionStats( | 439 void NetworkPortalDetectorImpl::RecordDetectionStats( |
| 524 const NetworkState* network, | 440 const NetworkState* network, |
| 525 CaptivePortalStatus status) { | 441 CaptivePortalStatus status) { |
| 526 // Don't record stats for offline state. | 442 // Don't record stats for offline state. |
| 527 if (!network) | 443 if (!network) |
| 528 return; | 444 return; |
| 529 | 445 |
| 530 if (!detection_start_time_.is_null()) { | 446 if (!detection_start_time_.is_null()) { |
| (...skipping 25 matching lines...) Expand all Loading... |
| 556 if (network->connection_state() != shill::kStateOnline) | 472 if (network->connection_state() != shill::kStateOnline) |
| 557 RecordDiscrepancyWithShill(network, status); | 473 RecordDiscrepancyWithShill(network, status); |
| 558 break; | 474 break; |
| 559 case NetworkPortalDetector::CAPTIVE_PORTAL_STATUS_COUNT: | 475 case NetworkPortalDetector::CAPTIVE_PORTAL_STATUS_COUNT: |
| 560 NOTREACHED(); | 476 NOTREACHED(); |
| 561 break; | 477 break; |
| 562 } | 478 } |
| 563 } | 479 } |
| 564 | 480 |
| 565 } // namespace chromeos | 481 } // namespace chromeos |
| OLD | NEW |