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