blob: 438ed41d2a0afd32cd596ed213564eadc93bf0d6 [file] [log] [blame]
// Copyright (c) 2012 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "update_engine/connection_manager.h"
#include <string>
#include <base/stl_util.h>
#include <base/string_util.h>
#include <chromeos/dbus/service_constants.h>
#include <dbus/dbus-glib.h>
#include <glib.h>
#include "update_engine/system_state.h"
#include "update_engine/utils.h"
using std::set;
using std::string;
namespace chromeos_update_engine {
namespace {
// Gets the DbusGProxy for FlimFlam. Must be free'd with ProxyUnref()
bool GetFlimFlamProxy(DbusGlibInterface* dbus_iface,
const char* path,
const char* interface,
DBusGProxy** out_proxy) {
DBusGConnection* bus;
DBusGProxy* proxy;
GError* error = NULL;
bus = dbus_iface->BusGet(DBUS_BUS_SYSTEM, &error);
if (!bus) {
LOG(ERROR) << "Failed to get system bus";
return false;
}
proxy = dbus_iface->ProxyNewForNameOwner(bus,
flimflam::kFlimflamServiceName,
path,
interface,
&error);
if (!proxy) {
LOG(ERROR) << "Error getting FlimFlam proxy: "
<< utils::GetAndFreeGError(&error);
return false;
}
*out_proxy = proxy;
return true;
}
// On success, caller owns the GHashTable at out_hash_table.
// Returns true on success.
bool GetProperties(DbusGlibInterface* dbus_iface,
const char* path,
const char* interface,
GHashTable** out_hash_table) {
DBusGProxy* proxy;
GError* error = NULL;
TEST_AND_RETURN_FALSE(GetFlimFlamProxy(dbus_iface,
path,
interface,
&proxy));
gboolean rc = dbus_iface->ProxyCall(proxy,
"GetProperties",
&error,
G_TYPE_INVALID,
dbus_g_type_get_map("GHashTable",
G_TYPE_STRING,
G_TYPE_VALUE),
out_hash_table,
G_TYPE_INVALID);
dbus_iface->ProxyUnref(proxy);
if (rc == FALSE) {
LOG(ERROR) << "dbus_g_proxy_call failed";
return false;
}
return true;
}
// Returns (via out_path) the default network path, or empty string if
// there's no network up.
// Returns true on success.
bool GetDefaultServicePath(DbusGlibInterface* dbus_iface, string* out_path) {
GHashTable* hash_table = NULL;
TEST_AND_RETURN_FALSE(GetProperties(dbus_iface,
flimflam::kFlimflamServicePath,
flimflam::kFlimflamManagerInterface,
&hash_table));
GValue* value = reinterpret_cast<GValue*>(g_hash_table_lookup(hash_table,
"Services"));
GArray* array = NULL;
bool success = false;
if (G_VALUE_HOLDS(value, DBUS_TYPE_G_OBJECT_PATH_ARRAY) &&
(array = reinterpret_cast<GArray*>(g_value_get_boxed(value))) &&
(array->len > 0)) {
*out_path = g_array_index(array, const char*, 0);
success = true;
}
g_hash_table_unref(hash_table);
return success;
}
NetworkConnectionType ParseConnectionType(const char* type_str) {
if (!strcmp(type_str, flimflam::kTypeEthernet)) {
return kNetEthernet;
} else if (!strcmp(type_str, flimflam::kTypeWifi)) {
return kNetWifi;
} else if (!strcmp(type_str, flimflam::kTypeWimax)) {
return kNetWimax;
} else if (!strcmp(type_str, flimflam::kTypeBluetooth)) {
return kNetBluetooth;
} else if (!strcmp(type_str, flimflam::kTypeCellular)) {
return kNetCellular;
}
return kNetUnknown;
}
bool GetServicePathType(DbusGlibInterface* dbus_iface,
const string& path,
NetworkConnectionType* out_type) {
GHashTable* hash_table = NULL;
TEST_AND_RETURN_FALSE(GetProperties(dbus_iface,
path.c_str(),
flimflam::kFlimflamServiceInterface,
&hash_table));
GValue* value = (GValue*)g_hash_table_lookup(hash_table, "Type");
const char* type_str = NULL;
bool success = false;
if (value != NULL && (type_str = g_value_get_string(value)) != NULL) {
*out_type = ParseConnectionType(type_str);
success = true;
}
g_hash_table_unref(hash_table);
return success;
}
} // namespace {}
ConnectionManager::ConnectionManager(SystemState *system_state)
: system_state_(system_state) {}
bool ConnectionManager::IsUpdateAllowedOver(NetworkConnectionType type) const {
switch (type) {
case kNetBluetooth:
return false;
case kNetCellular: {
set<string> allowed_types;
const policy::DevicePolicy* device_policy =
system_state_->GetDevicePolicy();
if (!device_policy) {
LOG(INFO) << "Disabling updates over cellular connection as there's no "
"device policy object present";
return false;
}
if (!device_policy->GetAllowedConnectionTypesForUpdate(&allowed_types)) {
LOG(INFO) << "Disabling updates over cellular connection as there's no "
"allowed connection types from policy";
return false;
}
if (!ContainsKey(allowed_types, flimflam::kTypeCellular)) {
LOG(INFO) << "Disabling updates over cellular connection as it's not "
"allowed in the device policy.";
return false;
}
LOG(INFO) << "Allowing updates over cellular per device policy";
return true;
}
default:
return true;
}
}
const char* ConnectionManager::StringForConnectionType(
NetworkConnectionType type) const {
static const char* const kValues[] = {flimflam::kTypeEthernet,
flimflam::kTypeWifi,
flimflam::kTypeWimax,
flimflam::kTypeBluetooth,
flimflam::kTypeCellular};
if (type < 0 || type >= static_cast<int>(arraysize(kValues))) {
return "Unknown";
}
return kValues[type];
}
bool ConnectionManager::GetConnectionType(
DbusGlibInterface* dbus_iface,
NetworkConnectionType* out_type) const {
string default_service_path;
TEST_AND_RETURN_FALSE(GetDefaultServicePath(dbus_iface,
&default_service_path));
TEST_AND_RETURN_FALSE(GetServicePathType(dbus_iface,
default_service_path,
out_type));
return true;
}
} // namespace chromeos_update_engine