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 "chrome/browser/browser_process.h" | 11 #include "chrome/browser/browser_process.h" |
11 #include "chrome/browser/chromeos/cros/cros_library.h" | 12 #include "chrome/browser/chromeos/cros/cros_library.h" |
12 #include "chrome/common/chrome_switches.h" | 13 #include "chrome/common/chrome_switches.h" |
13 #include "content/public/browser/browser_thread.h" | 14 #include "content/public/browser/browser_thread.h" |
14 #include "grit/generated_resources.h" | 15 #include "grit/generated_resources.h" |
15 #include "ui/base/l10n/l10n_util.h" | 16 #include "ui/base/l10n/l10n_util.h" |
16 | 17 |
17 using captive_portal::CaptivePortalDetector; | 18 using captive_portal::CaptivePortalDetector; |
18 | 19 |
19 namespace chromeos { | 20 namespace chromeos { |
20 | 21 |
21 namespace { | 22 namespace { |
22 | 23 |
24 const int kMaxRequestAttempts = 3; | |
Nikita (slow)
2012/11/20 12:58:45
nit: Please add comments for these contants
ygorshenin1
2012/11/21 09:08:06
Done.
| |
25 const int kMinTimeBetweenAttemptsSec = 3; | |
26 const int kRequestTimeoutSec = 10; | |
27 | |
23 std::string CaptivePortalStateString( | 28 std::string CaptivePortalStateString( |
24 NetworkPortalDetector::CaptivePortalState state) { | 29 NetworkPortalDetector::CaptivePortalState state) { |
25 switch (state) { | 30 switch (state) { |
26 case NetworkPortalDetector::CAPTIVE_PORTAL_STATE_UNKNOWN: | 31 case NetworkPortalDetector::CAPTIVE_PORTAL_STATE_UNKNOWN: |
27 return l10n_util::GetStringUTF8( | 32 return l10n_util::GetStringUTF8( |
28 IDS_CHROMEOS_CAPTIVE_PORTAL_STATE_UNKNOWN); | 33 IDS_CHROMEOS_CAPTIVE_PORTAL_STATE_UNKNOWN); |
29 case NetworkPortalDetector::CAPTIVE_PORTAL_STATE_OFFLINE: | 34 case NetworkPortalDetector::CAPTIVE_PORTAL_STATE_OFFLINE: |
30 return l10n_util::GetStringUTF8( | 35 return l10n_util::GetStringUTF8( |
31 IDS_CHROMEOS_CAPTIVE_PORTAL_STATE_OFFLINE); | 36 IDS_CHROMEOS_CAPTIVE_PORTAL_STATE_OFFLINE); |
32 case NetworkPortalDetector::CAPTIVE_PORTAL_STATE_ONLINE: | 37 case NetworkPortalDetector::CAPTIVE_PORTAL_STATE_ONLINE: |
33 return l10n_util::GetStringUTF8(IDS_CHROMEOS_CAPTIVE_PORTAL_STATE_ONLINE); | 38 return l10n_util::GetStringUTF8(IDS_CHROMEOS_CAPTIVE_PORTAL_STATE_ONLINE); |
34 case NetworkPortalDetector::CAPTIVE_PORTAL_STATE_PORTAL: | 39 case NetworkPortalDetector::CAPTIVE_PORTAL_STATE_PORTAL: |
35 return l10n_util::GetStringUTF8(IDS_CHROMEOS_CAPTIVE_PORTAL_STATE_PORTAL); | 40 return l10n_util::GetStringUTF8(IDS_CHROMEOS_CAPTIVE_PORTAL_STATE_PORTAL); |
36 } | 41 } |
37 return l10n_util::GetStringUTF8( | 42 return l10n_util::GetStringUTF8( |
38 IDS_CHROMEOS_CAPTIVE_PORTAL_STATE_UNRECOGNIZED); | 43 IDS_CHROMEOS_CAPTIVE_PORTAL_STATE_UNRECOGNIZED); |
39 } | 44 } |
40 | 45 |
41 NetworkPortalDetector* g_network_portal_detector = NULL; | 46 NetworkPortalDetector* g_network_portal_detector = NULL; |
42 | 47 |
43 } // namespace | 48 } // namespace |
44 | 49 |
45 NetworkPortalDetector::NetworkPortalDetector( | 50 NetworkPortalDetector::NetworkPortalDetector( |
46 const scoped_refptr<net::URLRequestContextGetter>& request_context) | 51 const scoped_refptr<net::URLRequestContextGetter>& request_context) |
47 : test_url_(CaptivePortalDetector::kDefaultURL) { | 52 : test_url_(CaptivePortalDetector::kDefaultURL), |
53 weak_ptr_factory_(this), | |
54 attempt_count_(0), | |
55 min_time_between_attempts_( | |
56 base::TimeDelta::FromSeconds(kMinTimeBetweenAttemptsSec)), | |
57 request_timeout_(base::TimeDelta::FromSeconds(kRequestTimeoutSec)) { | |
48 captive_portal_detector_.reset( | 58 captive_portal_detector_.reset( |
49 new CaptivePortalDetector(request_context)); | 59 new CaptivePortalDetector(request_context)); |
50 } | 60 } |
51 | 61 |
52 NetworkPortalDetector::~NetworkPortalDetector() { | 62 NetworkPortalDetector::~NetworkPortalDetector() { |
53 } | 63 } |
54 | 64 |
55 void NetworkPortalDetector::Init() { | 65 void NetworkPortalDetector::Init() { |
56 DCHECK(CalledOnValidThread()); | 66 DCHECK(CalledOnValidThread()); |
57 | 67 |
58 state_ = STATE_IDLE; | 68 state_ = STATE_IDLE; |
59 chromeos::NetworkLibrary* network_library = | 69 chromeos::NetworkLibrary* network_library = |
60 chromeos::CrosLibrary::Get()->GetNetworkLibrary(); | 70 chromeos::CrosLibrary::Get()->GetNetworkLibrary(); |
61 network_library->AddNetworkManagerObserver(this); | 71 network_library->AddNetworkManagerObserver(this); |
62 } | 72 } |
63 | 73 |
64 void NetworkPortalDetector::Shutdown() { | 74 void NetworkPortalDetector::Shutdown() { |
65 DCHECK(CalledOnValidThread()); | 75 DCHECK(CalledOnValidThread()); |
66 | 76 |
77 detection_task_.Cancel(); | |
78 detection_timeout_.Cancel(); | |
79 | |
67 captive_portal_detector_->Cancel(); | 80 captive_portal_detector_->Cancel(); |
68 captive_portal_detector_.reset(); | 81 captive_portal_detector_.reset(); |
69 observers_.Clear(); | 82 observers_.Clear(); |
70 chromeos::NetworkLibrary* network_library = | 83 chromeos::NetworkLibrary* network_library = |
71 chromeos::CrosLibrary::Get()->GetNetworkLibrary(); | 84 chromeos::CrosLibrary::Get()->GetNetworkLibrary(); |
72 network_library->RemoveNetworkManagerObserver(this); | 85 network_library->RemoveNetworkManagerObserver(this); |
73 } | 86 } |
74 | 87 |
75 void NetworkPortalDetector::AddObserver(Observer* observer) { | 88 void NetworkPortalDetector::AddObserver(Observer* observer) { |
76 DCHECK(CalledOnValidThread()); | 89 DCHECK(CalledOnValidThread()); |
90 | |
77 if (!observers_.HasObserver(observer)) | 91 if (!observers_.HasObserver(observer)) |
78 observers_.AddObserver(observer); | 92 observers_.AddObserver(observer); |
79 } | 93 } |
80 | 94 |
81 void NetworkPortalDetector::RemoveObserver(Observer* observer) { | 95 void NetworkPortalDetector::RemoveObserver(Observer* observer) { |
82 DCHECK(CalledOnValidThread()); | 96 DCHECK(CalledOnValidThread()); |
97 | |
83 observers_.RemoveObserver(observer); | 98 observers_.RemoveObserver(observer); |
84 } | 99 } |
85 | 100 |
86 NetworkPortalDetector::CaptivePortalState | 101 NetworkPortalDetector::CaptivePortalState |
87 NetworkPortalDetector::GetCaptivePortalState(const Network* network) { | 102 NetworkPortalDetector::GetCaptivePortalState(const Network* network) { |
103 DCHECK(CalledOnValidThread()); | |
104 | |
88 if (!network) | 105 if (!network) |
89 return CAPTIVE_PORTAL_STATE_UNKNOWN; | 106 return CAPTIVE_PORTAL_STATE_UNKNOWN; |
90 CaptivePortalStateMap::const_iterator it = | 107 CaptivePortalStateMap::const_iterator it = |
91 captive_portal_state_map_.find(network->unique_id()); | 108 captive_portal_state_map_.find(network->unique_id()); |
92 if (it == captive_portal_state_map_.end()) | 109 if (it == captive_portal_state_map_.end()) |
93 return CAPTIVE_PORTAL_STATE_UNKNOWN; | 110 return CAPTIVE_PORTAL_STATE_UNKNOWN; |
94 return it->second; | 111 return it->second; |
95 } | 112 } |
96 | 113 |
97 void NetworkPortalDetector::OnNetworkManagerChanged(NetworkLibrary* cros) { | 114 void NetworkPortalDetector::OnNetworkManagerChanged(NetworkLibrary* cros) { |
98 DCHECK(CalledOnValidThread()); | 115 DCHECK(CalledOnValidThread()); |
99 | 116 |
100 // Suppose that if there are no active network, then unique id is | 117 // Suppose that if there are no active network, then unique id is |
101 // empty and connection state is unknown. | 118 // empty and connection state is unknown. |
102 std::string new_active_network_id; | 119 std::string new_active_network_id; |
103 ConnectionState connection_state = STATE_UNKNOWN; | 120 ConnectionState connection_state = STATE_UNKNOWN; |
104 const Network* active_network = cros->active_network(); | 121 const Network* active_network = cros->active_network(); |
105 if (active_network) { | 122 if (active_network) { |
106 new_active_network_id = active_network->unique_id(); | 123 new_active_network_id = active_network->unique_id(); |
107 connection_state = active_network->connection_state(); | 124 connection_state = active_network->connection_state(); |
108 } | 125 } |
109 | 126 |
110 if (active_network_id_ != new_active_network_id) { | 127 if (active_network_id_ != new_active_network_id) { |
111 active_network_id_ = new_active_network_id; | 128 active_network_id_ = new_active_network_id; |
112 if (IsCheckingForPortal()) { | 129 attempt_count_ = 0; |
113 // Network is changed, so detection results will be incorrect. | 130 if (IsPortalCheckPending()) { |
114 state_ = STATE_CHECKING_FOR_PORTAL_NETWORK_CHANGED; | 131 detection_task_.Cancel(); |
115 } else if (Network::IsConnectedState(connection_state)) { | 132 detection_timeout_.Cancel(); |
116 // Start captive portal detection, if possible. | 133 } else if (IsCheckingForPortal()) { |
117 DetectCaptivePortal(); | 134 captive_portal_detector_->Cancel(); |
118 } | 135 } |
119 } else if (!IsCheckingForPortal() && | 136 state_ = STATE_IDLE; |
120 Network::IsConnectedState(connection_state)) { | 137 } |
138 if (!IsCheckingForPortal() && !IsPortalCheckPending() && | |
139 Network::IsConnectedState(connection_state) && | |
140 attempt_count_ < kMaxRequestAttempts) { | |
121 DCHECK(active_network); | 141 DCHECK(active_network); |
142 | |
122 // Initiate Captive Portal detection only if network's captive | 143 // Initiate Captive Portal detection only if network's captive |
123 // portal state is unknown (e.g. for freshly created networks) or offline. | 144 // portal state is unknown (e.g. for freshly created networks) or |
145 // offline. | |
124 CaptivePortalState state = GetCaptivePortalState(active_network); | 146 CaptivePortalState state = GetCaptivePortalState(active_network); |
125 if (state == CAPTIVE_PORTAL_STATE_UNKNOWN || | 147 if (state == CAPTIVE_PORTAL_STATE_UNKNOWN || |
126 state == CAPTIVE_PORTAL_STATE_OFFLINE) { | 148 state == CAPTIVE_PORTAL_STATE_OFFLINE) { |
127 DetectCaptivePortal(); | 149 DetectCaptivePortal(base::TimeDelta()); |
128 } | 150 } |
129 } | 151 } |
130 } | 152 } |
131 | 153 |
132 // static | 154 // static |
133 NetworkPortalDetector* NetworkPortalDetector::CreateInstance() { | 155 NetworkPortalDetector* NetworkPortalDetector::CreateInstance() { |
134 DCHECK(!g_network_portal_detector); | 156 DCHECK(!g_network_portal_detector); |
135 g_network_portal_detector = new NetworkPortalDetector( | 157 g_network_portal_detector = new NetworkPortalDetector( |
136 g_browser_process->system_request_context()); | 158 g_browser_process->system_request_context()); |
137 return g_network_portal_detector; | 159 return g_network_portal_detector; |
138 } | 160 } |
139 | 161 |
140 // static | 162 // static |
141 NetworkPortalDetector* NetworkPortalDetector::GetInstance() { | 163 NetworkPortalDetector* NetworkPortalDetector::GetInstance() { |
142 if (!g_network_portal_detector) | 164 if (!g_network_portal_detector) |
143 return CreateInstance(); | 165 return CreateInstance(); |
144 return g_network_portal_detector; | 166 return g_network_portal_detector; |
145 } | 167 } |
146 | 168 |
147 // static | 169 // static |
148 bool NetworkPortalDetector::IsEnabled() { | 170 bool NetworkPortalDetector::IsEnabled() { |
149 return !CommandLine::ForCurrentProcess()->HasSwitch( | 171 return !CommandLine::ForCurrentProcess()->HasSwitch( |
150 switches::kDisableChromeCaptivePortalDetector); | 172 switches::kDisableChromeCaptivePortalDetector); |
151 } | 173 } |
152 | 174 |
153 void NetworkPortalDetector::DetectCaptivePortal() { | 175 void NetworkPortalDetector::DetectCaptivePortal(const base::TimeDelta& delay) { |
176 DCHECK(!IsPortalCheckPending()); | |
177 DCHECK(!IsCheckingForPortal()); | |
178 DCHECK(attempt_count_ < kMaxRequestAttempts); | |
179 | |
Nikita (slow)
2012/11/20 12:58:45
I think it makes sense to clear tasks here just in
ygorshenin1
2012/11/21 09:08:06
Done.
| |
180 state_ = STATE_PORTAL_CHECK_PENDING; | |
181 | |
182 next_attempt_delay_ = delay; | |
183 if (attempt_count_ > 0) { | |
184 base::TimeTicks now = GetCurrentTimeTicks(); | |
185 base::TimeDelta elapsed_time; | |
186 if (now > attempt_start_time_) | |
187 elapsed_time = now - attempt_start_time_; | |
188 if (elapsed_time < min_time_between_attempts_ && | |
189 min_time_between_attempts_ - elapsed_time > next_attempt_delay_) { | |
190 next_attempt_delay_ = min_time_between_attempts_ - elapsed_time; | |
191 } | |
192 } | |
193 detection_task_.Reset( | |
194 base::Bind(&NetworkPortalDetector::DetectCaptivePortalTask, | |
195 weak_ptr_factory_.GetWeakPtr())); | |
196 MessageLoop::current()->PostDelayedTask(FROM_HERE, | |
197 detection_task_.callback(), | |
198 next_attempt_delay_); | |
199 } | |
200 | |
201 void NetworkPortalDetector::DetectCaptivePortalTask() { | |
202 DCHECK(IsPortalCheckPending()); | |
203 | |
154 state_ = STATE_CHECKING_FOR_PORTAL; | 204 state_ = STATE_CHECKING_FOR_PORTAL; |
205 | |
206 ++attempt_count_; | |
207 attempt_start_time_ = GetCurrentTimeTicks(); | |
208 | |
209 LOG(INFO) << "Portal detection starting attempt " << attempt_count_ | |
Nikita (slow)
2012/11/20 12:58:45
Note that by default LOG(INFO) is not captured in
ygorshenin1
2012/11/21 09:08:06
Done.
| |
210 << " of " << kMaxRequestAttempts; | |
211 | |
155 captive_portal_detector_->DetectCaptivePortal( | 212 captive_portal_detector_->DetectCaptivePortal( |
156 test_url_, | 213 test_url_, |
157 base::Bind(&NetworkPortalDetector::OnPortalDetectionCompleted, | 214 base::Bind(&NetworkPortalDetector::OnPortalDetectionCompleted, |
158 base::Unretained(this))); | 215 weak_ptr_factory_.GetWeakPtr())); |
216 detection_timeout_.Reset( | |
217 base::Bind(&NetworkPortalDetector::PortalDetectionTimeout, | |
218 weak_ptr_factory_.GetWeakPtr())); | |
219 MessageLoop::current()->PostDelayedTask(FROM_HERE, | |
220 detection_timeout_.callback(), | |
221 request_timeout_); | |
222 } | |
223 | |
224 void NetworkPortalDetector::PortalDetectionTimeout() { | |
225 DCHECK(CalledOnValidThread()); | |
226 DCHECK(IsCheckingForPortal()); | |
227 | |
228 LOG(ERROR) << "Portal detection timeout"; | |
229 | |
230 captive_portal_detector_->Cancel(); | |
231 CaptivePortalDetector::Results results; | |
232 results.result = captive_portal::RESULT_NO_RESPONSE; | |
233 OnPortalDetectionCompleted(results); | |
159 } | 234 } |
160 | 235 |
161 void NetworkPortalDetector::OnPortalDetectionCompleted( | 236 void NetworkPortalDetector::OnPortalDetectionCompleted( |
162 const CaptivePortalDetector::Results& results) { | 237 const CaptivePortalDetector::Results& results) { |
163 DCHECK(CalledOnValidThread()); | 238 DCHECK(CalledOnValidThread()); |
239 DCHECK(IsCheckingForPortal()); | |
164 | 240 |
165 DCHECK(IsCheckingForPortal()); | 241 LOG(ERROR) << "On portal detection completed"; |
Nikita (slow)
2012/11/20 12:58:45
LOG(INFO) or VLOG - see above.
ygorshenin1
2012/11/21 09:08:06
Done.
| |
242 | |
243 state_ = STATE_IDLE; | |
244 detection_timeout_.Cancel(); | |
166 | 245 |
167 NetworkLibrary* cros = CrosLibrary::Get()->GetNetworkLibrary(); | 246 NetworkLibrary* cros = CrosLibrary::Get()->GetNetworkLibrary(); |
168 const Network* active_network = cros->active_network(); | 247 const Network* active_network = cros->active_network(); |
169 if (!active_network) | 248 if (!active_network) |
170 return; | 249 return; |
171 | 250 |
172 if (state_ == STATE_CHECKING_FOR_PORTAL_NETWORK_CHANGED) { | |
173 // Can't use detection results, because network was changed. So | |
174 // retry portal detection for the active network or, if possible. | |
175 if (Network::IsConnectedState(active_network->connection_state()) && | |
176 GetCaptivePortalState(active_network) == | |
177 CAPTIVE_PORTAL_STATE_UNKNOWN) { | |
178 DetectCaptivePortal(); | |
179 } | |
180 return; | |
181 } | |
182 | |
183 state_ = STATE_IDLE; | |
184 | |
185 switch (results.result) { | 251 switch (results.result) { |
186 case captive_portal::RESULT_NO_RESPONSE: | 252 case captive_portal::RESULT_NO_RESPONSE: |
187 SetCaptivePortalState(active_network, CAPTIVE_PORTAL_STATE_OFFLINE); | 253 if (attempt_count_ >= kMaxRequestAttempts) |
254 SetCaptivePortalState(active_network, CAPTIVE_PORTAL_STATE_OFFLINE); | |
255 else | |
256 DetectCaptivePortal(results.retry_after_delta); | |
188 break; | 257 break; |
189 case captive_portal::RESULT_INTERNET_CONNECTED: | 258 case captive_portal::RESULT_INTERNET_CONNECTED: |
190 SetCaptivePortalState(active_network, CAPTIVE_PORTAL_STATE_ONLINE); | 259 SetCaptivePortalState(active_network, CAPTIVE_PORTAL_STATE_ONLINE); |
191 break; | 260 break; |
192 case captive_portal::RESULT_BEHIND_CAPTIVE_PORTAL: | 261 case captive_portal::RESULT_BEHIND_CAPTIVE_PORTAL: |
193 SetCaptivePortalState(active_network, CAPTIVE_PORTAL_STATE_PORTAL); | 262 SetCaptivePortalState(active_network, CAPTIVE_PORTAL_STATE_PORTAL); |
194 break; | 263 break; |
195 default: | 264 default: |
196 break; | 265 break; |
197 } | 266 } |
198 } | 267 } |
199 | 268 |
269 bool NetworkPortalDetector::IsPortalCheckPending() const { | |
270 return state_ == STATE_PORTAL_CHECK_PENDING; | |
271 } | |
272 | |
200 bool NetworkPortalDetector::IsCheckingForPortal() const { | 273 bool NetworkPortalDetector::IsCheckingForPortal() const { |
201 return state_ == STATE_CHECKING_FOR_PORTAL || | 274 return state_ == STATE_CHECKING_FOR_PORTAL; |
202 state_ == STATE_CHECKING_FOR_PORTAL_NETWORK_CHANGED; | |
203 } | 275 } |
204 | 276 |
205 void NetworkPortalDetector::SetCaptivePortalState(const Network* network, | 277 void NetworkPortalDetector::SetCaptivePortalState(const Network* network, |
206 CaptivePortalState state) { | 278 CaptivePortalState state) { |
207 DCHECK(network); | 279 DCHECK(network); |
280 | |
208 CaptivePortalStateMap::const_iterator it = | 281 CaptivePortalStateMap::const_iterator it = |
209 captive_portal_state_map_.find(network->unique_id()); | 282 captive_portal_state_map_.find(network->unique_id()); |
210 if (it == captive_portal_state_map_.end() || | 283 if (it == captive_portal_state_map_.end() || |
211 it->second != state) { | 284 it->second != state) { |
212 VLOG(2) << "Updating Chrome Captive Portal state: " | 285 VLOG(2) << "Updating Chrome Captive Portal state: " |
213 << "network=" << network->unique_id() << ", " | 286 << "network=" << network->unique_id() << ", " |
214 << "state=" << CaptivePortalStateString(state); | 287 << "state=" << CaptivePortalStateString(state); |
215 captive_portal_state_map_[network->unique_id()] = state; | 288 captive_portal_state_map_[network->unique_id()] = state; |
216 NotifyPortalStateChanged(network, state); | 289 NotifyPortalStateChanged(network, state); |
217 } | 290 } |
218 } | 291 } |
219 | 292 |
220 void NetworkPortalDetector::NotifyPortalStateChanged(const Network* network, | 293 void NetworkPortalDetector::NotifyPortalStateChanged(const Network* network, |
221 CaptivePortalState state) { | 294 CaptivePortalState state) { |
222 FOR_EACH_OBSERVER(Observer, observers_, OnPortalStateChanged(network, state)); | 295 FOR_EACH_OBSERVER(Observer, observers_, OnPortalStateChanged(network, state)); |
223 } | 296 } |
224 | 297 |
298 base::TimeTicks NetworkPortalDetector::GetCurrentTimeTicks() const { | |
299 if (time_ticks_for_testing_.is_null()) | |
300 return base::TimeTicks::Now(); | |
301 else | |
302 return time_ticks_for_testing_; | |
303 } | |
304 | |
225 } // namespace chromeos | 305 } // namespace chromeos |
OLD | NEW |