From 0f2362d8c3fd6bac9b357ec42c9babfd55a1a19e Mon Sep 17 00:00:00 2001 From: alivenets Date: Mon, 8 Aug 2022 13:54:09 +0200 Subject: [PATCH] feat: add support for session bus connection at custom address (#273) * Add methods to initiate custom session bus connection The new function helper `createSessionBusConnectionWithAddress` allows to create connection to session bus with custom address. Signed-off-by: Alexander Livenets * feat: add support for session bus connection at custom address Co-authored-by: Stanislav Angelovic --- include/sdbus-c++/IConnection.h | 30 ++++++++++++++------- src/Connection.cpp | 26 ++++++++++++------ src/Connection.h | 7 +++++ src/ISdBus.h | 3 ++- src/SdBus.cpp | 36 +++++++++++++++++++++++-- src/SdBus.h | 3 ++- tests/unittests/Connection_test.cpp | 41 ++++++++++++++++------------- tests/unittests/mocks/SdBusMock.h | 3 ++- 8 files changed, 108 insertions(+), 41 deletions(-) diff --git a/include/sdbus-c++/IConnection.h b/include/sdbus-c++/IConnection.h index b5d7d03..8030a1a 100644 --- a/include/sdbus-c++/IConnection.h +++ b/include/sdbus-c++/IConnection.h @@ -363,7 +363,7 @@ namespace sdbus { } /*! - * @brief Creates/opens D-Bus system connection + * @brief Creates/opens D-Bus system bus connection * * @return Connection instance * @@ -372,7 +372,7 @@ namespace sdbus { [[nodiscard]] std::unique_ptr createConnection(); /*! - * @brief Creates/opens D-Bus system connection with a name + * @brief Creates/opens D-Bus system bus connection with a name * * @param[in] name Name to request on the connection after its opening * @return Connection instance @@ -382,8 +382,7 @@ namespace sdbus { [[nodiscard]] std::unique_ptr createConnection(const std::string& name); /*! - * @brief Creates/opens D-Bus user connection when in a user context, - * and a system connection, otherwise. + * @brief Creates/opens D-Bus session bus connection when in a user context, and a system bus connection, otherwise. * * @return Connection instance * @@ -392,8 +391,7 @@ namespace sdbus { [[nodiscard]] std::unique_ptr createDefaultBusConnection(); /*! - * @brief Creates/opens D-Bus user connection with a name when in a user - * context, and a system connection with a name, otherwise. + * @brief Creates/opens D-Bus session bus connection with a name when in a user context, and a system bus connection with a name, otherwise. * * @param[in] name Name to request on the connection after its opening * @return Connection instance @@ -403,7 +401,7 @@ namespace sdbus { [[nodiscard]] std::unique_ptr createDefaultBusConnection(const std::string& name); /*! - * @brief Creates/opens D-Bus system connection + * @brief Creates/opens D-Bus system bus connection * * @return Connection instance * @@ -412,7 +410,7 @@ namespace sdbus { [[nodiscard]] std::unique_ptr createSystemBusConnection(); /*! - * @brief Creates/opens D-Bus system connection with a name + * @brief Creates/opens D-Bus system bus connection with a name * * @param[in] name Name to request on the connection after its opening * @return Connection instance @@ -422,7 +420,7 @@ namespace sdbus { [[nodiscard]] std::unique_ptr createSystemBusConnection(const std::string& name); /*! - * @brief Creates/opens D-Bus session connection + * @brief Creates/opens D-Bus session bus connection * * @return Connection instance * @@ -431,7 +429,7 @@ namespace sdbus { [[nodiscard]] std::unique_ptr createSessionBusConnection(); /*! - * @brief Creates/opens D-Bus session connection with a name + * @brief Creates/opens D-Bus session bus connection with a name * * @param[in] name Name to request on the connection after its opening * @return Connection instance @@ -440,6 +438,18 @@ namespace sdbus { */ [[nodiscard]] std::unique_ptr createSessionBusConnection(const std::string& name); + /*! + * @brief Creates/opens D-Bus session bus connection at a custom address + * + * @param[in] address ";"-separated list of addresses of bus brokers to try to connect + * @return Connection instance + * + * @throws sdbus::Error in case of failure + * + * Consult manual pages for `sd_bus_set_address` of the underlying sd-bus library for more information. + */ + [[nodiscard]] std::unique_ptr createSessionBusConnectionWithAddress(const std::string& address); + /*! * @brief Creates/opens D-Bus system connection on a remote host using ssh * diff --git a/src/Connection.cpp b/src/Connection.cpp index cf37186..1a558a3 100644 --- a/src/Connection.cpp +++ b/src/Connection.cpp @@ -60,6 +60,11 @@ Connection::Connection(std::unique_ptr&& interface, session_bus_t) { } +Connection::Connection(std::unique_ptr&& interface, custom_session_bus_t, const std::string& address) + : Connection(std::move(interface), [&](sd_bus** bus) { return iface_->sd_bus_open_user_with_address(bus, address.c_str()); }) +{ +} + Connection::Connection(std::unique_ptr&& interface, remote_system_bus_t, const std::string& host) : Connection(std::move(interface), [this, &host](sd_bus** bus){ return iface_->sd_bus_open_system_remote(bus, host.c_str()); }) { @@ -572,6 +577,8 @@ std::unique_ptr createConnection() namespace sdbus { +using internal::Connection; + std::unique_ptr createConnection() { return createSystemBusConnection(); @@ -585,8 +592,7 @@ std::unique_ptr createConnection(const std::string& name) std::unique_ptr createDefaultBusConnection() { auto interface = std::make_unique(); - constexpr sdbus::internal::Connection::default_bus_t default_bus; - return std::make_unique(std::move(interface), default_bus); + return std::make_unique(std::move(interface), Connection::default_bus); } std::unique_ptr createDefaultBusConnection(const std::string& name) @@ -599,8 +605,7 @@ std::unique_ptr createDefaultBusConnection(const std::string std::unique_ptr createSystemBusConnection() { auto interface = std::make_unique(); - constexpr sdbus::internal::Connection::system_bus_t system_bus; - return std::make_unique(std::move(interface), system_bus); + return std::make_unique(std::move(interface), Connection::system_bus); } std::unique_ptr createSystemBusConnection(const std::string& name) @@ -613,8 +618,7 @@ std::unique_ptr createSystemBusConnection(const std::string& std::unique_ptr createSessionBusConnection() { auto interface = std::make_unique(); - constexpr sdbus::internal::Connection::session_bus_t session_bus; - return std::make_unique(std::move(interface), session_bus); + return std::make_unique(std::move(interface), Connection::session_bus); } std::unique_ptr createSessionBusConnection(const std::string& name) @@ -624,11 +628,17 @@ std::unique_ptr createSessionBusConnection(const std::string return conn; } +std::unique_ptr createSessionBusConnectionWithAddress(const std::string &address) +{ + auto interface = std::make_unique(); + assert(interface != nullptr); + return std::make_unique(std::move(interface), Connection::custom_session_bus, address); +} + std::unique_ptr createRemoteSystemBusConnection(const std::string& host) { auto interface = std::make_unique(); - constexpr sdbus::internal::Connection::remote_system_bus_t remote_system_bus; - return std::make_unique(std::move(interface), remote_system_bus, host); + return std::make_unique(std::move(interface), Connection::remote_system_bus, host); } } // namespace sdbus diff --git a/src/Connection.h b/src/Connection.h index 2d46f86..32fe0b4 100644 --- a/src/Connection.h +++ b/src/Connection.h @@ -48,13 +48,20 @@ namespace sdbus::internal { public: // Bus type tags struct default_bus_t{}; + inline static constexpr default_bus_t default_bus{}; struct system_bus_t{}; + inline static constexpr system_bus_t system_bus{}; struct session_bus_t{}; + inline static constexpr session_bus_t session_bus{}; + struct custom_session_bus_t{}; + 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{}; Connection(std::unique_ptr&& interface, default_bus_t); Connection(std::unique_ptr&& interface, system_bus_t); Connection(std::unique_ptr&& interface, session_bus_t); + Connection(std::unique_ptr&& interface, custom_session_bus_t, const std::string& address); Connection(std::unique_ptr&& interface, remote_system_bus_t, const std::string& host); ~Connection() override; diff --git a/src/ISdBus.h b/src/ISdBus.h index 4d9b30d..10322c4 100644 --- a/src/ISdBus.h +++ b/src/ISdBus.h @@ -67,8 +67,9 @@ namespace sdbus::internal { virtual int sd_bus_emit_interfaces_removed_strv(sd_bus *bus, const char *path, char **interfaces) = 0; virtual int sd_bus_open(sd_bus **ret) = 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_open_user(sd_bus **ret) = 0; + virtual int sd_bus_open_user_with_address(sd_bus **ret, const char* address) = 0; virtual int sd_bus_open_system_remote(sd_bus **ret, const char* host) = 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; diff --git a/src/SdBus.cpp b/src/SdBus.cpp index a095295..6dfecaa 100644 --- a/src/SdBus.cpp +++ b/src/SdBus.cpp @@ -166,14 +166,46 @@ int SdBus::sd_bus_open(sd_bus **ret) return ::sd_bus_open(ret); } +int SdBus::sd_bus_open_system(sd_bus **ret) +{ + return ::sd_bus_open_system(ret); +} + int SdBus::sd_bus_open_user(sd_bus **ret) { return ::sd_bus_open_user(ret); } -int SdBus::sd_bus_open_system(sd_bus **ret) +int SdBus::sd_bus_open_user_with_address(sd_bus **ret, const char* address) { - return ::sd_bus_open_system(ret); + sd_bus* bus = nullptr; + + int r = sd_bus_new(&bus); + if (r < 0) + return r; + + r = sd_bus_set_address(bus, address); + if (r < 0) + return r; + + r = sd_bus_set_bus_client(bus, true); + if (r < 0) + return r; + + // Copying behavior from + // https://github.com/systemd/systemd/blob/fee6441601c979165ebcbb35472036439f8dad5f/src/libsystemd/sd-bus/sd-bus.c#L1381 + // Here, we make the bus as trusted + r = sd_bus_set_trusted(bus, true); + if (r < 0) + return r; + + r = sd_bus_start(bus); + if (r < 0) + return r; + + *ret = bus; + + return 0; } int SdBus::sd_bus_open_system_remote(sd_bus **ret, const char *host) diff --git a/src/SdBus.h b/src/SdBus.h index 224eb81..050496c 100644 --- a/src/SdBus.h +++ b/src/SdBus.h @@ -59,8 +59,9 @@ public: virtual int sd_bus_emit_interfaces_removed_strv(sd_bus *bus, const char *path, char **interfaces) override; virtual int sd_bus_open(sd_bus **ret) 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_open_user(sd_bus **ret) override; + virtual int sd_bus_open_user_with_address(sd_bus **ret, const char* address) override; virtual int sd_bus_open_system_remote(sd_bus **ret, const char* hsot) 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; diff --git a/tests/unittests/Connection_test.cpp b/tests/unittests/Connection_test.cpp index 26e3c5c..7e55ee1 100644 --- a/tests/unittests/Connection_test.cpp +++ b/tests/unittests/Connection_test.cpp @@ -35,11 +35,7 @@ using ::testing::DoAll; using ::testing::SetArgPointee; using ::testing::Return; using ::testing::NiceMock; -using sdbus::internal::Connection; -constexpr sdbus::internal::Connection::default_bus_t default_bus; -constexpr sdbus::internal::Connection::system_bus_t system_bus; -constexpr sdbus::internal::Connection::session_bus_t session_bus; -constexpr sdbus::internal::Connection::remote_system_bus_t remote_system_bus; +using ::sdbus::internal::Connection; class ConnectionCreationTest : public ::testing::Test { @@ -58,81 +54,81 @@ TEST_F(ADefaultBusConnection, OpensAndFlushesBusWhenCreated) { EXPECT_CALL(*sdBusIntfMock_, sd_bus_open(_)).WillOnce(DoAll(SetArgPointee<0>(fakeBusPtr_), Return(1))); EXPECT_CALL(*sdBusIntfMock_, sd_bus_flush(_)).Times(1); - Connection(std::move(sdBusIntfMock_), default_bus); + Connection(std::move(sdBusIntfMock_), Connection::default_bus); } TEST_F(ASystemBusConnection, OpensAndFlushesBusWhenCreated) { EXPECT_CALL(*sdBusIntfMock_, sd_bus_open_system(_)).WillOnce(DoAll(SetArgPointee<0>(fakeBusPtr_), Return(1))); EXPECT_CALL(*sdBusIntfMock_, sd_bus_flush(_)).Times(1); - Connection(std::move(sdBusIntfMock_), system_bus); + Connection(std::move(sdBusIntfMock_), Connection::system_bus); } TEST_F(ASessionBusConnection, OpensAndFlushesBusWhenCreated) { EXPECT_CALL(*sdBusIntfMock_, sd_bus_open_user(_)).WillOnce(DoAll(SetArgPointee<0>(fakeBusPtr_), Return(1))); EXPECT_CALL(*sdBusIntfMock_, sd_bus_flush(_)).Times(1); - Connection(std::move(sdBusIntfMock_), session_bus); + Connection(std::move(sdBusIntfMock_), Connection::session_bus); } TEST_F(ADefaultBusConnection, ClosesAndUnrefsBusWhenDestructed) { ON_CALL(*sdBusIntfMock_, sd_bus_open(_)).WillByDefault(DoAll(SetArgPointee<0>(fakeBusPtr_), Return(1))); EXPECT_CALL(*sdBusIntfMock_, sd_bus_flush_close_unref(_)).Times(1); - Connection(std::move(sdBusIntfMock_), default_bus); + Connection(std::move(sdBusIntfMock_), Connection::default_bus); } TEST_F(ASystemBusConnection, ClosesAndUnrefsBusWhenDestructed) { ON_CALL(*sdBusIntfMock_, sd_bus_open_system(_)).WillByDefault(DoAll(SetArgPointee<0>(fakeBusPtr_), Return(1))); EXPECT_CALL(*sdBusIntfMock_, sd_bus_flush_close_unref(_)).Times(1); - Connection(std::move(sdBusIntfMock_), system_bus); + Connection(std::move(sdBusIntfMock_), Connection::system_bus); } TEST_F(ASessionBusConnection, ClosesAndUnrefsBusWhenDestructed) { ON_CALL(*sdBusIntfMock_, sd_bus_open_user(_)).WillByDefault(DoAll(SetArgPointee<0>(fakeBusPtr_), Return(1))); EXPECT_CALL(*sdBusIntfMock_, sd_bus_flush_close_unref(_)).Times(1); - Connection(std::move(sdBusIntfMock_), session_bus); + Connection(std::move(sdBusIntfMock_), Connection::session_bus); } TEST_F(ADefaultBusConnection, ThrowsErrorWhenOpeningTheBusFailsDuringConstruction) { ON_CALL(*sdBusIntfMock_, sd_bus_open(_)).WillByDefault(DoAll(SetArgPointee<0>(fakeBusPtr_), Return(-1))); - ASSERT_THROW(Connection(std::move(sdBusIntfMock_), default_bus), sdbus::Error); + ASSERT_THROW(Connection(std::move(sdBusIntfMock_), Connection::default_bus), sdbus::Error); } TEST_F(ASystemBusConnection, ThrowsErrorWhenOpeningTheBusFailsDuringConstruction) { ON_CALL(*sdBusIntfMock_, sd_bus_open_system(_)).WillByDefault(DoAll(SetArgPointee<0>(fakeBusPtr_), Return(-1))); - ASSERT_THROW(Connection(std::move(sdBusIntfMock_), system_bus), sdbus::Error); + ASSERT_THROW(Connection(std::move(sdBusIntfMock_), Connection::system_bus), sdbus::Error); } TEST_F(ASessionBusConnection, ThrowsErrorWhenOpeningTheBusFailsDuringConstruction) { ON_CALL(*sdBusIntfMock_, sd_bus_open_user(_)).WillByDefault(DoAll(SetArgPointee<0>(fakeBusPtr_), Return(-1))); - ASSERT_THROW(Connection(std::move(sdBusIntfMock_), session_bus), sdbus::Error); + ASSERT_THROW(Connection(std::move(sdBusIntfMock_), Connection::session_bus), sdbus::Error); } TEST_F(ADefaultBusConnection, ThrowsErrorWhenFlushingTheBusFailsDuringConstruction) { ON_CALL(*sdBusIntfMock_, sd_bus_open(_)).WillByDefault(DoAll(SetArgPointee<0>(fakeBusPtr_), Return(1))); ON_CALL(*sdBusIntfMock_, sd_bus_flush(_)).WillByDefault(Return(-1)); - ASSERT_THROW(Connection(std::move(sdBusIntfMock_), default_bus), sdbus::Error); + ASSERT_THROW(Connection(std::move(sdBusIntfMock_), Connection::default_bus), sdbus::Error); } TEST_F(ASystemBusConnection, ThrowsErrorWhenFlushingTheBusFailsDuringConstruction) { ON_CALL(*sdBusIntfMock_, sd_bus_open_system(_)).WillByDefault(DoAll(SetArgPointee<0>(fakeBusPtr_), Return(1))); ON_CALL(*sdBusIntfMock_, sd_bus_flush(_)).WillByDefault(Return(-1)); - ASSERT_THROW(Connection(std::move(sdBusIntfMock_), system_bus), sdbus::Error); + ASSERT_THROW(Connection(std::move(sdBusIntfMock_), Connection::system_bus), sdbus::Error); } TEST_F(ASessionBusConnection, ThrowsErrorWhenFlushingTheBusFailsDuringConstruction) { ON_CALL(*sdBusIntfMock_, sd_bus_open_user(_)).WillByDefault(DoAll(SetArgPointee<0>(fakeBusPtr_), Return(1))); ON_CALL(*sdBusIntfMock_, sd_bus_flush(_)).WillByDefault(Return(-1)); - ASSERT_THROW(Connection(std::move(sdBusIntfMock_), session_bus), sdbus::Error); + ASSERT_THROW(Connection(std::move(sdBusIntfMock_), Connection::session_bus), sdbus::Error); } namespace @@ -169,6 +165,10 @@ template<> void AConnectionNameRequest::setUpBusOpenE { EXPECT_CALL(*sdBusIntfMock_, sd_bus_open_user(_)).WillOnce(DoAll(SetArgPointee<0>(fakeBusPtr_), Return(1))); } +template<> void AConnectionNameRequest::setUpBusOpenExpectation() +{ + EXPECT_CALL(*sdBusIntfMock_, sd_bus_open_user_with_address(_, _)).WillOnce(DoAll(SetArgPointee<0>(fakeBusPtr_), Return(1))); +} template<> void AConnectionNameRequest::setUpBusOpenExpectation() { EXPECT_CALL(*sdBusIntfMock_, sd_bus_open_system_remote(_, _)).WillOnce(DoAll(SetArgPointee<0>(fakeBusPtr_), Return(1))); @@ -178,14 +178,19 @@ std::unique_ptr AConnectionNameRequest<_BusTypeTag>::makeConnection( { return std::make_unique(std::unique_ptr>(sdBusIntfMock_), _BusTypeTag{}); } +template<> std::unique_ptr AConnectionNameRequest::makeConnection() +{ + return std::make_unique(std::unique_ptr>(sdBusIntfMock_), Connection::custom_session_bus, "custom session bus"); +} template<> std::unique_ptr AConnectionNameRequest::makeConnection() { - return std::make_unique(std::unique_ptr>(sdBusIntfMock_), remote_system_bus, "some host"); + return std::make_unique(std::unique_ptr>(sdBusIntfMock_), Connection::remote_system_bus, "some host"); } typedef ::testing::Types< Connection::default_bus_t , Connection::system_bus_t , Connection::session_bus_t + , Connection::custom_session_bus_t , Connection::remote_system_bus_t > BusTypeTags; diff --git a/tests/unittests/mocks/SdBusMock.h b/tests/unittests/mocks/SdBusMock.h index db0ed34..d89aa64 100644 --- a/tests/unittests/mocks/SdBusMock.h +++ b/tests/unittests/mocks/SdBusMock.h @@ -58,8 +58,9 @@ public: MOCK_METHOD3(sd_bus_emit_interfaces_removed_strv, int(sd_bus *bus, const char *path, char **interfaces)); MOCK_METHOD1(sd_bus_open, int(sd_bus **ret)); - MOCK_METHOD1(sd_bus_open_user, int(sd_bus **ret)); MOCK_METHOD1(sd_bus_open_system, int(sd_bus **ret)); + MOCK_METHOD1(sd_bus_open_user, int(sd_bus **ret)); + MOCK_METHOD2(sd_bus_open_user_with_address, int(sd_bus **ret, const char* address)); MOCK_METHOD2(sd_bus_open_system_remote, int(sd_bus **ret, const char *host)); MOCK_METHOD3(sd_bus_request_name, int(sd_bus *bus, const char *name, uint64_t flags)); MOCK_METHOD2(sd_bus_release_name, int(sd_bus *bus, const char *name));