network_state_handler.cc revision 2a99a7e74a7f215066514fe81d2bfa6639d9eddd
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/format_macros.h"
8#include "base/stl_util.h"
9#include "base/string_util.h"
10#include "base/stringprintf.h"
11#include "base/values.h"
12#include "chromeos/network/device_state.h"
13#include "chromeos/network/managed_state.h"
14#include "chromeos/network/network_event_log.h"
15#include "chromeos/network/network_state.h"
16#include "chromeos/network/network_state_handler_observer.h"
17#include "chromeos/network/shill_property_handler.h"
18#include "third_party/cros_system_api/dbus/service_constants.h"
19
20namespace {
21
22const char kLogModule[] = "NetworkStateHandler";
23
24// Returns true if |network->type()| == |match_type|, or it matches one of the
25// following special match types:
26// * kMatchTypeDefault matches any network (i.e. the first instance)
27// * kMatchTypeNonVirtual matches non virtual networks
28// * kMatchTypeWireless matches wireless networks
29// * kMatchTypeMobile matches cellular or wimax networks
30bool ManagedStateMatchesType(const chromeos::ManagedState* managed,
31                             const std::string& match_type) {
32  const std::string& type = managed->type();
33  if (match_type == chromeos::NetworkStateHandler::kMatchTypeDefault)
34    return true;
35  if (match_type == type)
36    return true;
37  if (match_type == chromeos::NetworkStateHandler::kMatchTypeNonVirtual &&
38      type != flimflam::kTypeVPN) {
39    return true;
40  }
41  if (match_type == chromeos::NetworkStateHandler::kMatchTypeWireless &&
42      type != flimflam::kTypeEthernet && type != flimflam::kTypeVPN) {
43    return true;
44  }
45  if (match_type == chromeos::NetworkStateHandler::kMatchTypeMobile &&
46      (type == flimflam::kTypeCellular || type == flimflam::kTypeWimax)) {
47    return true;
48  }
49  return false;
50}
51
52std::string ValueAsString(const base::Value& value) {
53  if (value.GetType() == base::Value::TYPE_BOOLEAN) {
54    bool bval = false;
55    value.GetAsBoolean(&bval);
56    return bval ? "true" : "false";
57  } else if (value.GetType() == base::Value::TYPE_INTEGER) {
58    int intval = 0;
59    value.GetAsInteger(&intval);
60    return base::StringPrintf("%d", intval);
61  } else if (value.GetType() == base::Value::TYPE_DOUBLE) {
62    double dval = 0;
63    value.GetAsDouble(&dval);
64    return base::StringPrintf("%g", dval);
65  } else if (value.GetType() == base::Value::TYPE_STRING) {
66    std::string vstr;
67    value.GetAsString(&vstr);
68    return vstr;
69  }
70  return "";
71}
72
73}  // namespace
74
75namespace chromeos {
76
77const char NetworkStateHandler::kMatchTypeDefault[] = "default";
78const char NetworkStateHandler::kMatchTypeWireless[] = "wireless";
79const char NetworkStateHandler::kMatchTypeMobile[] = "mobile";
80const char NetworkStateHandler::kMatchTypeNonVirtual[] = "non-virtual";
81
82static NetworkStateHandler* g_network_state_handler = NULL;
83
84NetworkStateHandler::NetworkStateHandler() {
85}
86
87NetworkStateHandler::~NetworkStateHandler() {
88  STLDeleteContainerPointers(network_list_.begin(), network_list_.end());
89  STLDeleteContainerPointers(device_list_.begin(), device_list_.end());
90}
91
92void NetworkStateHandler::InitShillPropertyHandler() {
93  shill_property_handler_.reset(new internal::ShillPropertyHandler(this));
94  shill_property_handler_->Init();
95}
96
97// static
98void NetworkStateHandler::Initialize() {
99  CHECK(!g_network_state_handler);
100  g_network_state_handler = new NetworkStateHandler();
101  g_network_state_handler->InitShillPropertyHandler();
102}
103
104// static
105bool NetworkStateHandler::IsInitialized() {
106  return g_network_state_handler != NULL;
107}
108
109// static
110void NetworkStateHandler::Shutdown() {
111  CHECK(g_network_state_handler);
112  delete g_network_state_handler;
113  g_network_state_handler = NULL;
114}
115
116// static
117NetworkStateHandler* NetworkStateHandler::Get() {
118  CHECK(g_network_state_handler)
119      << "NetworkStateHandler::Get() called before Initialize()";
120  return g_network_state_handler;
121}
122
123void NetworkStateHandler::AddObserver(NetworkStateHandlerObserver* observer) {
124  observers_.AddObserver(observer);
125}
126
127void NetworkStateHandler::RemoveObserver(
128    NetworkStateHandlerObserver* observer) {
129  observers_.RemoveObserver(observer);
130}
131
132bool NetworkStateHandler::TechnologyAvailable(const std::string& type) const {
133  if (type == kMatchTypeMobile) {
134    return shill_property_handler_->TechnologyAvailable(flimflam::kTypeWimax) ||
135        shill_property_handler_->TechnologyAvailable(flimflam::kTypeCellular);
136  }
137  return shill_property_handler_->TechnologyAvailable(type);
138}
139
140bool NetworkStateHandler::TechnologyEnabled(const std::string& type) const {
141  if (type == kMatchTypeMobile) {
142    return shill_property_handler_->TechnologyEnabled(flimflam::kTypeWimax) ||
143        shill_property_handler_->TechnologyEnabled(flimflam::kTypeCellular);
144  }
145  return shill_property_handler_->TechnologyEnabled(type);
146}
147
148bool NetworkStateHandler::TechnologyUninitialized(
149    const std::string& type) const {
150  if (type == kMatchTypeMobile) {
151    return
152        shill_property_handler_->TechnologyUninitialized(
153            flimflam::kTypeWimax) ||
154        shill_property_handler_->TechnologyUninitialized(
155            flimflam::kTypeCellular);
156  }
157  return shill_property_handler_->TechnologyUninitialized(type);
158}
159
160
161void NetworkStateHandler::SetTechnologyEnabled(
162    const std::string& type,
163    bool enabled,
164    const network_handler::ErrorCallback& error_callback) {
165  if (type == kMatchTypeMobile) {
166    shill_property_handler_->SetTechnologyEnabled(
167        flimflam::kTypeCellular, enabled, error_callback);
168    shill_property_handler_->SetTechnologyEnabled(
169        flimflam::kTypeWimax, enabled, error_callback);
170  } else {
171    shill_property_handler_->SetTechnologyEnabled(
172        type, enabled, error_callback);
173  }
174}
175
176const DeviceState* NetworkStateHandler::GetDeviceState(
177    const std::string& device_path) const {
178  return GetModifiableDeviceState(device_path);
179}
180
181const DeviceState* NetworkStateHandler::GetDeviceStateByType(
182    const std::string& type) const {
183  for (ManagedStateList::const_iterator iter = device_list_.begin();
184       iter != device_list_.end(); ++iter) {
185    ManagedState* device = *iter;
186    if (ManagedStateMatchesType(device, type))
187      return device->AsDeviceState();
188  }
189  return NULL;
190}
191
192bool NetworkStateHandler::GetScanningByType(const std::string& type) const {
193  for (ManagedStateList::const_iterator iter = device_list_.begin();
194       iter != device_list_.end(); ++iter) {
195    const DeviceState* device = (*iter)->AsDeviceState();
196    DCHECK(device);
197    if (ManagedStateMatchesType(device, type) && device->scanning())
198      return true;
199  }
200  return false;
201}
202
203const NetworkState* NetworkStateHandler::GetNetworkState(
204    const std::string& service_path) const {
205  return GetModifiableNetworkState(service_path);
206}
207
208const NetworkState* NetworkStateHandler::DefaultNetwork() const {
209  if (network_list_.empty())
210    return NULL;
211  const NetworkState* network = network_list_.front()->AsNetworkState();
212  DCHECK(network);
213  if (!network->IsConnectedState())
214    return NULL;
215  return network;
216}
217
218const NetworkState* NetworkStateHandler::ConnectedNetworkByType(
219    const std::string& type) const {
220  for (ManagedStateList::const_iterator iter = network_list_.begin();
221       iter != network_list_.end(); ++iter) {
222    const NetworkState* network = (*iter)->AsNetworkState();
223    DCHECK(network);
224    if (!network->IsConnectedState())
225      break;  // Connected networks are listed first.
226    if (ManagedStateMatchesType(network, type))
227      return network;
228  }
229  return NULL;
230}
231
232const NetworkState* NetworkStateHandler::ConnectingNetworkByType(
233    const std::string& type) const {
234  for (ManagedStateList::const_iterator iter = network_list_.begin();
235       iter != network_list_.end(); ++iter) {
236    const NetworkState* network = (*iter)->AsNetworkState();
237    DCHECK(network);
238    if (network->IsConnectedState())
239      continue;
240    if (!network->IsConnectingState())
241      break;  // Connected and connecting networks are listed first.
242    if (ManagedStateMatchesType(network, type))
243      return network;
244  }
245  return NULL;
246}
247
248const NetworkState* NetworkStateHandler::FirstNetworkByType(
249    const std::string& type) const {
250  for (ManagedStateList::const_iterator iter = network_list_.begin();
251       iter != network_list_.end(); ++iter) {
252    const NetworkState* network = (*iter)->AsNetworkState();
253    DCHECK(network);
254    if (ManagedStateMatchesType(network, type))
255      return network;
256  }
257  return NULL;
258}
259
260std::string NetworkStateHandler::HardwareAddressForType(
261    const std::string& type) const {
262  std::string result;
263  const NetworkState* network = ConnectedNetworkByType(type);
264  if (network) {
265    const DeviceState* device = GetDeviceState(network->device_path());
266    if (device)
267      result = device->mac_address();
268  }
269  StringToUpperASCII(&result);
270  return result;
271}
272
273std::string NetworkStateHandler::FormattedHardwareAddressForType(
274    const std::string& type) const {
275  std::string address = HardwareAddressForType(type);
276  if (address.size() % 2 != 0)
277    return address;
278  std::string result;
279  for (size_t i = 0; i < address.size(); ++i) {
280    if ((i != 0) && (i % 2 == 0))
281      result.push_back(':');
282    result.push_back(address[i]);
283  }
284  return result;
285}
286
287void NetworkStateHandler::GetNetworkList(NetworkStateList* list) const {
288  DCHECK(list);
289  NetworkStateList result;
290  list->clear();
291  for (ManagedStateList::const_iterator iter = network_list_.begin();
292       iter != network_list_.end(); ++iter) {
293    const NetworkState* network = (*iter)->AsNetworkState();
294    DCHECK(network);
295    list->push_back(network);
296  }
297}
298
299void NetworkStateHandler::RequestScan() const {
300  shill_property_handler_->RequestScan();
301}
302
303//------------------------------------------------------------------------------
304// ShillPropertyHandler::Delegate overrides
305
306void NetworkStateHandler::UpdateManagedList(ManagedState::ManagedType type,
307                                            const base::ListValue& entries) {
308  ManagedStateList* managed_list = GetManagedList(type);
309  VLOG(2) << "UpdateManagedList: " << type;
310  // Create a map of existing entries.
311  std::map<std::string, ManagedState*> managed_map;
312  for (ManagedStateList::iterator iter = managed_list->begin();
313       iter != managed_list->end(); ++iter) {
314    ManagedState* managed = *iter;
315    managed_map[managed->path()] = managed;
316  }
317  // Clear the list (pointers are owned by managed_map).
318  managed_list->clear();
319  // Updates managed_list and request updates for new entries.
320  for (base::ListValue::const_iterator iter = entries.begin();
321       iter != entries.end(); ++iter) {
322    std::string path;
323    (*iter)->GetAsString(&path);
324    DCHECK(!path.empty());
325    std::map<std::string, ManagedState*>::iterator found =
326        managed_map.find(path);
327    bool request_properties = false;
328    ManagedState* managed;
329    bool is_observing = shill_property_handler_->IsObservingNetwork(path);
330    if (found == managed_map.end()) {
331      request_properties = true;
332      managed = ManagedState::Create(type, path);
333      managed_list->push_back(managed);
334    } else {
335      managed = found->second;
336      managed_list->push_back(managed);
337      managed_map.erase(found);
338      if (!managed->is_observed() && is_observing)
339        request_properties = true;
340    }
341    if (is_observing)
342      managed->set_is_observed(true);
343    if (request_properties)
344      shill_property_handler_->RequestProperties(type, path);
345  }
346  // Delete any remaning entries in managed_map.
347  STLDeleteContainerPairSecondPointers(managed_map.begin(), managed_map.end());
348}
349
350void NetworkStateHandler::UpdateManagedStateProperties(
351    ManagedState::ManagedType type,
352    const std::string& path,
353    const base::DictionaryValue& properties) {
354  ManagedState* managed = GetModifiableManagedState(GetManagedList(type), path);
355  if (!managed) {
356    LOG(ERROR) << "GetPropertiesCallback: " << path << " Not found!";
357    return;
358  }
359  bool network_property_updated = false;
360  std::string prev_connection_state;
361  if (type == ManagedState::MANAGED_TYPE_NETWORK)
362    prev_connection_state = managed->AsNetworkState()->connection_state();
363  for (base::DictionaryValue::Iterator iter(properties);
364       iter.HasNext(); iter.Advance()) {
365    if (type == ManagedState::MANAGED_TYPE_NETWORK) {
366      if (managed->PropertyChanged(iter.key(), iter.value()))
367        network_property_updated = true;
368    } else {
369      managed->PropertyChanged(iter.key(), iter.value());
370    }
371  }
372  // Notify observers.
373  if (network_property_updated) {
374    NetworkState* network = managed->AsNetworkState();
375    DCHECK(network);
376    // Signal connection state changed after all properties have been updated.
377    if (network->connection_state() != prev_connection_state)
378      OnNetworkConnectionStateChanged(network);
379    NetworkPropertiesUpdated(network);
380  }
381  network_event_log::AddEntry(
382      kLogModule, "PropertiesReceived",
383      base::StringPrintf("%s (%s)", path.c_str(), managed->name().c_str()));
384}
385
386void NetworkStateHandler::UpdateNetworkServiceProperty(
387    const std::string& service_path,
388    const std::string& key,
389    const base::Value& value) {
390  NetworkState* network = GetModifiableNetworkState(service_path);
391  if (!network)
392    return;
393  std::string prev_connection_state = network->connection_state();
394  if (!network->PropertyChanged(key, value))
395    return;
396  if (network->connection_state() != prev_connection_state)
397    OnNetworkConnectionStateChanged(network);
398
399  NetworkPropertiesUpdated(network);
400
401  std::string detail = network->name() + "." + key;
402  std::string vstr = ValueAsString(value);
403  if (!vstr.empty())
404    detail += " = " + vstr;
405  network_event_log::AddEntry(kLogModule, "NetworkPropertyUpdated", detail);
406}
407
408void NetworkStateHandler::UpdateNetworkServiceIPAddress(
409    const std::string& service_path,
410    const std::string& ip_address) {
411  NetworkState* network = GetModifiableNetworkState(service_path);
412  if (!network)
413    return;
414  std::string detail = network->name() + ".IPAddress = " + ip_address;
415  network_event_log::AddEntry(kLogModule, "NetworkIPChanged", detail);
416  network->set_ip_address(ip_address);
417  NetworkPropertiesUpdated(network);
418}
419
420void NetworkStateHandler::UpdateDeviceProperty(const std::string& device_path,
421                                               const std::string& key,
422                                               const base::Value& value) {
423  DeviceState* device = GetModifiableDeviceState(device_path);
424  if (!device)
425    return;
426  if (!device->PropertyChanged(key, value))
427    return;
428
429  FOR_EACH_OBSERVER(NetworkStateHandlerObserver, observers_,
430                    DeviceListChanged());
431
432  std::string detail = device->name() + "." + key;
433  std::string vstr = ValueAsString(value);
434  if (!vstr.empty())
435    detail += " = " + vstr;
436  network_event_log::AddEntry(kLogModule, "DevicePropertyUpdated", detail);
437}
438
439void NetworkStateHandler::ManagerPropertyChanged() {
440  FOR_EACH_OBSERVER(NetworkStateHandlerObserver, observers_,
441                    NetworkManagerChanged());
442}
443
444void NetworkStateHandler::ManagedStateListChanged(
445    ManagedState::ManagedType type) {
446  if (type == ManagedState::MANAGED_TYPE_NETWORK) {
447    // Notify observers that the list of networks has changed.
448    network_event_log::AddEntry(
449        kLogModule, "NetworkListChanged",
450        base::StringPrintf("Size: %"PRIuS, network_list_.size()));
451    FOR_EACH_OBSERVER(NetworkStateHandlerObserver, observers_,
452                      NetworkListChanged());
453    // The list order may have changed, so check if the default network changed.
454    if (CheckDefaultNetworkChanged())
455      OnDefaultNetworkChanged();
456  } else if (type == ManagedState::MANAGED_TYPE_DEVICE) {
457    network_event_log::AddEntry(
458        kLogModule, "DeviceListChanged",
459        base::StringPrintf("Size: %"PRIuS, device_list_.size()));
460    FOR_EACH_OBSERVER(NetworkStateHandlerObserver, observers_,
461                      DeviceListChanged());
462  } else {
463    NOTREACHED();
464  }
465}
466
467//------------------------------------------------------------------------------
468// Private methods
469
470DeviceState* NetworkStateHandler::GetModifiableDeviceState(
471    const std::string& device_path) const {
472  ManagedState* managed = GetModifiableManagedState(&device_list_, device_path);
473  if (!managed)
474    return NULL;
475  return managed->AsDeviceState();
476}
477
478NetworkState* NetworkStateHandler::GetModifiableNetworkState(
479    const std::string& service_path) const {
480  ManagedState* managed =
481      GetModifiableManagedState(&network_list_, service_path);
482  if (!managed)
483    return NULL;
484  return managed->AsNetworkState();
485}
486
487ManagedState* NetworkStateHandler::GetModifiableManagedState(
488    const ManagedStateList* managed_list,
489    const std::string& path) const {
490  for (ManagedStateList::const_iterator iter = managed_list->begin();
491       iter != managed_list->end(); ++iter) {
492    ManagedState* managed = *iter;
493    if (managed->path() == path)
494      return managed;
495  }
496  return NULL;
497}
498
499NetworkStateHandler::ManagedStateList* NetworkStateHandler::GetManagedList(
500    ManagedState::ManagedType type) {
501  switch (type) {
502    case ManagedState::MANAGED_TYPE_NETWORK:
503      return &network_list_;
504    case ManagedState::MANAGED_TYPE_DEVICE:
505      return &device_list_;
506  }
507  NOTREACHED();
508  return NULL;
509}
510
511void NetworkStateHandler::OnNetworkConnectionStateChanged(
512    NetworkState* network) {
513  DCHECK(network);
514  std::string desc = base::StringPrintf(
515      "%s: %s", network->path().c_str(), network->connection_state().c_str());
516  network_event_log::AddEntry(
517      kLogModule, "NetworkConnectionStateChanged", desc);
518  FOR_EACH_OBSERVER(NetworkStateHandlerObserver, observers_,
519                    NetworkConnectionStateChanged(network));
520  if (CheckDefaultNetworkChanged() || network->path() == default_network_path_)
521    OnDefaultNetworkChanged();
522}
523
524bool NetworkStateHandler::CheckDefaultNetworkChanged() {
525  std::string new_default_network_path;
526  const NetworkState* new_default_network = DefaultNetwork();
527  if (new_default_network)
528    new_default_network_path = new_default_network->path();
529  if (new_default_network_path == default_network_path_)
530    return false;
531  default_network_path_ = new_default_network_path;
532  return true;
533}
534
535void NetworkStateHandler::OnDefaultNetworkChanged() {
536  const NetworkState* default_network = DefaultNetwork();
537  network_event_log::AddEntry(
538      kLogModule, "DefaultNetworkChanged",
539      default_network ? default_network->path() : "None");
540  FOR_EACH_OBSERVER(NetworkStateHandlerObserver, observers_,
541                    DefaultNetworkChanged(default_network));
542}
543
544void NetworkStateHandler::NetworkPropertiesUpdated(
545    const NetworkState* network) {
546  if (network->path() == connecting_network_ && !network->IsConnectingState())
547    connecting_network_.clear();
548  FOR_EACH_OBSERVER(NetworkStateHandlerObserver, observers_,
549                    NetworkPropertiesUpdated(network));
550}
551
552}  // namespace chromeos
553