Re-design sdbus-c++ approach to connections (#47)

Fixes #33 , among others
This commit is contained in:
Stanislav Angelovič
2019-03-25 16:28:31 +01:00
committed by GitHub
parent 26c6ea8730
commit fd7be39dd4
29 changed files with 526 additions and 452 deletions

View File

@@ -36,21 +36,23 @@
namespace sdbus { namespace internal {
Connection::Connection(Connection::BusType type, std::unique_ptr<ISdBus>&& interface)
: busType_(type)
, iface_(std::move(interface))
: iface_(std::move(interface))
, busType_(type)
{
assert(iface_ != nullptr);
auto bus = openBus(busType_);
bus_.reset(bus);
finishHandshake(bus);
notificationFd_ = createLoopNotificationDescriptor();
loopExitFd_ = createProcessingLoopExitDescriptor();
}
Connection::~Connection()
{
leaveProcessingLoop();
closeLoopNotificationDescriptor(notificationFd_);
closeProcessingLoopExitDescriptor(loopExitFd_);
}
void Connection::requestName(const std::string& name)
@@ -76,14 +78,13 @@ void Connection::enterProcessingLoop()
auto success = waitForNextRequest();
if (!success)
break; // Exit processing loop
if (success.asyncMsgsToProcess)
processAsynchronousMessages();
}
}
void Connection::enterProcessingLoopAsync()
{
asyncLoopThread_ = std::thread([this](){ enterProcessingLoop(); });
if (!asyncLoopThread_.joinable())
asyncLoopThread_ = std::thread([this](){ enterProcessingLoop(); });
}
void Connection::leaveProcessingLoop()
@@ -92,6 +93,16 @@ void Connection::leaveProcessingLoop()
joinWithProcessingLoop();
}
const ISdBus& Connection::getSdBusInterface() const
{
return *iface_.get();
}
ISdBus& Connection::getSdBusInterface()
{
return *iface_.get();
}
sd_bus_slot* Connection::addObjectVTable( const std::string& objectPath
, const std::string& interfaceName
, const sd_bus_vtable* vtable
@@ -116,16 +127,13 @@ void Connection::removeObjectVTable(sd_bus_slot* vtableHandle)
iface_->sd_bus_slot_unref(vtableHandle);
}
sdbus::MethodCall Connection::createMethodCall( const std::string& destination
, const std::string& objectPath
, const std::string& interfaceName
, const std::string& methodName ) const
MethodCall Connection::createMethodCall( const std::string& destination
, const std::string& objectPath
, const std::string& interfaceName
, const std::string& methodName ) const
{
sd_bus_message *sdbusMsg{};
// Returned message will become an owner of sdbusMsg
SCOPE_EXIT{ iface_->sd_bus_message_unref(sdbusMsg); };
auto r = iface_->sd_bus_message_new_method_call( bus_.get()
, &sdbusMsg
, destination.c_str()
@@ -135,18 +143,15 @@ sdbus::MethodCall Connection::createMethodCall( const std::string& destination
SDBUS_THROW_ERROR_IF(r < 0, "Failed to create method call", -r);
return MethodCall(sdbusMsg);
return MethodCall{sdbusMsg, iface_.get(), adopt_message};
}
sdbus::Signal Connection::createSignal( const std::string& objectPath
, const std::string& interfaceName
, const std::string& signalName ) const
Signal Connection::createSignal( const std::string& objectPath
, const std::string& interfaceName
, const std::string& signalName ) const
{
sd_bus_message *sdbusSignal{};
// Returned message will become an owner of sdbusSignal
SCOPE_EXIT{ iface_->sd_bus_message_unref(sdbusSignal); };
auto r = iface_->sd_bus_message_new_signal( bus_.get()
, &sdbusSignal
, objectPath.c_str()
@@ -155,7 +160,7 @@ sdbus::Signal Connection::createSignal( const std::string& objectPath
SDBUS_THROW_ERROR_IF(r < 0, "Failed to create signal", -r);
return Signal(sdbusSignal);
return Signal{sdbusSignal, iface_.get(), adopt_message};
}
sd_bus_slot* Connection::registerSignalHandler( const std::string& objectPath
@@ -179,20 +184,6 @@ void Connection::unregisterSignalHandler(sd_bus_slot* handlerCookie)
iface_->sd_bus_slot_unref(handlerCookie);
}
void Connection::sendReplyAsynchronously(const sdbus::MethodReply& reply)
{
std::lock_guard<std::mutex> guard(mutex_);
asyncReplies_.push(reply);
notifyProcessingLoop();
}
std::unique_ptr<sdbus::internal::IConnection> Connection::clone() const
{
auto interface = std::make_unique<SdBus>();
assert(interface != nullptr);
return std::make_unique<sdbus::internal::Connection>(busType_, std::move(interface));
}
sd_bus* Connection::openBus(Connection::BusType type)
{
sd_bus* bus{};
@@ -223,7 +214,7 @@ void Connection::finishHandshake(sd_bus* bus)
SDBUS_THROW_ERROR_IF(r < 0, "Failed to flush bus on opening", -r);
}
int Connection::createLoopNotificationDescriptor()
int Connection::createProcessingLoopExitDescriptor()
{
auto r = eventfd(0, EFD_SEMAPHORE | EFD_CLOEXEC | EFD_NONBLOCK);
@@ -232,26 +223,25 @@ int Connection::createLoopNotificationDescriptor()
return r;
}
void Connection::closeLoopNotificationDescriptor(int fd)
void Connection::closeProcessingLoopExitDescriptor(int fd)
{
close(fd);
}
void Connection::notifyProcessingLoop()
void Connection::notifyProcessingLoopToExit()
{
assert(notificationFd_ >= 0);
assert(loopExitFd_ >= 0);
uint64_t value = 1;
auto r = write(notificationFd_, &value, sizeof(value));
auto r = write(loopExitFd_, &value, sizeof(value));
SDBUS_THROW_ERROR_IF(r < 0, "Failed to notify processing loop", -errno);
}
void Connection::notifyProcessingLoopToExit()
void Connection::clearExitNotification()
{
exitLoopThread_ = true;
notifyProcessingLoop();
uint64_t value{};
auto r = read(loopExitFd_, &value, sizeof(value));
SDBUS_THROW_ERROR_IF(r < 0, "Failed to read from the event descriptor", -errno);
}
void Connection::joinWithProcessingLoop()
@@ -273,60 +263,35 @@ bool Connection::processPendingRequest()
return r > 0;
}
void Connection::processAsynchronousMessages()
{
std::lock_guard<std::mutex> guard(mutex_);
while (!asyncReplies_.empty())
{
auto reply = asyncReplies_.front();
asyncReplies_.pop();
reply.send();
}
}
Connection::WaitResult Connection::waitForNextRequest()
bool Connection::waitForNextRequest()
{
auto bus = bus_.get();
assert(bus != nullptr);
assert(notificationFd_ != 0);
assert(loopExitFd_ != 0);
auto r = iface_->sd_bus_get_fd(bus);
SDBUS_THROW_ERROR_IF(r < 0, "Failed to get bus descriptor", -r);
auto sdbusFd = r;
ISdBus::PollData sdbusPollData;
auto r = iface_->sd_bus_get_poll_data(bus, &sdbusPollData);
SDBUS_THROW_ERROR_IF(r < 0, "Failed to get bus poll data", -r);
r = iface_->sd_bus_get_events(bus);
SDBUS_THROW_ERROR_IF(r < 0, "Failed to get bus events", -r);
short int sdbusEvents = r;
uint64_t usec;
iface_->sd_bus_get_timeout(bus, &usec);
struct pollfd fds[] = {{sdbusFd, sdbusEvents, 0}, {notificationFd_, POLLIN, 0}};
struct pollfd fds[] = {{sdbusPollData.fd, sdbusPollData.events, 0}, {loopExitFd_, POLLIN, 0}};
auto fdsCount = sizeof(fds)/sizeof(fds[0]);
r = poll(fds, fdsCount, usec == (uint64_t) -1 ? -1 : (usec+999)/1000);
auto timeout = sdbusPollData.timeout_usec == (uint64_t) -1 ? (uint64_t)-1 : (sdbusPollData.timeout_usec+999)/1000;
r = poll(fds, fdsCount, timeout);
if (r < 0 && errno == EINTR)
return {true, false}; // Try again
return true; // Try again
SDBUS_THROW_ERROR_IF(r < 0, "Failed to wait on the bus", -errno);
if (fds[1].revents & POLLIN)
{
if (exitLoopThread_)
return {false, false}; // Got exit notification
// Otherwise we have some async messages to process
uint64_t value{};
auto r = read(notificationFd_, &value, sizeof(value));
SDBUS_THROW_ERROR_IF(r < 0, "Failed to read from the event descriptor", -errno);
return {false, true};
clearExitNotification();
return false;
}
return {true, false};
return true;
}
std::string Connection::composeSignalMatchFilter( const std::string& objectPath
@@ -361,8 +326,8 @@ std::unique_ptr<sdbus::IConnection> createSystemBusConnection()
{
auto interface = std::make_unique<sdbus::internal::SdBus>();
assert(interface != nullptr);
return std::make_unique<sdbus::internal::Connection>(sdbus::internal::Connection::BusType::eSystem,
std::move(interface));
return std::make_unique<sdbus::internal::Connection>( sdbus::internal::Connection::BusType::eSystem
, std::move(interface));
}
std::unique_ptr<sdbus::IConnection> createSystemBusConnection(const std::string& name)
@@ -376,8 +341,8 @@ std::unique_ptr<sdbus::IConnection> createSessionBusConnection()
{
auto interface = std::make_unique<sdbus::internal::SdBus>();
assert(interface != nullptr);
return std::make_unique<sdbus::internal::Connection>(sdbus::internal::Connection::BusType::eSession,
std::move(interface));
return std::make_unique<sdbus::internal::Connection>( sdbus::internal::Connection::BusType::eSession
, std::move(interface));
}
std::unique_ptr<sdbus::IConnection> createSessionBusConnection(const std::string& name)

View File

@@ -29,14 +29,11 @@
#include <sdbus-c++/IConnection.h>
#include <sdbus-c++/Message.h>
#include "IConnection.h"
#include "ScopeGuard.h"
#include "ISdBus.h"
#include <systemd/sd-bus.h>
#include <memory>
#include <thread>
#include <atomic>
#include <mutex>
#include <queue>
namespace sdbus { namespace internal {
@@ -60,19 +57,22 @@ namespace sdbus { namespace internal {
void enterProcessingLoopAsync() override;
void leaveProcessingLoop() override;
const ISdBus& getSdBusInterface() const override;
ISdBus& getSdBusInterface() override;
sd_bus_slot* addObjectVTable( const std::string& objectPath
, const std::string& interfaceName
, const sd_bus_vtable* vtable
, void* userData ) override;
void removeObjectVTable(sd_bus_slot* vtableHandle) override;
sdbus::MethodCall createMethodCall( const std::string& destination
, const std::string& objectPath
, const std::string& interfaceName
, const std::string& methodName ) const override;
sdbus::Signal createSignal( const std::string& objectPath
, const std::string& interfaceName
, const std::string& signalName ) const override;
MethodCall createMethodCall( const std::string& destination
, const std::string& objectPath
, const std::string& interfaceName
, const std::string& methodName ) const override;
Signal createSignal( const std::string& objectPath
, const std::string& interfaceName
, const std::string& signalName ) const override;
sd_bus_slot* registerSignalHandler( const std::string& objectPath
, const std::string& interfaceName
@@ -81,32 +81,18 @@ namespace sdbus { namespace internal {
, void* userData ) override;
void unregisterSignalHandler(sd_bus_slot* handlerCookie) override;
void sendReplyAsynchronously(const sdbus::MethodReply& reply) override;
std::unique_ptr<sdbus::internal::IConnection> clone() const override;
private:
struct WaitResult
{
bool msgsToProcess;
bool asyncMsgsToProcess;
operator bool()
{
return msgsToProcess || asyncMsgsToProcess;
}
};
sd_bus* openBus(Connection::BusType type);
void finishHandshake(sd_bus* bus);
static int createLoopNotificationDescriptor();
static void closeLoopNotificationDescriptor(int fd);
static int createProcessingLoopExitDescriptor();
static void closeProcessingLoopExitDescriptor(int fd);
bool processPendingRequest();
void processAsynchronousMessages();
WaitResult waitForNextRequest();
bool waitForNextRequest();
static std::string composeSignalMatchFilter( const std::string& objectPath
, const std::string& interfaceName
, const std::string& signalName );
void notifyProcessingLoop();
void notifyProcessingLoopToExit();
void clearExitNotification();
void joinWithProcessingLoop();
private:
@@ -115,14 +101,10 @@ namespace sdbus { namespace internal {
{
return iface_->sd_bus_flush_close_unref(bus);
}};
std::thread asyncLoopThread_;
std::mutex mutex_;
std::queue<MethodReply> asyncReplies_;
std::atomic<bool> exitLoopThread_;
int notificationFd_{-1};
BusType busType_;
static constexpr const uint64_t POLL_TIMEOUT_USEC = 500000;
std::thread asyncLoopThread_;
int loopExitFd_{-1};
};
}}

View File

@@ -33,8 +33,12 @@
// Forward declaration
namespace sdbus {
class MethodCall;
class AsyncMethodCall;
class MethodReply;
class Signal;
namespace internal {
class ISdBus;
}
}
namespace sdbus {
@@ -43,20 +47,23 @@ namespace internal {
class IConnection
{
public:
virtual const ISdBus& getSdBusInterface() const = 0;
virtual ISdBus& getSdBusInterface() = 0;
virtual sd_bus_slot* addObjectVTable( const std::string& objectPath
, const std::string& interfaceName
, const sd_bus_vtable* vtable
, void* userData ) = 0;
virtual void removeObjectVTable(sd_bus_slot* vtableHandle) = 0;
virtual sdbus::MethodCall createMethodCall( const std::string& destination
, const std::string& objectPath
, const std::string& interfaceName
, const std::string& methodName ) const = 0;
virtual MethodCall createMethodCall( const std::string& destination
, const std::string& objectPath
, const std::string& interfaceName
, const std::string& methodName ) const = 0;
virtual sdbus::Signal createSignal( const std::string& objectPath
, const std::string& interfaceName
, const std::string& signalName ) const = 0;
virtual Signal createSignal( const std::string& objectPath
, const std::string& interfaceName
, const std::string& signalName ) const = 0;
virtual sd_bus_slot* registerSignalHandler( const std::string& objectPath
, const std::string& interfaceName
@@ -68,10 +75,6 @@ namespace internal {
virtual void enterProcessingLoopAsync() = 0;
virtual void leaveProcessingLoop() = 0;
virtual void sendReplyAsynchronously(const sdbus::MethodReply& reply) = 0;
virtual std::unique_ptr<sdbus::internal::IConnection> clone() const = 0;
virtual ~IConnection() = default;
};

View File

@@ -34,21 +34,37 @@ namespace sdbus { namespace internal {
class ISdBus
{
public:
struct PollData
{
int fd;
short int events;
uint64_t timeout_usec;
};
virtual sd_bus_message* sd_bus_message_ref(sd_bus_message *m) = 0;
virtual sd_bus_message* sd_bus_message_unref(sd_bus_message *m) = 0;
virtual int sd_bus_send(sd_bus *bus, sd_bus_message *m, uint64_t *cookie) = 0;
virtual int sd_bus_call(sd_bus *bus, sd_bus_message *m, uint64_t usec, sd_bus_error *ret_error, sd_bus_message **reply) = 0;
virtual int sd_bus_call_async(sd_bus *bus, sd_bus_slot **slot, sd_bus_message *m, sd_bus_message_handler_t callback, void *userdata, uint64_t usec) = 0;
virtual int sd_bus_message_new_method_call(sd_bus *bus, sd_bus_message **m, const char *destination, const char *path, const char *interface, const char *member) = 0;
virtual int sd_bus_message_new_signal(sd_bus *bus, sd_bus_message **m, const char *path, const char *interface, const char *member) = 0;
virtual int sd_bus_message_new_method_return(sd_bus_message *call, sd_bus_message **m) = 0;
virtual int sd_bus_message_new_method_error(sd_bus_message *call, sd_bus_message **m, const sd_bus_error *e) = 0;
virtual int sd_bus_open_user(sd_bus **ret) = 0;
virtual int sd_bus_open_system(sd_bus **ret) = 0;
virtual int sd_bus_request_name(sd_bus *bus, const char *name, uint64_t flags) = 0;
virtual int sd_bus_release_name(sd_bus *bus, const char *name) = 0;
virtual int sd_bus_add_object_vtable(sd_bus *bus, sd_bus_slot **slot, const char *path, const char *interface, const sd_bus_vtable *vtable, void *userdata) = 0;
virtual sd_bus_slot* sd_bus_slot_unref(sd_bus_slot *slot) = 0;
virtual int sd_bus_message_new_method_call(sd_bus *bus, sd_bus_message **m, const char *destination, const char *path, const char *interface, const char *member) = 0;
virtual sd_bus_message* sd_bus_message_unref(sd_bus_message *m) = 0;
virtual int sd_bus_message_new_signal(sd_bus *bus, sd_bus_message **m, const char *path, const char *interface, const char *member) = 0;
virtual int sd_bus_add_match(sd_bus *bus, sd_bus_slot **slot, const char *match, sd_bus_message_handler_t callback, void *userdata) = 0;
virtual int sd_bus_open_user(sd_bus **ret) = 0;
virtual int sd_bus_open_system(sd_bus **ret) = 0;
virtual int sd_bus_flush(sd_bus *bus) = 0;
virtual sd_bus_slot* sd_bus_slot_unref(sd_bus_slot *slot) = 0;
virtual int sd_bus_process(sd_bus *bus, sd_bus_message **r) = 0;
virtual int sd_bus_get_fd(sd_bus *bus) = 0;
virtual int sd_bus_get_events(sd_bus *bus) = 0;
virtual int sd_bus_get_timeout(sd_bus *bus, uint64_t *timeout_usec) = 0;
virtual int sd_bus_get_poll_data(sd_bus *bus, PollData* data) = 0;
virtual int sd_bus_flush(sd_bus *bus) = 0;
virtual sd_bus *sd_bus_flush_close_unref(sd_bus *bus) = 0;
virtual ~ISdBus() = default;

View File

@@ -27,17 +27,34 @@
#include <sdbus-c++/Types.h>
#include <sdbus-c++/Error.h>
#include "MessageUtils.h"
#include "SdBus.h"
#include "ScopeGuard.h"
#include <systemd/sd-bus.h>
#include <cassert>
namespace sdbus {
Message::Message(void *msg) noexcept
Message::Message(internal::ISdBus* sdbus) noexcept
: sdbus_(sdbus)
{
assert(sdbus_ != nullptr);
}
Message::Message(void *msg, internal::ISdBus* sdbus) noexcept
: msg_(msg)
, sdbus_(sdbus)
{
assert(msg_ != nullptr);
sd_bus_message_ref((sd_bus_message*)msg_);
assert(sdbus_ != nullptr);
sdbus_->sd_bus_message_ref((sd_bus_message*)msg_);
}
Message::Message(void *msg, internal::ISdBus* sdbus, adopt_message_t) noexcept
: msg_(msg)
, sdbus_(sdbus)
{
assert(msg_ != nullptr);
assert(sdbus_ != nullptr);
}
Message::Message(const Message& other) noexcept
@@ -48,12 +65,13 @@ Message::Message(const Message& other) noexcept
Message& Message::operator=(const Message& other) noexcept
{
if (msg_)
sd_bus_message_unref((sd_bus_message*)msg_);
sdbus_->sd_bus_message_unref((sd_bus_message*)msg_);
msg_ = other.msg_;
sdbus_ = other.sdbus_;
ok_ = other.ok_;
sd_bus_message_ref((sd_bus_message*)msg_);
sdbus_->sd_bus_message_ref((sd_bus_message*)msg_);
return *this;
}
@@ -66,10 +84,12 @@ Message::Message(Message&& other) noexcept
Message& Message::operator=(Message&& other) noexcept
{
if (msg_)
sd_bus_message_unref((sd_bus_message*)msg_);
sdbus_->sd_bus_message_unref((sd_bus_message*)msg_);
msg_ = other.msg_;
other.msg_ = nullptr;
sdbus_ = other.sdbus_;
other.sdbus_ = nullptr;
ok_ = other.ok_;
other.ok_ = true;
@@ -79,7 +99,7 @@ Message& Message::operator=(Message&& other) noexcept
Message::~Message()
{
if (msg_)
sd_bus_message_unref((sd_bus_message*)msg_);
sdbus_->sd_bus_message_unref((sd_bus_message*)msg_);
}
Message& Message::operator<<(bool item)
@@ -558,7 +578,7 @@ void Message::peekType(std::string& type, std::string& contents) const
bool Message::isValid() const
{
return msg_ != nullptr;
return msg_ != nullptr && sdbus_ != nullptr;
}
bool Message::isEmpty() const
@@ -566,20 +586,15 @@ bool Message::isEmpty() const
return sd_bus_message_is_empty((sd_bus_message*)msg_);
}
void* Message::getMsg() const
{
return msg_;
}
void MethodCall::dontExpectReply()
{
auto r = sd_bus_message_set_expect_reply((sd_bus_message*)getMsg(), 0);
auto r = sd_bus_message_set_expect_reply((sd_bus_message*)msg_, 0);
SDBUS_THROW_ERROR_IF(r < 0, "Failed to set the dont-expect-reply flag", -r);
}
bool MethodCall::doesntExpectReply() const
{
auto r = sd_bus_message_get_expect_reply((sd_bus_message*)getMsg());
auto r = sd_bus_message_get_expect_reply((sd_bus_message*)msg_);
SDBUS_THROW_ERROR_IF(r < 0, "Failed to get the dont-expect-reply flag", -r);
return r > 0 ? false : true;
}
@@ -594,41 +609,35 @@ MethodReply MethodCall::send() const
MethodReply MethodCall::sendWithReply() const
{
sd_bus_message* sdbusReply{};
SCOPE_EXIT{ sd_bus_message_unref(sdbusReply); }; // Returned message will become an owner of sdbusReply
sd_bus_error sdbusError = SD_BUS_ERROR_NULL;
SCOPE_EXIT{ sd_bus_error_free(&sdbusError); };
auto r = sd_bus_call(nullptr, (sd_bus_message*)getMsg(), 0, &sdbusError, &sdbusReply);
sd_bus_message* sdbusReply{};
auto r = sdbus_->sd_bus_call(nullptr, (sd_bus_message*)msg_, 0, &sdbusError, &sdbusReply);
if (sd_bus_error_is_set(&sdbusError))
{
throw sdbus::Error(sdbusError.name, sdbusError.message);
}
SDBUS_THROW_ERROR_IF(r < 0, "Failed to call method", -r);
return MethodReply(sdbusReply);
return MethodReply{sdbusReply, sdbus_, adopt_message};
}
MethodReply MethodCall::sendWithNoReply() const
{
auto r = sd_bus_send(nullptr, (sd_bus_message*)getMsg(), nullptr);
auto r = sdbus_->sd_bus_send(nullptr, (sd_bus_message*)msg_, nullptr);
SDBUS_THROW_ERROR_IF(r < 0, "Failed to call method with no reply", -r);
return MethodReply{}; // No reply
}
MethodReply MethodCall::createReply() const
{
sd_bus_message *sdbusReply{};
SCOPE_EXIT{ sd_bus_message_unref(sdbusReply); }; // Returned message will become an owner of sdbusReply
auto r = sd_bus_message_new_method_return((sd_bus_message*)getMsg(), &sdbusReply);
sd_bus_message* sdbusReply{};
auto r = sdbus_->sd_bus_message_new_method_return((sd_bus_message*)msg_, &sdbusReply);
SDBUS_THROW_ERROR_IF(r < 0, "Failed to create method reply", -r);
assert(sdbusReply != nullptr);
return MethodReply(sdbusReply);
return MethodReply{sdbusReply, sdbus_, adopt_message};
}
MethodReply MethodCall::createErrorReply(const Error& error) const
@@ -637,37 +646,33 @@ MethodReply MethodCall::createErrorReply(const Error& error) const
SCOPE_EXIT{ sd_bus_error_free(&sdbusError); };
sd_bus_error_set(&sdbusError, error.getName().c_str(), error.getMessage().c_str());
sd_bus_message *sdbusErrorReply{};
SCOPE_EXIT{ sd_bus_message_unref(sdbusErrorReply); }; // Returned message will become an owner of sdbusErrorReply
auto r = sd_bus_message_new_method_error((sd_bus_message*)getMsg(), &sdbusErrorReply, &sdbusError);
sd_bus_message* sdbusErrorReply{};
auto r = sdbus_->sd_bus_message_new_method_error((sd_bus_message*)msg_, &sdbusErrorReply, &sdbusError);
SDBUS_THROW_ERROR_IF(r < 0, "Failed to create method error reply", -r);
assert(sdbusErrorReply != nullptr);
return MethodReply(sdbusErrorReply);
return MethodReply{sdbusErrorReply, sdbus_, adopt_message};
}
AsyncMethodCall::AsyncMethodCall(MethodCall&& call) noexcept
: Message(call)
: Message(std::move(call))
{
}
void AsyncMethodCall::send(void* callback, void* userData) const
{
auto r = sd_bus_call_async(nullptr, nullptr, (sd_bus_message*)getMsg(), (sd_bus_message_handler_t)callback, userData, 0);
auto r = sdbus_->sd_bus_call_async(nullptr, nullptr, (sd_bus_message*)msg_, (sd_bus_message_handler_t)callback, userData, 0);
SDBUS_THROW_ERROR_IF(r < 0, "Failed to call method asynchronously", -r);
}
void MethodReply::send() const
{
auto r = sd_bus_send(nullptr, (sd_bus_message*)getMsg(), nullptr);
auto r = sdbus_->sd_bus_send(nullptr, (sd_bus_message*)msg_, nullptr);
SDBUS_THROW_ERROR_IF(r < 0, "Failed to send reply", -r);
}
void Signal::send() const
{
auto r = sd_bus_send(nullptr, (sd_bus_message*)getMsg(), nullptr);
auto r = sdbus_->sd_bus_send(nullptr, (sd_bus_message*)msg_, nullptr);
SDBUS_THROW_ERROR_IF(r < 0, "Failed to emit signal", -r);
}
@@ -676,16 +681,24 @@ Message createPlainMessage()
int r;
sd_bus* bus{};
SCOPE_EXIT{ sd_bus_unref(bus); }; // sdbusMsg will hold reference to the bus
SCOPE_EXIT{ sd_bus_unref(bus); };
r = sd_bus_default_system(&bus);
SDBUS_THROW_ERROR_IF(r < 0, "Failed to get default system bus", -r);
thread_local struct BusReferenceKeeper
{
BusReferenceKeeper(sd_bus* bus) : bus_(bus) {}
~BusReferenceKeeper() { sd_bus_unref(bus_); }
sd_bus* bus_{};
} busReferenceKeeper{bus};
sd_bus_message* sdbusMsg{};
SCOPE_EXIT{ sd_bus_message_unref(sdbusMsg); }; // Returned message will become an owner of sdbusMsg
r = sd_bus_message_new(bus, &sdbusMsg, _SD_BUS_MESSAGE_TYPE_INVALID);
SDBUS_THROW_ERROR_IF(r < 0, "Failed to create a new message", -r);
return Message(sdbusMsg);
thread_local internal::SdBus sdbus;
return Message{sdbusMsg, &sdbus, adopt_message};
}
}

View File

@@ -1,43 +0,0 @@
/**
* (C) 2017 KISTLER INSTRUMENTE AG, Winterthur, Switzerland
*
* @file Object.cpp
*
* 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/>.
*/
#include <sdbus-c++/MethodResult.h>
#include "Object.h"
namespace sdbus {
MethodResult::MethodResult(const MethodCall& msg, sdbus::internal::Object& object)
: call_(msg)
, object_(&object)
{
}
void MethodResult::send(const MethodReply& reply) const
{
assert(object_ != nullptr);
object_->sendReplyAsynchronously(reply);
}
}

View File

@@ -74,10 +74,10 @@ void Object::registerMethod( const std::string& interfaceName
{
SDBUS_THROW_ERROR_IF(!asyncMethodCallback, "Invalid method callback provided", EINVAL);
auto asyncCallback = [this, callback = std::move(asyncMethodCallback)](MethodCall& msg)
auto asyncCallback = [callback = std::move(asyncMethodCallback)](MethodCall& msg)
{
MethodResult result{msg, *this};
callback(msg, result);
MethodResult result{msg};
callback(std::move(msg), std::move(result));
};
auto& interface = interfaces_[interfaceName];
@@ -156,17 +156,9 @@ sdbus::Signal Object::createSignal(const std::string& interfaceName, const std::
void Object::emitSignal(const sdbus::Signal& message)
{
// TODO: Make signal emitting asynchronous. Now signal can probably be emitted only from user code
// handled within the D-Bus processing loop thread, but not from any thread. In principle it will
// be the same as async replies.
message.send();
}
void Object::sendReplyAsynchronously(const MethodReply& reply)
{
connection_.sendReplyAsynchronously(reply);
}
const std::vector<sd_bus_vtable>& Object::createInterfaceVTable(InterfaceData& interfaceData)
{
auto& vtable = interfaceData.vtable_;
@@ -242,9 +234,11 @@ void Object::activateInterfaceVTable( const std::string& interfaceName
int Object::sdbus_method_callback(sd_bus_message *sdbusMessage, void *userData, sd_bus_error *retError)
{
MethodCall message(sdbusMessage);
auto* object = static_cast<Object*>(userData);
assert(object != nullptr);
MethodCall message{sdbusMessage, &object->connection_.getSdBusInterface()};
// Note: The lookup can be optimized by using sorted vectors instead of associative containers
auto& callback = object->interfaces_[message.getInterfaceName()].methods_[message.getMemberName()].callback_;
assert(callback);
@@ -269,9 +263,9 @@ int Object::sdbus_property_get_callback( sd_bus */*bus*/
, void *userData
, sd_bus_error *retError )
{
Message reply(sdbusReply);
auto* object = static_cast<Object*>(userData);
assert(object != nullptr);
// Note: The lookup can be optimized by using sorted vectors instead of associative containers
auto& callback = object->interfaces_[interface].properties_[property].getCallback_;
// Getter can be empty - the case of "write-only" property
@@ -281,6 +275,8 @@ int Object::sdbus_property_get_callback( sd_bus */*bus*/
return 1;
}
Message reply{sdbusReply, &object->connection_.getSdBusInterface()};
try
{
callback(reply);
@@ -301,13 +297,15 @@ int Object::sdbus_property_set_callback( sd_bus */*bus*/
, void *userData
, sd_bus_error *retError )
{
Message value(sdbusValue);
auto* object = static_cast<Object*>(userData);
assert(object != nullptr);
// Note: The lookup can be optimized by using sorted vectors instead of associative containers
auto& callback = object->interfaces_[interface].properties_[property].setCallback_;
assert(callback);
Message value{sdbusValue, &object->connection_.getSdBusInterface()};
try
{
callback(value);

View File

@@ -84,8 +84,6 @@ namespace internal {
sdbus::Signal createSignal(const std::string& interfaceName, const std::string& signalName) override;
void emitSignal(const sdbus::Signal& message) override;
void sendReplyAsynchronously(const MethodReply& reply);
private:
using InterfaceName = std::string;
struct InterfaceData

View File

@@ -30,45 +30,40 @@
#include "IConnection.h"
#include <systemd/sd-bus.h>
#include <cassert>
#include <chrono>
#include <thread>
namespace sdbus { namespace internal {
ObjectProxy::ObjectProxy(sdbus::internal::IConnection& connection, std::string destination, std::string objectPath)
: connection_(&connection, [](sdbus::internal::IConnection *){ /* Intentionally left empty */ })
, ownConnection_(false)
, destination_(std::move(destination))
, objectPath_(std::move(objectPath))
{
// The connection is not ours only, it is managed by the client and we just reference it here,
// so we expect the client to manage the event loop upon this connection themselves.
}
ObjectProxy::ObjectProxy( std::unique_ptr<sdbus::internal::IConnection>&& connection
, std::string destination
, std::string objectPath )
: connection_(std::move(connection))
, ownConnection_(true)
, destination_(std::move(destination))
, objectPath_(std::move(objectPath))
{
}
ObjectProxy::~ObjectProxy()
{
// If the dedicated connection for signals is used, we have to stop the processing loop
// upon this connection prior to unregistering signal slots in the interfaces_ container,
// otherwise we might have a race condition of two threads working upon one connection.
if (signalConnection_ != nullptr)
signalConnection_->leaveProcessingLoop();
// The connection is ours only, so we have to manage event loop upon this connection,
// so we get signals, async replies, and other messages from D-Bus.
connection_->enterProcessingLoopAsync();
}
MethodCall ObjectProxy::createMethodCall(const std::string& interfaceName, const std::string& methodName)
{
// Tell, don't ask
return connection_->createMethodCall(destination_, objectPath_, interfaceName, methodName);
}
AsyncMethodCall ObjectProxy::createAsyncMethodCall(const std::string& interfaceName, const std::string& methodName)
{
return AsyncMethodCall{createMethodCall(interfaceName, methodName)};
return AsyncMethodCall{ObjectProxy::createMethodCall(interfaceName, methodName)};
}
MethodReply ObjectProxy::callMethod(const MethodCall& message)
@@ -78,8 +73,11 @@ MethodReply ObjectProxy::callMethod(const MethodCall& message)
void ObjectProxy::callMethod(const AsyncMethodCall& message, async_reply_handler asyncReplyCallback)
{
// The new-ed handler gets deleted in the sdbus_async_reply_handler
message.send((void*)&ObjectProxy::sdbus_async_reply_handler, new async_reply_handler(std::move(asyncReplyCallback)));
auto callback = (void*)&ObjectProxy::sdbus_async_reply_handler;
// Allocated userData gets deleted in the sdbus_async_reply_handler
auto userData = new AsyncReplyUserData{*this, std::move(asyncReplyCallback)};
message.send(callback, userData);
}
void ObjectProxy::registerSignalHandler( const std::string& interfaceName
@@ -99,30 +97,7 @@ void ObjectProxy::registerSignalHandler( const std::string& interfaceName
void ObjectProxy::finishRegistration()
{
bool hasSignals = listensToSignals();
if (hasSignals && ownConnection_)
{
// Let's use dedicated signalConnection_ for signals,
// which will then be used by the processing loop thread.
signalConnection_ = connection_->clone();
registerSignalHandlers(*signalConnection_);
signalConnection_->enterProcessingLoopAsync();
}
else if (hasSignals)
{
// Let's used connection provided from the outside.
registerSignalHandlers(*connection_);
}
}
bool ObjectProxy::listensToSignals() const
{
for (auto& interfaceItem : interfaces_)
if (!interfaceItem.second.signals_.empty())
return true;
return false;
registerSignalHandlers(*connection_);
}
void ObjectProxy::registerSignalHandlers(sdbus::internal::IConnection& connection)
@@ -149,31 +124,34 @@ void ObjectProxy::registerSignalHandlers(sdbus::internal::IConnection& connectio
int ObjectProxy::sdbus_async_reply_handler(sd_bus_message *sdbusMessage, void *userData, sd_bus_error *retError)
{
MethodReply message(sdbusMessage);
// We are assuming the ownership of the async reply handler pointer passed here
std::unique_ptr<async_reply_handler> asyncReplyCallback{static_cast<async_reply_handler*>(userData)};
assert(asyncReplyCallback != nullptr);
std::unique_ptr<AsyncReplyUserData> asyncReplyUserData{static_cast<AsyncReplyUserData*>(userData)};
assert(asyncReplyUserData != nullptr);
assert(asyncReplyUserData->callback);
if (!sd_bus_error_is_set(retError))
MethodReply message{sdbusMessage, &asyncReplyUserData->proxy.connection_->getSdBusInterface()};
const auto* error = sd_bus_message_get_error(sdbusMessage);
if (error == nullptr)
{
(*asyncReplyCallback)(message, nullptr);
asyncReplyUserData->callback(message, nullptr);
}
else
{
sdbus::Error error(retError->name, retError->message);
(*asyncReplyCallback)(message, &error);
sdbus::Error exception(error->name, error->message);
asyncReplyUserData->callback(message, &exception);
}
}
int ObjectProxy::sdbus_signal_callback(sd_bus_message *sdbusMessage, void *userData, sd_bus_error */*retError*/)
{
Signal message(sdbusMessage);
auto* proxy = static_cast<ObjectProxy*>(userData);
assert(proxy != nullptr);
Signal message{sdbusMessage, &proxy->connection_->getSdBusInterface()};
auto* object = static_cast<ObjectProxy*>(userData);
assert(object != nullptr);
// Note: The lookup can be optimized by using sorted vectors instead of associative containers
auto& callback = object->interfaces_[message.getInterfaceName()].signals_[message.getMemberName()].callback_;
auto& callback = proxy->interfaces_[message.getInterfaceName()].signals_[message.getMemberName()].callback_;
assert(callback);
callback(message);

View File

@@ -50,7 +50,6 @@ namespace internal {
ObjectProxy( std::unique_ptr<sdbus::internal::IConnection>&& connection
, std::string destination
, std::string objectPath );
~ObjectProxy() override;
MethodCall createMethodCall(const std::string& interfaceName, const std::string& methodName) override;
AsyncMethodCall createAsyncMethodCall(const std::string& interfaceName, const std::string& methodName) override;
@@ -63,7 +62,12 @@ namespace internal {
void finishRegistration() override;
private:
bool listensToSignals() const;
struct AsyncReplyUserData
{
ObjectProxy& proxy;
async_reply_handler callback;
};
void registerSignalHandlers(sdbus::internal::IConnection& connection);
static int sdbus_async_reply_handler(sd_bus_message *sdbusMessage, void *userData, sd_bus_error *retError);
static int sdbus_signal_callback(sd_bus_message *sdbusMessage, void *userData, sd_bus_error *retError);
@@ -72,8 +76,6 @@ namespace internal {
std::unique_ptr< sdbus::internal::IConnection
, std::function<void(sdbus::internal::IConnection*)>
> connection_;
bool ownConnection_{};
std::unique_ptr<sdbus::internal::IConnection> signalConnection_;
std::string destination_;
std::string objectPath_;

View File

@@ -28,44 +28,67 @@
namespace sdbus { namespace internal {
int SdBus::sd_bus_request_name(sd_bus *bus, const char *name, uint64_t flags)
sd_bus_message* SdBus::sd_bus_message_ref(sd_bus_message *m)
{
return ::sd_bus_request_name(bus, name, flags);
}
std::unique_lock<std::recursive_mutex> lock(sdbusMutex_);
int SdBus::sd_bus_release_name(sd_bus *bus, const char *name)
{
return ::sd_bus_release_name(bus, name);
}
int SdBus::sd_bus_add_object_vtable(sd_bus *bus, sd_bus_slot **slot, const char *path, const char *interface, const sd_bus_vtable *vtable, void *userdata)
{
return ::sd_bus_add_object_vtable(bus, slot, path, interface, vtable, userdata);
}
sd_bus_slot* SdBus::sd_bus_slot_unref(sd_bus_slot *slot)
{
return ::sd_bus_slot_unref(slot);
}
int SdBus::sd_bus_message_new_method_call(sd_bus *bus, sd_bus_message **m, const char *destination, const char *path, const char *interface, const char *member)
{
return ::sd_bus_message_new_method_call(bus, m, destination, path, interface, member);
return ::sd_bus_message_ref(m);
}
sd_bus_message* SdBus::sd_bus_message_unref(sd_bus_message *m)
{
std::unique_lock<std::recursive_mutex> lock(sdbusMutex_);
return ::sd_bus_message_unref(m);
}
int SdBus::sd_bus_send(sd_bus *bus, sd_bus_message *m, uint64_t *cookie)
{
std::unique_lock<std::recursive_mutex> lock(sdbusMutex_);
return ::sd_bus_send(bus, m, cookie);
}
int SdBus::sd_bus_call(sd_bus *bus, sd_bus_message *m, uint64_t usec, sd_bus_error *ret_error, sd_bus_message **reply)
{
std::unique_lock<std::recursive_mutex> lock(sdbusMutex_);
return ::sd_bus_call(bus, m, usec, ret_error, reply);
}
int SdBus::sd_bus_call_async(sd_bus *bus, sd_bus_slot **slot, sd_bus_message *m, sd_bus_message_handler_t callback, void *userdata, uint64_t usec)
{
std::unique_lock<std::recursive_mutex> lock(sdbusMutex_);
return ::sd_bus_call_async(bus, slot, m, callback, userdata, usec);
}
int SdBus::sd_bus_message_new_method_call(sd_bus *bus, sd_bus_message **m, const char *destination, const char *path, const char *interface, const char *member)
{
std::unique_lock<std::recursive_mutex> lock(sdbusMutex_);
return ::sd_bus_message_new_method_call(bus, m, destination, path, interface, member);
}
int SdBus::sd_bus_message_new_signal(sd_bus *bus, sd_bus_message **m, const char *path, const char *interface, const char *member)
{
std::unique_lock<std::recursive_mutex> lock(sdbusMutex_);
return ::sd_bus_message_new_signal(bus, m, path, interface, member);
}
int SdBus::sd_bus_add_match(sd_bus *bus, sd_bus_slot **slot, const char *match, sd_bus_message_handler_t callback, void *userdata)
int SdBus::sd_bus_message_new_method_return(sd_bus_message *call, sd_bus_message **m)
{
return :: sd_bus_add_match(bus, slot, match, callback, userdata);
std::unique_lock<std::recursive_mutex> lock(sdbusMutex_);
return ::sd_bus_message_new_method_return(call, m);
}
int SdBus::sd_bus_message_new_method_error(sd_bus_message *call, sd_bus_message **m, const sd_bus_error *e)
{
std::unique_lock<std::recursive_mutex> lock(sdbusMutex_);
return ::sd_bus_message_new_method_error(call, m, e);
}
int SdBus::sd_bus_open_user(sd_bus **ret)
@@ -78,29 +101,70 @@ int SdBus::sd_bus_open_system(sd_bus **ret)
return ::sd_bus_open_system(ret);
}
int SdBus::sd_bus_flush(sd_bus *bus)
int SdBus::sd_bus_request_name(sd_bus *bus, const char *name, uint64_t flags)
{
return ::sd_bus_flush(bus);
std::unique_lock<std::recursive_mutex> lock(sdbusMutex_);
return ::sd_bus_request_name(bus, name, flags);
}
int SdBus::sd_bus_release_name(sd_bus *bus, const char *name)
{
std::unique_lock<std::recursive_mutex> lock(sdbusMutex_);
return ::sd_bus_release_name(bus, name);
}
int SdBus::sd_bus_add_object_vtable(sd_bus *bus, sd_bus_slot **slot, const char *path, const char *interface, const sd_bus_vtable *vtable, void *userdata)
{
std::unique_lock<std::recursive_mutex> lock(sdbusMutex_);
return ::sd_bus_add_object_vtable(bus, slot, path, interface, vtable, userdata);
}
int SdBus::sd_bus_add_match(sd_bus *bus, sd_bus_slot **slot, const char *match, sd_bus_message_handler_t callback, void *userdata)
{
std::unique_lock<std::recursive_mutex> lock(sdbusMutex_);
return :: sd_bus_add_match(bus, slot, match, callback, userdata);
}
sd_bus_slot* SdBus::sd_bus_slot_unref(sd_bus_slot *slot)
{
std::unique_lock<std::recursive_mutex> lock(sdbusMutex_);
return ::sd_bus_slot_unref(slot);
}
int SdBus::sd_bus_process(sd_bus *bus, sd_bus_message **r)
{
std::unique_lock<std::recursive_mutex> lock(sdbusMutex_);
return ::sd_bus_process(bus, r);
}
int SdBus::sd_bus_get_fd(sd_bus *bus)
int SdBus::sd_bus_get_poll_data(sd_bus *bus, PollData* data)
{
return ::sd_bus_get_fd(bus);
std::unique_lock<std::recursive_mutex> lock(sdbusMutex_);
auto r = ::sd_bus_get_fd(bus);
if (r < 0)
return r;
data->fd = r;
r = ::sd_bus_get_events(bus);
if (r < 0)
return r;
data->events = static_cast<short int>(r);
r = ::sd_bus_get_timeout(bus, &data->timeout_usec);
return r;
}
int SdBus::sd_bus_get_events(sd_bus *bus)
int SdBus::sd_bus_flush(sd_bus *bus)
{
return ::sd_bus_get_events(bus);
}
int SdBus::sd_bus_get_timeout(sd_bus *bus, uint64_t *timeout_usec)
{
return ::sd_bus_get_timeout(bus, timeout_usec);
return ::sd_bus_flush(bus);
}
sd_bus* SdBus::sd_bus_flush_close_unref(sd_bus *bus)

View File

@@ -28,28 +28,41 @@
#define SDBUS_CXX_SDBUS_H
#include "ISdBus.h"
#include <mutex>
namespace sdbus { namespace internal {
class SdBus : public ISdBus
class SdBus final : public ISdBus
{
public:
int sd_bus_request_name(sd_bus *bus, const char *name, uint64_t flags) override;
int sd_bus_release_name(sd_bus *bus, const char *name) override;
int sd_bus_add_object_vtable(sd_bus *bus, sd_bus_slot **slot, const char *path, const char *interface, const sd_bus_vtable *vtable, void *userdata) override;
sd_bus_slot* sd_bus_slot_unref(sd_bus_slot *slot) override;
int sd_bus_message_new_method_call(sd_bus *bus, sd_bus_message **m, const char *destination, const char *path, const char *interface, const char *member) override;
sd_bus_message* sd_bus_message_unref(sd_bus_message *m) override;
int sd_bus_message_new_signal(sd_bus *bus, sd_bus_message **m, const char *path, const char *interface, const char *member) override;
int sd_bus_add_match(sd_bus *bus, sd_bus_slot **slot, const char *match, sd_bus_message_handler_t callback, void *userdata) override;
int sd_bus_open_user(sd_bus **ret) override;
int sd_bus_open_system(sd_bus **ret) override;
int sd_bus_flush(sd_bus *bus) override;
int sd_bus_process(sd_bus *bus, sd_bus_message **r) override;
int sd_bus_get_fd(sd_bus *bus) override;
int sd_bus_get_events(sd_bus *bus) override;
int sd_bus_get_timeout(sd_bus *bus, uint64_t *timeout_usec) override;
sd_bus *sd_bus_flush_close_unref(sd_bus *bus) override;
virtual sd_bus_message* sd_bus_message_ref(sd_bus_message *m) override;
virtual sd_bus_message* sd_bus_message_unref(sd_bus_message *m) override;
virtual int sd_bus_send(sd_bus *bus, sd_bus_message *m, uint64_t *cookie) override;
virtual int sd_bus_call(sd_bus *bus, sd_bus_message *m, uint64_t usec, sd_bus_error *ret_error, sd_bus_message **reply) override;
virtual int sd_bus_call_async(sd_bus *bus, sd_bus_slot **slot, sd_bus_message *m, sd_bus_message_handler_t callback, void *userdata, uint64_t usec) override;
virtual int sd_bus_message_new_method_call(sd_bus *bus, sd_bus_message **m, const char *destination, const char *path, const char *interface, const char *member) override;
virtual int sd_bus_message_new_signal(sd_bus *bus, sd_bus_message **m, const char *path, const char *interface, const char *member) override;
virtual int sd_bus_message_new_method_return(sd_bus_message *call, sd_bus_message **m) override;
virtual int sd_bus_message_new_method_error(sd_bus_message *call, sd_bus_message **m, const sd_bus_error *e) override;
virtual int sd_bus_open_user(sd_bus **ret) override;
virtual int sd_bus_open_system(sd_bus **ret) override;
virtual int sd_bus_request_name(sd_bus *bus, const char *name, uint64_t flags) override;
virtual int sd_bus_release_name(sd_bus *bus, const char *name) override;
virtual int sd_bus_add_object_vtable(sd_bus *bus, sd_bus_slot **slot, const char *path, const char *interface, const sd_bus_vtable *vtable, void *userdata) override;
virtual int sd_bus_add_match(sd_bus *bus, sd_bus_slot **slot, const char *match, sd_bus_message_handler_t callback, void *userdata) override;
virtual sd_bus_slot* sd_bus_slot_unref(sd_bus_slot *slot) override;
virtual int sd_bus_process(sd_bus *bus, sd_bus_message **r) override;
virtual int sd_bus_get_poll_data(sd_bus *bus, PollData* data) override;
virtual int sd_bus_flush(sd_bus *bus) override;
virtual sd_bus *sd_bus_flush_close_unref(sd_bus *bus) override;
private:
std::recursive_mutex sdbusMutex_;
};
}}

View File

@@ -29,7 +29,7 @@
#include <systemd/sd-bus.h>
#include <cassert>
namespace sdbus { /*namespace internal {*/
namespace sdbus {
Variant::Variant()
: msg_(createPlainMessage())