xref: /openbmc/sdbusplus/include/sdbusplus/sdbuspp_support/server.hpp (revision a4bfefde28e409148a3bd4e0c65d1f2d00007aed)
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