Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(893)

Side by Side Diff: chrome/browser/local_discovery/wifi/wifi_manager_nonchromeos.cc

Issue 226883002: WiFi client for GCD bootstrapping (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Created 6 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
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
14 using ::wifi::WiFiService;
15
16 namespace local_discovery {
17
18 namespace wifi {
19
20 namespace {
21
22 const int kConnectionTimeoutSeconds = 10;
23
24 scoped_ptr<base::DictionaryValue> MakeProperties(const std::string& ssid,
25 const std::string& password) {
26 scoped_ptr<base::DictionaryValue> properties(new base::DictionaryValue);
27
28 properties->SetString(onc::network_config::kType, onc::network_type::kWiFi);
29 base::DictionaryValue* wifi = new base::DictionaryValue;
30 properties->Set(onc::network_config::kWiFi, wifi);
31
32 wifi->SetString(onc::wifi::kSSID, ssid);
33 if (!password.empty()) {
34 wifi->SetString(onc::wifi::kPassphrase, password);
35 // TODO(noamsml): Allow choosing security mechanism in a more fine-grained
36 // manner.
37 wifi->SetString(onc::wifi::kSecurity, onc::wifi::kWPA2_PSK);
38 } else {
39 wifi->SetString(onc::wifi::kSecurity, onc::wifi::kNone);
40 }
41
42 return properties.Pass();
43 }
44
45 } // namespace
46
47 class WifiManagerNonChromeos::WifiServiceWrapper {
48 public:
49 explicit WifiServiceWrapper(
50 base::WeakPtr<WifiManagerNonChromeos> wifi_manager);
51
52 ~WifiServiceWrapper();
53
54 void Start();
55
56 void GetSSIDList(const WifiManager::SSIDListCallback& callback);
57
58 void ConfigureAndConnectPskNetwork(
59 const std::string& ssid,
60 const std::string& password,
61 const WifiManager::SuccessCallback& callback);
62
63 base::WeakPtr<WifiManagerNonChromeos::WifiServiceWrapper> AsWeakPtr();
64
65 void RequestScan();
66
67 void ConnectToNetworkByID(const std::string& network_guid,
68 const WifiManager::SuccessCallback& callback);
69
70 void RequestNetworkCredentials(
71 const std::string& network_guid,
72 const WifiManager::CredentialsCallback& callback);
73
74 private:
75 void GetSSIDListInternal(NetworkPropertiesList* ssid_list);
76
77 void OnNetworkListChangedEvent(const std::vector<std::string>& network_guids);
78
79 void OnNetworksChangedEvent(const std::vector<std::string>& network_guids);
80
81 std::string GetConnectedGUID();
82
83 bool IsConnected(const std::string& network_guid);
84
85 void OnConnectToNetworkTimeout();
86
87 void PostClosure(const base::Closure& closure);
88
89 bool FindAndConfigureNetwork(const std::string& ssid,
90 const std::string& password,
91 std::string* network_guid);
92
93 scoped_ptr<WiFiService> wifi_service_;
94
95 base::WeakPtr<WifiManagerNonChromeos> wifi_manager_;
96
97 WifiManager::SuccessCallback connect_success_callback_;
98 base::CancelableClosure connect_failure_callback_;
99
100 // SSID of previously connected network.
101 std::string connected_network_guid_;
102
103 // SSID of network we are connecting to.
104 std::string connecting_network_guid_;
105
106 scoped_refptr<base::MessageLoopProxy> callback_runner_;
107
108 base::WeakPtrFactory<WifiServiceWrapper> weak_factory_;
109
110 DISALLOW_COPY_AND_ASSIGN(WifiServiceWrapper);
111 };
112
113 WifiManagerNonChromeos::WifiServiceWrapper::WifiServiceWrapper(
114 base::WeakPtr<WifiManagerNonChromeos> wifi_manager)
115 : wifi_manager_(wifi_manager),
116 callback_runner_(base::MessageLoopProxy::current()),
117 weak_factory_(this) {
118 }
119
120 WifiManagerNonChromeos::WifiServiceWrapper::~WifiServiceWrapper() {
121 }
122
123 void WifiManagerNonChromeos::WifiServiceWrapper::Start() {
124 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::FILE));
125 wifi_service_.reset(WiFiService::Create());
126
127 wifi_service_->Initialize(base::MessageLoopProxy::current());
128
129 wifi_service_->SetEventObservers(
130 base::MessageLoopProxy::current(),
131 base::Bind(&WifiServiceWrapper::OnNetworksChangedEvent,
mef 2014/05/30 20:48:32 FYI, on Mac this works off regular Network Change
Noam Samuel 2014/05/30 22:04:42 Added NetworkChangeNotifier subscription
132 base::Unretained(this)),
133 base::Bind(&WifiServiceWrapper::OnNetworkListChangedEvent,
134 base::Unretained(this)));
135 }
136
137 void WifiManagerNonChromeos::WifiServiceWrapper::GetSSIDList(
138 const WifiManager::SSIDListCallback& callback) {
139 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::FILE));
140
141 scoped_ptr<NetworkPropertiesList> ssid_list(new NetworkPropertiesList);
142 GetSSIDListInternal(ssid_list.get());
143
144 callback_runner_->PostTask(
145 FROM_HERE,
146 base::Bind(&WifiManagerNonChromeos::PostSSIDListCallback,
147 wifi_manager_,
148 callback,
149 base::Passed(&ssid_list)));
150 }
151
152 void WifiManagerNonChromeos::WifiServiceWrapper::ConfigureAndConnectPskNetwork(
153 const std::string& ssid,
154 const std::string& password,
155 const WifiManager::SuccessCallback& callback) {
156 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::FILE));
157 scoped_ptr<base::DictionaryValue> properties = MakeProperties(ssid, password);
158
159 std::string network_guid;
160 std::string error_string;
161 // Will fail without changing system state if network already exists.
162 wifi_service_->CreateNetwork(
163 false, properties.Pass(), &network_guid, &error_string);
164
165 if (error_string.empty()) {
166 ConnectToNetworkByID(network_guid, callback);
167 return;
168 }
169
170 // If we cannot create the network, attempt to configure and connect to an
171 // existing network.
172 if (FindAndConfigureNetwork(ssid, password, &network_guid)) {
173 ConnectToNetworkByID(network_guid, callback);
174 } else {
175 PostClosure(base::Bind(callback, false /* success */));
176 }
177 }
178
179 void WifiManagerNonChromeos::WifiServiceWrapper::OnNetworkListChangedEvent(
180 const std::vector<std::string>& network_guids) {
181 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::FILE));
182 scoped_ptr<NetworkPropertiesList> ssid_list(new NetworkPropertiesList);
183 GetSSIDListInternal(ssid_list.get());
184 callback_runner_->PostTask(
185 FROM_HERE,
186 base::Bind(&WifiManagerNonChromeos::OnNetworkListChanged,
187 wifi_manager_,
188 base::Passed(&ssid_list)));
189 }
190
191 void WifiManagerNonChromeos::WifiServiceWrapper::OnNetworksChangedEvent(
192 const std::vector<std::string>& network_guids) {
193 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::FILE));
194 if (connecting_network_guid_.empty() ||
195 !IsConnected(connecting_network_guid_)) {
196 return;
197 }
198
199 connecting_network_guid_.clear();
200 connect_failure_callback_.Cancel();
201
202 PostClosure(base::Bind(connect_success_callback_, true));
203
204 connect_success_callback_.Reset();
205 }
206
207 base::WeakPtr<WifiManagerNonChromeos::WifiServiceWrapper>
208 WifiManagerNonChromeos::WifiServiceWrapper::AsWeakPtr() {
209 return weak_factory_.GetWeakPtr();
210 }
211
212 void WifiManagerNonChromeos::WifiServiceWrapper::RequestScan() {
213 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::FILE));
214 wifi_service_->RequestNetworkScan();
215 }
216
217 void WifiManagerNonChromeos::WifiServiceWrapper::ConnectToNetworkByID(
218 const std::string& network_guid,
219 const WifiManager::SuccessCallback& callback) {
220 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::FILE));
221
222 std::string connected_network_id = GetConnectedGUID();
223 std::string error_string;
224 wifi_service_->StartConnect(network_guid, &error_string);
225
226 if (!error_string.empty()) {
227 LOG(ERROR) << "Could not connect to network by ID: " << error_string;
228 PostClosure(base::Bind(callback, false /* success */));
229 wifi_service_->StartConnect(connected_network_id, &error_string);
230 return;
231 }
232
233 if (IsConnected(network_guid)) {
234 PostClosure(base::Bind(callback, true /* success */));
235 return;
236 }
237
238 connect_success_callback_ = callback;
239 connecting_network_guid_ = network_guid;
240 connected_network_guid_ = connected_network_id;
241
242 connect_failure_callback_.Reset(base::Bind(
243 &WifiServiceWrapper::OnConnectToNetworkTimeout, base::Unretained(this)));
244
245 base::MessageLoop::current()->PostDelayedTask(
246 FROM_HERE,
247 connect_failure_callback_.callback(),
248 base::TimeDelta::FromSeconds(kConnectionTimeoutSeconds));
249 }
250
251 void WifiManagerNonChromeos::WifiServiceWrapper::OnConnectToNetworkTimeout() {
252 bool connected = IsConnected(connecting_network_guid_);
253 std::string error_string;
254
255 // If we did not connect, return to the network the user was originally
256 // connected to.
257 if (!connected)
258 wifi_service_->StartConnect(connected_network_guid_, &error_string);
259
260 connecting_network_guid_.clear();
261
262 PostClosure(base::Bind(connect_success_callback_, connected /* success */));
263
264 connect_success_callback_.Reset();
265 }
266
267 void WifiManagerNonChromeos::WifiServiceWrapper::RequestNetworkCredentials(
268 const std::string& network_guid,
269 const WifiManager::CredentialsCallback& callback) {
270 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::FILE));
271
272 bool success = true;
273 std::string ssid;
274 std::string key;
275
276 #if defined(OS_WIN)
277 NOTIMPLEMENTED();
278 success = false;
279 #else
280 base::DictionaryValue properties;
281 std::string error_string;
282 wifi_service_->GetProperties(network_guid, &properties, &error_string);
283
284 if (!error_string.empty()) {
285 LOG(ERROR) << "Could not get network properties: " << error_string;
286 success = false;
287 }
288
289 if (!properties.GetString(onc::network_config::kName, &ssid)) {
290 LOG(ERROR) << "Could not get network SSID";
291 success = false;
292 }
293
294 if (success) {
295 wifi_service_->GetKeyFromSystem(network_guid, &key, &error_string);
mef 2014/05/30 20:48:32 FYI, on OS X this brings up prompt for admin crede
Noam Samuel 2014/05/30 22:04:42 Added comment on wifi_manager.h
296
297 if (!error_string.empty()) {
298 LOG(ERROR) << "Could not get key from system: " << error_string;
299 success = false;
300 }
301 }
302 #endif // OS_WIN
303 PostClosure(base::Bind(callback, success, ssid, key));
304 }
305
306 void WifiManagerNonChromeos::WifiServiceWrapper::GetSSIDListInternal(
307 NetworkPropertiesList* ssid_list) {
308 base::ListValue visible_networks;
309
310 wifi_service_->GetVisibleNetworks(onc::network_type::kWiFi,
311 &visible_networks);
312
313 for (size_t i = 0; i < visible_networks.GetSize(); i++) {
314 const base::DictionaryValue* network_value = NULL;
315 NetworkProperties network_properties;
316
317 if (!visible_networks.GetDictionary(i, &network_value)) {
318 NOTREACHED();
319 }
320
321 network_properties.UpdateFromValue(*network_value);
322
323 // HACK: On OSX the ssid comes out empty, but the network name is always the
mef 2014/05/30 20:48:32 Can this be fixed in wifi_service_mac.mm instead o
Noam Samuel 2014/05/30 22:04:42 Fixed in network_properties.cc where the problem t
324 // ssid.
325 if (network_properties.ssid.empty()) {
326 network_properties.ssid = network_properties.name;
327 }
328
329 ssid_list->push_back(network_properties);
330 }
331 }
332
333 std::string WifiManagerNonChromeos::WifiServiceWrapper::GetConnectedGUID() {
334 NetworkPropertiesList ssid_list;
335 GetSSIDListInternal(&ssid_list);
336
337 for (NetworkPropertiesList::const_iterator it = ssid_list.begin();
338 it != ssid_list.end();
339 ++it) {
340 if (it->connection_state == onc::connection_state::kConnected)
341 return it->guid;
342 }
343
344 return "";
345 }
346
347 bool WifiManagerNonChromeos::WifiServiceWrapper::IsConnected(
348 const std::string& network_guid) {
349 NetworkPropertiesList ssid_list;
350 GetSSIDListInternal(&ssid_list);
351
352 for (NetworkPropertiesList::const_iterator it = ssid_list.begin();
353 it != ssid_list.end();
354 ++it) {
355 if (it->connection_state == onc::connection_state::kConnected &&
356 it->guid == network_guid)
357 return true;
358 }
359
360 return false;
361 }
362
363 bool WifiManagerNonChromeos::WifiServiceWrapper::FindAndConfigureNetwork(
364 const std::string& ssid,
365 const std::string& password,
366 std::string* network_guid) {
367 std::string provisional_network_guid;
368 NetworkPropertiesList network_property_list;
369 GetSSIDListInternal(&network_property_list);
370
371 for (size_t i = 0; i < network_property_list.size(); i++) {
372 // TODO(noamsml): Handle case where there are multiple networks with the
373 // same SSID but different security.
374 if (network_property_list[i].ssid == ssid) {
375 provisional_network_guid = network_property_list[i].guid;
376 break;
377 }
378 }
379
380 if (provisional_network_guid.empty())
381 return false;
382
383 scoped_ptr<base::DictionaryValue> properties = MakeProperties(ssid, password);
384
385 std::string error_string;
386 wifi_service_->SetProperties(
387 provisional_network_guid, properties.Pass(), &error_string);
388
389 if (!error_string.empty()) {
390 LOG(ERROR) << "Could not set properties on network: " << error_string;
391 return false;
392 }
393
394 *network_guid = provisional_network_guid;
395 return true;
396 }
397
398 void WifiManagerNonChromeos::WifiServiceWrapper::PostClosure(
399 const base::Closure& closure) {
400 callback_runner_->PostTask(
401 FROM_HERE,
402 base::Bind(&WifiManagerNonChromeos::PostClosure, wifi_manager_, closure));
403 }
404
405 scoped_ptr<WifiManager> WifiManager::Create() {
406 return scoped_ptr<WifiManager>(new WifiManagerNonChromeos());
407 }
408
409 WifiManagerNonChromeos::WifiManagerNonChromeos()
410 : wifi_wrapper_(NULL), weak_factory_(this) {
411 }
412
413 WifiManagerNonChromeos::~WifiManagerNonChromeos() {
414 if (wifi_wrapper_) {
415 content::BrowserThread::DeleteSoon(
416 content::BrowserThread::FILE, FROM_HERE, wifi_wrapper_);
417 }
418 }
419
420 void WifiManagerNonChromeos::Start() {
421 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
422 task_runner_ = content::BrowserThread::GetMessageLoopProxyForThread(
423 content::BrowserThread::FILE);
424
425 // Allocated on UI thread, but all initialization is done on file
426 // thread. Destroyed on file thread, which should be safe since all of the
427 // thread-unsafe members are created on the file thread.
428 wifi_wrapper_ = new WifiServiceWrapper(weak_factory_.GetWeakPtr());
429
430 task_runner_->PostTask(
431 FROM_HERE,
432 base::Bind(&WifiServiceWrapper::Start, wifi_wrapper_->AsWeakPtr()));
433 }
434
435 void WifiManagerNonChromeos::GetSSIDList(const SSIDListCallback& callback) {
436 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
437 task_runner_->PostTask(FROM_HERE,
438 base::Bind(&WifiServiceWrapper::GetSSIDList,
439 wifi_wrapper_->AsWeakPtr(),
440 callback));
441 }
442
443 void WifiManagerNonChromeos::RequestScan() {
444 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
445 task_runner_->PostTask(
446 FROM_HERE,
447 base::Bind(&WifiServiceWrapper::RequestScan, wifi_wrapper_->AsWeakPtr()));
448 }
449
450 void WifiManagerNonChromeos::OnNetworkListChanged(
451 scoped_ptr<NetworkPropertiesList> ssid_list) {
452 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
453 FOR_EACH_OBSERVER(NetworkListObserver,
454 network_list_observers_,
455 OnNetworkListChanged(*ssid_list));
456 }
457
458 void WifiManagerNonChromeos::PostClosure(const base::Closure& callback) {
459 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
460 callback.Run();
461 }
462
463 void WifiManagerNonChromeos::PostSSIDListCallback(
464 const SSIDListCallback& callback,
465 scoped_ptr<NetworkPropertiesList> ssid_list) {
466 callback.Run(*ssid_list);
467 }
468
469 void WifiManagerNonChromeos::ConfigureAndConnectNetwork(
470 const std::string& ssid,
471 const WifiCredentials& credentials,
472 const SuccessCallback& callback) {
473 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
474 task_runner_->PostTask(
475 FROM_HERE,
476 base::Bind(&WifiServiceWrapper::ConfigureAndConnectPskNetwork,
477 wifi_wrapper_->AsWeakPtr(),
478 ssid,
479 credentials.psk,
480 callback));
481 }
482
483 void WifiManagerNonChromeos::ConnectToNetworkByID(
484 const std::string& internal_id,
485 const SuccessCallback& callback) {
486 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
487 task_runner_->PostTask(FROM_HERE,
488 base::Bind(&WifiServiceWrapper::ConnectToNetworkByID,
489 wifi_wrapper_->AsWeakPtr(),
490 internal_id,
491 callback));
492 }
493
494 void WifiManagerNonChromeos::RequestNetworkCredentials(
495 const std::string& internal_id,
496 const CredentialsCallback& callback) {
497 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
498 task_runner_->PostTask(
499 FROM_HERE,
500 base::Bind(&WifiServiceWrapper::RequestNetworkCredentials,
501 wifi_wrapper_->AsWeakPtr(),
502 internal_id,
503 callback));
504 }
505
506 void WifiManagerNonChromeos::AddNetworkListObserver(
507 NetworkListObserver* observer) {
508 network_list_observers_.AddObserver(observer);
509 }
510
511 void WifiManagerNonChromeos::RemoveNetworkListObserver(
512 NetworkListObserver* observer) {
513 network_list_observers_.RemoveObserver(observer);
514 }
515
516 } // namespace wifi
517
518 } // namespace local_discovery
OLDNEW
« no previous file with comments | « chrome/browser/local_discovery/wifi/wifi_manager_nonchromeos.h ('k') | chrome/chrome_browser.gypi » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698