network_change_notifier_chromeos.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 <string>
6
7#include "base/basictypes.h"
8#include "base/bind.h"
9#include "base/string_util.h"
10#include "chromeos/dbus/dbus_thread_manager.h"
11#include "chromeos/network/network_change_notifier_chromeos.h"
12#include "chromeos/network/network_state.h"
13#include "chromeos/network/network_state_handler.h"
14#include "net/base/network_change_notifier.h"
15#include "net/dns/dns_config_service_posix.h"
16#include "third_party/cros_system_api/dbus/service_constants.h"
17
18namespace chromeos {
19
20// DNS config services on Chrome OS are signalled by the network state handler
21// rather than relying on watching files in /etc.
22class NetworkChangeNotifierChromeos::DnsConfigService
23    : public net::internal::DnsConfigServicePosix {
24 public:
25  DnsConfigService();
26  virtual ~DnsConfigService();
27
28  // net::internal::DnsConfigService() overrides.
29  virtual bool StartWatching() OVERRIDE;
30
31  virtual void OnNetworkChange();
32};
33
34NetworkChangeNotifierChromeos::DnsConfigService::DnsConfigService() {
35}
36
37NetworkChangeNotifierChromeos::DnsConfigService::~DnsConfigService() {
38}
39
40bool NetworkChangeNotifierChromeos::DnsConfigService::StartWatching() {
41  // DNS config changes are handled and notified by the network state handlers.
42  return true;
43}
44
45void NetworkChangeNotifierChromeos::DnsConfigService::OnNetworkChange() {
46  InvalidateConfig();
47  InvalidateHosts();
48  ReadNow();
49}
50
51NetworkChangeNotifierChromeos::NetworkChangeNotifierChromeos()
52    : NetworkChangeNotifier(NetworkChangeCalculatorParamsChromeos()),
53      connection_type_(CONNECTION_NONE) {
54}
55
56NetworkChangeNotifierChromeos::~NetworkChangeNotifierChromeos() {
57}
58
59void NetworkChangeNotifierChromeos::Initialize() {
60  DBusThreadManager::Get()->GetPowerManagerClient()->AddObserver(this);
61  NetworkHandler::Get()->network_state_handler()->AddObserver(this);
62
63  dns_config_service_.reset(new DnsConfigService());
64  dns_config_service_->WatchConfig(
65      base::Bind(net::NetworkChangeNotifier::SetDnsConfig));
66
67  // Update initial connection state.
68  DefaultNetworkChanged(
69      NetworkHandler::Get()->network_state_handler()->DefaultNetwork());
70}
71
72void NetworkChangeNotifierChromeos::Shutdown() {
73  dns_config_service_.reset();
74  NetworkHandler::Get()->network_state_handler()->RemoveObserver(this);
75  DBusThreadManager::Get()->GetPowerManagerClient()->RemoveObserver(this);
76}
77
78net::NetworkChangeNotifier::ConnectionType
79NetworkChangeNotifierChromeos::GetCurrentConnectionType() const {
80  return connection_type_;
81}
82
83void NetworkChangeNotifierChromeos::SystemResumed(
84    const base::TimeDelta& sleep_duration) {
85  // Force invalidation of network resources on resume.
86  NetworkChangeNotifier::NotifyObserversOfIPAddressChange();
87}
88
89
90void NetworkChangeNotifierChromeos::DefaultNetworkChanged(
91    const chromeos::NetworkState* default_network) {
92  bool connection_type_changed = false;
93  bool ip_address_changed = false;
94  bool dns_changed = false;
95
96  UpdateState(default_network, &connection_type_changed,
97              &ip_address_changed, &dns_changed);
98
99  if (connection_type_changed)
100    NetworkChangeNotifier::NotifyObserversOfConnectionTypeChange();
101  if (ip_address_changed)
102    NetworkChangeNotifier::NotifyObserversOfIPAddressChange();
103  if (dns_changed)
104    dns_config_service_->OnNetworkChange();
105}
106
107void NetworkChangeNotifierChromeos::UpdateState(
108    const chromeos::NetworkState* default_network,
109    bool* connection_type_changed,
110    bool* ip_address_changed,
111    bool* dns_changed) {
112  *connection_type_changed = false;
113  *ip_address_changed = false;
114  *dns_changed = false;
115  if (!default_network || !default_network->IsConnectedState()) {
116    // If we lost a default network, we must update our state and notify
117    // observers, otherwise we have nothing to do. (Under normal circumstances,
118    // we should never get duplicate no default network notifications).
119    if (connection_type_ != CONNECTION_NONE) {
120      VLOG(1) << "Lost default network!";
121      *ip_address_changed = true;
122      *dns_changed = true;
123      *connection_type_changed = true;
124      connection_type_ = CONNECTION_NONE;
125      service_path_.clear();
126      ip_address_.clear();
127      dns_servers_.clear();
128    }
129    return;
130  }
131
132  // We do have a default network and it is connected.
133  net::NetworkChangeNotifier::ConnectionType new_connection_type =
134      ConnectionTypeFromShill(default_network->type(),
135                              default_network->technology());
136  if (new_connection_type != connection_type_) {
137    VLOG(1) << "Connection type changed from " << connection_type_ << " -> "
138            << new_connection_type;
139    *connection_type_changed = true;
140  }
141  if (default_network->path() != service_path_) {
142    VLOG(1) << "Service path changed from " << service_path_ << " -> "
143            << default_network->path();
144    // If we had a default network service change, network resources
145    // must always be invalidated.
146    *ip_address_changed = true;
147    *dns_changed = true;
148  }
149  if (default_network->ip_address() != ip_address_) {
150    VLOG(1) << "IP Address changed from " << ip_address_ << " -> "
151            << default_network->ip_address();
152    *ip_address_changed = true;
153  }
154  if (default_network->dns_servers() != dns_servers_) {
155    VLOG(1) << "DNS servers changed.\n"
156            << "Old DNS servers were: "
157            << JoinString(dns_servers_, ",") << "\n"
158            << "New DNS servers are: "
159            << JoinString(default_network->dns_servers(), ",");
160    *dns_changed = true;
161  }
162
163  connection_type_ = new_connection_type;
164  service_path_ = default_network->path();
165  ip_address_ = default_network->ip_address();
166  dns_servers_ = default_network->dns_servers();
167}
168
169// static
170net::NetworkChangeNotifier::ConnectionType
171NetworkChangeNotifierChromeos::ConnectionTypeFromShill(
172    const std::string& type, const std::string& technology) {
173  if (type == flimflam::kTypeEthernet)
174    return CONNECTION_ETHERNET;
175  else if (type == flimflam::kTypeWifi)
176    return CONNECTION_WIFI;
177  else if (type == flimflam::kTypeWimax)
178    return CONNECTION_4G;
179
180  if (type != flimflam::kTypeCellular)
181    return CONNECTION_UNKNOWN;
182
183  // For cellular types, mapping depends on the technology.
184  if (technology == flimflam::kNetworkTechnologyEvdo ||
185      technology == flimflam::kNetworkTechnologyGsm ||
186      technology == flimflam::kNetworkTechnologyUmts ||
187      technology == flimflam::kNetworkTechnologyHspa) {
188    return CONNECTION_3G;
189  } else if (technology == flimflam::kNetworkTechnologyHspaPlus ||
190             technology == flimflam::kNetworkTechnologyLte ||
191             technology == flimflam::kNetworkTechnologyLteAdvanced) {
192    return CONNECTION_4G;
193  } else {
194    return CONNECTION_2G;  // Default cellular type is 2G.
195  }
196}
197
198// static
199net::NetworkChangeNotifier::NetworkChangeCalculatorParams
200NetworkChangeNotifierChromeos::NetworkChangeCalculatorParamsChromeos() {
201  NetworkChangeCalculatorParams params;
202  // Delay values arrived at by simple experimentation and adjusted so as to
203  // produce a single signal when switching between network connections.
204  params.ip_address_offline_delay_ = base::TimeDelta::FromMilliseconds(4000);
205  params.ip_address_online_delay_ = base::TimeDelta::FromMilliseconds(1000);
206  params.connection_type_offline_delay_ =
207      base::TimeDelta::FromMilliseconds(500);
208  params.connection_type_online_delay_ = base::TimeDelta::FromMilliseconds(500);
209  return params;
210}
211
212}  // namespace chromeos
213