Add bus bindings
Add C++ bindings for the sd_bus_(bus) class interfaces. This
binding creates a unique_ptr wrapper around sd_bus*, using the
appropriate sd_bus deref calls when the unique_ptr leaves scope.
Change-Id: I0bb3842e384217ac5606bb3bf350d7fc3babf1ad
Signed-off-by: Patrick Williams <patrick@stwcx.xyz>
diff --git a/sdbusplus/bus.hpp b/sdbusplus/bus.hpp
new file mode 100644
index 0000000..8ca107d
--- /dev/null
+++ b/sdbusplus/bus.hpp
@@ -0,0 +1,166 @@
+#pragma once
+
+#include <memory>
+#include <systemd/sd-bus.h>
+
+namespace sdbusplus
+{
+namespace bus
+{
+
+using busp_t = sd_bus*;
+class bus;
+
+/** @brief Get an instance of the 'default' bus. */
+bus new_default();
+/** @brief Get an instance of the 'user' session bus. */
+bus new_user();
+/** @brief Get an instance of the 'system' bus. */
+bus new_system();
+
+namespace details
+{
+
+/** @brief unique_ptr functor to release a bus reference. */
+struct BusDeleter
+{
+ void operator()(sd_bus* ptr) const
+ {
+ sd_bus_flush_close_unref(ptr);
+ }
+};
+
+/* @brief Alias 'bus' to a unique_ptr type for auto-release. */
+using bus = std::unique_ptr<sd_bus, BusDeleter>;
+
+} // namespace details
+
+/** @class bus
+ * @brief Provides C++ bindings to the sd_bus_* class functions.
+ */
+struct bus
+{
+ /* Define all of the basic class operations:
+ * Not allowed:
+ * - Default constructor to avoid nullptrs.
+ * - Copy operations due to internal unique_ptr.
+ * Allowed:
+ * - Move operations.
+ * - Destructor.
+ */
+ bus() = delete;
+ bus(const bus&) = delete;
+ bus& operator=(const bus&) = delete;
+ bus(bus&&) = default;
+ bus& operator=(bus&&) = default;
+ ~bus() = default;
+
+ /** @brief Conversion constructor from 'busp_t'.
+ *
+ * Takes ownership of the bus-pointer and releases it when done.
+ */
+ explicit bus(busp_t b) : _bus(b) {}
+
+ /** @brief Release ownership of the stored bus-pointer. */
+ busp_t release() { return _bus.release(); }
+
+ /** @brief Wait for new dbus messages or signals.
+ *
+ * @param[in] timeout_us - Timeout in usec.
+ */
+ void wait(uint64_t timeout_us = 0)
+ {
+ sd_bus_wait(_bus.get(), timeout_us);
+ }
+
+ /** @brief Process waiting dbus messages or signals. */
+ auto process()
+ {
+ sd_bus_message* m = nullptr;
+ sd_bus_process(_bus.get(), &m);
+
+ return m;
+ }
+
+ /** @brief Claim a service name on the dbus.
+ *
+ * @param[in] service - The service name to claim.
+ */
+ void request_name(const char* service)
+ {
+ sd_bus_request_name(_bus.get(), service, 0);
+ }
+
+ /** @brief Create a method_call message.
+ *
+ * @param[in] service - The service to call.
+ * @param[in] objpath - The object's path for the call.
+ * @param[in] interf - The object's interface to call.
+ * @param[in] method - The object's method to call.
+ *
+ * @return A newly constructed message.
+ */
+ auto new_method_call(const char* service, const char* objpath,
+ const char* interf, const char* method)
+ {
+ sd_bus_message* m = nullptr;
+ sd_bus_message_new_method_call(_bus.get(), &m, service, objpath,
+ interf, method);
+
+ return m;
+ }
+
+ /** @brief Perform a message call.
+ *
+ * @param[in] m - The method_call message.
+ * @param[in] timeout_us - The timeout for the method call.
+ *
+ * @return The response message.
+ */
+ auto call(sd_bus_message* m, uint64_t timeout_us = 0)
+ {
+ sd_bus_message* reply = nullptr;
+ sd_bus_call(_bus.get(), m, timeout_us, nullptr, &reply);
+
+ return reply;
+ }
+
+ /** @brief Perform a message call, ignoring the reply.
+ *
+ * @param[in] m - The method_call message.
+ * @param[in] timeout_us - The timeout for the method call.
+ */
+ void call_noreply(sd_bus_message* m, uint64_t timeout_us = 0)
+ {
+ sd_bus_call(_bus.get(), m, timeout_us, nullptr, nullptr);
+ }
+
+ private:
+ details::bus _bus;
+};
+
+bus new_default()
+{
+ sd_bus* b = nullptr;
+ sd_bus_open(&b);
+ return bus(b);
+}
+
+bus new_user()
+{
+ sd_bus* b = nullptr;
+ sd_bus_open_user(&b);
+ return bus(b);
+}
+
+bus new_system()
+{
+ sd_bus* b = nullptr;
+ sd_bus_open_system(&b);
+ return bus(b);
+}
+
+
+} // namespace bus
+
+} // namespace sdbusplus
diff --git a/test/message/append.cpp b/test/message/append.cpp
index 1b0f70b..c9c2e47 100644
--- a/test/message/append.cpp
+++ b/test/message/append.cpp
@@ -1,6 +1,7 @@
#include <iostream>
#include <sdbusplus/message/append.hpp>
#include <cassert>
+#include <sdbusplus/bus.hpp>
// Global to share the dbus type string between client and server.
static std::string verifyTypeString;
@@ -11,29 +12,27 @@
static constexpr auto QUIT_METHOD = "quit";
// Open up the sdbus and claim SERVICE name.
-void serverInit(sd_bus** b)
+auto serverInit()
{
- assert(0 <= sd_bus_open(b));
- assert(0 <= sd_bus_request_name(*b, SERVICE, 0));
+ auto b = sdbusplus::bus::new_default();
+ b.request_name(SERVICE);
+
+ return std::move(b);
}
// Thread to run the dbus server.
void* server(void* b)
{
- auto bus = reinterpret_cast<sd_bus*>(b);
+ auto bus = sdbusplus::bus::bus(reinterpret_cast<sdbusplus::bus::busp_t>(b));
while(1)
{
// Wait for messages.
- sd_bus_message *m = nullptr;
- if (0 == sd_bus_process(bus, &m))
- {
- sd_bus_wait(bus, 0);
- continue;
- }
+ sd_bus_message *m = bus.process();
- if(!m)
+ if(m == nullptr)
{
+ bus.wait();
continue;
}
@@ -54,12 +53,10 @@
}
}
-void newMethodCall__test(sd_bus* b, sd_bus_message** m)
+void newMethodCall__test(sdbusplus::bus::bus& b, sd_bus_message** m)
{
// Allocate a method-call message for INTERFACE,TEST_METHOD.
- assert(0 <= sd_bus_message_new_method_call(b, m, SERVICE, "/", INTERFACE,
- TEST_METHOD));
- sd_bus_message_set_expect_reply(*m, true);
+ *m = b.new_method_call(SERVICE, "/", INTERFACE, TEST_METHOD);
}
void runTests()
@@ -67,17 +64,14 @@
using namespace std::literals;
sd_bus_message* m = nullptr;
- sd_bus* b = nullptr;
-
- // Connect to dbus.
- assert(0 <= sd_bus_open(&b));
+ auto b = sdbusplus::bus::new_default();
// Test r-value int.
{
newMethodCall__test(b, &m);
sdbusplus::message::append(m, 1);
verifyTypeString = "i";
- sd_bus_call(b, m, 0, nullptr, nullptr);
+ b.call_noreply(m);
}
// Test l-value int.
@@ -86,7 +80,7 @@
int a = 1;
sdbusplus::message::append(m, a, a);
verifyTypeString = "ii";
- sd_bus_call(b, m, 0, nullptr, nullptr);
+ b.call_noreply(m);
}
// Test multiple ints.
@@ -94,7 +88,7 @@
newMethodCall__test(b, &m);
sdbusplus::message::append(m, 1, 2, 3, 4, 5);
verifyTypeString = "iiiii";
- sd_bus_call(b, m, 0, nullptr, nullptr);
+ b.call_noreply(m);
}
// Test r-value string.
@@ -102,7 +96,7 @@
newMethodCall__test(b, &m);
sdbusplus::message::append(m, "asdf"s);
verifyTypeString = "s";
- sd_bus_call(b, m, 0, nullptr, nullptr);
+ b.call_noreply(m);
}
// Test multiple strings, various forms.
@@ -113,12 +107,12 @@
sdbusplus::message::append(m, 1, "asdf", "ASDF"s, str,
std::move(str2), 5);
verifyTypeString = "issssi";
- sd_bus_call(b, m, 0, nullptr, nullptr);
+ b.call_noreply(m);
}
// Shutdown server.
- sd_bus_call_method(b, SERVICE, "/", INTERFACE, QUIT_METHOD,
- nullptr, nullptr, nullptr);
+ m = b.new_method_call(SERVICE, "/", INTERFACE, QUIT_METHOD);
+ b.call_noreply(m);
}
int main()
@@ -126,9 +120,8 @@
// Initialize and start server thread.
pthread_t t;
{
- sd_bus* b;
- serverInit(&b);
- pthread_create(&t, NULL, server, b);
+ auto b = serverInit();
+ pthread_create(&t, NULL, server, b.release());
}
runTests();