Update To 11.40.268.0
[platform/framework/web/crosswalk.git] / src / chrome / browser / local_discovery / wifi / wifi_manager_nonchromeos.cc
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.
4
5 #include "chrome/browser/local_discovery/wifi/wifi_manager_nonchromeos.h"
6
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"
14
15 #if defined(OS_WIN)
16 #include "chrome/browser/local_discovery/wifi/credential_getter_win.h"
17 #endif  // OS_WIN
18
19 using ::wifi::WiFiService;
20
21 namespace local_discovery {
22
23 namespace wifi {
24
25 namespace {
26
27 const int kConnectionTimeoutSeconds = 10;
28
29 scoped_ptr<base::DictionaryValue> MakeProperties(const std::string& ssid,
30                                                  const std::string& password) {
31   scoped_ptr<base::DictionaryValue> properties(new base::DictionaryValue);
32
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);
36
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);
45   }
46
47   return properties.Pass();
48 }
49
50 }  // namespace
51
52 class WifiManagerNonChromeos::WifiServiceWrapper
53     : public net::NetworkChangeNotifier::NetworkChangeObserver {
54  public:
55   explicit WifiServiceWrapper(
56       base::WeakPtr<WifiManagerNonChromeos> wifi_manager);
57
58   ~WifiServiceWrapper() override;
59
60   void Start();
61
62   void GetSSIDList(const WifiManager::SSIDListCallback& callback);
63
64   void ConfigureAndConnectPskNetwork(
65       const std::string& ssid,
66       const std::string& password,
67       const WifiManager::SuccessCallback& callback);
68
69   base::WeakPtr<WifiManagerNonChromeos::WifiServiceWrapper> AsWeakPtr();
70
71   void RequestScan();
72
73   void ConnectToNetworkByID(const std::string& network_guid,
74                             const WifiManager::SuccessCallback& callback);
75
76   void RequestNetworkCredentials(
77       const std::string& ssid,
78       const WifiManager::CredentialsCallback& callback);
79
80  private:
81   // net::NetworkChangeNotifier::NetworkChangeObserver implementation.
82   void OnNetworkChanged(
83       net::NetworkChangeNotifier::ConnectionType type) override;
84
85   void GetSSIDListInternal(NetworkPropertiesList* ssid_list);
86
87   void OnNetworkListChangedEvent(const std::vector<std::string>& network_guids);
88
89   void OnNetworksChangedEvent(const std::vector<std::string>& network_guids);
90
91   std::string GetConnectedGUID();
92
93   bool IsConnected(const std::string& network_guid);
94
95   void OnConnectToNetworkTimeout();
96
97   void PostClosure(const base::Closure& closure);
98
99   bool FindAndConfigureNetwork(const std::string& ssid,
100                                const std::string& password,
101                                std::string* network_guid);
102
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
109
110   scoped_ptr<WiFiService> wifi_service_;
111
112   base::WeakPtr<WifiManagerNonChromeos> wifi_manager_;
113
114   WifiManager::SuccessCallback connect_success_callback_;
115   base::CancelableClosure connect_failure_callback_;
116
117   // SSID of previously connected network.
118   std::string connected_network_guid_;
119
120   // SSID of network we are connecting to.
121   std::string connecting_network_guid_;
122
123   scoped_refptr<base::MessageLoopProxy> callback_runner_;
124
125   base::WeakPtrFactory<WifiServiceWrapper> weak_factory_;
126
127 #if defined(OS_WIN)
128   scoped_refptr<CredentialGetterWin> credential_getter_;
129 #endif  // OS_WIN
130
131   DISALLOW_COPY_AND_ASSIGN(WifiServiceWrapper);
132 };
133
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) {
139 }
140
141 WifiManagerNonChromeos::WifiServiceWrapper::~WifiServiceWrapper() {
142   net::NetworkChangeNotifier::RemoveNetworkChangeObserver(this);
143 }
144
145 void WifiManagerNonChromeos::WifiServiceWrapper::Start() {
146   DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::FILE));
147   wifi_service_.reset(WiFiService::Create());
148
149   wifi_service_->Initialize(base::MessageLoopProxy::current());
150
151   wifi_service_->SetEventObservers(
152       base::MessageLoopProxy::current(),
153       base::Bind(&WifiServiceWrapper::OnNetworksChangedEvent, AsWeakPtr()),
154       base::Bind(&WifiServiceWrapper::OnNetworkListChangedEvent, AsWeakPtr()));
155
156   net::NetworkChangeNotifier::AddNetworkChangeObserver(this);
157 }
158
159 void WifiManagerNonChromeos::WifiServiceWrapper::GetSSIDList(
160     const WifiManager::SSIDListCallback& callback) {
161   DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::FILE));
162
163   scoped_ptr<NetworkPropertiesList> ssid_list(new NetworkPropertiesList);
164   GetSSIDListInternal(ssid_list.get());
165
166   callback_runner_->PostTask(
167       FROM_HERE,
168       base::Bind(&WifiManagerNonChromeos::PostSSIDListCallback,
169                  wifi_manager_,
170                  callback,
171                  base::Passed(&ssid_list)));
172 }
173
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);
180
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);
186
187   if (error_string.empty()) {
188     ConnectToNetworkByID(network_guid, callback);
189     return;
190   }
191
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 */));
199   }
200 }
201
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)));
212 }
213
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;
220   }
221
222   connecting_network_guid_.clear();
223   connect_failure_callback_.Cancel();
224
225   if (!connect_success_callback_.is_null())
226     PostClosure(base::Bind(connect_success_callback_, true));
227
228   connect_success_callback_.Reset();
229 }
230
231 base::WeakPtr<WifiManagerNonChromeos::WifiServiceWrapper>
232 WifiManagerNonChromeos::WifiServiceWrapper::AsWeakPtr() {
233   return weak_factory_.GetWeakPtr();
234 }
235
236 void WifiManagerNonChromeos::WifiServiceWrapper::RequestScan() {
237   DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::FILE));
238   wifi_service_->RequestNetworkScan();
239 }
240
241 void WifiManagerNonChromeos::WifiServiceWrapper::ConnectToNetworkByID(
242     const std::string& network_guid,
243     const WifiManager::SuccessCallback& callback) {
244   DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::FILE));
245
246   std::string connected_network_id = GetConnectedGUID();
247   std::string error_string;
248   wifi_service_->StartConnect(network_guid, &error_string);
249
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;
255   }
256
257   if (IsConnected(network_guid)) {
258     if (!callback.is_null())
259       PostClosure(base::Bind(callback, true /* success */));
260     return;
261   }
262
263   connect_success_callback_ = callback;
264   connecting_network_guid_ = network_guid;
265   connected_network_guid_ = connected_network_id;
266
267   connect_failure_callback_.Reset(base::Bind(
268       &WifiServiceWrapper::OnConnectToNetworkTimeout, base::Unretained(this)));
269
270   base::MessageLoop::current()->PostDelayedTask(
271       FROM_HERE,
272       connect_failure_callback_.callback(),
273       base::TimeDelta::FromSeconds(kConnectionTimeoutSeconds));
274 }
275
276 void WifiManagerNonChromeos::WifiServiceWrapper::OnConnectToNetworkTimeout() {
277   bool connected = IsConnected(connecting_network_guid_);
278   std::string error_string;
279
280   WifiManager::SuccessCallback connect_success_callback =
281       connect_success_callback_;
282
283   connect_success_callback_.Reset();
284
285   connecting_network_guid_.clear();
286
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);
291
292   PostClosure(base::Bind(connect_success_callback, connected /* success */));
293 }
294
295 void WifiManagerNonChromeos::WifiServiceWrapper::RequestNetworkCredentials(
296     const std::string& ssid,
297     const WifiManager::CredentialsCallback& callback) {
298   DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::FILE));
299
300   bool success = true;
301   std::string guid;
302   std::string key;
303
304   NetworkPropertiesList network_list;
305
306   GetSSIDListInternal(&network_list);
307
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;
314     }
315   }
316
317   if (guid.empty()) {
318     success = false;
319   }
320
321   if (!success) {
322     PostClosure(base::Bind(callback, success, "", ""));
323     return;
324   }
325
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);
338
339     if (!error_string.empty()) {
340       LOG(ERROR) << "Could not get key from system: " << error_string;
341       success = false;
342     }
343
344     PostClosure(base::Bind(callback, success, ssid, key));
345   }
346 #endif  // OS_WIN
347 }
348
349 void WifiManagerNonChromeos::WifiServiceWrapper::OnNetworkChanged(
350     net::NetworkChangeNotifier::ConnectionType type) {
351   wifi_service_->RequestConnectedNetworkUpdate();
352 }
353
354 void WifiManagerNonChromeos::WifiServiceWrapper::GetSSIDListInternal(
355     NetworkPropertiesList* ssid_list) {
356   base::ListValue visible_networks;
357
358   wifi_service_->GetVisibleNetworks(
359       onc::network_type::kWiFi, &visible_networks, true);
360
361   for (size_t i = 0; i < visible_networks.GetSize(); i++) {
362     const base::DictionaryValue* network_value = NULL;
363     NetworkProperties network_properties;
364
365     if (!visible_networks.GetDictionary(i, &network_value)) {
366       NOTREACHED();
367     }
368
369     network_properties.UpdateFromValue(*network_value);
370
371     ssid_list->push_back(network_properties);
372   }
373 }
374
375 std::string WifiManagerNonChromeos::WifiServiceWrapper::GetConnectedGUID() {
376   NetworkPropertiesList ssid_list;
377   GetSSIDListInternal(&ssid_list);
378
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;
384   }
385
386   return "";
387 }
388
389 bool WifiManagerNonChromeos::WifiServiceWrapper::IsConnected(
390     const std::string& network_guid) {
391   NetworkPropertiesList ssid_list;
392   GetSSIDListInternal(&ssid_list);
393
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;
400   }
401
402   return false;
403 }
404
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);
412
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;
419     }
420   }
421
422   if (provisional_network_guid.empty())
423     return false;
424
425   scoped_ptr<base::DictionaryValue> properties = MakeProperties(ssid, password);
426
427   std::string error_string;
428   wifi_service_->SetProperties(
429       provisional_network_guid, properties.Pass(), &error_string);
430
431   if (!error_string.empty()) {
432     LOG(ERROR) << "Could not set properties on network: " << error_string;
433     return false;
434   }
435
436   *network_guid = provisional_network_guid;
437   return true;
438 }
439
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));
445 }
446
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));
454 }
455
456 #endif  // OS_WIN
457
458 scoped_ptr<WifiManager> WifiManager::CreateDefault() {
459   return scoped_ptr<WifiManager>(new WifiManagerNonChromeos());
460 }
461
462 WifiManagerNonChromeos::WifiManagerNonChromeos()
463     : wifi_wrapper_(NULL), weak_factory_(this) {
464 }
465
466 WifiManagerNonChromeos::~WifiManagerNonChromeos() {
467   if (wifi_wrapper_) {
468     content::BrowserThread::DeleteSoon(
469         content::BrowserThread::FILE, FROM_HERE, wifi_wrapper_);
470   }
471 }
472
473 void WifiManagerNonChromeos::Start() {
474   DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
475   task_runner_ = content::BrowserThread::GetMessageLoopProxyForThread(
476       content::BrowserThread::FILE);
477
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());
482
483   task_runner_->PostTask(
484       FROM_HERE,
485       base::Bind(&WifiServiceWrapper::Start, wifi_wrapper_->AsWeakPtr()));
486 }
487
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));
494 }
495
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()));
501 }
502
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));
509 }
510
511 void WifiManagerNonChromeos::PostClosure(const base::Closure& callback) {
512   DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
513   callback.Run();
514 }
515
516 void WifiManagerNonChromeos::PostSSIDListCallback(
517     const SSIDListCallback& callback,
518     scoped_ptr<NetworkPropertiesList> ssid_list) {
519   callback.Run(*ssid_list);
520 }
521
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));
534 }
535
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));
545 }
546
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));
557 }
558
559 void WifiManagerNonChromeos::AddNetworkListObserver(
560     NetworkListObserver* observer) {
561   network_list_observers_.AddObserver(observer);
562 }
563
564 void WifiManagerNonChromeos::RemoveNetworkListObserver(
565     NetworkListObserver* observer) {
566   network_list_observers_.RemoveObserver(observer);
567 }
568
569 }  // namespace wifi
570
571 }  // namespace local_discovery