blob: 90973e45ec10ffa56a85aa028c89e6a4d683761e [file] [log] [blame]
Gilad Arnold55f39b72014-01-28 12:51:45 -08001// Copyright (c) 2014 The Chromium OS 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
Gilad Arnold55f39b72014-01-28 12:51:45 -08005#include "update_engine/policy_manager/real_shill_provider.h"
6
Gilad Arnold5ef9c482014-03-03 13:51:02 -08007#include <string>
8
9#include <base/logging.h>
Alex Vakulenko75039d72014-03-25 12:36:28 -070010#include <base/strings/stringprintf.h>
Gilad Arnold5ef9c482014-03-03 13:51:02 -080011#include <chromeos/dbus/service_constants.h>
12
13#include "update_engine/policy_manager/generic_variables.h"
14#include "update_engine/utils.h"
15
16using std::string;
17
18namespace {
19
20// Looks up a key in a hash table and returns the string inside of the returned
21// GValue.
22const char* GetStrProperty(GHashTable* hash_table, const char* key) {
23 auto gval = reinterpret_cast<GValue*>(g_hash_table_lookup(hash_table, key));
24 return (gval ? g_value_get_string(gval) : NULL);
25}
26
27}; // namespace
28
29
Gilad Arnold55f39b72014-01-28 12:51:45 -080030namespace chromeos_policy_manager {
31
Gilad Arnoldbeb39e92014-03-11 11:34:50 -070032// ShillConnector methods.
33
Gilad Arnold5ef9c482014-03-03 13:51:02 -080034const ShillConnector::ConnStrToType ShillConnector::shill_conn_str_to_type[] = {
Gilad Arnoldaf309d52014-03-13 11:21:55 -070035 {shill::kTypeEthernet, ConnectionType::kEthernet},
36 {shill::kTypeWifi, ConnectionType::kWifi},
37 {shill::kTypeWimax, ConnectionType::kWimax},
38 {shill::kTypeBluetooth, ConnectionType::kBluetooth},
39 {shill::kTypeCellular, ConnectionType::kCellular},
Gilad Arnold5ef9c482014-03-03 13:51:02 -080040};
Gilad Arnold55f39b72014-01-28 12:51:45 -080041
Gilad Arnoldbeb39e92014-03-11 11:34:50 -070042ShillConnector::~ShillConnector() {
43 if (!is_init_)
44 return;
45
46 // Detach signal handler, free manager proxy.
47 dbus_->ProxyDisconnectSignal(manager_proxy_, shill::kMonitorPropertyChanged,
48 G_CALLBACK(signal_handler_), signal_data_);
49 dbus_->ProxyUnref(manager_proxy_);
50}
51
Gilad Arnold5ef9c482014-03-03 13:51:02 -080052bool ShillConnector::Init() {
Gilad Arnoldbeb39e92014-03-11 11:34:50 -070053 if (is_init_)
54 return true;
55
56 // Obtain a DBus connection.
Gilad Arnold5ef9c482014-03-03 13:51:02 -080057 GError* error = NULL;
58 connection_ = dbus_->BusGet(DBUS_BUS_SYSTEM, &error);
59 if (!connection_) {
60 LOG(ERROR) << "Failed to initialize DBus connection: "
61 << chromeos_update_engine::utils::GetAndFreeGError(&error);
62 return false;
63 }
Gilad Arnoldbeb39e92014-03-11 11:34:50 -070064
65 // Allocate a shill manager proxy.
Gilad Arnold5ef9c482014-03-03 13:51:02 -080066 manager_proxy_ = GetProxy(shill::kFlimflamServicePath,
67 shill::kFlimflamManagerInterface);
Gilad Arnold55f39b72014-01-28 12:51:45 -080068
Gilad Arnoldbeb39e92014-03-11 11:34:50 -070069 // Subscribe to the manager's PropertyChanged signal.
70 dbus_->ProxyAddSignal_2(manager_proxy_, shill::kMonitorPropertyChanged,
71 G_TYPE_STRING, G_TYPE_VALUE);
72 dbus_->ProxyConnectSignal(manager_proxy_, shill::kMonitorPropertyChanged,
73 G_CALLBACK(signal_handler_), signal_data_, NULL);
Gilad Arnold5ef9c482014-03-03 13:51:02 -080074
Gilad Arnoldbeb39e92014-03-11 11:34:50 -070075 return is_init_ = true;
Gilad Arnold5ef9c482014-03-03 13:51:02 -080076}
77
78bool ShillConnector::GetConnectionType(const string& service_path,
Gilad Arnoldaf309d52014-03-13 11:21:55 -070079 ConnectionType* conn_type_p) {
Gilad Arnold5ef9c482014-03-03 13:51:02 -080080 // Obtain a proxy for the service path.
81 DBusGProxy* service_proxy = GetProxy(service_path.c_str(),
82 shill::kFlimflamServiceInterface);
83
84 GHashTable* hash_table = NULL;
85 bool success = false;
86 bool is_vpn = false;
87 if (GetProperties(service_proxy, &hash_table)) {
88 const char* type_str = GetStrProperty(hash_table, shill::kTypeProperty);
89 if (type_str && !strcmp(type_str, shill::kTypeVPN)) {
90 is_vpn = true;
91 type_str = GetStrProperty(hash_table, shill::kPhysicalTechnologyProperty);
92 }
93 if (type_str) {
94 success = true;
95 *conn_type_p = ParseConnType(type_str);
96 }
97 g_hash_table_unref(hash_table);
98 }
99
100 if (!success) {
101 LOG(ERROR) << "Could not find type of "
102 << (is_vpn ? "physical connection underlying VPN " : "")
103 << "connection (" << service_path << ")";
104 }
105
106 dbus_->ProxyUnref(service_proxy);
107 return success;
108}
109
110DBusGProxy* ShillConnector::GetProxy(const char* path, const char* interface) {
111 return dbus_->ProxyNewForName(connection_, shill::kFlimflamServiceName,
112 path, interface);
113}
114
Gilad Arnoldaf309d52014-03-13 11:21:55 -0700115ConnectionType ShillConnector::ParseConnType(const char* str) {
Gilad Arnold5ef9c482014-03-03 13:51:02 -0800116 for (unsigned i = 0; i < arraysize(shill_conn_str_to_type); i++)
117 if (!strcmp(str, shill_conn_str_to_type[i].str))
118 return shill_conn_str_to_type[i].type;
119
Gilad Arnoldaf309d52014-03-13 11:21:55 -0700120 return ConnectionType::kUnknown;
Gilad Arnold5ef9c482014-03-03 13:51:02 -0800121}
122
Gilad Arnold5ef9c482014-03-03 13:51:02 -0800123bool ShillConnector::GetProperties(DBusGProxy* proxy, GHashTable** result_p) {
124 GError* error = NULL;
125 if (!dbus_->ProxyCall_0_1(proxy, shill::kGetPropertiesFunction, &error,
126 result_p)) {
127 LOG(ERROR) << "Calling shill via DBus proxy failed: "
128 << chromeos_update_engine::utils::GetAndFreeGError(&error);
129 return false;
130 }
131 return true;
132}
133
Gilad Arnold5ef9c482014-03-03 13:51:02 -0800134
135// A variable returning the curent connection type.
Gilad Arnoldaf309d52014-03-13 11:21:55 -0700136class ConnTypeVariable : public Variable<ConnectionType> {
Gilad Arnold5ef9c482014-03-03 13:51:02 -0800137 public:
138 ConnTypeVariable(const string& name, ShillConnector* connector,
Gilad Arnoldbeb39e92014-03-11 11:34:50 -0700139 RealShillProvider* provider)
Gilad Arnoldaf309d52014-03-13 11:21:55 -0700140 : Variable<ConnectionType>(name, kVariableModePoll),
Gilad Arnoldbeb39e92014-03-11 11:34:50 -0700141 connector_(connector), provider_(provider) {}
Gilad Arnold5ef9c482014-03-03 13:51:02 -0800142
143 protected:
Gilad Arnoldbeb39e92014-03-11 11:34:50 -0700144 // TODO(garnold) Shift to a non-blocking version, respect the timeout.
Gilad Arnoldaf309d52014-03-13 11:21:55 -0700145 virtual const ConnectionType* GetValue(base::TimeDelta /* timeout */,
146 string* errmsg) {
Gilad Arnoldbeb39e92014-03-11 11:34:50 -0700147 if (!(provider_->is_connected_)) {
148 if (errmsg)
149 *errmsg = "No connection detected";
Gilad Arnold5ef9c482014-03-03 13:51:02 -0800150 return NULL;
Gilad Arnoldbeb39e92014-03-11 11:34:50 -0700151 }
Gilad Arnold5ef9c482014-03-03 13:51:02 -0800152
Gilad Arnoldaf309d52014-03-13 11:21:55 -0700153 ConnectionType conn_type;
Gilad Arnoldbeb39e92014-03-11 11:34:50 -0700154 if (provider_->is_conn_type_valid_) {
155 conn_type = provider_->conn_type_;
156 } else {
157 if (!connector_->GetConnectionType(provider_->default_service_path_,
158 &conn_type)) {
159 if (errmsg)
Alex Vakulenko75039d72014-03-25 12:36:28 -0700160 *errmsg = base::StringPrintf(
Gilad Arnoldbeb39e92014-03-11 11:34:50 -0700161 "Could not retrieve type of default connection (%s)",
162 provider_->default_service_path_.c_str());
163 return NULL;
164 }
165 provider_->is_conn_type_valid_ = true;
166 }
167
Gilad Arnoldaf309d52014-03-13 11:21:55 -0700168 return new ConnectionType(conn_type);
Gilad Arnold5ef9c482014-03-03 13:51:02 -0800169 }
170
171 private:
Gilad Arnoldbeb39e92014-03-11 11:34:50 -0700172 // The DBus connector.
Gilad Arnold5ef9c482014-03-03 13:51:02 -0800173 ShillConnector* connector_;
Gilad Arnoldbeb39e92014-03-11 11:34:50 -0700174
175 // The shill provider object (we need to read/update some internal members).
176 RealShillProvider* provider_;
Gilad Arnold5ef9c482014-03-03 13:51:02 -0800177
178 DISALLOW_COPY_AND_ASSIGN(ConnTypeVariable);
179};
180
Gilad Arnoldbeb39e92014-03-11 11:34:50 -0700181
182// RealShillProvider methods.
183
Gilad Arnold5ef9c482014-03-03 13:51:02 -0800184bool RealShillProvider::DoInit() {
185 // Initialize a DBus connection and obtain the shill manager proxy.
Gilad Arnoldbeb39e92014-03-11 11:34:50 -0700186 connector_.reset(new ShillConnector(dbus_, HandlePropertyChangedStatic,
187 this));
Gilad Arnold5ef9c482014-03-03 13:51:02 -0800188 if (!connector_->Init())
189 return false;
190
Gilad Arnoldbeb39e92014-03-11 11:34:50 -0700191 // Read initial connection status.
192 GHashTable* hash_table = NULL;
193 if (!connector_->GetManagerProperties(&hash_table))
194 return false;
195 GValue* value = reinterpret_cast<GValue*>(
196 g_hash_table_lookup(hash_table, shill::kDefaultServiceProperty));
197 bool success = ProcessDefaultService(value);
198 g_hash_table_unref(hash_table);
199 if (!success)
200 return false;
201
Gilad Arnold5ef9c482014-03-03 13:51:02 -0800202 // Initialize variables.
Alex Deymo540d9422014-02-27 11:17:31 -0800203 set_var_is_connected(
Gilad Arnoldbeb39e92014-03-11 11:34:50 -0700204 new CopyVariable<bool>("is_connected", kVariableModePoll, is_connected_));
Alex Deymo540d9422014-02-27 11:17:31 -0800205 set_var_conn_type(
Gilad Arnoldbeb39e92014-03-11 11:34:50 -0700206 new ConnTypeVariable("conn_type", connector_.get(), this));
Alex Deymo540d9422014-02-27 11:17:31 -0800207 set_var_conn_last_changed(
Gilad Arnold5ef9c482014-03-03 13:51:02 -0800208 new CopyVariable<base::Time>("conn_last_changed", kVariableModePoll,
209 conn_last_changed_));
Gilad Arnold55f39b72014-01-28 12:51:45 -0800210 return true;
211}
212
Gilad Arnoldbeb39e92014-03-11 11:34:50 -0700213bool RealShillProvider::ProcessDefaultService(GValue* value) {
214 // Decode the string from the boxed value.
215 const char* default_service_path_str = NULL;
216 if (!(value && (default_service_path_str = g_value_get_string(value))))
217 return false;
218
219 // Update the connection status.
220 is_connected_ = strcmp(default_service_path_str, "/");
221 if (default_service_path_ != default_service_path_str)
222 conn_last_changed_ = clock_->GetWallclockTime();
223 default_service_path_ = default_service_path_str;
224 is_conn_type_valid_ = false;
225 return true;
226}
227
228void RealShillProvider::HandlePropertyChanged(DBusGProxy* proxy,
229 const char* name, GValue* value) {
230 if (!strcmp(name, shill::kDefaultServiceProperty))
231 ProcessDefaultService(value);
232}
233
234void RealShillProvider::HandlePropertyChangedStatic(DBusGProxy* proxy,
235 const char* name,
236 GValue* value,
237 void* data) {
238 auto obj = reinterpret_cast<RealShillProvider*>(data);
239 obj->HandlePropertyChanged(proxy, name, value);
240}
241
Gilad Arnold55f39b72014-01-28 12:51:45 -0800242} // namespace chromeos_policy_manager