Add GCMChannelStatusSyncer to schedule requests and enable/disable GCM
[chromium-blink-merge.git] / chrome / browser / local_discovery / wifi / wifi_manager_nonchromeos.cc
blob5660007918da20b50928ebde377dab8f8b94ee3a
1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "chrome/browser/local_discovery/wifi/wifi_manager_nonchromeos.h"
7 #include "base/cancelable_callback.h"
8 #include "base/threading/sequenced_worker_pool.h"
9 #include "base/threading/thread.h"
10 #include "components/onc/onc_constants.h"
11 #include "components/wifi/wifi_service.h"
12 #include "content/public/browser/browser_thread.h"
13 #include "net/base/network_change_notifier.h"
15 #if defined(OS_WIN)
16 #include "chrome/browser/local_discovery/wifi/credential_getter_win.h"
17 #endif // OS_WIN
19 using ::wifi::WiFiService;
21 namespace local_discovery {
23 namespace wifi {
25 namespace {
27 const int kConnectionTimeoutSeconds = 10;
29 scoped_ptr<base::DictionaryValue> MakeProperties(const std::string& ssid,
30 const std::string& password) {
31 scoped_ptr<base::DictionaryValue> properties(new base::DictionaryValue);
33 properties->SetString(onc::network_config::kType, onc::network_type::kWiFi);
34 base::DictionaryValue* wifi = new base::DictionaryValue;
35 properties->Set(onc::network_config::kWiFi, wifi);
37 wifi->SetString(onc::wifi::kSSID, ssid);
38 if (!password.empty()) {
39 wifi->SetString(onc::wifi::kPassphrase, password);
40 // TODO(noamsml): Allow choosing security mechanism in a more fine-grained
41 // manner.
42 wifi->SetString(onc::wifi::kSecurity, onc::wifi::kWPA2_PSK);
43 } else {
44 wifi->SetString(onc::wifi::kSecurity, onc::wifi::kSecurityNone);
47 return properties.Pass();
50 } // namespace
52 class WifiManagerNonChromeos::WifiServiceWrapper
53 : public net::NetworkChangeNotifier::NetworkChangeObserver {
54 public:
55 explicit WifiServiceWrapper(
56 base::WeakPtr<WifiManagerNonChromeos> wifi_manager);
58 virtual ~WifiServiceWrapper();
60 void Start();
62 void GetSSIDList(const WifiManager::SSIDListCallback& callback);
64 void ConfigureAndConnectPskNetwork(
65 const std::string& ssid,
66 const std::string& password,
67 const WifiManager::SuccessCallback& callback);
69 base::WeakPtr<WifiManagerNonChromeos::WifiServiceWrapper> AsWeakPtr();
71 void RequestScan();
73 void ConnectToNetworkByID(const std::string& network_guid,
74 const WifiManager::SuccessCallback& callback);
76 void RequestNetworkCredentials(
77 const std::string& ssid,
78 const WifiManager::CredentialsCallback& callback);
80 private:
81 // net::NetworkChangeNotifier::NetworkChangeObserver implementation.
82 virtual void OnNetworkChanged(
83 net::NetworkChangeNotifier::ConnectionType type) OVERRIDE;
85 void GetSSIDListInternal(NetworkPropertiesList* ssid_list);
87 void OnNetworkListChangedEvent(const std::vector<std::string>& network_guids);
89 void OnNetworksChangedEvent(const std::vector<std::string>& network_guids);
91 std::string GetConnectedGUID();
93 bool IsConnected(const std::string& network_guid);
95 void OnConnectToNetworkTimeout();
97 void PostClosure(const base::Closure& closure);
99 bool FindAndConfigureNetwork(const std::string& ssid,
100 const std::string& password,
101 std::string* network_guid);
103 #if defined(OS_WIN)
104 void PostCredentialsCallback(const WifiManager::CredentialsCallback& callback,
105 const std::string& ssid,
106 bool success,
107 const std::string& password);
108 #endif // OS_WIN
110 scoped_ptr<WiFiService> wifi_service_;
112 base::WeakPtr<WifiManagerNonChromeos> wifi_manager_;
114 WifiManager::SuccessCallback connect_success_callback_;
115 base::CancelableClosure connect_failure_callback_;
117 // SSID of previously connected network.
118 std::string connected_network_guid_;
120 // SSID of network we are connecting to.
121 std::string connecting_network_guid_;
123 scoped_refptr<base::MessageLoopProxy> callback_runner_;
125 base::WeakPtrFactory<WifiServiceWrapper> weak_factory_;
127 #if defined(OS_WIN)
128 scoped_refptr<CredentialGetterWin> credential_getter_;
129 #endif // OS_WIN
131 DISALLOW_COPY_AND_ASSIGN(WifiServiceWrapper);
134 WifiManagerNonChromeos::WifiServiceWrapper::WifiServiceWrapper(
135 base::WeakPtr<WifiManagerNonChromeos> wifi_manager)
136 : wifi_manager_(wifi_manager),
137 callback_runner_(base::MessageLoopProxy::current()),
138 weak_factory_(this) {
141 WifiManagerNonChromeos::WifiServiceWrapper::~WifiServiceWrapper() {
142 net::NetworkChangeNotifier::RemoveNetworkChangeObserver(this);
145 void WifiManagerNonChromeos::WifiServiceWrapper::Start() {
146 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::FILE));
147 wifi_service_.reset(WiFiService::Create());
149 wifi_service_->Initialize(base::MessageLoopProxy::current());
151 wifi_service_->SetEventObservers(
152 base::MessageLoopProxy::current(),
153 base::Bind(&WifiServiceWrapper::OnNetworksChangedEvent, AsWeakPtr()),
154 base::Bind(&WifiServiceWrapper::OnNetworkListChangedEvent, AsWeakPtr()));
156 net::NetworkChangeNotifier::AddNetworkChangeObserver(this);
159 void WifiManagerNonChromeos::WifiServiceWrapper::GetSSIDList(
160 const WifiManager::SSIDListCallback& callback) {
161 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::FILE));
163 scoped_ptr<NetworkPropertiesList> ssid_list(new NetworkPropertiesList);
164 GetSSIDListInternal(ssid_list.get());
166 callback_runner_->PostTask(
167 FROM_HERE,
168 base::Bind(&WifiManagerNonChromeos::PostSSIDListCallback,
169 wifi_manager_,
170 callback,
171 base::Passed(&ssid_list)));
174 void WifiManagerNonChromeos::WifiServiceWrapper::ConfigureAndConnectPskNetwork(
175 const std::string& ssid,
176 const std::string& password,
177 const WifiManager::SuccessCallback& callback) {
178 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::FILE));
179 scoped_ptr<base::DictionaryValue> properties = MakeProperties(ssid, password);
181 std::string network_guid;
182 std::string error_string;
183 // Will fail without changing system state if network already exists.
184 wifi_service_->CreateNetwork(
185 false, properties.Pass(), &network_guid, &error_string);
187 if (error_string.empty()) {
188 ConnectToNetworkByID(network_guid, callback);
189 return;
192 // If we cannot create the network, attempt to configure and connect to an
193 // existing network.
194 if (FindAndConfigureNetwork(ssid, password, &network_guid)) {
195 ConnectToNetworkByID(network_guid, callback);
196 } else {
197 if (!callback.is_null())
198 PostClosure(base::Bind(callback, false /* success */));
202 void WifiManagerNonChromeos::WifiServiceWrapper::OnNetworkListChangedEvent(
203 const std::vector<std::string>& network_guids) {
204 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::FILE));
205 scoped_ptr<NetworkPropertiesList> ssid_list(new NetworkPropertiesList);
206 GetSSIDListInternal(ssid_list.get());
207 callback_runner_->PostTask(
208 FROM_HERE,
209 base::Bind(&WifiManagerNonChromeos::OnNetworkListChanged,
210 wifi_manager_,
211 base::Passed(&ssid_list)));
214 void WifiManagerNonChromeos::WifiServiceWrapper::OnNetworksChangedEvent(
215 const std::vector<std::string>& network_guids) {
216 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::FILE));
217 if (connecting_network_guid_.empty() ||
218 !IsConnected(connecting_network_guid_)) {
219 return;
222 connecting_network_guid_.clear();
223 connect_failure_callback_.Cancel();
225 if (!connect_success_callback_.is_null())
226 PostClosure(base::Bind(connect_success_callback_, true));
228 connect_success_callback_.Reset();
231 base::WeakPtr<WifiManagerNonChromeos::WifiServiceWrapper>
232 WifiManagerNonChromeos::WifiServiceWrapper::AsWeakPtr() {
233 return weak_factory_.GetWeakPtr();
236 void WifiManagerNonChromeos::WifiServiceWrapper::RequestScan() {
237 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::FILE));
238 wifi_service_->RequestNetworkScan();
241 void WifiManagerNonChromeos::WifiServiceWrapper::ConnectToNetworkByID(
242 const std::string& network_guid,
243 const WifiManager::SuccessCallback& callback) {
244 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::FILE));
246 std::string connected_network_id = GetConnectedGUID();
247 std::string error_string;
248 wifi_service_->StartConnect(network_guid, &error_string);
250 if (!error_string.empty()) {
251 LOG(ERROR) << "Could not connect to network by ID: " << error_string;
252 PostClosure(base::Bind(callback, false /* success */));
253 wifi_service_->StartConnect(connected_network_id, &error_string);
254 return;
257 if (IsConnected(network_guid)) {
258 if (!callback.is_null())
259 PostClosure(base::Bind(callback, true /* success */));
260 return;
263 connect_success_callback_ = callback;
264 connecting_network_guid_ = network_guid;
265 connected_network_guid_ = connected_network_id;
267 connect_failure_callback_.Reset(base::Bind(
268 &WifiServiceWrapper::OnConnectToNetworkTimeout, base::Unretained(this)));
270 base::MessageLoop::current()->PostDelayedTask(
271 FROM_HERE,
272 connect_failure_callback_.callback(),
273 base::TimeDelta::FromSeconds(kConnectionTimeoutSeconds));
276 void WifiManagerNonChromeos::WifiServiceWrapper::OnConnectToNetworkTimeout() {
277 bool connected = IsConnected(connecting_network_guid_);
278 std::string error_string;
280 WifiManager::SuccessCallback connect_success_callback =
281 connect_success_callback_;
283 connect_success_callback_.Reset();
285 connecting_network_guid_.clear();
287 // If we did not connect, return to the network the user was originally
288 // connected to.
289 if (!connected)
290 wifi_service_->StartConnect(connected_network_guid_, &error_string);
292 PostClosure(base::Bind(connect_success_callback, connected /* success */));
295 void WifiManagerNonChromeos::WifiServiceWrapper::RequestNetworkCredentials(
296 const std::string& ssid,
297 const WifiManager::CredentialsCallback& callback) {
298 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::FILE));
300 bool success = true;
301 std::string guid;
302 std::string key;
304 NetworkPropertiesList network_list;
306 GetSSIDListInternal(&network_list);
308 for (NetworkPropertiesList::iterator i = network_list.begin();
309 i != network_list.end();
310 i++) {
311 if (i->ssid == ssid) {
312 guid = i->guid;
313 break;
317 if (guid.empty()) {
318 success = false;
321 if (!success) {
322 PostClosure(base::Bind(callback, success, "", ""));
323 return;
326 #if defined(OS_WIN)
327 credential_getter_ = new CredentialGetterWin();
328 credential_getter_->StartGetCredentials(
329 guid,
330 base::Bind(&WifiServiceWrapper::PostCredentialsCallback,
331 AsWeakPtr(),
332 callback,
333 ssid));
334 #else
335 if (success) {
336 std::string error_string;
337 wifi_service_->GetKeyFromSystem(guid, &key, &error_string);
339 if (!error_string.empty()) {
340 LOG(ERROR) << "Could not get key from system: " << error_string;
341 success = false;
344 PostClosure(base::Bind(callback, success, ssid, key));
346 #endif // OS_WIN
349 void WifiManagerNonChromeos::WifiServiceWrapper::OnNetworkChanged(
350 net::NetworkChangeNotifier::ConnectionType type) {
351 wifi_service_->RequestConnectedNetworkUpdate();
354 void WifiManagerNonChromeos::WifiServiceWrapper::GetSSIDListInternal(
355 NetworkPropertiesList* ssid_list) {
356 base::ListValue visible_networks;
358 wifi_service_->GetVisibleNetworks(
359 onc::network_type::kWiFi, &visible_networks, true);
361 for (size_t i = 0; i < visible_networks.GetSize(); i++) {
362 const base::DictionaryValue* network_value = NULL;
363 NetworkProperties network_properties;
365 if (!visible_networks.GetDictionary(i, &network_value)) {
366 NOTREACHED();
369 network_properties.UpdateFromValue(*network_value);
371 ssid_list->push_back(network_properties);
375 std::string WifiManagerNonChromeos::WifiServiceWrapper::GetConnectedGUID() {
376 NetworkPropertiesList ssid_list;
377 GetSSIDListInternal(&ssid_list);
379 for (NetworkPropertiesList::const_iterator it = ssid_list.begin();
380 it != ssid_list.end();
381 ++it) {
382 if (it->connection_state == onc::connection_state::kConnected)
383 return it->guid;
386 return "";
389 bool WifiManagerNonChromeos::WifiServiceWrapper::IsConnected(
390 const std::string& network_guid) {
391 NetworkPropertiesList ssid_list;
392 GetSSIDListInternal(&ssid_list);
394 for (NetworkPropertiesList::const_iterator it = ssid_list.begin();
395 it != ssid_list.end();
396 ++it) {
397 if (it->connection_state == onc::connection_state::kConnected &&
398 it->guid == network_guid)
399 return true;
402 return false;
405 bool WifiManagerNonChromeos::WifiServiceWrapper::FindAndConfigureNetwork(
406 const std::string& ssid,
407 const std::string& password,
408 std::string* network_guid) {
409 std::string provisional_network_guid;
410 NetworkPropertiesList network_property_list;
411 GetSSIDListInternal(&network_property_list);
413 for (size_t i = 0; i < network_property_list.size(); i++) {
414 // TODO(noamsml): Handle case where there are multiple networks with the
415 // same SSID but different security.
416 if (network_property_list[i].ssid == ssid) {
417 provisional_network_guid = network_property_list[i].guid;
418 break;
422 if (provisional_network_guid.empty())
423 return false;
425 scoped_ptr<base::DictionaryValue> properties = MakeProperties(ssid, password);
427 std::string error_string;
428 wifi_service_->SetProperties(
429 provisional_network_guid, properties.Pass(), &error_string);
431 if (!error_string.empty()) {
432 LOG(ERROR) << "Could not set properties on network: " << error_string;
433 return false;
436 *network_guid = provisional_network_guid;
437 return true;
440 void WifiManagerNonChromeos::WifiServiceWrapper::PostClosure(
441 const base::Closure& closure) {
442 callback_runner_->PostTask(
443 FROM_HERE,
444 base::Bind(&WifiManagerNonChromeos::PostClosure, wifi_manager_, closure));
447 #if defined(OS_WIN)
448 void WifiManagerNonChromeos::WifiServiceWrapper::PostCredentialsCallback(
449 const WifiManager::CredentialsCallback& callback,
450 const std::string& ssid,
451 bool success,
452 const std::string& password) {
453 PostClosure(base::Bind(callback, success, ssid, password));
456 #endif // OS_WIN
458 scoped_ptr<WifiManager> WifiManager::CreateDefault() {
459 return scoped_ptr<WifiManager>(new WifiManagerNonChromeos());
462 WifiManagerNonChromeos::WifiManagerNonChromeos()
463 : wifi_wrapper_(NULL), weak_factory_(this) {
466 WifiManagerNonChromeos::~WifiManagerNonChromeos() {
467 if (wifi_wrapper_) {
468 content::BrowserThread::DeleteSoon(
469 content::BrowserThread::FILE, FROM_HERE, wifi_wrapper_);
473 void WifiManagerNonChromeos::Start() {
474 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
475 task_runner_ = content::BrowserThread::GetMessageLoopProxyForThread(
476 content::BrowserThread::FILE);
478 // Allocated on UI thread, but all initialization is done on file
479 // thread. Destroyed on file thread, which should be safe since all of the
480 // thread-unsafe members are created on the file thread.
481 wifi_wrapper_ = new WifiServiceWrapper(weak_factory_.GetWeakPtr());
483 task_runner_->PostTask(
484 FROM_HERE,
485 base::Bind(&WifiServiceWrapper::Start, wifi_wrapper_->AsWeakPtr()));
488 void WifiManagerNonChromeos::GetSSIDList(const SSIDListCallback& callback) {
489 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
490 task_runner_->PostTask(FROM_HERE,
491 base::Bind(&WifiServiceWrapper::GetSSIDList,
492 wifi_wrapper_->AsWeakPtr(),
493 callback));
496 void WifiManagerNonChromeos::RequestScan() {
497 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
498 task_runner_->PostTask(
499 FROM_HERE,
500 base::Bind(&WifiServiceWrapper::RequestScan, wifi_wrapper_->AsWeakPtr()));
503 void WifiManagerNonChromeos::OnNetworkListChanged(
504 scoped_ptr<NetworkPropertiesList> ssid_list) {
505 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
506 FOR_EACH_OBSERVER(NetworkListObserver,
507 network_list_observers_,
508 OnNetworkListChanged(*ssid_list));
511 void WifiManagerNonChromeos::PostClosure(const base::Closure& callback) {
512 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
513 callback.Run();
516 void WifiManagerNonChromeos::PostSSIDListCallback(
517 const SSIDListCallback& callback,
518 scoped_ptr<NetworkPropertiesList> ssid_list) {
519 callback.Run(*ssid_list);
522 void WifiManagerNonChromeos::ConfigureAndConnectNetwork(
523 const std::string& ssid,
524 const WifiCredentials& credentials,
525 const SuccessCallback& callback) {
526 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
527 task_runner_->PostTask(
528 FROM_HERE,
529 base::Bind(&WifiServiceWrapper::ConfigureAndConnectPskNetwork,
530 wifi_wrapper_->AsWeakPtr(),
531 ssid,
532 credentials.psk,
533 callback));
536 void WifiManagerNonChromeos::ConnectToNetworkByID(
537 const std::string& internal_id,
538 const SuccessCallback& callback) {
539 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
540 task_runner_->PostTask(FROM_HERE,
541 base::Bind(&WifiServiceWrapper::ConnectToNetworkByID,
542 wifi_wrapper_->AsWeakPtr(),
543 internal_id,
544 callback));
547 void WifiManagerNonChromeos::RequestNetworkCredentials(
548 const std::string& ssid,
549 const CredentialsCallback& callback) {
550 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
551 task_runner_->PostTask(
552 FROM_HERE,
553 base::Bind(&WifiServiceWrapper::RequestNetworkCredentials,
554 wifi_wrapper_->AsWeakPtr(),
555 ssid,
556 callback));
559 void WifiManagerNonChromeos::AddNetworkListObserver(
560 NetworkListObserver* observer) {
561 network_list_observers_.AddObserver(observer);
564 void WifiManagerNonChromeos::RemoveNetworkListObserver(
565 NetworkListObserver* observer) {
566 network_list_observers_.RemoveObserver(observer);
569 } // namespace wifi
571 } // namespace local_discovery