2017-11-27 14:13:55 +01:00
|
|
|
/**
|
|
|
|
|
* (C) 2017 KISTLER INSTRUMENTE AG, Winterthur, Switzerland
|
|
|
|
|
*
|
2019-04-09 21:28:07 +02:00
|
|
|
* @file Proxy.cpp
|
2017-11-27 14:13:55 +01:00
|
|
|
*
|
|
|
|
|
* Created on: Nov 8, 2016
|
|
|
|
|
* Project: sdbus-c++
|
|
|
|
|
* Description: High-level D-Bus IPC C++ library based on sd-bus
|
|
|
|
|
*
|
|
|
|
|
* This file is part of sdbus-c++.
|
|
|
|
|
*
|
|
|
|
|
* sdbus-c++ is free software; you can redistribute it and/or modify it
|
|
|
|
|
* under the terms of the GNU Lesser General Public License as published by
|
|
|
|
|
* the Free Software Foundation, either version 2.1 of the License, or
|
|
|
|
|
* (at your option) any later version.
|
|
|
|
|
*
|
|
|
|
|
* sdbus-c++ is distributed in the hope that it will be useful,
|
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
|
* GNU Lesser General Public License for more details.
|
|
|
|
|
*
|
|
|
|
|
* You should have received a copy of the GNU Lesser General Public License
|
|
|
|
|
* along with sdbus-c++. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
|
*/
|
|
|
|
|
|
2019-04-09 21:28:07 +02:00
|
|
|
#include "Proxy.h"
|
2017-11-27 14:13:55 +01:00
|
|
|
#include "IConnection.h"
|
2019-06-10 21:38:30 +02:00
|
|
|
#include "MessageUtils.h"
|
2019-04-09 21:28:07 +02:00
|
|
|
#include "sdbus-c++/Message.h"
|
|
|
|
|
#include "sdbus-c++/IConnection.h"
|
|
|
|
|
#include "sdbus-c++/Error.h"
|
2019-04-13 21:17:37 +02:00
|
|
|
#include "ScopeGuard.h"
|
2017-11-27 14:13:55 +01:00
|
|
|
#include <systemd/sd-bus.h>
|
|
|
|
|
#include <cassert>
|
2019-03-25 16:28:31 +01:00
|
|
|
#include <chrono>
|
|
|
|
|
#include <thread>
|
2017-11-27 14:13:55 +01:00
|
|
|
|
|
|
|
|
namespace sdbus { namespace internal {
|
|
|
|
|
|
2019-04-09 21:28:07 +02:00
|
|
|
Proxy::Proxy(sdbus::internal::IConnection& connection, std::string destination, std::string objectPath)
|
2017-11-27 14:13:55 +01:00
|
|
|
: connection_(&connection, [](sdbus::internal::IConnection *){ /* Intentionally left empty */ })
|
|
|
|
|
, destination_(std::move(destination))
|
|
|
|
|
, objectPath_(std::move(objectPath))
|
|
|
|
|
{
|
2019-04-13 21:17:37 +02:00
|
|
|
// The connection is not ours only, it is owned and managed by the user and we just reference
|
|
|
|
|
// it here, so we expect the client to manage the event loop upon this connection themselves.
|
2017-11-27 14:13:55 +01:00
|
|
|
}
|
|
|
|
|
|
2019-04-09 21:28:07 +02:00
|
|
|
Proxy::Proxy( std::unique_ptr<sdbus::internal::IConnection>&& connection
|
|
|
|
|
, std::string destination
|
|
|
|
|
, std::string objectPath )
|
2017-11-27 14:13:55 +01:00
|
|
|
: connection_(std::move(connection))
|
|
|
|
|
, destination_(std::move(destination))
|
|
|
|
|
, objectPath_(std::move(objectPath))
|
|
|
|
|
{
|
2019-04-13 21:17:37 +02:00
|
|
|
// The connection is ours only, i.e. it's us who has to manage the event loop upon this connection,
|
|
|
|
|
// in order that we get and process signals, async call replies, and other messages from D-Bus.
|
2019-03-25 16:28:31 +01:00
|
|
|
connection_->enterProcessingLoopAsync();
|
2017-11-27 14:13:55 +01:00
|
|
|
}
|
|
|
|
|
|
2019-04-09 21:28:07 +02:00
|
|
|
MethodCall Proxy::createMethodCall(const std::string& interfaceName, const std::string& methodName)
|
2017-11-27 14:13:55 +01:00
|
|
|
{
|
|
|
|
|
return connection_->createMethodCall(destination_, objectPath_, interfaceName, methodName);
|
|
|
|
|
}
|
|
|
|
|
|
2019-04-09 21:28:07 +02:00
|
|
|
AsyncMethodCall Proxy::createAsyncMethodCall(const std::string& interfaceName, const std::string& methodName)
|
2019-03-25 14:45:48 +01:00
|
|
|
{
|
2019-04-09 21:28:07 +02:00
|
|
|
return AsyncMethodCall{Proxy::createMethodCall(interfaceName, methodName)};
|
2019-03-25 14:45:48 +01:00
|
|
|
}
|
|
|
|
|
|
2019-04-09 21:28:07 +02:00
|
|
|
MethodReply Proxy::callMethod(const MethodCall& message)
|
2017-11-27 14:13:55 +01:00
|
|
|
{
|
|
|
|
|
return message.send();
|
|
|
|
|
}
|
|
|
|
|
|
2019-04-09 21:28:07 +02:00
|
|
|
void Proxy::callMethod(const AsyncMethodCall& message, async_reply_handler asyncReplyCallback)
|
2019-03-25 14:45:48 +01:00
|
|
|
{
|
2019-04-09 21:28:07 +02:00
|
|
|
auto callback = (void*)&Proxy::sdbus_async_reply_handler;
|
2019-04-13 21:17:37 +02:00
|
|
|
auto callData = std::make_unique<AsyncCalls::CallData>(AsyncCalls::CallData{*this, std::move(asyncReplyCallback), {}});
|
2019-03-25 16:28:31 +01:00
|
|
|
|
2019-04-13 21:17:37 +02:00
|
|
|
callData->slot = message.send(callback, callData.get());
|
|
|
|
|
|
|
|
|
|
pendingAsyncCalls_.addCall(callData->slot.get(), std::move(callData));
|
2019-03-25 14:45:48 +01:00
|
|
|
}
|
|
|
|
|
|
2019-04-09 21:28:07 +02:00
|
|
|
void Proxy::registerSignalHandler( const std::string& interfaceName
|
|
|
|
|
, const std::string& signalName
|
|
|
|
|
, signal_handler signalHandler )
|
2017-11-27 14:13:55 +01:00
|
|
|
{
|
|
|
|
|
SDBUS_THROW_ERROR_IF(!signalHandler, "Invalid signal handler provided", EINVAL);
|
|
|
|
|
|
|
|
|
|
auto& interface = interfaces_[interfaceName];
|
|
|
|
|
|
|
|
|
|
InterfaceData::SignalData signalData{std::move(signalHandler), nullptr};
|
|
|
|
|
auto insertionResult = interface.signals_.emplace(signalName, std::move(signalData));
|
|
|
|
|
|
|
|
|
|
auto inserted = insertionResult.second;
|
|
|
|
|
SDBUS_THROW_ERROR_IF(!inserted, "Failed to register signal handler: handler already exists", EINVAL);
|
|
|
|
|
}
|
|
|
|
|
|
2019-04-09 21:28:07 +02:00
|
|
|
void Proxy::finishRegistration()
|
2017-11-27 14:13:55 +01:00
|
|
|
{
|
2019-03-25 16:28:31 +01:00
|
|
|
registerSignalHandlers(*connection_);
|
2017-11-27 14:13:55 +01:00
|
|
|
}
|
|
|
|
|
|
2019-04-09 21:28:07 +02:00
|
|
|
void Proxy::registerSignalHandlers(sdbus::internal::IConnection& connection)
|
2017-11-27 14:13:55 +01:00
|
|
|
{
|
|
|
|
|
for (auto& interfaceItem : interfaces_)
|
|
|
|
|
{
|
|
|
|
|
const auto& interfaceName = interfaceItem.first;
|
|
|
|
|
auto& signalsOnInterface = interfaceItem.second.signals_;
|
|
|
|
|
|
|
|
|
|
for (auto& signalItem : signalsOnInterface)
|
|
|
|
|
{
|
|
|
|
|
const auto& signalName = signalItem.first;
|
|
|
|
|
auto& slot = signalItem.second.slot_;
|
2019-05-29 22:28:15 +02:00
|
|
|
slot = connection.registerSignalHandler( objectPath_
|
|
|
|
|
, interfaceName
|
|
|
|
|
, signalName
|
|
|
|
|
, &Proxy::sdbus_signal_callback
|
|
|
|
|
, this );
|
2017-11-27 14:13:55 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2019-04-13 21:17:37 +02:00
|
|
|
void Proxy::unregister()
|
|
|
|
|
{
|
|
|
|
|
pendingAsyncCalls_.clear();
|
|
|
|
|
interfaces_.clear();
|
|
|
|
|
}
|
|
|
|
|
|
2019-04-12 22:39:14 +02:00
|
|
|
int Proxy::sdbus_async_reply_handler(sd_bus_message *sdbusMessage, void *userData, sd_bus_error */*retError*/)
|
2019-03-25 14:45:48 +01:00
|
|
|
{
|
2019-04-13 21:17:37 +02:00
|
|
|
auto* asyncCallData = static_cast<AsyncCalls::CallData*>(userData);
|
|
|
|
|
assert(asyncCallData != nullptr);
|
|
|
|
|
assert(asyncCallData->callback);
|
|
|
|
|
auto& proxy = asyncCallData->proxy;
|
|
|
|
|
|
|
|
|
|
SCOPE_EXIT{ proxy.pendingAsyncCalls_.removeCall(asyncCallData->slot.get()); };
|
2019-03-25 14:45:48 +01:00
|
|
|
|
2019-06-10 21:38:30 +02:00
|
|
|
auto message = Message::Factory::create<MethodReply>(sdbusMessage, &proxy.connection_->getSdBusInterface());
|
2019-03-25 16:28:31 +01:00
|
|
|
|
|
|
|
|
const auto* error = sd_bus_message_get_error(sdbusMessage);
|
|
|
|
|
if (error == nullptr)
|
2019-03-25 14:45:48 +01:00
|
|
|
{
|
2019-04-13 21:17:37 +02:00
|
|
|
asyncCallData->callback(message, nullptr);
|
2019-03-25 14:45:48 +01:00
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2019-03-25 16:28:31 +01:00
|
|
|
sdbus::Error exception(error->name, error->message);
|
2019-04-13 21:17:37 +02:00
|
|
|
asyncCallData->callback(message, &exception);
|
2019-03-25 14:45:48 +01:00
|
|
|
}
|
2019-04-12 22:39:14 +02:00
|
|
|
|
|
|
|
|
return 1;
|
2019-03-25 14:45:48 +01:00
|
|
|
}
|
|
|
|
|
|
2019-04-09 21:28:07 +02:00
|
|
|
int Proxy::sdbus_signal_callback(sd_bus_message *sdbusMessage, void *userData, sd_bus_error */*retError*/)
|
2017-11-27 14:13:55 +01:00
|
|
|
{
|
2019-04-09 21:28:07 +02:00
|
|
|
auto* proxy = static_cast<Proxy*>(userData);
|
2019-03-25 16:28:31 +01:00
|
|
|
assert(proxy != nullptr);
|
|
|
|
|
|
2019-06-10 21:38:30 +02:00
|
|
|
auto message = Message::Factory::create<Signal>(sdbusMessage, &proxy->connection_->getSdBusInterface());
|
2017-11-27 14:13:55 +01:00
|
|
|
|
|
|
|
|
// Note: The lookup can be optimized by using sorted vectors instead of associative containers
|
2019-03-25 16:28:31 +01:00
|
|
|
auto& callback = proxy->interfaces_[message.getInterfaceName()].signals_[message.getMemberName()].callback_;
|
2017-11-27 14:13:55 +01:00
|
|
|
assert(callback);
|
|
|
|
|
|
|
|
|
|
callback(message);
|
|
|
|
|
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}}
|
|
|
|
|
|
|
|
|
|
namespace sdbus {
|
|
|
|
|
|
2019-04-09 21:28:07 +02:00
|
|
|
std::unique_ptr<sdbus::IProxy> createProxy( IConnection& connection
|
|
|
|
|
, std::string destination
|
|
|
|
|
, std::string objectPath )
|
2017-11-27 14:13:55 +01:00
|
|
|
{
|
|
|
|
|
auto* sdbusConnection = dynamic_cast<sdbus::internal::IConnection*>(&connection);
|
|
|
|
|
SDBUS_THROW_ERROR_IF(!sdbusConnection, "Connection is not a real sdbus-c++ connection", EINVAL);
|
|
|
|
|
|
2019-04-09 21:28:07 +02:00
|
|
|
return std::make_unique<sdbus::internal::Proxy>( *sdbusConnection
|
|
|
|
|
, std::move(destination)
|
|
|
|
|
, std::move(objectPath) );
|
2017-11-27 14:13:55 +01:00
|
|
|
}
|
|
|
|
|
|
2019-04-09 21:28:07 +02:00
|
|
|
std::unique_ptr<sdbus::IProxy> createProxy( std::unique_ptr<IConnection>&& connection
|
|
|
|
|
, std::string destination
|
|
|
|
|
, std::string objectPath )
|
2018-03-15 17:03:49 +01:00
|
|
|
{
|
|
|
|
|
auto* sdbusConnection = dynamic_cast<sdbus::internal::IConnection*>(connection.get());
|
|
|
|
|
SDBUS_THROW_ERROR_IF(!sdbusConnection, "Connection is not a real sdbus-c++ connection", EINVAL);
|
|
|
|
|
|
|
|
|
|
connection.release();
|
|
|
|
|
|
2019-04-09 21:28:07 +02:00
|
|
|
return std::make_unique<sdbus::internal::Proxy>( std::unique_ptr<sdbus::internal::IConnection>(sdbusConnection)
|
|
|
|
|
, std::move(destination)
|
|
|
|
|
, std::move(objectPath) );
|
2018-03-15 17:03:49 +01:00
|
|
|
}
|
|
|
|
|
|
2019-04-09 21:28:07 +02:00
|
|
|
std::unique_ptr<sdbus::IProxy> createProxy( std::string destination
|
|
|
|
|
, std::string objectPath )
|
2017-11-27 14:13:55 +01:00
|
|
|
{
|
|
|
|
|
auto connection = sdbus::createConnection();
|
|
|
|
|
|
|
|
|
|
auto sdbusConnection = std::unique_ptr<sdbus::internal::IConnection>(dynamic_cast<sdbus::internal::IConnection*>(connection.release()));
|
|
|
|
|
assert(sdbusConnection != nullptr);
|
|
|
|
|
|
2019-04-09 21:28:07 +02:00
|
|
|
return std::make_unique<sdbus::internal::Proxy>( std::move(sdbusConnection)
|
|
|
|
|
, std::move(destination)
|
|
|
|
|
, std::move(objectPath) );
|
2017-11-27 14:13:55 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|