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

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 Round 2 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 "base/bind.h"
8 #include "base/stl_util.h"
9 #include "base/string_util.h"
10 #include "base/values.h"
11 #include "chromeos/dbus/dbus_thread_manager.h"
12 #include "chromeos/dbus/shill_device_client.h"
13 #include "chromeos/dbus/shill_ipconfig_client.h"
14 #include "chromeos/dbus/shill_manager_client.h"
15 #include "chromeos/dbus/shill_service_client.h"
16 #include "chromeos/network/device_state.h"
17 #include "chromeos/network/managed_state.h"
18 #include "chromeos/network/network_state.h"
19 #include "chromeos/network/network_state_handler_observer.h"
20 #include "chromeos/network/shill_service_observer.h"
21 #include "dbus/object_path.h"
22 #include "third_party/cros_system_api/dbus/service_constants.h"
23
24 namespace {
25
26 void ErrorCallbackFunction(const std::string& error_name,
27 const std::string& error_message) {
28 // TODO(stevenjb): Add error logging.
29 LOG(ERROR) << "Shill Error: " << error_name << " : " << error_message;
30 }
31
32 const base::ListValue* GetListValue(const std::string& key,
33 const base::Value& value) {
34 const base::ListValue* vlist = NULL;
35 if (!value.GetAsList(&vlist)) {
36 LOG(ERROR) << "Error parsing key as list: " << key;
37 return NULL;
38 }
39 return vlist;
40 }
41
42 }
43
44 namespace chromeos {
45
46 NetworkStateHandler::NetworkStateHandler()
47 : shill_manager_(DBusThreadManager::Get()->GetShillManagerClient()),
48 weak_ptr_factory_(this) {
49 }
50
51 NetworkStateHandler::~NetworkStateHandler() {
52 STLDeleteContainerPointers(network_list_.begin(), network_list_.end());
pneubeck (no reviews) 2012/10/26 08:17:46 This line can be removed for scoped_vector
53 // Delete network service observers.
54 STLDeleteContainerPairSecondPointers(
55 observed_networks_.begin(), observed_networks_.end());
56 CHECK(shill_manager_ == DBusThreadManager::Get()->GetShillManagerClient());
57 shill_manager_->RemovePropertyChangedObserver(this);
58 }
pneubeck (no reviews) 2012/10/26 08:17:46 The second STLDeleteContainerPointers(device_list_
stevenjb 2012/10/26 21:36:39 Fixed.
59
60 void NetworkStateHandler::Init() {
61 shill_manager_->GetProperties(
62 base::Bind(&NetworkStateHandler::ManagerPropertiesCallback,
63 weak_ptr_factory_.GetWeakPtr()));
64 shill_manager_->AddPropertyChangedObserver(this);
65 }
66
67 void NetworkStateHandler::AddObserver(NetworkStateHandlerObserver* observer) {
68 observers_.AddObserver(observer);
69 }
70
71 void NetworkStateHandler::RemoveObserver(
72 NetworkStateHandlerObserver* observer) {
73 observers_.RemoveObserver(observer);
74 }
75
76 bool NetworkStateHandler::TechnologyAvailable(
77 const std::string& technology) const {
78 return available_technologies_.find(technology) !=
79 available_technologies_.end();
80 }
81
82 bool NetworkStateHandler::TechnologyEnabled(
83 const std::string& technology) const {
84 return enabled_technologies_.find(technology) !=
85 enabled_technologies_.end();
86 }
87
88 void NetworkStateHandler::SetTechnologyEnabled(const std::string& technology,
89 bool enabled) {
90 if (enabled) {
91 shill_manager_->EnableTechnology(technology,
92 base::Bind(&base::DoNothing),
93 base::Bind(&ErrorCallbackFunction));
94 } else {
95 shill_manager_->DisableTechnology(technology,
96 base::Bind(&base::DoNothing),
97 base::Bind(&ErrorCallbackFunction));
98 }
99 }
100
101 const DeviceState* NetworkStateHandler::GetDeviceState(
102 const std::string& path) const {
103 return GetModifiableDeviceState(path);
104 }
105
106 const DeviceState* NetworkStateHandler::GetDeviceStateByType(
107 const std::string& type) const {
108 for (DeviceStateList::const_iterator iter = device_list_.begin();
109 iter != device_list_.end(); ++iter) {
110 const DeviceState* device = *iter;
111 if (device->type() == type)
112 return device;
113 }
114 return NULL;
115 }
116
117 const NetworkState* NetworkStateHandler::GetNetworkState(
118 const std::string& path) const {
119 return GetModifiableNetworkState(path);
120 }
121
122 const NetworkState* NetworkStateHandler::ActiveNetwork() const {
123 if (network_list_.empty())
124 return NULL;
125 const NetworkState* network = network_list_.front();
126 if (!network->IsConnectedState())
127 return NULL;
128 return network;
129 }
130
131 const NetworkState* NetworkStateHandler::ConnectedNetworkByType(
132 const std::string& type) const {
133 for (NetworkStateList::const_iterator iter = network_list_.begin();
134 iter != network_list_.end(); ++iter) {
135 const NetworkState* network = *iter;
136 if (!network->IsConnectedState())
137 break; // Connected networks are listed first.
gauravsh 2012/10/26 01:15:01 I think we should not make this assumption. It tie
pneubeck (no reviews) 2012/10/26 08:17:46 Optimization shouldn't be a concern if we don't ha
stevenjb 2012/10/26 21:36:39 This list *can* be quite long, O(100), and I prefe
gauravsh 2012/10/27 00:26:33 To be fair, the problem with NetworkLibrary is tha
138 if (network->type() == type)
139 return network;
140 }
141 return NULL;
142 }
143
144 const NetworkState* NetworkStateHandler::ConnectingNetworkByType(
145 const std::string& type) const {
146 for (NetworkStateList::const_iterator iter = network_list_.begin();
147 iter != network_list_.end(); ++iter) {
148 const NetworkState* network = *iter;
149 if (network->IsConnectedState())
150 continue;
151 if (!network->IsConnectingState())
152 break; // Connected and connecting networks are listed first.
153 if (network->type() == type ||
154 (type.empty() && type != flimflam::kTypeEthernet)) {
155 return network;
156 }
157 }
158 return NULL;
159 }
160
161 std::string NetworkStateHandler::HardwareAddress(
162 const std::string& type) const {
163 std::string result;
164 const NetworkState* network = ConnectedNetworkByType(type);
165 if (network) {
166 const DeviceState* device = GetDeviceState(network->device_path());
167 if (device)
168 result = device->mac_address();
169 }
170 StringToUpperASCII(&result);
171 return result;
172 }
173
174 std::string NetworkStateHandler::HardwareAddressFormatted(
175 const std::string& type) const {
176 std::string address = HardwareAddress(type);
gauravsh 2012/10/26 01:15:01 This should have an associated unit test.
177 if (address.size() % 2 != 0)
178 return address;
179 std::string result;
180 for (size_t i = 0; i < address.size(); ++i) {
gauravsh 2012/10/26 01:15:01 You may consider changing this to i+=2, and also p
stevenjb 2012/10/26 21:36:39 I copied this from NetworkLibrary; I'm not 100% ce
gauravsh 2012/10/27 00:26:33 The optimization was just a suggestion to improve
181 if ((i != 0) && (i % 2 == 0))
182 result.push_back(':');
183 result.push_back(address[i]);
184 }
185 return result;
186 }
187
188 const NetworkStateHandler::NetworkStateList&
189 NetworkStateHandler::GetNetworkList() const {
gauravsh 2012/10/26 01:15:01 See my comment in .h about the potentially confusi
190 RequestScan();
191 return network_list_;
192 }
193
194 void NetworkStateHandler::OnPropertyChanged(const std::string& key,
195 const base::Value& value) {
196 if (ManagerPropertyChanged(key, value))
197 FOR_EACH_OBSERVER(NetworkStateHandlerObserver, observers_,
198 NetworkManagerChanged(key));
199 }
200
201 //------------------------------------------------------------------------------
202 // Private methods
203
204 DeviceState* NetworkStateHandler::GetModifiableDeviceState(
205 const std::string& path) const {
206 for (DeviceStateList::const_iterator iter = device_list_.begin();
207 iter != device_list_.end(); ++iter) {
208 DeviceState* device = *iter;
209 if (device->path() == path)
210 return device;
211 }
212 return NULL;
213 }
214
215 NetworkState* NetworkStateHandler::GetModifiableNetworkState(
216 const std::string& path) const {
217 for (NetworkStateList::const_iterator iter = network_list_.begin();
218 iter != network_list_.end(); ++iter) {
219 NetworkState* network = *iter;
220 if (network->path() == path)
221 return network;
222 }
223 return NULL;
224 }
225
226 void NetworkStateHandler::ManagerPropertiesCallback(
227 DBusMethodCallStatus call_status,
228 const base::DictionaryValue& properties) {
229 if (call_status != DBUS_METHOD_CALL_SUCCESS) {
230 LOG(ERROR) << "Failed to get Manager properties:" << call_status;
231 return;
232 }
233 bool notify = false;
234 for (base::DictionaryValue::Iterator iter(properties);
235 iter.HasNext(); iter.Advance()) {
236 notify |= ManagerPropertyChanged(iter.key(), iter.value());
237 }
238 if (notify) {
239 FOR_EACH_OBSERVER(NetworkStateHandlerObserver, observers_,
240 NetworkManagerChanged(std::string()));
241 }
242 }
243
244 bool NetworkStateHandler::ManagerPropertyChanged(const std::string& key,
245 const base::Value& value) {
246 bool notify_manager_changed = false;
247 if (key == flimflam::kServicesProperty) {
248 const base::ListValue* vlist = GetListValue(key, value);
249 if (vlist) {
250 UpdateManagedList(ManagedState::MANAGED_TYPE_NETWORK, *vlist);
251 // Do not send an UpdateManagerChanged notification to observers.
252 // An UpdateNetworkList notification will be sent when the service list
253 // updates have completed.
254 }
255 } else if (key == flimflam::kDevicesProperty) {
256 const ListValue* vlist = GetListValue(key, value);
257 if (vlist) {
258 UpdateManagedList(ManagedState::MANAGED_TYPE_DEVICE, *vlist);
259 notify_manager_changed = true;
260 }
261 } else if (key == flimflam::kAvailableTechnologiesProperty) {
262 const base::ListValue* vlist = GetListValue(key, value);
263 if (vlist ) {
264 UpdateAvailableTechnologies(*vlist);
265 notify_manager_changed = true;
266 }
267 } else if (key == flimflam::kEnabledTechnologiesProperty) {
268 const base::ListValue* vlist = GetListValue(key, value);
269 if (vlist) {
270 UpdateEnabledTechnologies(*vlist);
271 notify_manager_changed = true;
272 }
273 }
274 return notify_manager_changed;
275 }
276
277 NetworkStateHandler::ManagedStateList* NetworkStateHandler::GetManagedList(
278 ManagedState::ManagedType type) {
279 // Use reinterpret_cast here to avoid copying the list to a list of identical
280 // base class pointers.
281 switch(type) {
282 case ManagedState::MANAGED_TYPE_NETWORK:
283 return reinterpret_cast<ManagedStateList*>(&network_list_);
gauravsh 2012/10/26 01:15:01 This makes me iffy too. I wouldn't be surprised if
stevenjb 2012/10/26 21:36:39 This has been refactored.
284 case ManagedState::MANAGED_TYPE_DEVICE:
285 return reinterpret_cast<ManagedStateList*>(&device_list_);
286 }
287 return NULL;
288 }
289
290 void NetworkStateHandler::UpdateManagedList(ManagedState::ManagedType type,
291 const base::ListValue& entries) {
292 ManagedStateList* managed_list = GetManagedList(type);
293 VLOG(2) << "UpdateManagedList: " << type;
294 // Create a map of existing entries.
295 std::map<std::string, ManagedState*> managed_map;
296 for (ManagedStateList::iterator iter = managed_list->begin();
297 iter != managed_list->end(); ++iter) {
298 ManagedState* managed = *iter;
299 managed_map[managed->path()] = managed;
300 }
301 // Clear the list (pointers are owned by managed_map).
302 managed_list->clear();
pneubeck (no reviews) 2012/10/26 08:17:46 This will be weak_clear() for scoped_vector, so th
stevenjb 2012/10/26 21:36:39 Personally I think that as soon as you use weak_cl
303 // Updates managed_list and request updates for new entries.
304 for (base::ListValue::const_iterator iter = entries.begin();
305 iter != entries.end(); ++iter) {
306 std::string path;
307 (*iter)->GetAsString(&path);
308 if (path.empty())
309 continue;
310 std::map<std::string, ManagedState*>::iterator found =
311 managed_map.find(path);
312 bool request_properties = false;
313 if (found == managed_map.end()) {
314 request_properties = true;
315 managed_list->push_back(ManagedState::Create(type, path));
316 } else {
317 ManagedState* managed = found->second;
318 managed_list->push_back(managed);
319 managed_map.erase(found);
320 }
321 if (request_properties) {
322 ++pending_updates_[type];
323 RequestProperties(type, path);
324 }
325 }
326 // Delete any remaning entries in managed_map.
327 STLDeleteContainerPairSecondPointers(managed_map.begin(), managed_map.end());
328 }
329
330 void NetworkStateHandler::UpdateObservedNetworkServices() {
331 // Watch any connected or connecting networks.
332 ShillServiceObserverMap new_observed;
333 for (NetworkStateList::const_iterator iter = network_list_.begin();
334 iter != network_list_.end(); ++iter) {
335 const NetworkState* network = *iter;
336 if (!network->IsConnectedState() && !network->IsConnectingState())
337 break; // Connected and connecting networks are listed first.
338 const std::string& path = network->path();
339 ShillServiceObserverMap::iterator iter = observed_networks_.find(path);
340 if (iter != observed_networks_.end()) {
341 new_observed[path] = observed_networks_[path];
342 } else {
343 new_observed[path] = new ShillServiceObserver(
344 path, base::Bind(&NetworkStateHandler::NetworkServicePropertyChanged,
345 weak_ptr_factory_.GetWeakPtr()));
346 }
347 observed_networks_.erase(path);
348 }
349 VLOG(2) << "UpdateObservedNetworkServices, new observed: "
350 << new_observed.size();
351 // Delete network service observers still in observed_networks_.
352 STLDeleteContainerPairSecondPointers(
353 observed_networks_.begin(), observed_networks_.end());
354 observed_networks_.swap(new_observed);
355 // Notify observers that the list of networks has changed.
356 FOR_EACH_OBSERVER(NetworkStateHandlerObserver, observers_,
357 NetworkListChanged(network_list_));
358 // Notify observers if the active network has changed.
359 const NetworkState* new_active_network =
360 network_list_.empty() ? NULL : network_list_.front();
361 if (new_active_network->path() != active_network_path_) {
362 active_network_path_ = new_active_network->path();
363 FOR_EACH_OBSERVER(NetworkStateHandlerObserver, observers_,
364 ActiveNetworkChanged(new_active_network));
365 }
366 }
367
368 void NetworkStateHandler::UpdateAvailableTechnologies(
369 const base::ListValue& technologies) {
370 available_technologies_.clear();
371 for (base::ListValue::const_iterator iter = technologies.begin();
372 iter != technologies.end(); ++iter) {
373 std::string technology;
374 (*iter)->GetAsString(&technology);
375 if (technology.empty())
gauravsh 2012/10/26 01:15:01 Should this log a warning?
stevenjb 2012/10/26 21:36:39 Should never happen and wouldn't hurt anything, I'
376 continue;
377 available_technologies_.insert(technology);
378 }
379 }
380
381 void NetworkStateHandler::UpdateEnabledTechnologies(
382 const base::ListValue& technologies) {
383 enabled_technologies_.clear();
384 for (base::ListValue::const_iterator iter = technologies.begin();
385 iter != technologies.end(); ++iter) {
386 std::string technology;
387 (*iter)->GetAsString(&technology);
388 if (technology.empty())
gauravsh 2012/10/26 01:15:01 Should this log a warning?
stevenjb 2012/10/26 21:36:39 Same as above.
389 continue;
390 enabled_technologies_.insert(technology);
391 }
392 }
393
394 void NetworkStateHandler::RequestProperties(ManagedState::ManagedType type,
395 const std::string& path) {
396 switch(type) {
397 case ManagedState::MANAGED_TYPE_NETWORK:
398 DBusThreadManager::Get()->GetShillServiceClient()->GetProperties(
399 dbus::ObjectPath(path),
400 base::Bind(&NetworkStateHandler::GetPropertiesCallback,
401 weak_ptr_factory_.GetWeakPtr(),
402 type, path));
403 break;
404 case ManagedState::MANAGED_TYPE_DEVICE:
405 DBusThreadManager::Get()->GetShillDeviceClient()->GetProperties(
406 dbus::ObjectPath(path),
407 base::Bind(&NetworkStateHandler::GetPropertiesCallback,
408 weak_ptr_factory_.GetWeakPtr(),
409 type, path));
410 break;
411 }
412 }
413
414 void NetworkStateHandler::GetPropertiesCallback(
415 ManagedState::ManagedType type,
416 const std::string& path,
417 DBusMethodCallStatus call_status,
418 const base::DictionaryValue& properties) {
419 VLOG(2) << "GetPropertiesCallback: " << type << " : " << path;
420 --pending_updates_[type];
421 if (call_status != DBUS_METHOD_CALL_SUCCESS) {
422 LOG(ERROR) << "Failed to get properties for: " << path
423 << ": " << call_status;
424 return;
425 }
426 bool found = false;
427 ManagedStateList* list = GetManagedList(type);
428 for (ManagedStateList::iterator iter = list->begin();
429 iter != list->end(); ++iter) {
430 ManagedState* managed = *iter;
431 if (managed->path() == path) {
432 ParseProperties(managed, properties);
433 found = true;
434 break;
435 }
436 }
437 if (!found)
438 LOG(ERROR) << "GetPropertiesCallback: " << path << " Not found!";
439 // Notify observers only when all updates for that type have completed.
440 if (type == ManagedState::MANAGED_TYPE_NETWORK &&
441 pending_updates_[type] == 0) {
442 UpdateObservedNetworkServices();
443 }
444 }
445
446 void NetworkStateHandler::ParseProperties(
447 ManagedState* managed,
448 const base::DictionaryValue& properties) {
449 for (base::DictionaryValue::Iterator iter(properties);
450 iter.HasNext(); iter.Advance()) {
451 bool success = false;
452 // Handle IPConfig here since it requires additional complexity that is
453 // better handled here than in NetworkState::PropertyChanged (e.g.
454 // observer notification).
455 if (iter.key() == shill::kIPConfigProperty) {
456 DCHECK(managed->managed_type() == ManagedState::MANAGED_TYPE_NETWORK);
457 std::string ip_config_path;
458 if (iter.value().GetAsString(&ip_config_path)) {
459 DBusThreadManager::Get()->GetShillIPConfigClient()->GetProperties(
460 dbus::ObjectPath(ip_config_path),
461 base::Bind(&NetworkStateHandler::GetIPConfigCallback,
462 weak_ptr_factory_.GetWeakPtr(),
463 managed->path()));
464 success = true;
465 }
466 } else {
467 success = managed->PropertyChanged(iter.key(), iter.value());
468 }
469 if (!success)
470 LOG(ERROR) << "Error getting value for key: " << iter.key();
471 }
472 }
473
474 void NetworkStateHandler::NetworkServicePropertyChanged(
475 const std::string& path,
476 const std::string& key,
477 const base::Value& value) {
478 NetworkState* network = GetModifiableNetworkState(path);
479 if (!network)
480 return;
481 if (network->PropertyChanged(key, value)) {
482 FOR_EACH_OBSERVER(NetworkStateHandlerObserver, observers_,
483 NetworkServicePropertyChanged(network, key));
484 if (network == network_list_.front() && key == flimflam::kStateProperty) {
gauravsh 2012/10/26 01:15:01 Is there a guarantee that the manager update with
stevenjb 2012/10/26 21:36:39 I think that separate management would add the kin
gauravsh 2012/10/27 00:26:33 Since dbus signals are handled asynchronously, thi
485 FOR_EACH_OBSERVER(NetworkStateHandlerObserver, observers_,
486 ActiveNetworkStateChanged(network));
gauravsh 2012/10/26 01:15:01 Where do you notify the observes when we transitio
stevenjb 2012/10/26 21:36:39 In UpdateObservedNetworkServices() (now NotifyNetw
487 }
488 }
489 }
490
491 void NetworkStateHandler::GetIPConfigCallback(
492 const std::string& service_path,
493 DBusMethodCallStatus call_status,
494 const base::DictionaryValue& properties) {
495 if (call_status != DBUS_METHOD_CALL_SUCCESS) {
496 LOG(ERROR) << "Failed to get IP properties for: " << service_path;
497 return;
498 }
499 std::string ip_address;
500 if (!properties.GetStringWithoutPathExpansion(flimflam::kAddressProperty,
501 &ip_address)) {
502 LOG(ERROR) << "Failed to get IP Address property for: " << service_path;
503 return;
504 }
505 NetworkState* network = GetModifiableNetworkState(service_path);
506 if (!network)
507 return;
508 network->set_ip_address(ip_address);
509 FOR_EACH_OBSERVER(
510 NetworkStateHandlerObserver, observers_,
511 NetworkServicePropertyChanged(network, flimflam::kAddressProperty));
512 }
513
514 void NetworkStateHandler::RequestScan() const {
515 shill_manager_->RequestScan("",
516 base::Bind(&base::DoNothing),
517 base::Bind(&ErrorCallbackFunction));
518 }
519
520 } // namespace chromeos
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698