| 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 |