Merge Chromium + Blink git repositories
[chromium-blink-merge.git] / chrome / browser / local_discovery / wifi / wifi_manager_nonchromeos.cc
blob531c92476073b402538200102d9ee5fbcbac5213
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/thread_task_runner_handle.h"
9 #include "base/threading/sequenced_worker_pool.h"
10 #include "base/threading/thread.h"
11 #include "components/onc/onc_constants.h"
12 #include "components/wifi/wifi_service.h"
13 #include "content/public/browser/browser_thread.h"
14 #include "net/base/network_change_notifier.h"
16 #if defined(OS_WIN)
17 #include "chrome/browser/local_discovery/wifi/credential_getter_win.h"
18 #endif // OS_WIN
20 using ::wifi::WiFiService;
22 namespace local_discovery {
24 namespace wifi {
26 namespace {
28 const int kConnectionTimeoutSeconds = 10;
30 scoped_ptr<base::DictionaryValue> MakeProperties(const std::string& ssid,
31 const std::string& password) {
32 scoped_ptr<base::DictionaryValue> properties(new base::DictionaryValue);
34 properties->SetString(onc::network_config::kType, onc::network_type::kWiFi);
35 base::DictionaryValue* wifi = new base::DictionaryValue;
36 properties->Set(onc::network_config::kWiFi, wifi);
38 wifi->SetString(onc::wifi::kSSID, ssid);
39 if (!password.empty()) {
40 wifi->SetString(onc::wifi::kPassphrase, password);
41 // TODO(noamsml): Allow choosing security mechanism in a more fine-grained
42 // manner.
43 wifi->SetString(onc::wifi::kSecurity, onc::wifi::kWPA2_PSK);
44 } else {
45 wifi->SetString(onc::wifi::kSecurity, onc::wifi::kSecurityNone);
48 return properties.Pass();
51 } // namespace
53 class WifiManagerNonChromeos::WifiServiceWrapper
54 : public net::NetworkChangeNotifier::NetworkChangeObserver {
55 public:
56 explicit WifiServiceWrapper(
57 base::WeakPtr<WifiManagerNonChromeos> wifi_manager);
59 ~WifiServiceWrapper() override;
61 void Start();
63 void GetSSIDList(const WifiManager::SSIDListCallback& callback);
65 void ConfigureAndConnectPskNetwork(
66 const std::string& ssid,
67 const std::string& password,
68 const WifiManager::SuccessCallback& callback);
70 base::WeakPtr<WifiManagerNonChromeos::WifiServiceWrapper> AsWeakPtr();
72 void RequestScan();
74 void ConnectToNetworkByID(const std::string& network_guid,
75 const WifiManager::SuccessCallback& callback);
77 void RequestNetworkCredentials(
78 const std::string& ssid,
79 const WifiManager::CredentialsCallback& callback);
81 private:
82 // net::NetworkChangeNotifier::NetworkChangeObserver implementation.
83 void OnNetworkChanged(
84 net::NetworkChangeNotifier::ConnectionType type) override;
86 void GetSSIDListInternal(NetworkPropertiesList* ssid_list);
88 void OnNetworkListChangedEvent(const std::vector<std::string>& network_guids);
90 void OnNetworksChangedEvent(const std::vector<std::string>& network_guids);
92 std::string GetConnectedGUID();
94 bool IsConnected(const std::string& network_guid);
96 void OnConnectToNetworkTimeout();
98 void PostClosure(const base::Closure& closure);
100 bool FindAndConfigureNetwork(const std::string& ssid,
101 const std::string& password,
102 std::string* network_guid);
104 #if defined(OS_WIN)
105 void PostCredentialsCallback(const WifiManager::CredentialsCallback& callback,
106 const std::string& ssid,
107 bool success,
108 const std::string& password);
109 #endif // OS_WIN
111 scoped_ptr<WiFiService> wifi_service_;
113 base::WeakPtr<WifiManagerNonChromeos> wifi_manager_;
115 WifiManager::SuccessCallback connect_success_callback_;
116 base::CancelableClosure connect_failure_callback_;
118 // SSID of previously connected network.
119 std::string connected_network_guid_;
121 // SSID of network we are connecting to.
122 std::string connecting_network_guid_;
124 scoped_refptr<base::SingleThreadTaskRunner> callback_runner_;
126 #if defined(OS_WIN)
127 scoped_refptr<CredentialGetterWin> credential_getter_;
128 #endif // OS_WIN
130 base::WeakPtrFactory<WifiServiceWrapper> weak_factory_;
132 DISALLOW_COPY_AND_ASSIGN(WifiServiceWrapper);
135 WifiManagerNonChromeos::WifiServiceWrapper::WifiServiceWrapper(
136 base::WeakPtr<WifiManagerNonChromeos> wifi_manager)
137 : wifi_manager_(wifi_manager),
138 callback_runner_(base::ThreadTaskRunnerHandle::Get()),
139 weak_factory_(this) {
142 WifiManagerNonChromeos::WifiServiceWrapper::~WifiServiceWrapper() {
143 net::NetworkChangeNotifier::RemoveNetworkChangeObserver(this);
146 void WifiManagerNonChromeos::WifiServiceWrapper::Start() {
147 DCHECK_CURRENTLY_ON(content::BrowserThread::FILE);
148 wifi_service_.reset(WiFiService::Create());
150 wifi_service_->Initialize(base::ThreadTaskRunnerHandle::Get());
152 wifi_service_->SetEventObservers(
153 base::ThreadTaskRunnerHandle::Get(),
154 base::Bind(&WifiServiceWrapper::OnNetworksChangedEvent, AsWeakPtr()),
155 base::Bind(&WifiServiceWrapper::OnNetworkListChangedEvent, AsWeakPtr()));
157 net::NetworkChangeNotifier::AddNetworkChangeObserver(this);
160 void WifiManagerNonChromeos::WifiServiceWrapper::GetSSIDList(
161 const WifiManager::SSIDListCallback& callback) {
162 DCHECK_CURRENTLY_ON(content::BrowserThread::FILE);
164 scoped_ptr<NetworkPropertiesList> ssid_list(new NetworkPropertiesList);
165 GetSSIDListInternal(ssid_list.get());
167 callback_runner_->PostTask(
168 FROM_HERE,
169 base::Bind(&WifiManagerNonChromeos::PostSSIDListCallback,
170 wifi_manager_,
171 callback,
172 base::Passed(&ssid_list)));
175 void WifiManagerNonChromeos::WifiServiceWrapper::ConfigureAndConnectPskNetwork(
176 const std::string& ssid,
177 const std::string& password,
178 const WifiManager::SuccessCallback& callback) {
179 DCHECK_CURRENTLY_ON(content::BrowserThread::FILE);
180 scoped_ptr<base::DictionaryValue> properties = MakeProperties(ssid, password);
182 std::string network_guid;
183 std::string error_string;
184 // Will fail without changing system state if network already exists.
185 wifi_service_->CreateNetwork(
186 false, properties.Pass(), &network_guid, &error_string);
188 if (error_string.empty()) {
189 ConnectToNetworkByID(network_guid, callback);
190 return;
193 // If we cannot create the network, attempt to configure and connect to an
194 // existing network.
195 if (FindAndConfigureNetwork(ssid, password, &network_guid)) {
196 ConnectToNetworkByID(network_guid, callback);
197 } else {
198 if (!callback.is_null())
199 PostClosure(base::Bind(callback, false /* success */));
203 void WifiManagerNonChromeos::WifiServiceWrapper::OnNetworkListChangedEvent(
204 const std::vector<std::string>& network_guids) {
205 DCHECK_CURRENTLY_ON(content::BrowserThread::FILE);
206 scoped_ptr<NetworkPropertiesList> ssid_list(new NetworkPropertiesList);
207 GetSSIDListInternal(ssid_list.get());
208 callback_runner_->PostTask(
209 FROM_HERE,
210 base::Bind(&WifiManagerNonChromeos::OnNetworkListChanged,
211 wifi_manager_,
212 base::Passed(&ssid_list)));
215 void WifiManagerNonChromeos::WifiServiceWrapper::OnNetworksChangedEvent(
216 const std::vector<std::string>& network_guids) {
217 DCHECK_CURRENTLY_ON(content::BrowserThread::FILE);
218 if (connecting_network_guid_.empty() ||
219 !IsConnected(connecting_network_guid_)) {
220 return;
223 connecting_network_guid_.clear();
224 connect_failure_callback_.Cancel();
226 if (!connect_success_callback_.is_null())
227 PostClosure(base::Bind(connect_success_callback_, true));
229 connect_success_callback_.Reset();
232 base::WeakPtr<WifiManagerNonChromeos::WifiServiceWrapper>
233 WifiManagerNonChromeos::WifiServiceWrapper::AsWeakPtr() {
234 return weak_factory_.GetWeakPtr();
237 void WifiManagerNonChromeos::WifiServiceWrapper::RequestScan() {
238 DCHECK_CURRENTLY_ON(content::BrowserThread::FILE);
239 wifi_service_->RequestNetworkScan();
242 void WifiManagerNonChromeos::WifiServiceWrapper::ConnectToNetworkByID(
243 const std::string& network_guid,
244 const WifiManager::SuccessCallback& callback) {
245 DCHECK_CURRENTLY_ON(content::BrowserThread::FILE);
247 std::string connected_network_id = GetConnectedGUID();
248 std::string error_string;
249 wifi_service_->StartConnect(network_guid, &error_string);
251 if (!error_string.empty()) {
252 LOG(ERROR) << "Could not connect to network by ID: " << error_string;
253 PostClosure(base::Bind(callback, false /* success */));
254 wifi_service_->StartConnect(connected_network_id, &error_string);
255 return;
258 if (IsConnected(network_guid)) {
259 if (!callback.is_null())
260 PostClosure(base::Bind(callback, true /* success */));
261 return;
264 connect_success_callback_ = callback;
265 connecting_network_guid_ = network_guid;
266 connected_network_guid_ = connected_network_id;
268 connect_failure_callback_.Reset(base::Bind(
269 &WifiServiceWrapper::OnConnectToNetworkTimeout, base::Unretained(this)));
271 base::MessageLoop::current()->PostDelayedTask(
272 FROM_HERE,
273 connect_failure_callback_.callback(),
274 base::TimeDelta::FromSeconds(kConnectionTimeoutSeconds));
277 void WifiManagerNonChromeos::WifiServiceWrapper::OnConnectToNetworkTimeout() {
278 bool connected = IsConnected(connecting_network_guid_);
279 std::string error_string;
281 WifiManager::SuccessCallback connect_success_callback =
282 connect_success_callback_;
284 connect_success_callback_.Reset();
286 connecting_network_guid_.clear();
288 // If we did not connect, return to the network the user was originally
289 // connected to.
290 if (!connected)
291 wifi_service_->StartConnect(connected_network_guid_, &error_string);
293 PostClosure(base::Bind(connect_success_callback, connected /* success */));
296 void WifiManagerNonChromeos::WifiServiceWrapper::RequestNetworkCredentials(
297 const std::string& ssid,
298 const WifiManager::CredentialsCallback& callback) {
299 DCHECK_CURRENTLY_ON(content::BrowserThread::FILE);
301 bool success = true;
302 std::string guid;
303 std::string key;
305 NetworkPropertiesList network_list;
307 GetSSIDListInternal(&network_list);
309 for (NetworkPropertiesList::iterator i = network_list.begin();
310 i != network_list.end();
311 i++) {
312 if (i->ssid == ssid) {
313 guid = i->guid;
314 break;
318 if (guid.empty()) {
319 success = false;
322 if (!success) {
323 PostClosure(base::Bind(callback, success, "", ""));
324 return;
327 #if defined(OS_WIN)
328 credential_getter_ = new CredentialGetterWin();
329 credential_getter_->StartGetCredentials(
330 guid,
331 base::Bind(&WifiServiceWrapper::PostCredentialsCallback,
332 AsWeakPtr(),
333 callback,
334 ssid));
335 #else
336 if (success) {
337 std::string error_string;
338 wifi_service_->GetKeyFromSystem(guid, &key, &error_string);
340 if (!error_string.empty()) {
341 LOG(ERROR) << "Could not get key from system: " << error_string;
342 success = false;
345 PostClosure(base::Bind(callback, success, ssid, key));
347 #endif // OS_WIN
350 void WifiManagerNonChromeos::WifiServiceWrapper::OnNetworkChanged(
351 net::NetworkChangeNotifier::ConnectionType type) {
352 wifi_service_->RequestConnectedNetworkUpdate();
355 void WifiManagerNonChromeos::WifiServiceWrapper::GetSSIDListInternal(
356 NetworkPropertiesList* ssid_list) {
357 base::ListValue visible_networks;
359 wifi_service_->GetVisibleNetworks(
360 onc::network_type::kWiFi, &visible_networks, true);
362 for (size_t i = 0; i < visible_networks.GetSize(); i++) {
363 const base::DictionaryValue* network_value = NULL;
364 NetworkProperties network_properties;
366 if (!visible_networks.GetDictionary(i, &network_value)) {
367 NOTREACHED();
370 network_properties.UpdateFromValue(*network_value);
372 ssid_list->push_back(network_properties);
376 std::string WifiManagerNonChromeos::WifiServiceWrapper::GetConnectedGUID() {
377 NetworkPropertiesList ssid_list;
378 GetSSIDListInternal(&ssid_list);
380 for (NetworkPropertiesList::const_iterator it = ssid_list.begin();
381 it != ssid_list.end();
382 ++it) {
383 if (it->connection_state == onc::connection_state::kConnected)
384 return it->guid;
387 return "";
390 bool WifiManagerNonChromeos::WifiServiceWrapper::IsConnected(
391 const std::string& network_guid) {
392 NetworkPropertiesList ssid_list;
393 GetSSIDListInternal(&ssid_list);
395 for (NetworkPropertiesList::const_iterator it = ssid_list.begin();
396 it != ssid_list.end();
397 ++it) {
398 if (it->connection_state == onc::connection_state::kConnected &&
399 it->guid == network_guid)
400 return true;
403 return false;
406 bool WifiManagerNonChromeos::WifiServiceWrapper::FindAndConfigureNetwork(
407 const std::string& ssid,
408 const std::string& password,
409 std::string* network_guid) {
410 std::string provisional_network_guid;
411 NetworkPropertiesList network_property_list;
412 GetSSIDListInternal(&network_property_list);
414 for (size_t i = 0; i < network_property_list.size(); i++) {
415 // TODO(noamsml): Handle case where there are multiple networks with the
416 // same SSID but different security.
417 if (network_property_list[i].ssid == ssid) {
418 provisional_network_guid = network_property_list[i].guid;
419 break;
423 if (provisional_network_guid.empty())
424 return false;
426 scoped_ptr<base::DictionaryValue> properties = MakeProperties(ssid, password);
428 std::string error_string;
429 wifi_service_->SetProperties(
430 provisional_network_guid, properties.Pass(), &error_string);
432 if (!error_string.empty()) {
433 LOG(ERROR) << "Could not set properties on network: " << error_string;
434 return false;
437 *network_guid = provisional_network_guid;
438 return true;
441 void WifiManagerNonChromeos::WifiServiceWrapper::PostClosure(
442 const base::Closure& closure) {
443 callback_runner_->PostTask(
444 FROM_HERE,
445 base::Bind(&WifiManagerNonChromeos::PostClosure, wifi_manager_, closure));
448 #if defined(OS_WIN)
449 void WifiManagerNonChromeos::WifiServiceWrapper::PostCredentialsCallback(
450 const WifiManager::CredentialsCallback& callback,
451 const std::string& ssid,
452 bool success,
453 const std::string& password) {
454 PostClosure(base::Bind(callback, success, ssid, password));
457 #endif // OS_WIN
459 scoped_ptr<WifiManager> WifiManager::CreateDefault() {
460 return scoped_ptr<WifiManager>(new WifiManagerNonChromeos());
463 WifiManagerNonChromeos::WifiManagerNonChromeos()
464 : wifi_wrapper_(NULL), weak_factory_(this) {
467 WifiManagerNonChromeos::~WifiManagerNonChromeos() {
468 if (wifi_wrapper_) {
469 content::BrowserThread::DeleteSoon(
470 content::BrowserThread::FILE, FROM_HERE, wifi_wrapper_);
474 void WifiManagerNonChromeos::Start() {
475 DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
476 task_runner_ = content::BrowserThread::GetMessageLoopProxyForThread(
477 content::BrowserThread::FILE);
479 // Allocated on UI thread, but all initialization is done on file
480 // thread. Destroyed on file thread, which should be safe since all of the
481 // thread-unsafe members are created on the file thread.
482 wifi_wrapper_ = new WifiServiceWrapper(weak_factory_.GetWeakPtr());
484 task_runner_->PostTask(
485 FROM_HERE,
486 base::Bind(&WifiServiceWrapper::Start, wifi_wrapper_->AsWeakPtr()));
489 void WifiManagerNonChromeos::GetSSIDList(const SSIDListCallback& callback) {
490 DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
491 task_runner_->PostTask(FROM_HERE,
492 base::Bind(&WifiServiceWrapper::GetSSIDList,
493 wifi_wrapper_->AsWeakPtr(),
494 callback));
497 void WifiManagerNonChromeos::RequestScan() {
498 DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
499 task_runner_->PostTask(
500 FROM_HERE,
501 base::Bind(&WifiServiceWrapper::RequestScan, wifi_wrapper_->AsWeakPtr()));
504 void WifiManagerNonChromeos::OnNetworkListChanged(
505 scoped_ptr<NetworkPropertiesList> ssid_list) {
506 DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
507 FOR_EACH_OBSERVER(NetworkListObserver,
508 network_list_observers_,
509 OnNetworkListChanged(*ssid_list));
512 void WifiManagerNonChromeos::PostClosure(const base::Closure& callback) {
513 DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
514 callback.Run();
517 void WifiManagerNonChromeos::PostSSIDListCallback(
518 const SSIDListCallback& callback,
519 scoped_ptr<NetworkPropertiesList> ssid_list) {
520 callback.Run(*ssid_list);
523 void WifiManagerNonChromeos::ConfigureAndConnectNetwork(
524 const std::string& ssid,
525 const WifiCredentials& credentials,
526 const SuccessCallback& callback) {
527 DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
528 task_runner_->PostTask(
529 FROM_HERE,
530 base::Bind(&WifiServiceWrapper::ConfigureAndConnectPskNetwork,
531 wifi_wrapper_->AsWeakPtr(),
532 ssid,
533 credentials.psk,
534 callback));
537 void WifiManagerNonChromeos::ConnectToNetworkByID(
538 const std::string& internal_id,
539 const SuccessCallback& callback) {
540 DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
541 task_runner_->PostTask(FROM_HERE,
542 base::Bind(&WifiServiceWrapper::ConnectToNetworkByID,
543 wifi_wrapper_->AsWeakPtr(),
544 internal_id,
545 callback));
548 void WifiManagerNonChromeos::RequestNetworkCredentials(
549 const std::string& ssid,
550 const CredentialsCallback& callback) {
551 DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
552 task_runner_->PostTask(
553 FROM_HERE,
554 base::Bind(&WifiServiceWrapper::RequestNetworkCredentials,
555 wifi_wrapper_->AsWeakPtr(),
556 ssid,
557 callback));
560 void WifiManagerNonChromeos::AddNetworkListObserver(
561 NetworkListObserver* observer) {
562 network_list_observers_.AddObserver(observer);
565 void WifiManagerNonChromeos::RemoveNetworkListObserver(
566 NetworkListObserver* observer) {
567 network_list_observers_.RemoveObserver(observer);
570 } // namespace wifi
572 } // namespace local_discovery