// Copyright 2014 The Chromium 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 "chromeos/dbus/peer_daemon_manager_client.h" #include "base/bind.h" #include "base/callback.h" #include "base/location.h" #include "base/logging.h" #include "base/memory/weak_ptr.h" #include "base/observer_list.h" #include "base/single_thread_task_runner.h" #include "base/thread_task_runner_handle.h" #include "dbus/bus.h" #include "dbus/message.h" #include "dbus/object_manager.h" #include "dbus/object_proxy.h" #include "dbus/values_util.h" namespace chromeos { namespace { // TODO(benchan): Move these constants to system_api. namespace peerd { const char kPeerdServiceName[] = "org.chromium.peerd"; const char kPeerdObjectManagerServicePath[] = "/org/chromium/peerd"; const char kPeerdManagerPath[] = "/org/chromium/peerd/Manager"; const char kManagerInterface[] = "org.chromium.peerd.Manager"; const char kServiceInterface[] = "org.chromium.peerd.Service"; const char kPeerInterface[] = "org.chromium.peerd.Peer"; const char kStartMonitoringMethod[] = "StartMonitoring"; const char kStopMonitoringMethod[] = "StopMonitoring"; const char kExposeServiceMethod[] = "ExposeService"; const char kRemoveExposedServiceMethod[] = "RemoveExposedService"; const char kPingMethod[] = "Ping"; } // namespace peerd // The PeerDaemonManagerClient implementation used in production. class PeerDaemonManagerClientImpl : public PeerDaemonManagerClient, public dbus::ObjectManager::Interface { public: PeerDaemonManagerClientImpl(); ~PeerDaemonManagerClientImpl() override; // DBusClient overrides. void Init(dbus::Bus* bus) override; // PeerDaemonManagerClient overrides. void AddObserver(Observer* observer) override; void RemoveObserver(Observer* observer) override; std::vector GetServices() override; std::vector GetPeers() override; ServiceProperties* GetServiceProperties( const dbus::ObjectPath& object_path) override; PeerProperties* GetPeerProperties( const dbus::ObjectPath& object_path) override; void StartMonitoring( const std::vector& requested_technologies, const base::DictionaryValue& options, const StringDBusMethodCallback& callback) override; void StopMonitoring(const std::string& monitoring_token, const VoidDBusMethodCallback& callback) override; void ExposeService( const std::string& service_id, const std::map& service_info, const base::DictionaryValue& options, const StringDBusMethodCallback& callback) override; void RemoveExposedService(const std::string& service_token, const VoidDBusMethodCallback& callback) override; void Ping(const StringDBusMethodCallback& callback) override; // dbus::ObjectManager::Interface overrides. dbus::PropertySet* CreateProperties( dbus::ObjectProxy* object_proxy, const dbus::ObjectPath& object_path, const std::string& interface_name) override; void ObjectAdded(const dbus::ObjectPath& object_path, const std::string& interface_name) override; void ObjectRemoved(const dbus::ObjectPath& object_path, const std::string& interface_name) override; private: void OnStringDBusMethod(const StringDBusMethodCallback& callback, dbus::Response* response); void OnVoidDBusMethod(const VoidDBusMethodCallback& callback, dbus::Response* response); void OnManagerPropertyChanged(const std::string& property_name); void OnServicePropertyChanged(const dbus::ObjectPath& object_path, const std::string& property_name); void OnPeerPropertyChanged(const dbus::ObjectPath& object_path, const std::string& property_name); // List of observers interested in event notifications from us. base::ObserverList observers_; dbus::ObjectManager* object_manager_; base::WeakPtrFactory weak_ptr_factory_; DISALLOW_COPY_AND_ASSIGN(PeerDaemonManagerClientImpl); }; PeerDaemonManagerClientImpl::PeerDaemonManagerClientImpl() : object_manager_(nullptr), weak_ptr_factory_(this) { } PeerDaemonManagerClientImpl::~PeerDaemonManagerClientImpl() { if (object_manager_) { object_manager_->UnregisterInterface(peerd::kManagerInterface); object_manager_->UnregisterInterface(peerd::kServiceInterface); object_manager_->UnregisterInterface(peerd::kPeerInterface); } } void PeerDaemonManagerClientImpl::AddObserver(Observer* observer) { DCHECK(observer); observers_.AddObserver(observer); } void PeerDaemonManagerClientImpl::RemoveObserver(Observer* observer) { DCHECK(observer); observers_.RemoveObserver(observer); } std::vector PeerDaemonManagerClientImpl::GetServices() { return object_manager_->GetObjectsWithInterface(peerd::kServiceInterface); } std::vector PeerDaemonManagerClientImpl::GetPeers() { return object_manager_->GetObjectsWithInterface(peerd::kPeerInterface); } PeerDaemonManagerClient::ServiceProperties* PeerDaemonManagerClientImpl::GetServiceProperties( const dbus::ObjectPath& object_path) { return static_cast( object_manager_->GetProperties(object_path, peerd::kServiceInterface)); } PeerDaemonManagerClient::PeerProperties* PeerDaemonManagerClientImpl::GetPeerProperties( const dbus::ObjectPath& object_path) { return static_cast( object_manager_->GetProperties(object_path, peerd::kPeerInterface)); } void PeerDaemonManagerClientImpl::StartMonitoring( const std::vector& requested_technologies, const base::DictionaryValue& options, const StringDBusMethodCallback& callback) { dbus::ObjectProxy* object_proxy = object_manager_->GetObjectProxy( dbus::ObjectPath(peerd::kPeerdManagerPath)); if (!object_proxy) { base::ThreadTaskRunnerHandle::Get()->PostTask( FROM_HERE, base::Bind(&PeerDaemonManagerClientImpl::OnStringDBusMethod, weak_ptr_factory_.GetWeakPtr(), callback, nullptr)); return; } dbus::MethodCall method_call(peerd::kManagerInterface, peerd::kStartMonitoringMethod); dbus::MessageWriter writer(&method_call); writer.AppendArrayOfStrings(requested_technologies); dbus::AppendValueData(&writer, options); object_proxy->CallMethod( &method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT, base::Bind(&PeerDaemonManagerClientImpl::OnStringDBusMethod, weak_ptr_factory_.GetWeakPtr(), callback)); } void PeerDaemonManagerClientImpl::StopMonitoring( const std::string& monitoring_token, const VoidDBusMethodCallback& callback) { dbus::ObjectProxy* object_proxy = object_manager_->GetObjectProxy( dbus::ObjectPath(peerd::kPeerdManagerPath)); if (!object_proxy) { base::ThreadTaskRunnerHandle::Get()->PostTask( FROM_HERE, base::Bind(&PeerDaemonManagerClientImpl::OnVoidDBusMethod, weak_ptr_factory_.GetWeakPtr(), callback, nullptr)); return; } dbus::MethodCall method_call(peerd::kManagerInterface, peerd::kStopMonitoringMethod); dbus::MessageWriter writer(&method_call); writer.AppendString(monitoring_token); object_proxy->CallMethod( &method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT, base::Bind(&PeerDaemonManagerClientImpl::OnVoidDBusMethod, weak_ptr_factory_.GetWeakPtr(), callback)); } void PeerDaemonManagerClientImpl::ExposeService( const std::string& service_id, const std::map& service_info, const base::DictionaryValue& options, const StringDBusMethodCallback& callback) { dbus::ObjectProxy* object_proxy = object_manager_->GetObjectProxy( dbus::ObjectPath(peerd::kPeerdManagerPath)); if (!object_proxy) { base::ThreadTaskRunnerHandle::Get()->PostTask( FROM_HERE, base::Bind(&PeerDaemonManagerClientImpl::OnStringDBusMethod, weak_ptr_factory_.GetWeakPtr(), callback, nullptr)); return; } dbus::MethodCall method_call(peerd::kManagerInterface, peerd::kExposeServiceMethod); dbus::MessageWriter writer(&method_call); writer.AppendString(service_id); dbus::MessageWriter array_writer(nullptr); writer.OpenArray("{ss}", &array_writer); for (const auto& entry : service_info) { dbus::MessageWriter dict_entry_writer(nullptr); array_writer.OpenDictEntry(&dict_entry_writer); dict_entry_writer.AppendString(entry.first); dict_entry_writer.AppendString(entry.second); array_writer.CloseContainer(&dict_entry_writer); } writer.CloseContainer(&array_writer); dbus::AppendValueData(&writer, options); object_proxy->CallMethod( &method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT, base::Bind(&PeerDaemonManagerClientImpl::OnStringDBusMethod, weak_ptr_factory_.GetWeakPtr(), callback)); } void PeerDaemonManagerClientImpl::RemoveExposedService( const std::string& service_token, const VoidDBusMethodCallback& callback) { dbus::MethodCall method_call(peerd::kManagerInterface, peerd::kRemoveExposedServiceMethod); dbus::ObjectProxy* object_proxy = object_manager_->GetObjectProxy( dbus::ObjectPath(peerd::kPeerdManagerPath)); if (!object_proxy) { base::ThreadTaskRunnerHandle::Get()->PostTask( FROM_HERE, base::Bind(&PeerDaemonManagerClientImpl::OnVoidDBusMethod, weak_ptr_factory_.GetWeakPtr(), callback, nullptr)); return; } dbus::MessageWriter writer(&method_call); writer.AppendString(service_token); object_proxy->CallMethod( &method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT, base::Bind(&PeerDaemonManagerClientImpl::OnVoidDBusMethod, weak_ptr_factory_.GetWeakPtr(), callback)); } void PeerDaemonManagerClientImpl::Ping( const StringDBusMethodCallback& callback) { dbus::MethodCall method_call(peerd::kManagerInterface, peerd::kPingMethod); dbus::ObjectProxy* object_proxy = object_manager_->GetObjectProxy( dbus::ObjectPath(peerd::kPeerdManagerPath)); if (!object_proxy) { base::ThreadTaskRunnerHandle::Get()->PostTask( FROM_HERE, base::Bind(&PeerDaemonManagerClientImpl::OnStringDBusMethod, weak_ptr_factory_.GetWeakPtr(), callback, nullptr)); return; } dbus::MessageWriter writer(&method_call); object_proxy->CallMethod( &method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT, base::Bind(&PeerDaemonManagerClientImpl::OnStringDBusMethod, weak_ptr_factory_.GetWeakPtr(), callback)); } dbus::PropertySet* PeerDaemonManagerClientImpl::CreateProperties( dbus::ObjectProxy* object_proxy, const dbus::ObjectPath& object_path, const std::string& interface_name) { dbus::PropertySet* properties = nullptr; if (interface_name == peerd::kManagerInterface) { properties = new ManagerProperties( object_proxy, base::Bind(&PeerDaemonManagerClientImpl::OnManagerPropertyChanged, weak_ptr_factory_.GetWeakPtr())); } else if (interface_name == peerd::kServiceInterface) { properties = new ServiceProperties( object_proxy, base::Bind(&PeerDaemonManagerClientImpl::OnServicePropertyChanged, weak_ptr_factory_.GetWeakPtr(), object_path)); } else if (interface_name == peerd::kPeerInterface) { properties = new PeerProperties( object_proxy, base::Bind(&PeerDaemonManagerClientImpl::OnPeerPropertyChanged, weak_ptr_factory_.GetWeakPtr(), object_path)); } else { NOTREACHED() << "Unhandled interface name " << interface_name; } return properties; } void PeerDaemonManagerClientImpl::ObjectAdded( const dbus::ObjectPath& object_path, const std::string& interface_name) { if (interface_name == peerd::kManagerInterface) { FOR_EACH_OBSERVER(Observer, observers_, ManagerAdded()); } else if (interface_name == peerd::kServiceInterface) { FOR_EACH_OBSERVER(Observer, observers_, ServiceAdded(object_path)); } else if (interface_name == peerd::kPeerInterface) { FOR_EACH_OBSERVER(Observer, observers_, PeerAdded(object_path)); } else { NOTREACHED() << "Unhandled interface name " << interface_name; } } void PeerDaemonManagerClientImpl::ObjectRemoved( const dbus::ObjectPath& object_path, const std::string& interface_name) { if (interface_name == peerd::kManagerInterface) { FOR_EACH_OBSERVER(Observer, observers_, ManagerRemoved()); } else if (interface_name == peerd::kServiceInterface) { FOR_EACH_OBSERVER(Observer, observers_, ServiceRemoved(object_path)); } else if (interface_name == peerd::kPeerInterface) { FOR_EACH_OBSERVER(Observer, observers_, PeerRemoved(object_path)); } else { NOTREACHED() << "Unhandled interface name " << interface_name; } } void PeerDaemonManagerClientImpl::OnStringDBusMethod( const StringDBusMethodCallback& callback, dbus::Response* response) { if (!response) { callback.Run(DBUS_METHOD_CALL_FAILURE, std::string()); return; } dbus::MessageReader reader(response); std::string result; if (!reader.PopString(&result)) { callback.Run(DBUS_METHOD_CALL_FAILURE, std::string()); return; } callback.Run(DBUS_METHOD_CALL_SUCCESS, result); } void PeerDaemonManagerClientImpl::OnVoidDBusMethod( const VoidDBusMethodCallback& callback, dbus::Response* response) { callback.Run(response ? DBUS_METHOD_CALL_SUCCESS : DBUS_METHOD_CALL_FAILURE); } void PeerDaemonManagerClientImpl::Init(dbus::Bus* bus) { object_manager_ = bus->GetObjectManager( peerd::kPeerdServiceName, dbus::ObjectPath(peerd::kPeerdObjectManagerServicePath)); object_manager_->RegisterInterface(peerd::kManagerInterface, this); object_manager_->RegisterInterface(peerd::kServiceInterface, this); object_manager_->RegisterInterface(peerd::kPeerInterface, this); } void PeerDaemonManagerClientImpl::OnManagerPropertyChanged( const std::string& property_name) { FOR_EACH_OBSERVER(Observer, observers_, ManagerPropertyChanged(property_name)); } void PeerDaemonManagerClientImpl::OnServicePropertyChanged( const dbus::ObjectPath& object_path, const std::string& property_name) { FOR_EACH_OBSERVER(Observer, observers_, ServicePropertyChanged(object_path, property_name)); } void PeerDaemonManagerClientImpl::OnPeerPropertyChanged( const dbus::ObjectPath& object_path, const std::string& property_name) { FOR_EACH_OBSERVER(Observer, observers_, PeerPropertyChanged(object_path, property_name)); } } // namespace PeerDaemonManagerClient::ManagerProperties::ManagerProperties( dbus::ObjectProxy* object_proxy, const PropertyChangedCallback& callback) : dbus::PropertySet{object_proxy, peerd::kManagerInterface, callback} { RegisterProperty("MonitoredTechnologies", &monitored_technologies_); } PeerDaemonManagerClient::ManagerProperties::~ManagerProperties() { } PeerDaemonManagerClient::ServiceProperties::ServiceProperties( dbus::ObjectProxy* object_proxy, const PropertyChangedCallback& callback) : dbus::PropertySet{object_proxy, peerd::kServiceInterface, callback} { RegisterProperty("ServiceId", &service_id_); RegisterProperty("ServiceInfo", &service_info_); RegisterProperty("IpInfos", &ip_infos_); } PeerDaemonManagerClient::ServiceProperties::~ServiceProperties() { } PeerDaemonManagerClient::PeerProperties::PeerProperties( dbus::ObjectProxy* object_proxy, const PropertyChangedCallback& callback) : dbus::PropertySet{object_proxy, peerd::kPeerInterface, callback} { RegisterProperty("UUID", &uuid_); RegisterProperty("LastSeen", &last_seen_); } PeerDaemonManagerClient::PeerProperties::~PeerProperties() { } PeerDaemonManagerClient::PeerDaemonManagerClient() { } PeerDaemonManagerClient::~PeerDaemonManagerClient() { } // static PeerDaemonManagerClient* PeerDaemonManagerClient::Create() { return new PeerDaemonManagerClientImpl(); } } // namespace chromeos