refactor: use pseudo D-Bus connection for plain messages

This commit is contained in:
Stanislav Angelovic
2022-08-03 13:05:18 +02:00
committed by Stanislav Angelovič
parent 0f2362d8c3
commit 2991fa4960
9 changed files with 80 additions and 2 deletions

View File

@ -70,6 +70,13 @@ Connection::Connection(std::unique_ptr<ISdBus>&& interface, remote_system_bus_t,
{
}
Connection::Connection(std::unique_ptr<ISdBus>&& interface, pseudo_bus_t)
: iface_(std::move(interface))
, bus_(openPseudoBus())
{
assert(iface_ != nullptr);
}
Connection::~Connection()
{
Connection::leaveEventLoop();
@ -394,6 +401,23 @@ Connection::BusPtr Connection::openBus(const BusFactory& busFactory)
return busPtr;
}
Connection::BusPtr Connection::openPseudoBus()
{
sd_bus* bus{};
int r = iface_->sd_bus_new(&bus);
SDBUS_THROW_ERROR_IF(r < 0, "Failed to open pseudo bus", -r);
(void)iface_->sd_bus_start(bus);
// It is expected that sd_bus_start has failed here, returning -EINVAL, due to having
// not set a bus address, but it will leave the bus in an OPENING state, which enables
// us to create plain D-Bus messages as a local data storage (for Variant, for example),
// without dependency on real IPC communication with the D-Bus broker daemon.
SDBUS_THROW_ERROR_IF(r < 0 && r != -EINVAL, "Failed to start pseudo bus", -r);
return {bus, [this](sd_bus* bus){ return iface_->sd_bus_close_unref(bus); }};
}
void Connection::finishHandshake(sd_bus* bus)
{
// Process all requests that are part of the initial handshake,
@ -573,6 +597,12 @@ std::unique_ptr<sdbus::internal::IConnection> createConnection()
return std::unique_ptr<sdbus::internal::IConnection>(connectionInternal);
}
std::unique_ptr<sdbus::internal::IConnection> createPseudoConnection()
{
auto interface = std::make_unique<sdbus::internal::SdBus>();
return std::make_unique<sdbus::internal::Connection>(std::move(interface), Connection::pseudo_bus);
}
} // namespace sdbus::internal
namespace sdbus {

View File

@ -57,12 +57,15 @@ namespace sdbus::internal {
inline static constexpr custom_session_bus_t custom_session_bus{};
struct remote_system_bus_t{};
inline static constexpr remote_system_bus_t remote_system_bus{};
struct pseudo_bus_t{}; // A bus connection that is not really established with D-Bus daemon
inline static constexpr pseudo_bus_t pseudo_bus{};
Connection(std::unique_ptr<ISdBus>&& interface, default_bus_t);
Connection(std::unique_ptr<ISdBus>&& interface, system_bus_t);
Connection(std::unique_ptr<ISdBus>&& interface, session_bus_t);
Connection(std::unique_ptr<ISdBus>&& interface, custom_session_bus_t, const std::string& address);
Connection(std::unique_ptr<ISdBus>&& interface, remote_system_bus_t, const std::string& host);
Connection(std::unique_ptr<ISdBus>&& interface, pseudo_bus_t);
~Connection() override;
void requestName(const std::string& name) override;
@ -126,6 +129,7 @@ namespace sdbus::internal {
Connection(std::unique_ptr<ISdBus>&& interface, const BusFactory& busFactory);
BusPtr openBus(const std::function<int(sd_bus**)>& busFactory);
BusPtr openPseudoBus();
void finishHandshake(sd_bus* bus);
bool waitForNextRequest();
static std::string composeSignalMatchFilter( const std::string &sender

View File

@ -95,6 +95,7 @@ namespace sdbus::internal {
};
[[nodiscard]] std::unique_ptr<sdbus::internal::IConnection> createConnection();
[[nodiscard]] std::unique_ptr<sdbus::internal::IConnection> createPseudoConnection();
}

View File

@ -79,11 +79,15 @@ namespace sdbus::internal {
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 sd_bus_slot* sd_bus_slot_unref(sd_bus_slot *slot) = 0;
virtual int sd_bus_new(sd_bus **ret) = 0;
virtual int sd_bus_start(sd_bus *bus) = 0;
virtual int sd_bus_process(sd_bus *bus, sd_bus_message **r) = 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 sd_bus *sd_bus_close_unref(sd_bus *bus) = 0;
virtual int sd_bus_message_set_destination(sd_bus_message *m, const char *destination) = 0;

View File

@ -864,9 +864,13 @@ void Signal::setDestination(const std::string& destination)
PlainMessage createPlainMessage()
{
static auto connection = internal::createConnection();
//static auto connection = internal::createConnection();
// Let's create a pseudo connection -- one that does not really connect to the real bus.
// This is a bit of a hack, but it enables use to work with D-Bus message locally without
// the need of D-Bus daemon. This is especially useful in unit tests of both sdbus-c++ and client code.
// Additionally, it's light-weight and fast solution.
static auto connection = internal::createPseudoConnection();
return connection->createPlainMessage();
}
}

View File

@ -261,6 +261,16 @@ sd_bus_slot* SdBus::sd_bus_slot_unref(sd_bus_slot *slot)
return ::sd_bus_slot_unref(slot);
}
int SdBus::sd_bus_new(sd_bus **ret)
{
return ::sd_bus_new(ret);
}
int SdBus::sd_bus_start(sd_bus *bus)
{
return ::sd_bus_start(bus);
}
int SdBus::sd_bus_process(sd_bus *bus, sd_bus_message **r)
{
std::lock_guard lock(sdbusMutex_);
@ -297,6 +307,16 @@ sd_bus* SdBus::sd_bus_flush_close_unref(sd_bus *bus)
return ::sd_bus_flush_close_unref(bus);
}
sd_bus* SdBus::sd_bus_close_unref(sd_bus *bus)
{
#if LIBSYSTEMD_VERSION>=241
return ::sd_bus_close_unref(bus);
#else
::sd_bus_close(bus);
return ::sd_bus_unref(bus);
#endif
}
int SdBus::sd_bus_message_set_destination(sd_bus_message *m, const char *destination)
{
std::lock_guard lock(sdbusMutex_);

View File

@ -71,11 +71,15 @@ public:
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_new(sd_bus **ret) override;
virtual int sd_bus_start(sd_bus *bus) 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;
virtual sd_bus *sd_bus_close_unref(sd_bus *bus) override;
virtual int sd_bus_message_set_destination(sd_bus_message *m, const char *destination) override;

View File

@ -173,6 +173,12 @@ template<> void AConnectionNameRequest<Connection::remote_system_bus_t>::setUpBu
{
EXPECT_CALL(*sdBusIntfMock_, sd_bus_open_system_remote(_, _)).WillOnce(DoAll(SetArgPointee<0>(fakeBusPtr_), Return(1)));
}
template<> void AConnectionNameRequest<Connection::pseudo_bus_t>::setUpBusOpenExpectation()
{
EXPECT_CALL(*sdBusIntfMock_, sd_bus_new(_)).WillOnce(DoAll(SetArgPointee<0>(fakeBusPtr_), Return(1)));
// `sd_bus_start` for pseudo connection shall return an error value, remember this is a fake connection...
EXPECT_CALL(*sdBusIntfMock_, sd_bus_start(fakeBusPtr_)).WillOnce(Return(-EINVAL));
}
template <typename _BusTypeTag>
std::unique_ptr<Connection> AConnectionNameRequest<_BusTypeTag>::makeConnection()
{
@ -192,6 +198,7 @@ typedef ::testing::Types< Connection::default_bus_t
, Connection::session_bus_t
, Connection::custom_session_bus_t
, Connection::remote_system_bus_t
, Connection::pseudo_bus_t
> BusTypeTags;
TYPED_TEST_SUITE(AConnectionNameRequest, BusTypeTags);

View File

@ -70,11 +70,15 @@ public:
MOCK_METHOD5(sd_bus_add_match, int(sd_bus *bus, sd_bus_slot **slot, const char *match, sd_bus_message_handler_t callback, void *userdata));
MOCK_METHOD1(sd_bus_slot_unref, sd_bus_slot*(sd_bus_slot *slot));
MOCK_METHOD1(sd_bus_new, int(sd_bus **ret));
MOCK_METHOD1(sd_bus_start, int(sd_bus *bus));
MOCK_METHOD2(sd_bus_process, int(sd_bus *bus, sd_bus_message **r));
MOCK_METHOD2(sd_bus_get_poll_data, int(sd_bus *bus, PollData* data));
MOCK_METHOD1(sd_bus_flush, int(sd_bus *bus));
MOCK_METHOD1(sd_bus_flush_close_unref, sd_bus *(sd_bus *bus));
MOCK_METHOD1(sd_bus_close_unref, sd_bus *(sd_bus *bus));
MOCK_METHOD2(sd_bus_message_set_destination, int(sd_bus_message *m, const char *destination));