1 #pragma once
2 #include <sdbusplus/message.hpp>
3 #include <sdbusplus/server.hpp>
4
5 #include <type_traits>
6
7 /** This file contains support functions for sdbus++-generated server
8 * bindings, which result in space savings by having common definitions.
9 */
10
11 namespace sdbusplus
12 {
13 namespace sdbuspp
14 {
15
16 /** Handle common parts of a get/set property callback.
17 *
18 * @param[in] msg The message to read to / write from.
19 * @param[in] intf The SdBusInterface type.
20 * @param[in] error The error object for any errors.
21 * @param[in] f The interface function for the get/set.
22 *
23 * This function will unpack a message's contents, redirect them to the
24 * function 'f', and then pack them into the response message.
25 */
26 template <typename... Args, typename Return>
property_callback(sd_bus_message * msg,sdbusplus::SdBusInterface * intf,sd_bus_error * error,std::function<Return (Args &&...)> f)27 int property_callback(sd_bus_message* msg, sdbusplus::SdBusInterface* intf,
28 sd_bus_error* error, std::function<Return(Args&&...)> f)
29 {
30 try
31 {
32 // Refcount the message.
33 auto m = message_t(msg, intf);
34
35 // Set up the transaction.
36 server::transaction::set_id(m);
37
38 // Read arguments from the message.
39 std::tuple<Args...> arg{};
40 std::apply([&](Args&... a) { (m.read(a), ...); }, arg);
41
42 // Call the function with the arguments.
43 if constexpr (!std::is_same_v<void, Return>)
44 {
45 // Pack results back into message.
46 m.append(std::apply(f, std::move(arg)));
47 }
48 else
49 {
50 // No return, just direct call.
51 std::apply(f, std::move(arg));
52 }
53 }
54 catch (const sdbusplus::internal_exception_t& e)
55 {
56 return e.set_error(intf, error);
57 }
58
59 // A positive integer must be returned to indicate that the callback
60 // has done its work (and not delegate to a later callback in the vtable).
61 return 1;
62 }
63
64 /** Handle common parts of a method callback.
65 *
66 * @tparam multi_return Set to true if the function returns multiple results.
67 * Otherwise, this function is unable to differentiate
68 * between a tuple that should be returned as a tuple or
69 * a tuple that contains the multiple results and should
70 * be returned without the tuple wrapper.
71 *
72 * @param[in] msg The message to read to / write from.
73 * @param[in] intf The SdBusInterface type.
74 * @param[in] error The error object for any errors.
75 * @param[in] f The interface function for the get/set.
76 *
77 * @return a negative return-code on error.
78 *
79 * This function will unpack a message's contents, redirect them to the
80 * function 'f', and then pack them into the response message.
81 */
82 template <bool multi_return = false, typename... Args, typename Return>
method_callback(sd_bus_message * msg,sdbusplus::SdBusInterface * intf,sd_bus_error * error,std::function<Return (Args &&...)> f)83 int method_callback(sd_bus_message* msg, sdbusplus::SdBusInterface* intf,
84 sd_bus_error* error, std::function<Return(Args&&...)> f)
85 {
86 try
87 {
88 // Refcount the message.
89 auto m = message_t(msg, intf);
90
91 // Set up the transaction.
92 server::transaction::set_id(m);
93
94 // Read arguments from the message.
95 std::tuple<Args...> arg{};
96 std::apply([&](Args&... a) { (m.read(a), ...); }, arg);
97
98 // Get the reply message.
99 auto reply = m.new_method_return();
100
101 // Call the function with the arguments.
102 if constexpr (std::is_same_v<void, Return>)
103 {
104 // No return value, direct call.
105 std::apply(f, std::move(arg));
106 }
107 else if constexpr (!multi_return)
108 {
109 // Single return value; call and append to reply message.
110 reply.append(std::apply(f, std::move(arg)));
111 }
112 else
113 {
114 // Multi return values; call and append to reply message.
115 // Step 1: call 'f' with args from message.
116 // - std::apply(f, std::move(arg))
117 // Step 2: append each return from f into the reply message one
118 // at a time.
119 // - Apply on return from 'f' into lambda that does an append.
120 std::apply([&](auto&&... v) { (reply.append(std::move(v)), ...); },
121 std::apply(f, std::move(arg)));
122 }
123
124 // Indicate reply complete.
125 reply.method_return();
126 }
127 catch (const sdbusplus::internal_exception_t& e)
128 {
129 return e.set_error(intf, error);
130 }
131
132 // A positive integer must be returned to indicate that the callback
133 // has done its work (and not delegate to a later callback in the vtable).
134 return 1;
135 }
136
137 } // namespace sdbuspp
138 } // namespace sdbusplus
139