blob: df6a6ae0cb1f7d14116b839fc416e9e107e2d082 [file] [log] [blame]
// Copyright 2014 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 "buffet/peerd_client.h"
#include <map>
#include <vector>
#include <base/message_loop/message_loop.h>
#include <brillo/errors/error.h>
#include <brillo/strings/string_utils.h>
namespace buffet {
namespace {
// Commit changes only if no update request happened during the timeout.
// Usually updates happen in batches, so we don't want to flood network with
// updates relevant for a short amount of time.
const int kCommitTimeoutSeconds = 1;
void OnError(const std::string& operation, brillo::Error* error) {
LOG(ERROR) << operation << " failed:" << error->GetMessage();
}
const char kExpectedServiceType[] = "_privet._tcp";
const char kServiceName[] = "privet";
} // namespace
PeerdClient::PeerdClient(const scoped_refptr<dbus::Bus>& bus)
: peerd_object_manager_proxy_{bus} {
peerd_object_manager_proxy_.SetManagerAddedCallback(
base::Bind(&PeerdClient::OnPeerdOnline, weak_ptr_factory_.GetWeakPtr()));
peerd_object_manager_proxy_.SetManagerRemovedCallback(
base::Bind(&PeerdClient::OnPeerdOffline, weak_ptr_factory_.GetWeakPtr()));
}
PeerdClient::~PeerdClient() {
RemoveService();
}
void PeerdClient::PublishService(const std::string& service_type,
uint16_t port,
const std::vector<std::string>& txt) {
// Only one service supported.
CHECK_EQ(service_type, kExpectedServiceType);
port_ = port;
txt_ = txt;
Update();
}
void PeerdClient::StopPublishing(const std::string& service_type) {
// Only one service supported.
CHECK_EQ(service_type, kExpectedServiceType);
port_ = 0;
Update();
}
void PeerdClient::Update() {
// Abort pending updates, and wait for more changes.
restart_weak_ptr_factory_.InvalidateWeakPtrs();
base::MessageLoop::current()->PostDelayedTask(
FROM_HERE, base::Bind(&PeerdClient::UpdateImpl,
restart_weak_ptr_factory_.GetWeakPtr()),
base::TimeDelta::FromSeconds(kCommitTimeoutSeconds));
}
void PeerdClient::OnPeerdOnline(
org::chromium::peerd::ManagerProxyInterface* manager_proxy) {
peerd_manager_proxy_ = manager_proxy;
VLOG(1) << "Peerd manager is online at '"
<< manager_proxy->GetObjectPath().value() << "'.";
Update();
}
void PeerdClient::OnPeerdOffline(const dbus::ObjectPath& object_path) {
peerd_manager_proxy_ = nullptr;
VLOG(1) << "Peerd manager is now offline.";
}
void PeerdClient::ExposeService() {
// Do nothing if peerd hasn't started yet.
if (peerd_manager_proxy_ == nullptr)
return;
VLOG(1) << "Starting peerd advertising.";
CHECK_NE(port_, 0);
CHECK(!txt_.empty());
std::map<std::string, brillo::Any> mdns_options{
{"port", brillo::Any{port_}},
};
std::map<std::string, std::string> txt;
for (const auto& record : txt_) {
auto name_value = brillo::string_utils::SplitAtFirst(record, "=");
CHECK(!name_value.second.empty());
txt.emplace(std::move(name_value));
}
published_ = true;
peerd_manager_proxy_->ExposeServiceAsync(
kServiceName, txt, {{"mdns", mdns_options}}, base::Closure(),
base::Bind(&OnError, "ExposeService"));
}
void PeerdClient::RemoveService() {
if (peerd_manager_proxy_ == nullptr)
return;
VLOG(1) << "Stopping peerd advertising.";
if (published_) {
published_ = false;
peerd_manager_proxy_->RemoveExposedServiceAsync(
kServiceName, base::Closure(), base::Bind(&OnError, "RemoveService"));
}
}
void PeerdClient::UpdateImpl() {
if (port_ == 0)
return RemoveService();
ExposeService();
}
} // namespace buffet