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

Side by Side Diff: chromeos/network/network_state_handler.cc

Issue 11192024: Add chromeos::NetworkStateManager (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Respond to feedback Created 8 years, 1 month 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 | Annotate | Revision Log
OLDNEW
(Empty)
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
3 // found in the LICENSE file.
4
5 #include "chromeos/network/network_state_handler.h"
6
7 #include <algorithm>
pneubeck (no reviews) 2012/10/25 14:42:17 unused?
stevenjb 2012/10/25 22:05:22 Removed
8
9 #include "base/bind.h"
10 #include "base/stl_util.h"
11 #include "base/string_util.h"
12 #include "base/values.h"
13 #include "chromeos/dbus/dbus_thread_manager.h"
14 #include "chromeos/dbus/shill_device_client.h"
15 #include "chromeos/dbus/shill_ipconfig_client.h"
16 #include "chromeos/dbus/shill_manager_client.h"
17 #include "chromeos/dbus/shill_service_client.h"
18 #include "chromeos/network/device_state.h"
19 #include "chromeos/network/managed_state.h"
20 #include "chromeos/network/network_state.h"
21 #include "chromeos/network/network_state_handler_observer.h"
22 #include "chromeos/network/network_service_observer.h"
23 #include "dbus/object_path.h"
24
25 namespace {
26
27 void ErrorCallbackFunction(const std::string& error_name,
28 const std::string& error_message) {
29 // TODO(stevenjb): Add error logging.
30 LOG(ERROR) << "Shill Error: " << error_name << " : " << error_message;
31 }
32
33 const base::ListValue* GetListValue(const std::string& key,
34 const base::Value& value) {
35 const base::ListValue* vlist = NULL;
36 if (!value.GetAsList(&vlist)) {
37 LOG(ERROR) << "Error parsing key as list: " << key;
38 return NULL;
39 }
40 return vlist;
41 }
42
43 }
44
45 namespace chromeos {
46
47 NetworkStateHandler::NetworkStateHandler()
48 : shill_manager_(DBusThreadManager::Get()->GetShillManagerClient()),
49 weak_ptr_factory_(this) {
50 }
51
52 NetworkStateHandler::~NetworkStateHandler() {
53 STLDeleteContainerPointers(network_list_.begin(), network_list_.end());
54 // Delete network service observers.
55 STLDeleteContainerPairSecondPointers(
56 observed_networks_.begin(), observed_networks_.end());
57 CHECK(shill_manager_ == DBusThreadManager::Get()->GetShillManagerClient());
58 shill_manager_->RemovePropertyChangedObserver(this);
59 }
60
61 void NetworkStateHandler::Init() {
62 shill_manager_->GetProperties(
63 base::Bind(&NetworkStateHandler::ManagerPropertiesCallback,
64 weak_ptr_factory_.GetWeakPtr()));
65 shill_manager_->AddPropertyChangedObserver(this);
66 }
67
68 void NetworkStateHandler::AddObserver(NetworkStateHandlerObserver* observer) {
69 observers_.AddObserver(observer);
70 }
71
72 void NetworkStateHandler::RemoveObserver(
73 NetworkStateHandlerObserver* observer) {
74 observers_.RemoveObserver(observer);
75 }
76
77 bool NetworkStateHandler::TechnologyAvailable(
78 const std::string& technology) const {
79 return available_technologies_.find(technology) !=
80 available_technologies_.end();
81 }
82
83 bool NetworkStateHandler::TechnologyEnabled(
84 const std::string& technology) const {
85 return enabled_technologies_.find(technology) !=
86 enabled_technologies_.end();
87 }
88
89 void NetworkStateHandler::SetTechnologyEnabled(const std::string& technology,
90 bool enabled) {
91 if (enabled) {
92 shill_manager_->EnableTechnology(technology,
93 base::Bind(&base::DoNothing),
94 base::Bind(&ErrorCallbackFunction));
95 } else {
96 shill_manager_->DisableTechnology(technology,
97 base::Bind(&base::DoNothing),
98 base::Bind(&ErrorCallbackFunction));
99 }
100 }
101
102 const DeviceState* NetworkStateHandler::GetDeviceState(
103 const std::string& path) const {
104 return const_cast<NetworkStateHandler*>(this)->GetModifiableDeviceState(path);
pneubeck (no reviews) 2012/10/25 14:42:17 I understand that for public functions. But why wo
stevenjb 2012/10/25 22:05:22 Yeah, I see your point. It seems a bit awkward, bu
105 }
106
107 const DeviceState* NetworkStateHandler::GetDeviceStateByType(
108 const std::string& type) const {
109 for (DeviceStateList::const_iterator iter = device_list_.begin();
110 iter != device_list_.end(); ++iter) {
111 const DeviceState* device = *iter;
112 if (device->type() == type)
113 return device;
114 }
115 return NULL;
116 }
117
118 const NetworkState* NetworkStateHandler::GetNetworkState(
119 const std::string& path) const {
120 return const_cast<NetworkStateHandler*>(this)->GetModifiableNetworkState(
121 path);
122 }
123
124 const NetworkState* NetworkStateHandler::ActiveNetwork() const {
125 if (network_list_.empty())
126 return NULL;
127 const NetworkState* network = network_list_.front();
128 if (!network->IsConnectedState())
129 return NULL;
130 return network;
131 }
132
133 const NetworkState* NetworkStateHandler::ConnectedNetworkByType(
134 const std::string& type) const {
135 for (NetworkStateList::const_iterator iter = network_list_.begin();
136 iter != network_list_.end(); ++iter) {
137 const NetworkState* network = *iter;
138 if (!network->IsConnectedState())
139 break; // Connected networks are listed first.
140 if (network->type() == type)
141 return network;
142 }
143 return NULL;
144 }
145
146 const NetworkState* NetworkStateHandler::ConnectingNetworkByType(
147 const std::string& type) const {
148 for (NetworkStateList::const_iterator iter = network_list_.begin();
149 iter != network_list_.end(); ++iter) {
150 const NetworkState* network = *iter;
151 if (network->IsConnectedState())
152 continue;
153 if (!network->IsConnectingState())
154 break; // Connected and connecting networks are listed first.
155 if (network->type() == type ||
156 (type.empty() && type != flimflam::kTypeEthernet)) {
157 return network;
158 }
159 }
160 return NULL;
161 }
162
163 std::string NetworkStateHandler::HardwareAddress(
164 const std::string& type) const {
165 std::string result;
166 const NetworkState* network = ConnectedNetworkByType(type);
167 if (network) {
168 const DeviceState* device = GetDeviceState(network->device_path());
169 if (device)
170 result = device->mac_address();
171 }
172 StringToUpperASCII(&result);
173 return result;
174 }
175
176 std::string NetworkStateHandler::HardwareAddressFormatted(
177 const std::string& type) const {
178 std::string address = HardwareAddress(type);
179 if (address.size() % 2 != 0)
180 return address;
181 std::string result;
182 for (size_t i = 0; i < address.size(); ++i) {
183 if ((i != 0) && (i % 2 == 0))
184 result.push_back(':');
185 result.push_back(address[i]);
186 }
187 return result;
188 }
189
190 const NetworkStateHandler::NetworkStateList&
191 NetworkStateHandler::GetNetworkList() const {
192 RequestScan();
pneubeck (no reviews) 2012/10/25 14:42:17 Why not expose RequestScan publicly and remove it
stevenjb 2012/10/25 22:05:22 We decidedly to explicitly not expose RequestScan.
193 return network_list_;
194 }
195
196 void NetworkStateHandler::OnPropertyChanged(const std::string& key,
197 const base::Value& value) {
198 if (ManagerPropertyChanged(key, value))
199 FOR_EACH_OBSERVER(NetworkStateHandlerObserver, observers_,
200 NetworkManagerChanged(key));
201 }
202
203 //------------------------------------------------------------------------------
204 // Private methods
205
206 DeviceState* NetworkStateHandler::GetModifiableDeviceState(
207 const std::string& path) {
208 for (DeviceStateList::iterator iter = device_list_.begin();
209 iter != device_list_.end(); ++iter) {
210 DeviceState* device = *iter;
211 if (device->path() == path)
212 return device;
213 }
214 return NULL;
215 }
216
217 NetworkState* NetworkStateHandler::GetModifiableNetworkState(
218 const std::string& path) {
219 for (NetworkStateList::iterator iter = network_list_.begin();
220 iter != network_list_.end(); ++iter) {
221 NetworkState* network = *iter;
222 if (network->path() == path)
223 return network;
224 }
225 return NULL;
226 }
227
228 void NetworkStateHandler::ManagerPropertiesCallback(
229 DBusMethodCallStatus call_status,
230 const base::DictionaryValue& properties) {
231 if (call_status != DBUS_METHOD_CALL_SUCCESS) {
232 LOG(ERROR) << "Failed to get Manager properties:" << call_status;
233 return;
234 }
235 bool notify = false;
236 for (base::DictionaryValue::key_iterator iter = properties.begin_keys();
pneubeck (no reviews) 2012/10/25 14:42:17 You could use DictionaryValue::Iterator in this ca
stevenjb 2012/10/25 22:05:22 I'd never seen that before. Nice. Done.
237 iter != properties.end_keys(); ++iter) {
238 const std::string& key = *iter;
239 const base::Value* value;
240 bool res = properties.GetWithoutPathExpansion(key, &value);
241 if (res)
242 notify |= ManagerPropertyChanged(key, *value);
243 else
244 LOG(ERROR) << "Error getting value for key: " << key;
245 }
246 if (notify) {
247 FOR_EACH_OBSERVER(NetworkStateHandlerObserver, observers_,
248 NetworkManagerChanged(std::string()));
249 }
250 }
251
252 bool NetworkStateHandler::ManagerPropertyChanged(const std::string& key,
253 const base::Value& value) {
254 bool notify_manager_changed = false;
255 if (key == flimflam::kServicesProperty) {
256 const base::ListValue* vlist = GetListValue(key, value);
257 if (vlist) {
258 UpdateManagedList(ManagedState::MANAGED_TYPE_NETWORK, *vlist);
259 // Do not send an UpdateManagerChanged notification to observers.
260 // An UpdateNetworkList notification will be sent when the service list
261 // updates have completed.
262 }
263 } else if (key == flimflam::kDevicesProperty) {
264 const ListValue* vlist = GetListValue(key, value);
265 if (vlist) {
266 UpdateManagedList(ManagedState::MANAGED_TYPE_DEVICE, *vlist);
267 notify_manager_changed = true;
268 }
269 } else if (key == flimflam::kAvailableTechnologiesProperty) {
270 const base::ListValue* vlist = GetListValue(key, value);
271 if (vlist ) {
272 UpdateAvailableTechnologies(*vlist);
273 notify_manager_changed = true;
274 }
275 } else if (key == flimflam::kEnabledTechnologiesProperty) {
276 const base::ListValue* vlist = GetListValue(key, value);
277 if (vlist) {
278 UpdateEnabledTechnologies(*vlist);
279 notify_manager_changed = true;
280 }
281 }
282 return notify_manager_changed;
283 }
284
285 NetworkStateHandler::ManagedStateList* NetworkStateHandler::GetManagedList(
286 ManagedState::ManagedType type) {
287 // Use reinterpret_cast here to avoid copying the list to a list of identical
pneubeck (no reviews) 2012/10/25 14:42:17 Copying a vector<*> of about 10 entries should be
stevenjb 2012/10/25 22:05:22 I have had difficulty stepping through templated f
288 // base class pointers.
289 switch(type) {
290 case ManagedState::MANAGED_TYPE_NETWORK:
291 return reinterpret_cast<ManagedStateList*>(&network_list_);
292 case ManagedState::MANAGED_TYPE_DEVICE:
293 return reinterpret_cast<ManagedStateList*>(&device_list_);
294 }
295 return NULL;
296 }
297
298 void NetworkStateHandler::UpdateManagedList(ManagedState::ManagedType type,
299 const base::ListValue& entries) {
300 ManagedStateList* managed_list = GetManagedList(type);
301 VLOG(2) << "UpdateManagedList: " << type;
302 // Create a map of existing entries.
303 std::map<std::string, ManagedState*> managed_map;
304 for (ManagedStateList::iterator iter = managed_list->begin();
305 iter != managed_list->end(); ++iter) {
306 ManagedState* managed = *iter;
307 managed_map[managed->path()] = managed;
308 }
309 // Clear the list (pointers are owned by managed_map).
310 managed_list->clear();
311 // Updates managed_list and request updates for new entries.
312 for (base::ListValue::const_iterator iter = entries.begin();
313 iter != entries.end(); ++iter) {
314 std::string path;
315 (*iter)->GetAsString(&path);
316 if (path.empty())
317 continue;
318 std::map<std::string, ManagedState*>::iterator found =
319 managed_map.find(path);
320 bool request_properties = false;
321 if (found == managed_map.end()) {
322 request_properties = true;
323 managed_list->push_back(ManagedState::Create(type, path));
324 } else {
325 ManagedState* managed = found->second;
326 managed_list->push_back(managed);
327 managed_map.erase(found);
328 }
329 if (request_properties) {
330 ++pending_updates_[type];
331 RequestProperties(type, path);
332 }
333 }
334 // Delete any remaning entries in managed_map.
335 STLDeleteContainerPairSecondPointers(managed_map.begin(), managed_map.end());
336 }
337
338 void NetworkStateHandler::UpdateObservedNetworkServices() {
339 // Watch any connected or connecting networks.
340 NetworkServiceObserverMap new_observed;
341 for (NetworkStateList::const_iterator iter = network_list_.begin();
342 iter != network_list_.end(); ++iter) {
343 const NetworkState* network = *iter;
344 if (!network->IsConnectedState() && !network->IsConnectingState())
pneubeck (no reviews) 2012/10/25 14:42:17 Doesn't this also mean, that we cannot observe e.g
stevenjb 2012/10/25 22:05:22 Shill does not update the strength or other proper
345 break; // Connected and connecting networks are listed first.
346 const std::string& path = network->path();
347 NetworkServiceObserverMap::iterator iter = observed_networks_.find(path);
348 if (iter != observed_networks_.end()) {
349 new_observed[path] = observed_networks_[path];
350 } else {
351 new_observed[path] = new NetworkServiceObserver(
352 path, base::Bind(&NetworkStateHandler::NetworkServicePropertyChanged,
353 weak_ptr_factory_.GetWeakPtr()));
354 }
355 observed_networks_.erase(path);
356 }
357 VLOG(2) << "UpdateObservedNetworkServices, new observed: "
358 << new_observed.size();
359 // Delete network service observers still in observed_networks_.
360 STLDeleteContainerPairSecondPointers(
361 observed_networks_.begin(), observed_networks_.end());
362 observed_networks_.swap(new_observed);
363 // Notify observers that the list of networks has changed.
364 FOR_EACH_OBSERVER(NetworkStateHandlerObserver, observers_,
365 NetworkListChanged(network_list_));
366 // Notify observers if the active network has changed.
367 const NetworkState* new_active_network =
368 network_list_.empty() ? NULL : network_list_.front();
369 if (new_active_network->path() != active_network_path_) {
370 active_network_path_ = new_active_network->path();
371 FOR_EACH_OBSERVER(NetworkStateHandlerObserver, observers_,
372 ActiveNetworkChanged(new_active_network));
373 }
374 }
375
376 void NetworkStateHandler::UpdateAvailableTechnologies(
377 const base::ListValue& technologies) {
378 available_technologies_.clear();
379 for (base::ListValue::const_iterator iter = technologies.begin();
380 iter != technologies.end(); ++iter) {
381 std::string technology;
382 (*iter)->GetAsString(&technology);
383 if (technology.empty())
384 continue;
385 available_technologies_.insert(technology);
386 }
387 }
388
389 void NetworkStateHandler::UpdateEnabledTechnologies(
390 const base::ListValue& technologies) {
391 enabled_technologies_.clear();
392 for (base::ListValue::const_iterator iter = technologies.begin();
393 iter != technologies.end(); ++iter) {
394 std::string technology;
395 (*iter)->GetAsString(&technology);
396 if (technology.empty())
397 continue;
398 enabled_technologies_.insert(technology);
399 }
400 }
401
402 void NetworkStateHandler::RequestProperties(ManagedState::ManagedType type,
403 const std::string& path) {
404 switch(type) {
405 case ManagedState::MANAGED_TYPE_NETWORK:
406 DBusThreadManager::Get()->GetShillServiceClient()->GetProperties(
407 dbus::ObjectPath(path),
408 base::Bind(&NetworkStateHandler::GetPropertiesCallback,
409 weak_ptr_factory_.GetWeakPtr(),
410 type, path));
411 break;
412 case ManagedState::MANAGED_TYPE_DEVICE:
413 DBusThreadManager::Get()->GetShillDeviceClient()->GetProperties(
414 dbus::ObjectPath(path),
415 base::Bind(&NetworkStateHandler::GetPropertiesCallback,
416 weak_ptr_factory_.GetWeakPtr(),
417 type, path));
418 break;
419 }
420 }
421
422 void NetworkStateHandler::GetPropertiesCallback(
423 ManagedState::ManagedType type,
424 const std::string& path,
425 DBusMethodCallStatus call_status,
426 const base::DictionaryValue& properties) {
427 VLOG(2) << "GetPropertiesCallback: " << type << " : " << path;
428 --pending_updates_[type];
429 if (call_status != DBUS_METHOD_CALL_SUCCESS) {
430 LOG(ERROR) << "Failed to get properties for: " << path
431 << ": " << call_status;
432 return;
433 }
434 bool found = false;
435 ManagedStateList* list = GetManagedList(type);
436 for (ManagedStateList::iterator iter = list->begin();
pneubeck (no reviews) 2012/10/25 14:42:17 Here, you could use ManagedState* managed = GetMod
stevenjb 2012/10/25 22:05:22 I've been trying to keep Type specific code out of
437 iter != list->end(); ++iter) {
438 ManagedState* managed = *iter;
439 if (managed->path() == path) {
440 ParseProperties(managed, properties);
441 found = true;
442 break;
443 }
444 }
445 if (!found)
446 LOG(ERROR) << "GetPropertiesCallback: " << path << " Not found!";
447 // Notify observers only when all updates for that type have completed.
448 if (type == ManagedState::MANAGED_TYPE_NETWORK &&
449 pending_updates_[type] == 0) {
450 UpdateObservedNetworkServices();
451 }
452 }
453
454 void NetworkStateHandler::ParseProperties(
455 ManagedState* managed,
456 const base::DictionaryValue& properties) {
457 for (base::DictionaryValue::key_iterator iter = properties.begin_keys();
pneubeck (no reviews) 2012/10/25 14:42:17 DictionaryValue::Iterator
stevenjb 2012/10/25 22:05:22 Done.
458 iter != properties.end_keys(); ++iter) {
459 bool success = false;
460 const std::string& key = *iter;
461 // Handle IPConfig here since it requires additional complexity that is
462 // better handled here than in NetworkService::PropertyChanged (e.g.
pneubeck (no reviews) 2012/10/25 14:42:17 NetworkState::PropertyChanged?
stevenjb 2012/10/25 22:05:22 Done.
463 // observer notification).
464 if (key == shill::kIPConfigProperty) {
465 DCHECK(managed->managed_type() == ManagedState::MANAGED_TYPE_NETWORK);
466 std::string ip_config_path;
467 if (properties.GetStringWithoutPathExpansion(key, &ip_config_path)) {
468 DBusThreadManager::Get()->GetShillIPConfigClient()->GetProperties(
pneubeck (no reviews) 2012/10/25 14:42:17 This means, that the state can even be inconsisten
stevenjb 2012/10/25 22:05:22 That's always true; shill will send us single prop
469 dbus::ObjectPath(ip_config_path),
470 base::Bind(&NetworkStateHandler::GetIPConfigCallback,
471 weak_ptr_factory_.GetWeakPtr(),
472 managed->path()));
473 success = true;
474 }
475 } else {
476 const base::Value* value;
477 if (properties.GetWithoutPathExpansion(key, &value))
478 success = managed->PropertyChanged(key, *value);
479 }
480 if (!success)
481 LOG(ERROR) << "Error getting value for key: " << key;
482 }
483 }
484
485 void NetworkStateHandler::NetworkServicePropertyChanged(
486 const std::string& path,
487 const std::string& key,
488 const base::Value& value) {
489 NetworkState* network = GetModifiableNetworkState(path);
490 if (!network)
491 return;
492 if (network->PropertyChanged(key, value)) {
493 FOR_EACH_OBSERVER(NetworkStateHandlerObserver, observers_,
494 NetworkServicePropertyChanged(network, key));
495 if (network == network_list_.front() && key == flimflam::kStateProperty) {
496 FOR_EACH_OBSERVER(NetworkStateHandlerObserver, observers_,
497 ActiveNetworkStateChanged(network));
498 }
499 }
500 }
501
502 void NetworkStateHandler::GetIPConfigCallback(
503 const std::string& path,
pneubeck (no reviews) 2012/10/25 14:42:17 this could be both ipconfig path or service path,
stevenjb 2012/10/25 22:05:22 Done.
504 DBusMethodCallStatus call_status,
505 const base::DictionaryValue& properties) {
506 if (call_status != DBUS_METHOD_CALL_SUCCESS) {
507 LOG(ERROR) << "Failed to get IP properties for: " << path;
508 return;
509 }
510 bool success = false;
511 for (base::DictionaryValue::key_iterator iter = properties.begin_keys();
pneubeck (no reviews) 2012/10/25 14:42:17 DictionaryValue::Iterator
stevenjb 2012/10/25 22:05:22 Actually, no need to iterate, this can just be pro
512 iter != properties.end_keys(); ++iter) {
513 const std::string& key = *iter;
514 if (key == flimflam::kAddressProperty) {
515 std::string ip_config;
516 properties.GetStringWithoutPathExpansion(key, &ip_config);
517 NetworkState* network = GetModifiableNetworkState(path);
518 if (network) {
519 network->set_ip_config(ip_config);
520 success = true;
521 }
522 break;
523 }
524 }
525 if (success) {
526 FOR_EACH_OBSERVER(NetworkStateHandlerObserver, observers_,
527 NetworkManagerChanged(shill::kIPConfigProperty));
528 }
529 }
530
531 void NetworkStateHandler::RequestScan() const {
532 if (TechnologyEnabled(flimflam::kTypeWifi)) {
533 shill_manager_->RequestScan(flimflam::kTypeWifi,
pneubeck (no reviews) 2012/10/25 14:42:17 According to manager-api.txt you can simply use ""
stevenjb 2012/10/25 22:05:22 Ah, that's new. This was copied from NetworkLibrar
534 base::Bind(&base::DoNothing),
535 base::Bind(&ErrorCallbackFunction));
536 }
537 if (TechnologyEnabled(flimflam::kTypeWimax)) {
538 shill_manager_->RequestScan(flimflam::kTypeWimax,
539 base::Bind(&base::DoNothing),
540 base::Bind(&ErrorCallbackFunction));
541 }
542 }
543
544 } // namespace chromeos
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698