blob: 57df1bf37a1c55e58d15d6bfb40dc95d3316ab77 [file] [log] [blame]
Patrick Williams5b485792016-08-02 07:35:14 -05001#pragma once
2
Brad Bishopd2945572017-02-15 23:40:15 -05003#include <algorithm>
Patrick Williams5b485792016-08-02 07:35:14 -05004#include <memory>
Brad Bishop887ebf62016-10-12 15:40:04 -04005#include <climits>
Brad Bishopd2945572017-02-15 23:40:15 -05006#include <vector>
7#include <string>
Patrick Williams5b485792016-08-02 07:35:14 -05008#include <systemd/sd-bus.h>
Yi Li8ac39ee2017-01-16 16:21:51 +08009#include <systemd/sd-event.h>
Patrick Williams7802c072016-09-02 15:20:22 -050010#include <sdbusplus/message.hpp>
Patrick Williams5b485792016-08-02 07:35:14 -050011
12namespace sdbusplus
13{
Patrick Williams13f1ef72016-10-17 14:09:33 -050014
15// Forward declare.
16namespace server { namespace interface { struct interface; } }
Patrick Williams05aab8b2016-10-17 14:12:12 -050017namespace server { namespace manager { struct manager; } }
Patrick Williamsd1102f42016-10-17 21:42:38 -050018namespace server { namespace object { template<class...> struct object; } }
Christian Andersenc69def62016-12-20 13:51:52 +010019namespace bus { namespace match { struct match; } }
Patrick Williams13f1ef72016-10-17 14:09:33 -050020
Patrick Williams5b485792016-08-02 07:35:14 -050021namespace bus
22{
23
24using busp_t = sd_bus*;
25class bus;
26
27/** @brief Get an instance of the 'default' bus. */
28bus new_default();
29/** @brief Get an instance of the 'user' session bus. */
30bus new_user();
31/** @brief Get an instance of the 'system' bus. */
32bus new_system();
33
34namespace details
35{
36
37/** @brief unique_ptr functor to release a bus reference. */
38struct BusDeleter
39{
40 void operator()(sd_bus* ptr) const
41 {
Patrick Williamsba6f50c2017-04-18 11:38:30 -050042 deleter(ptr);
Patrick Williams5b485792016-08-02 07:35:14 -050043 }
Patrick Williamsba6f50c2017-04-18 11:38:30 -050044
45 decltype(&sd_bus_flush_close_unref) deleter = sd_bus_flush_close_unref;
Patrick Williams5b485792016-08-02 07:35:14 -050046};
47
Brad Bishopd2945572017-02-15 23:40:15 -050048/** @brief Convert a vector of strings to c-style char** array. */
49class Strv
50{
51 public:
52 ~Strv() = default;
53 Strv() = delete;
54 Strv(const Strv&) = delete;
55 Strv& operator=(const Strv&) = delete;
56 Strv(Strv&&) = default;
57 Strv& operator=(Strv&&) = default;
58
59 explicit Strv(const std::vector<std::string>& v)
60 {
61 std::transform(v.begin(), v.end(),
62 std::back_inserter(ptrs),
63 [](const auto& i){ return i.c_str(); });
64 ptrs.push_back(nullptr);
65 }
66
67 explicit operator char**()
68 {
69 return const_cast<char**>(&ptrs.front());
70 }
71
72 private:
73
74 std::vector<const char*> ptrs;
75};
76
Patrick Williams5b485792016-08-02 07:35:14 -050077/* @brief Alias 'bus' to a unique_ptr type for auto-release. */
78using bus = std::unique_ptr<sd_bus, BusDeleter>;
79
80} // namespace details
81
82/** @class bus
83 * @brief Provides C++ bindings to the sd_bus_* class functions.
84 */
85struct bus
86{
87 /* Define all of the basic class operations:
88 * Not allowed:
89 * - Default constructor to avoid nullptrs.
90 * - Copy operations due to internal unique_ptr.
91 * Allowed:
92 * - Move operations.
93 * - Destructor.
94 */
95 bus() = delete;
96 bus(const bus&) = delete;
97 bus& operator=(const bus&) = delete;
98 bus(bus&&) = default;
99 bus& operator=(bus&&) = default;
100 ~bus() = default;
101
102 /** @brief Conversion constructor from 'busp_t'.
103 *
Patrick Williamsba6f50c2017-04-18 11:38:30 -0500104 * Increments ref-count of the bus-pointer and releases it when done.
Patrick Williams5b485792016-08-02 07:35:14 -0500105 */
Patrick Williamsbee1a6a2017-02-16 16:06:51 -0600106 explicit bus(busp_t b);
Patrick Williams5b485792016-08-02 07:35:14 -0500107
Patrick Williamsba6f50c2017-04-18 11:38:30 -0500108 /** @brief Constructor for 'bus'.
109 *
110 * Takes ownership of the bus-pointer and releases it when done.
111 * This method will also cause the bus to be flushed and closed
112 * on destruction.
113 */
114 bus(busp_t b, std::false_type);
115
Patrick Williams5b485792016-08-02 07:35:14 -0500116 /** @brief Release ownership of the stored bus-pointer. */
117 busp_t release() { return _bus.release(); }
118
119 /** @brief Wait for new dbus messages or signals.
120 *
121 * @param[in] timeout_us - Timeout in usec.
122 */
Brad Bishop887ebf62016-10-12 15:40:04 -0400123 void wait(uint64_t timeout_us = ULLONG_MAX)
Patrick Williams5b485792016-08-02 07:35:14 -0500124 {
125 sd_bus_wait(_bus.get(), timeout_us);
126 }
127
128 /** @brief Process waiting dbus messages or signals. */
129 auto process()
130 {
131 sd_bus_message* m = nullptr;
132 sd_bus_process(_bus.get(), &m);
133
Patrick Williams560e5fd2017-01-12 10:00:17 -0600134 return message::message(m, std::false_type());
Patrick Williams5b485792016-08-02 07:35:14 -0500135 }
136
Patrick Williamsc7ba66f2016-10-18 11:30:07 -0500137 /** @brief Process waiting dbus messages or signals, discarding unhandled.
138 */
139 void process_discard()
140 {
141 sd_bus_process(_bus.get(), nullptr);
142 }
143
Patrick Williams5b485792016-08-02 07:35:14 -0500144 /** @brief Claim a service name on the dbus.
145 *
146 * @param[in] service - The service name to claim.
147 */
148 void request_name(const char* service)
149 {
150 sd_bus_request_name(_bus.get(), service, 0);
151 }
152
153 /** @brief Create a method_call message.
154 *
155 * @param[in] service - The service to call.
156 * @param[in] objpath - The object's path for the call.
157 * @param[in] interf - The object's interface to call.
158 * @param[in] method - The object's method to call.
159 *
160 * @return A newly constructed message.
161 */
162 auto new_method_call(const char* service, const char* objpath,
163 const char* interf, const char* method)
164 {
165 sd_bus_message* m = nullptr;
166 sd_bus_message_new_method_call(_bus.get(), &m, service, objpath,
167 interf, method);
168
Patrick Williams560e5fd2017-01-12 10:00:17 -0600169 return message::message(m, std::false_type());
Patrick Williams5b485792016-08-02 07:35:14 -0500170 }
171
Patrick Williams20d82462016-10-18 08:01:33 -0500172 /** @brief Create a signal message.
173 *
174 * @param[in] objpath - The object's path for the signal.
175 * @param[in] interf - The object's interface for the signal.
176 * @param[in] member - The signal name.
177 *
178 * @return A newly constructed message.
179 */
180 auto new_signal(const char* objpath, const char* interf, const char* member)
181 {
182 sd_bus_message* m = nullptr;
183 sd_bus_message_new_signal(_bus.get(), &m, objpath, interf, member);
184
Patrick Williams560e5fd2017-01-12 10:00:17 -0600185 return message::message(m, std::false_type());
Patrick Williams20d82462016-10-18 08:01:33 -0500186 }
187
Patrick Williams5b485792016-08-02 07:35:14 -0500188 /** @brief Perform a message call.
189 *
190 * @param[in] m - The method_call message.
191 * @param[in] timeout_us - The timeout for the method call.
192 *
193 * @return The response message.
194 */
Patrick Williams7802c072016-09-02 15:20:22 -0500195 auto call(message::message& m, uint64_t timeout_us = 0)
Patrick Williams5b485792016-08-02 07:35:14 -0500196 {
197 sd_bus_message* reply = nullptr;
Patrick Williams7802c072016-09-02 15:20:22 -0500198 sd_bus_call(_bus.get(), m.get(), timeout_us, nullptr, &reply);
Patrick Williams5b485792016-08-02 07:35:14 -0500199
Patrick Williams560e5fd2017-01-12 10:00:17 -0600200 return message::message(reply, std::false_type());
Patrick Williams5b485792016-08-02 07:35:14 -0500201 }
202
203 /** @brief Perform a message call, ignoring the reply.
204 *
205 * @param[in] m - The method_call message.
206 * @param[in] timeout_us - The timeout for the method call.
207 */
Patrick Williams7802c072016-09-02 15:20:22 -0500208 void call_noreply(message::message& m, uint64_t timeout_us = 0)
Patrick Williams5b485792016-08-02 07:35:14 -0500209 {
Patrick Williams7802c072016-09-02 15:20:22 -0500210 sd_bus_call(_bus.get(), m.get(), timeout_us, nullptr, nullptr);
Patrick Williams5b485792016-08-02 07:35:14 -0500211 }
212
Adriana Kobylakc5496772017-01-04 09:57:23 -0600213 /** @brief Get the bus unique name. Ex: ":1.11".
214 *
215 * @return The bus unique name.
216 */
217 auto get_unique_name()
218 {
219 const char* unique = nullptr;
220 sd_bus_get_unique_name(_bus.get(), &unique);
221 return std::string(unique);
222 }
223
Yi Li8ac39ee2017-01-16 16:21:51 +0800224 /** @brief Attach the bus with a sd-event event loop object.
225 *
226 * @param[in] event - sd_event object.
227 * @param[in] priority - priority of bus event source.
228 */
229 void attach_event(sd_event* event, int priority)
230 {
231 sd_bus_attach_event(_bus.get(), event, priority);
232 }
233
234 /** @brief Detach the bus from its sd-event event loop object */
235 void detach_event()
236 {
237 sd_bus_detach_event(_bus.get());
238 }
239
240 /** @brief Get the sd-event event loop object of the bus */
241 auto get_event()
242 {
243 return sd_bus_get_event(_bus.get());
244 }
245
Brad Bishopd2945572017-02-15 23:40:15 -0500246 /** @brief Wrapper for sd_bus_emit_interfaces_added_strv
247 *
248 * In general the similarly named server::object::object API should
249 * be used to manage emission of ObjectManager signals in favor
250 * of this one. Provided here for complex usage scenarios.
251 *
252 * @param[in] path - The path to forward.
253 * @param[in] ifaces - The interfaces to forward.
254 */
255 void emit_interfaces_added(const char* path,
256 const std::vector<std::string>& ifaces)
257 {
258 details::Strv s{ifaces};
259 sd_bus_emit_interfaces_added_strv(_bus.get(),
260 path,
261 static_cast<char**>(s));
262 }
263
264 /** @brief Wrapper for sd_bus_emit_interfaces_removed_strv
265 *
266 * In general the similarly named server::object::object API should
267 * be used to manage emission of ObjectManager signals in favor
268 * of this one. Provided here for complex usage scenarios.
269 *
270 * @param[in] path - The path to forward.
271 * @param[in] ifaces - The interfaces to forward.
272 */
273 void emit_interfaces_removed(const char* path,
274 const std::vector<std::string>& ifaces)
275 {
276 details::Strv s{ifaces};
277 sd_bus_emit_interfaces_removed_strv(_bus.get(),
278 path,
279 static_cast<char**>(s));
280 }
281
Brad Bishop9a0baf52017-02-03 20:05:22 -0500282 /** @brief Wrapper for sd_bus_emit_object_added
283 *
284 * In general the similarly named server::object::object API should
285 * be used to manage emission of ObjectManager signals in favor
286 * of this one. Provided here for complex usage scenarios.
287 *
288 * @param[in] path - The path to forward to sd_bus_emit_object_added
289 */
290 void emit_object_added(const char* path)
291 {
292 sd_bus_emit_object_added(_bus.get(), path);
293 }
294
295 /** @brief Wrapper for sd_bus_emit_object_removed
296 *
297 * In general the similarly named server::object::object API should
298 * be used to manage emission of ObjectManager signals in favor
299 * of this one. Provided here for complex usage scenarios.
300 *
301 * @param[in] path - The path to forward to sd_bus_emit_object_removed
302 */
303 void emit_object_removed(const char* path)
304 {
305 sd_bus_emit_object_removed(_bus.get(), path);
306 }
307
Patrick Williamsb4041d42017-04-27 21:49:00 -0500308 /** @brief Wrapper for sd_bus_list_names.
309 *
310 * @return A vector of strings containing the 'acquired' names from
311 * sd_bus_list_names.
312 */
313 auto list_names_acquired()
314 {
315 char** names = nullptr;
316
317 sd_bus_list_names(_bus.get(), &names, nullptr);
318
319 std::vector<std::string> result;
320 for(auto ptr = names; ptr && *ptr; ++ptr)
321 {
322 result.push_back(*ptr);
323 free(*ptr);
324 }
325 free(names);
326
327 return result;
328 }
329
Patrick Williams13f1ef72016-10-17 14:09:33 -0500330 friend struct server::interface::interface;
Patrick Williams05aab8b2016-10-17 14:12:12 -0500331 friend struct server::manager::manager;
Patrick Williamsd1102f42016-10-17 21:42:38 -0500332 template<class... Args> friend struct server::object::object;
Christian Andersenc69def62016-12-20 13:51:52 +0100333 friend struct match::match;
Patrick Williams13f1ef72016-10-17 14:09:33 -0500334
Patrick Williams5b485792016-08-02 07:35:14 -0500335 private:
Patrick Williams13f1ef72016-10-17 14:09:33 -0500336 busp_t get() { return _bus.get(); }
Patrick Williams5b485792016-08-02 07:35:14 -0500337 details::bus _bus;
338};
339
Patrick Williamsba6f50c2017-04-18 11:38:30 -0500340inline bus::bus(busp_t b) : _bus(sd_bus_ref(b))
341{
342 _bus.get_deleter().deleter = sd_bus_unref;
343
344#if @WANT_TRANSACTION@
345 // Emitting object added causes a message to get the properties
346 // which can trigger a 'transaction' in the server bindings. If
347 // the bus isn't up far enough, this causes an assert deep in
348 // sd-bus code. Get the 'unique_name' to ensure the bus is up far
349 // enough to avoid the assert.
350 if (b != nullptr)
351 {
352 get_unique_name();
353 }
354#endif
355}
356
357inline bus::bus(busp_t b, std::false_type) : _bus(b)
Patrick Williamsbee1a6a2017-02-16 16:06:51 -0600358{
Adriana Kobylakfd43ef72017-02-12 09:12:37 -0600359#if @WANT_TRANSACTION@
Patrick Williamsbee1a6a2017-02-16 16:06:51 -0600360 // Emitting object added causes a message to get the properties
361 // which can trigger a 'transaction' in the server bindings. If
362 // the bus isn't up far enough, this causes an assert deep in
363 // sd-bus code. Get the 'unique_name' to ensure the bus is up far
364 // enough to avoid the assert.
365 if (b != nullptr)
366 {
367 get_unique_name();
368 }
369#endif
370}
371
372
Brad Bishopaed81792016-10-12 08:40:34 -0400373inline bus new_default()
Patrick Williams5b485792016-08-02 07:35:14 -0500374{
375 sd_bus* b = nullptr;
376 sd_bus_open(&b);
Patrick Williamsba6f50c2017-04-18 11:38:30 -0500377 return bus(b, std::false_type());
Patrick Williams5b485792016-08-02 07:35:14 -0500378}
379
Brad Bishopaed81792016-10-12 08:40:34 -0400380inline bus new_user()
Patrick Williams5b485792016-08-02 07:35:14 -0500381{
382 sd_bus* b = nullptr;
383 sd_bus_open_user(&b);
Patrick Williamsba6f50c2017-04-18 11:38:30 -0500384 return bus(b, std::false_type());
Patrick Williams5b485792016-08-02 07:35:14 -0500385}
386
Brad Bishopaed81792016-10-12 08:40:34 -0400387inline bus new_system()
Patrick Williams5b485792016-08-02 07:35:14 -0500388{
389 sd_bus* b = nullptr;
390 sd_bus_open_system(&b);
Patrick Williamsba6f50c2017-04-18 11:38:30 -0500391 return bus(b, std::false_type());
Patrick Williams5b485792016-08-02 07:35:14 -0500392}
393
Patrick Williams5b485792016-08-02 07:35:14 -0500394} // namespace bus
395
Adriana Kobylak63122252017-01-26 15:09:00 -0600396/** @brief Get the dbus bus from the message.
397 *
398 * @return The dbus bus.
399 */
400inline auto message::message::get_bus()
401{
402 sd_bus* b = nullptr;
403 b = sd_bus_message_get_bus(_msg.get());
Patrick Williamsba6f50c2017-04-18 11:38:30 -0500404 return bus::bus(b);
Adriana Kobylak63122252017-01-26 15:09:00 -0600405}
406
Patrick Williams5b485792016-08-02 07:35:14 -0500407} // namespace sdbusplus