blob: b20be68e9becb8e3701e595bf642fab4cb321445 [file] [log] [blame]
// Copyright 2018 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 "vm_tools/concierge/shill_client.h"
#include <utility>
#include <vector>
#include <base/bind.h>
#include <base/logging.h>
#include <brillo/variant_dictionary.h>
#include <chromeos/dbus/service_constants.h>
namespace vm_tools {
namespace concierge {
ShillClient::ShillClient(scoped_refptr<dbus::Bus> bus)
: bus_(bus),
manager_proxy_(new org::chromium::flimflam::ManagerProxy(bus_)) {
manager_proxy_->RegisterPropertyChangedSignalHandler(
base::Bind(&ShillClient::OnManagerPropertyChange,
weak_factory_.GetWeakPtr()),
base::Bind(&ShillClient::OnManagerPropertyChangeRegistration,
weak_factory_.GetWeakPtr()));
}
bool ShillClient::GetResolvConfig(std::vector<std::string>* nameservers,
std::vector<std::string>* search_domains) {
DCHECK(nameservers);
DCHECK(search_domains);
brillo::VariantDictionary manager_props;
if (!manager_proxy_->GetProperties(&manager_props, nullptr)) {
LOG(ERROR) << "Unable to get manager properties";
return false;
}
auto it = manager_props.find(shill::kDefaultServiceProperty);
if (it == manager_props.end()) {
LOG(ERROR) << "Manager properties is missing default service";
return false;
}
dbus::ObjectPath service_path = it->second.TryGet<dbus::ObjectPath>();
// A path of "/" indicates that there is no default service.
// Allow returning empty nameservers here since there's no network
// connectivity anyway.
if (!service_path.IsValid() || service_path.value() == "/") {
return true;
}
org::chromium::flimflam::ServiceProxy service_proxy(bus_, service_path);
brillo::VariantDictionary service_props;
if (!service_proxy.GetProperties(&service_props, nullptr)) {
LOG(ERROR) << "Can't retrieve properties for service";
return false;
}
it = service_props.find(shill::kStateProperty);
if (it == service_props.end()) {
LOG(ERROR) << "Service properties are missing state";
return false;
}
std::string state = it->second.TryGet<std::string>();
if (state != shill::kStateOnline) {
// Found the default service, but it is still connecting.
return true;
}
it = service_props.find(shill::kIPConfigProperty);
if (it == service_props.end()) {
LOG(ERROR) << "Service properties are missing IP config";
return false;
}
dbus::ObjectPath ipconfig_path = it->second.TryGet<dbus::ObjectPath>();
if (!ipconfig_path.IsValid()) {
LOG(ERROR) << "Invalid ipconfig path";
return false;
}
org::chromium::flimflam::IPConfigProxy ipconfig_proxy(bus_, ipconfig_path);
brillo::VariantDictionary ipconfig_props;
if (!ipconfig_proxy.GetProperties(&ipconfig_props, nullptr)) {
LOG(ERROR) << "Can't retrieve properties for ipconfig";
return false;
}
it = ipconfig_props.find(shill::kNameServersProperty);
if (it == ipconfig_props.end()) {
LOG(ERROR) << "IPConfig properties are missing nameservers list";
return false;
}
// Nameservers are required.
std::vector<std::string> new_nameservers =
it->second.TryGet<std::vector<std::string>>();
if (new_nameservers.empty()) {
LOG(ERROR) << "IPConfig nameservers list is empty";
return false;
}
// Search domains can be omitted.
it = ipconfig_props.find(shill::kSearchDomainsProperty);
if (it == ipconfig_props.end()) {
LOG(ERROR) << "IPConfig properties are missing search domains list";
return false;
}
std::vector<std::string> new_search_domains =
it->second.TryGet<std::vector<std::string>>();
*nameservers = std::move(new_nameservers);
*search_domains = std::move(new_search_domains);
return true;
}
void ShillClient::OnManagerPropertyChangeRegistration(
const std::string& interface,
const std::string& signal_name,
bool success) {
CHECK(success) << "Unable to register for interface change events";
}
void ShillClient::OnManagerPropertyChange(const std::string& property_name,
const brillo::Any& property_value) {
if (property_name != shill::kDefaultServiceProperty &&
property_name != shill::kConnectionStateProperty) {
return;
}
std::vector<std::string> new_nameservers;
std::vector<std::string> new_search_domains;
if (!GetResolvConfig(&new_nameservers, &new_search_domains) ||
(nameservers_ == new_nameservers &&
search_domains_ == new_search_domains)) {
return;
}
nameservers_ = std::move(new_nameservers);
search_domains_ = std::move(new_search_domains);
if (!config_changed_callback_.is_null()) {
config_changed_callback_.Run(nameservers_, search_domains_);
}
}
void ShillClient::RegisterResolvConfigChangedHandler(
base::Callback<void(std::vector<std::string>, std::vector<std::string>)>
callback) {
config_changed_callback_ = std::move(callback);
if (!GetResolvConfig(&nameservers_, &search_domains_)) {
return;
}
CHECK(!config_changed_callback_.is_null());
config_changed_callback_.Run(nameservers_, search_domains_);
}
} // namespace concierge
} // namespace vm_tools