| Gilad Arnold | 55f39b7 | 2014-01-28 12:51:45 -0800 | [diff] [blame] | 1 | // 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 Arnold | 55f39b7 | 2014-01-28 12:51:45 -0800 | [diff] [blame] | 5 | #include "update_engine/policy_manager/real_shill_provider.h" | 
|  | 6 |  | 
| Gilad Arnold | 5ef9c48 | 2014-03-03 13:51:02 -0800 | [diff] [blame^] | 7 | #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 |  | 
|  | 15 | using std::string; | 
|  | 16 |  | 
|  | 17 | namespace { | 
|  | 18 |  | 
|  | 19 | // Looks up a key in a hash table and returns the string inside of the returned | 
|  | 20 | // GValue. | 
|  | 21 | const 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 Arnold | 55f39b7 | 2014-01-28 12:51:45 -0800 | [diff] [blame] | 29 | namespace chromeos_policy_manager { | 
|  | 30 |  | 
| Gilad Arnold | 5ef9c48 | 2014-03-03 13:51:02 -0800 | [diff] [blame^] | 31 | const 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 Arnold | 55f39b7 | 2014-01-28 12:51:45 -0800 | [diff] [blame] | 38 |  | 
| Gilad Arnold | 5ef9c48 | 2014-03-03 13:51:02 -0800 | [diff] [blame^] | 39 | bool 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 Arnold | 55f39b7 | 2014-01-28 12:51:45 -0800 | [diff] [blame] | 51 |  | 
| Gilad Arnold | 5ef9c48 | 2014-03-03 13:51:02 -0800 | [diff] [blame^] | 52 | bool 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 |  | 
|  | 72 | bool 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 |  | 
|  | 104 | DBusGProxy* ShillConnector::GetProxy(const char* path, const char* interface) { | 
|  | 105 | return dbus_->ProxyNewForName(connection_, shill::kFlimflamServiceName, | 
|  | 106 | path, interface); | 
|  | 107 | } | 
|  | 108 |  | 
|  | 109 | ShillConnType 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. | 
|  | 119 | bool 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. | 
|  | 131 | class 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. | 
|  | 157 | class 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. | 
|  | 189 | bool 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 Deymo | 540d942 | 2014-02-27 11:17:31 -0800 | [diff] [blame] | 196 | set_var_is_connected( | 
| Gilad Arnold | 5ef9c48 | 2014-03-03 13:51:02 -0800 | [diff] [blame^] | 197 | new IsConnectedVariable("is_connected", connector_.get(), | 
|  | 198 | &is_connected_tracker_)); | 
| Alex Deymo | 540d942 | 2014-02-27 11:17:31 -0800 | [diff] [blame] | 199 | set_var_conn_type( | 
| Gilad Arnold | 5ef9c48 | 2014-03-03 13:51:02 -0800 | [diff] [blame^] | 200 | new ConnTypeVariable("conn_type", connector_.get(), | 
|  | 201 | &is_connected_tracker_)); | 
| Alex Deymo | 540d942 | 2014-02-27 11:17:31 -0800 | [diff] [blame] | 202 | set_var_conn_last_changed( | 
| Gilad Arnold | 5ef9c48 | 2014-03-03 13:51:02 -0800 | [diff] [blame^] | 203 | new CopyVariable<base::Time>("conn_last_changed", kVariableModePoll, | 
|  | 204 | conn_last_changed_)); | 
| Gilad Arnold | 55f39b7 | 2014-01-28 12:51:45 -0800 | [diff] [blame] | 205 | return true; | 
|  | 206 | } | 
|  | 207 |  | 
|  | 208 | }  // namespace chromeos_policy_manager |