blob: f2ac6e2f4962c209e2bc4749f0c1250633d9dcb5 [file] [log] [blame]
// Copyright 2015 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 "leaderd/peerd_client.h"
#include <base/format_macros.h>
#include <base/logging.h>
#include <base/strings/string_util.h>
#include <base/strings/stringprintf.h>
namespace leaderd {
namespace {
const char kGroupFieldFormat[] = "group_%" PRIuS;
const char kGroupFieldPrefix[] = "group_";
const char kPeerdPeerSelfPath[] = "/org/chromium/peerd/Self";
const char kServiceName[] = "privet-ldrsp";
} // namespace
using org::chromium::peerd::ServiceProxyInterface;
void PeerdClient::SetDelegate(Delegate* delegate) { delegate_ = delegate; }
std::set<std::string> PeerdClient::GetPeersMatchingGroup(
const std::string& in_group_id) {
std::set<std::string> peers;
for (const auto& uuid_path_pair : uuids_to_paths_) {
const ServiceProxyInterface* service_proxy =
GetServiceProxy(uuid_path_pair.second);
if (!service_proxy) {
continue;
}
// Take all the group fields out of the text record.
std::map<std::string, std::string> service_info =
service_proxy->service_info();
for (const auto& field : service_info) {
if (StartsWithASCII(field.first, kGroupFieldPrefix, true) &&
field.second == in_group_id) {
peers.insert(uuid_path_pair.first);
break;
}
}
}
return peers;
}
void PeerdClient::StartMonitoring() {
if (monitoring_) {
return;
}
monitoring_ = true;
chromeos::ErrorPtr error;
org::chromium::peerd::ManagerProxyInterface* proxy = GetManagerProxy();
if (proxy && !proxy->StartMonitoring({"mDNS"}, {}, &monitor_token_, &error)) {
LOG(ERROR) << "StartMonitoring failed:" << error->GetMessage();
}
}
void PeerdClient::StopMonitoring() {
monitoring_ = false;
if (monitor_token_.empty()) {
return;
}
chromeos::ErrorPtr error;
org::chromium::peerd::ManagerProxyInterface* proxy = GetManagerProxy();
if (proxy && !proxy->StopMonitoring(monitor_token_, &error)) {
LOG(ERROR) << "StopMonitoring failed:" << error->GetMessage();
}
}
std::vector<std::tuple<std::vector<uint8_t>, uint16_t>> PeerdClient::GetIPInfo(
const std::string& peer_uuid) {
std::vector<std::tuple<std::vector<uint8_t>, uint16_t>> addresses;
const auto& uuid_to_path = uuids_to_paths_.find(peer_uuid);
if (uuid_to_path == uuids_to_paths_.end()) {
return addresses;
}
const org::chromium::peerd::ServiceProxyInterface* service =
GetServiceProxy(uuid_to_path->second);
if (service) {
addresses = service->ip_infos();
}
return addresses;
}
void PeerdClient::UpdatePeerService(
ServiceProxyInterface* service_proxy,
const dbus::ObjectPath& service_object_path) {
if (StartsWithASCII(service_object_path.value(), kPeerdPeerSelfPath, true)) {
VLOG(3) << "Ignoring service discovered on ourselves.";
return;
}
VLOG(1) << "Found peer with id=" << service_proxy->peer_id();
uuids_to_paths_[service_proxy->peer_id()] = service_object_path;
// Take all the group fields out of the text record.
std::map<std::string, std::string> service_info =
service_proxy->service_info();
std::set<std::string> groups;
for (const auto& txt_field_pair : service_info) {
if (StartsWithASCII(txt_field_pair.first, kGroupFieldPrefix, true)) {
groups.insert(txt_field_pair.second);
}
}
delegate_->OnPeerGroupsChanged(service_proxy->peer_id(), groups);
}
void PeerdClient::RemovePeerService(const dbus::ObjectPath& object_path) {
ServiceProxyInterface* service = GetServiceProxy(object_path);
DCHECK(service) << "Failed to retrieve ServiceProxy instance.";
const auto it = uuids_to_paths_.find(service->peer_id());
if (it == uuids_to_paths_.end()) {
return; // Must have been a service we don't care about.
}
delegate_->OnPeerGroupsChanged(service->peer_id(), {});
uuids_to_paths_.erase(service->peer_id());
}
void PeerdClient::PublishGroups(uint16_t port,
const std::vector<std::string>& groups) {
org::chromium::peerd::ManagerProxyInterface* proxy = GetManagerProxy();
if (!proxy) {
return;
}
std::map<std::string, chromeos::Any> mdns_options{
{"port", chromeos::Any{port}},
};
std::map<std::string, std::string> txt_record{
{"leaderd_ver", "1.0"},
};
size_t group_index = 0;
for (const auto& group : groups) {
std::string field = base::StringPrintf(kGroupFieldFormat, ++group_index);
txt_record.emplace(field, group);
}
chromeos::ErrorPtr error;
if (!proxy->ExposeService(kServiceName, txt_record, {{"mdns", mdns_options}},
&error)) {
LOG(ERROR) << "ExposeService failed:" << error->GetMessage();
}
}
PeerdClientImpl::PeerdClientImpl(const scoped_refptr<dbus::Bus>& bus,
const std::string& peerd_service_name)
: peerd_object_manager_proxy_{bus, peerd_service_name} {
peerd_object_manager_proxy_.SetManagerAddedCallback(base::Bind(
&PeerdClientImpl::OnPeerdManagerAdded, weak_ptr_factory_.GetWeakPtr()));
peerd_object_manager_proxy_.SetManagerRemovedCallback(base::Bind(
&PeerdClientImpl::OnPeerdManagerRemoved, weak_ptr_factory_.GetWeakPtr()));
peerd_object_manager_proxy_.SetPeerAddedCallback(base::Bind(
&PeerdClientImpl::OnPeerdPeerAdded, weak_ptr_factory_.GetWeakPtr()));
peerd_object_manager_proxy_.SetServiceAddedCallback(base::Bind(
&PeerdClientImpl::OnPeerdServiceAdded, weak_ptr_factory_.GetWeakPtr()));
peerd_object_manager_proxy_.SetServiceRemovedCallback(base::Bind(
&PeerdClientImpl::OnPeerdServiceRemoved, weak_ptr_factory_.GetWeakPtr()));
}
void PeerdClientImpl::OnPeerdManagerAdded(
org::chromium::peerd::ManagerProxy* manager_proxy) {
VLOG(1) << "peerd manager online.";
if (monitoring_) {
// StartMonitoring will adjust it back; setting it false forces us to
// reconnect to it.
monitoring_ = false;
StartMonitoring();
}
delegate_->OnPeerdAvailable();
}
void PeerdClientImpl::OnPeerdManagerRemoved(
const dbus::ObjectPath& object_path) {
VLOG(1) << "peerd manager offline.";
delegate_->OnPeerdDeath();
monitor_token_.clear();
}
void PeerdClientImpl::OnPeerdPeerAdded(
org::chromium::peerd::PeerProxy* peer_proxy) {
if (peer_proxy->GetObjectPath().value() == kPeerdPeerSelfPath) {
delegate_->OnSelfIdChanged(peer_proxy->uuid());
}
}
void PeerdClientImpl::OnPeerdServiceAdded(
org::chromium::peerd::ServiceProxy* service_proxy) {
if (service_proxy->service_id() != kServiceName) return;
UpdatePeerService(service_proxy, service_proxy->GetObjectPath());
service_proxy->SetPropertyChangedCallback(base::Bind(
&PeerdClientImpl::OnPeerdServiceChanged, weak_ptr_factory_.GetWeakPtr()));
}
void PeerdClientImpl::OnPeerdServiceRemoved(
const dbus::ObjectPath& object_path) {
RemovePeerService(object_path);
}
void PeerdClientImpl::OnPeerdServiceChanged(
org::chromium::peerd::ServiceProxy* service_proxy,
const std::string& property) {
UpdatePeerService(service_proxy, service_proxy->GetObjectPath());
}
org::chromium::peerd::PeerProxyInterface* PeerdClientImpl::GetPeerProxy(
const dbus::ObjectPath& object_path) {
return peerd_object_manager_proxy_.GetPeerProxy(object_path);
}
org::chromium::peerd::ServiceProxyInterface* PeerdClientImpl::GetServiceProxy(
const dbus::ObjectPath& object_path) {
return peerd_object_manager_proxy_.GetServiceProxy(object_path);
}
org::chromium::peerd::ManagerProxyInterface*
PeerdClientImpl::GetManagerProxy() {
return peerd_object_manager_proxy_.GetManagerProxy();
}
} // namespace leaderd