blob: 60a953ff4f3f468942fdacaf751cf84d7b23a01d [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>
10#include <chromeos/dbus/service_constants.h>
11
12#include "update_engine/policy_manager/generic_variables.h"
13#include "update_engine/utils.h"
14
15using std::string;
16
17namespace {
18
19// Looks up a key in a hash table and returns the string inside of the returned
20// GValue.
21const char* GetStrProperty(GHashTable* hash_table, const char* key) {
22 auto gval = reinterpret_cast<GValue*>(g_hash_table_lookup(hash_table, key));
23 return (gval ? g_value_get_string(gval) : NULL);
24}
25
26}; // namespace
27
28
Gilad Arnold55f39b72014-01-28 12:51:45 -080029namespace chromeos_policy_manager {
30
Gilad Arnold5ef9c482014-03-03 13:51:02 -080031const ShillConnector::ConnStrToType ShillConnector::shill_conn_str_to_type[] = {
32 {shill::kTypeEthernet, kShillConnTypeEthernet},
33 {shill::kTypeWifi, kShillConnTypeWifi},
34 {shill::kTypeWimax, kShillConnTypeWimax},
35 {shill::kTypeBluetooth, kShillConnTypeBluetooth},
36 {shill::kTypeCellular, kShillConnTypeCellular},
37};
Gilad Arnold55f39b72014-01-28 12:51:45 -080038
Gilad Arnold5ef9c482014-03-03 13:51:02 -080039bool ShillConnector::Init() {
40 GError* error = NULL;
41 connection_ = dbus_->BusGet(DBUS_BUS_SYSTEM, &error);
42 if (!connection_) {
43 LOG(ERROR) << "Failed to initialize DBus connection: "
44 << chromeos_update_engine::utils::GetAndFreeGError(&error);
45 return false;
46 }
47 manager_proxy_ = GetProxy(shill::kFlimflamServicePath,
48 shill::kFlimflamManagerInterface);
49 return true;
50}
Gilad Arnold55f39b72014-01-28 12:51:45 -080051
Gilad Arnold5ef9c482014-03-03 13:51:02 -080052bool ShillConnector::GetDefaultConnection(bool* is_connected_p,
53 string* default_service_path_p) {
54 GHashTable* hash_table = NULL;
55 if (!GetProperties(manager_proxy_, &hash_table))
56 return false;
57 GValue* value = reinterpret_cast<GValue*>(
58 g_hash_table_lookup(hash_table, shill::kDefaultServiceProperty));
59 const char* default_service_path_str = NULL;
60 bool success = false;
61 if (value && (default_service_path_str = g_value_get_string(value))) {
62 success = true;
63 *is_connected_p = strcmp(default_service_path_str, "/");
64 if (*is_connected_p)
65 *default_service_path_p = default_service_path_str;
66 }
67 g_hash_table_unref(hash_table);
68
69 return success;
70}
71
72bool ShillConnector::GetConnectionType(const string& service_path,
73 ShillConnType* conn_type_p) {
74 // Obtain a proxy for the service path.
75 DBusGProxy* service_proxy = GetProxy(service_path.c_str(),
76 shill::kFlimflamServiceInterface);
77
78 GHashTable* hash_table = NULL;
79 bool success = false;
80 bool is_vpn = false;
81 if (GetProperties(service_proxy, &hash_table)) {
82 const char* type_str = GetStrProperty(hash_table, shill::kTypeProperty);
83 if (type_str && !strcmp(type_str, shill::kTypeVPN)) {
84 is_vpn = true;
85 type_str = GetStrProperty(hash_table, shill::kPhysicalTechnologyProperty);
86 }
87 if (type_str) {
88 success = true;
89 *conn_type_p = ParseConnType(type_str);
90 }
91 g_hash_table_unref(hash_table);
92 }
93
94 if (!success) {
95 LOG(ERROR) << "Could not find type of "
96 << (is_vpn ? "physical connection underlying VPN " : "")
97 << "connection (" << service_path << ")";
98 }
99
100 dbus_->ProxyUnref(service_proxy);
101 return success;
102}
103
104DBusGProxy* ShillConnector::GetProxy(const char* path, const char* interface) {
105 return dbus_->ProxyNewForName(connection_, shill::kFlimflamServiceName,
106 path, interface);
107}
108
109ShillConnType ShillConnector::ParseConnType(const char* str) {
110 for (unsigned i = 0; i < arraysize(shill_conn_str_to_type); i++)
111 if (!strcmp(str, shill_conn_str_to_type[i].str))
112 return shill_conn_str_to_type[i].type;
113
114 return kShillConnTypeUnknown;
115}
116
117// Issues a GetProperties call through a given |proxy|, storing the result to
118// |*result_p|. Returns |true| on success.
119bool ShillConnector::GetProperties(DBusGProxy* proxy, GHashTable** result_p) {
120 GError* error = NULL;
121 if (!dbus_->ProxyCall_0_1(proxy, shill::kGetPropertiesFunction, &error,
122 result_p)) {
123 LOG(ERROR) << "Calling shill via DBus proxy failed: "
124 << chromeos_update_engine::utils::GetAndFreeGError(&error);
125 return false;
126 }
127 return true;
128}
129
130// A variable returning whether or not we have a network connection.
131class IsConnectedVariable : public Variable<bool> {
132 public:
133 IsConnectedVariable(const string& name, ShillConnector* connector,
134 LastValueTracker<bool>* is_connected_tracker)
135 : Variable<bool>(name, kVariableModePoll),
136 connector_(connector),
137 is_connected_tracker_(is_connected_tracker) {}
138
139 protected:
140 virtual const bool* GetValue(base::TimeDelta timeout, string* errmsg) {
141 bool is_connected;
142 string default_service_path;
143 if (!connector_->GetDefaultConnection(&is_connected, &default_service_path))
144 return NULL;;
145
146 return new bool(is_connected_tracker_->Update(is_connected));
147 }
148
149 private:
150 ShillConnector* connector_;
151 LastValueTracker<bool>* is_connected_tracker_;
152
153 DISALLOW_COPY_AND_ASSIGN(IsConnectedVariable);
154};
155
156// A variable returning the curent connection type.
157class ConnTypeVariable : public Variable<ShillConnType> {
158 public:
159 ConnTypeVariable(const string& name, ShillConnector* connector,
160 LastValueTracker<bool>* is_connected_tracker)
161 : Variable<ShillConnType>(name, kVariableModePoll),
162 connector_(connector),
163 is_connected_tracker_(is_connected_tracker) {}
164
165 protected:
166 virtual const ShillConnType* GetValue(base::TimeDelta timeout,
167 string* errmsg) {
168 bool is_connected;
169 string default_service_path;
170 ShillConnType conn_type;
171 if (!(connector_->GetDefaultConnection(&is_connected,
172 &default_service_path) &&
173 is_connected &&
174 connector_->GetConnectionType(default_service_path, &conn_type)))
175 return NULL;
176
177 is_connected_tracker_->Update(is_connected);
178 return new ShillConnType(conn_type);
179 }
180
181 private:
182 ShillConnector* connector_;
183 LastValueTracker<bool>* is_connected_tracker_;
184
185 DISALLOW_COPY_AND_ASSIGN(ConnTypeVariable);
186};
187
188// A real implementation of the ShillProvider.
189bool RealShillProvider::DoInit() {
190 // Initialize a DBus connection and obtain the shill manager proxy.
191 connector_.reset(new ShillConnector(dbus_));
192 if (!connector_->Init())
193 return false;
194
195 // Initialize variables.
Alex Deymo540d9422014-02-27 11:17:31 -0800196 set_var_is_connected(
Gilad Arnold5ef9c482014-03-03 13:51:02 -0800197 new IsConnectedVariable("is_connected", connector_.get(),
198 &is_connected_tracker_));
Alex Deymo540d9422014-02-27 11:17:31 -0800199 set_var_conn_type(
Gilad Arnold5ef9c482014-03-03 13:51:02 -0800200 new ConnTypeVariable("conn_type", connector_.get(),
201 &is_connected_tracker_));
Alex Deymo540d9422014-02-27 11:17:31 -0800202 set_var_conn_last_changed(
Gilad Arnold5ef9c482014-03-03 13:51:02 -0800203 new CopyVariable<base::Time>("conn_last_changed", kVariableModePoll,
204 conn_last_changed_));
Gilad Arnold55f39b72014-01-28 12:51:45 -0800205 return true;
206}
207
208} // namespace chromeos_policy_manager