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

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

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

Powered by Google App Engine
This is Rietveld 408576698