xref: /openbmc/phosphor-fan-presence/sdbusplus.hpp (revision 33618bc1845e5e7c4e12a2d2ed7f1c47a6a03de1)
1 #pragma once
2 
3 #include <sdbusplus/bus.hpp>
4 #include <sdbusplus/message.hpp>
5 #include <sdbusplus/bus/match.hpp>
6 #include <phosphor-logging/log.hpp>
7 #include <phosphor-logging/elog.hpp>
8 #include <phosphor-logging/elog-errors.hpp>
9 #include <xyz/openbmc_project/Common/error.hpp>
10 
11 namespace phosphor
12 {
13 namespace fan
14 {
15 namespace util
16 {
17 namespace detail
18 {
19 namespace errors = sdbusplus::xyz::openbmc_project::Common::Error;
20 } // namespace detail
21 
22 /** @brief Alias for PropertiesChanged signal callbacks. */
23 template <typename ...T>
24 using Properties = std::map<std::string, sdbusplus::message::variant<T...>>;
25 
26 /** @class SDBusPlus
27  *  @brief DBus access delegate implementation for sdbusplus.
28  */
29 class SDBusPlus
30 {
31 
32     public:
33         /** @brief Get the bus connection. */
34         static auto& getBus() __attribute__((pure))
35         {
36             static auto bus = sdbusplus::bus::new_default();
37             return bus;
38         }
39 
40         /** @brief Invoke a method. */
41         template <typename ...Args>
42         static auto callMethod(
43             sdbusplus::bus::bus& bus,
44             const std::string& busName,
45             const std::string& path,
46             const std::string& interface,
47             const std::string& method,
48             Args&& ... args)
49         {
50             auto reqMsg = bus.new_method_call(
51                     busName.c_str(),
52                     path.c_str(),
53                     interface.c_str(),
54                     method.c_str());
55             reqMsg.append(std::forward<Args>(args)...);
56             auto respMsg = bus.call(reqMsg);
57 
58             if (respMsg.is_method_error())
59             {
60                 phosphor::logging::log<phosphor::logging::level::INFO>(
61                         "Failed to invoke DBus method.",
62                         phosphor::logging::entry("PATH=%s", path.c_str()),
63                         phosphor::logging::entry(
64                                 "INTERFACE=%s", interface.c_str()),
65                         phosphor::logging::entry("METHOD=%s", method.c_str()));
66                 phosphor::logging::elog<detail::errors::InternalFailure>();
67             }
68 
69             return respMsg;
70         }
71 
72         /** @brief Invoke a method. */
73         template <typename ...Args>
74         static auto callMethod(
75             const std::string& busName,
76             const std::string& path,
77             const std::string& interface,
78             const std::string& method,
79             Args&& ... args)
80         {
81             return callMethod(
82                     getBus(),
83                     busName,
84                     path,
85                     interface,
86                     method,
87                     std::forward<Args>(args)...);
88         }
89 
90         /** @brief Invoke a method and read the response. */
91         template <typename Ret, typename ...Args>
92         static auto callMethodAndRead(
93             sdbusplus::bus::bus& bus,
94             const std::string& busName,
95             const std::string& path,
96             const std::string& interface,
97             const std::string& method,
98             Args&& ... args)
99         {
100             sdbusplus::message::message respMsg =
101                     callMethod<Args...>(
102                             bus,
103                             busName,
104                             path,
105                             interface,
106                             method,
107                             std::forward<Args>(args)...);
108             Ret resp;
109             respMsg.read(resp);
110             return resp;
111         }
112 
113         /** @brief Invoke a method and read the response. */
114         template <typename Ret, typename ...Args>
115         static auto callMethodAndRead(
116             const std::string& busName,
117             const std::string& path,
118             const std::string& interface,
119             const std::string& method,
120             Args&& ... args)
121         {
122             return callMethodAndRead<Ret>(
123                     getBus(),
124                     busName,
125                     path,
126                     interface,
127                     method,
128                     std::forward<Args>(args)...);
129         }
130 
131         /** @brief Get subtree from the mapper. */
132         static auto getSubTree(
133             sdbusplus::bus::bus& bus,
134             const std::string& path,
135             const std::string& interface,
136             int32_t depth)
137         {
138             using namespace std::literals::string_literals;
139 
140             using Path = std::string;
141             using Intf = std::string;
142             using Serv = std::string;
143             using Intfs = std::vector<Intf>;
144             using Objects = std::map<Path, std::map<Serv, Intfs>>;
145             Intfs intfs = {interface};
146 
147             auto mapperResp = callMethodAndRead<Objects>(
148                     bus,
149                     "xyz.openbmc_project.ObjectMapper"s,
150                     "/xyz/openbmc_project/object_mapper"s,
151                     "xyz.openbmc_project.ObjectMapper"s,
152                     "GetSubTree"s,
153                     path,
154                     depth,
155                     intfs);
156 
157             if (mapperResp.empty())
158             {
159                 phosphor::logging::log<phosphor::logging::level::ERR>(
160                         "Empty response from mapper GetSubTree",
161                         phosphor::logging::entry("SUBTREE=%s", path.c_str()),
162                         phosphor::logging::entry(
163                                 "INTERFACE=%s", interface.c_str()),
164                         phosphor::logging::entry("DEPTH=%u", depth));
165                 phosphor::logging::elog<detail::errors::InternalFailure>();
166             }
167             return mapperResp;
168         }
169 
170         /** @brief Get service from the mapper. */
171         static auto getService(
172             sdbusplus::bus::bus& bus,
173             const std::string& path,
174             const std::string& interface)
175         {
176             using namespace std::literals::string_literals;
177             using GetObject = std::map<std::string, std::vector<std::string>>;
178 
179             auto mapperResp = callMethodAndRead<GetObject>(
180                     bus,
181                     "xyz.openbmc_project.ObjectMapper"s,
182                     "/xyz/openbmc_project/object_mapper"s,
183                     "xyz.openbmc_project.ObjectMapper"s,
184                     "GetObject"s,
185                     path,
186                     GetObject::mapped_type{interface});
187 
188             if (mapperResp.empty())
189             {
190                 phosphor::logging::log<phosphor::logging::level::INFO>(
191                         "Object not found.",
192                         phosphor::logging::entry("PATH=%s", path.c_str()),
193                         phosphor::logging::entry(
194                                 "INTERFACE=%s", interface.c_str()));
195                 phosphor::logging::elog<detail::errors::InternalFailure>();
196             }
197             return mapperResp.begin()->first;
198         }
199 
200         /** @brief Get service from the mapper. */
201         static auto getService(
202             const std::string& path,
203             const std::string& interface)
204         {
205             return getService(
206                     getBus(),
207                     path,
208                     interface);
209         }
210 
211         /** @brief Get a property with mapper lookup. */
212         template <typename Property>
213         static auto getProperty(
214             sdbusplus::bus::bus& bus,
215             const std::string& path,
216             const std::string& interface,
217             const std::string& property)
218         {
219             using namespace std::literals::string_literals;
220 
221             auto msg = callMethod(
222                     bus,
223                     getService(bus, path, interface),
224                     path,
225                     "org.freedesktop.DBus.Properties"s,
226                     "Get"s,
227                     interface,
228                     property);
229             sdbusplus::message::variant<Property> value;
230             msg.read(value);
231             return value.template get<Property>();
232         }
233 
234         /** @brief Get a property with mapper lookup. */
235         template <typename Property>
236         static auto getProperty(
237             const std::string& path,
238             const std::string& interface,
239             const std::string& property)
240         {
241             return getProperty<Property>(
242                     getBus(),
243                     path,
244                     interface,
245                     property);
246         }
247 
248         /** @brief Get a property variant with mapper lookup. */
249         template <typename Variant>
250         static auto getPropertyVariant(
251             sdbusplus::bus::bus& bus,
252             const std::string& path,
253             const std::string& interface,
254             const std::string& property)
255         {
256             using namespace std::literals::string_literals;
257 
258             auto msg = callMethod(
259                     bus,
260                     getService(bus, path, interface),
261                     path,
262                     "org.freedesktop.DBus.Properties"s,
263                     "Get"s,
264                     interface,
265                     property);
266             Variant value;
267             msg.read(value);
268             return value;
269         }
270 
271         /** @brief Get a property variant with mapper lookup. */
272         template <typename Variant>
273         static auto getPropertyVariant(
274             const std::string& path,
275             const std::string& interface,
276             const std::string& property)
277         {
278             return getPropertyVariant<Variant>(
279                     getBus(),
280                     path,
281                     interface,
282                     property);
283         }
284 
285         /** @brief Get a property without mapper lookup. */
286         template <typename Property>
287         static auto getProperty(
288             sdbusplus::bus::bus& bus,
289             const std::string& service,
290             const std::string& path,
291             const std::string& interface,
292             const std::string& property)
293         {
294             using namespace std::literals::string_literals;
295 
296             auto msg = callMethod(
297                     bus,
298                     service,
299                     path,
300                     "org.freedesktop.DBus.Properties"s,
301                     "Get"s,
302                     interface,
303                     property);
304             sdbusplus::message::variant<Property> value;
305             msg.read(value);
306             return value.template get<Property>();
307         }
308 
309         /** @brief Get a property without mapper lookup. */
310         template <typename Property>
311         static auto getProperty(
312             const std::string& service,
313             const std::string& path,
314             const std::string& interface,
315             const std::string& property)
316         {
317             return getProperty<Property>(
318                     getBus(),
319                     service,
320                     path,
321                     interface,
322                     property);
323         }
324 
325         /** @brief Get a property variant without mapper lookup. */
326         template <typename Variant>
327         static auto getPropertyVariant(
328             sdbusplus::bus::bus& bus,
329             const std::string& service,
330             const std::string& path,
331             const std::string& interface,
332             const std::string& property)
333         {
334             using namespace std::literals::string_literals;
335 
336             auto msg = callMethod(
337                     bus,
338                     service,
339                     path,
340                     "org.freedesktop.DBus.Properties"s,
341                     "Get"s,
342                     interface,
343                     property);
344             Variant value;
345             msg.read(value);
346             return value;
347         }
348 
349         /** @brief Get a property variant without mapper lookup. */
350         template <typename Variant>
351         static auto getPropertyVariant(
352             const std::string& service,
353             const std::string& path,
354             const std::string& interface,
355             const std::string& property)
356         {
357             return getPropertyVariant<Variant>(
358                     getBus(),
359                     service,
360                     path,
361                     interface,
362                     property);
363         }
364 
365         /** @brief Set a property with mapper lookup. */
366         template <typename Property>
367         static void setProperty(
368             sdbusplus::bus::bus& bus,
369             const std::string& path,
370             const std::string& interface,
371             const std::string& property,
372             Property&& value)
373         {
374             using namespace std::literals::string_literals;
375 
376             sdbusplus::message::variant<Property> varValue(
377                     std::forward<Property>(value));
378 
379             callMethod(
380                     bus,
381                     getService(bus, path, interface),
382                     path,
383                     "org.freedesktop.DBus.Properties"s,
384                     "Set"s,
385                     interface,
386                     property,
387                     varValue);
388         }
389 
390         /** @brief Set a property with mapper lookup. */
391         template <typename Property>
392         static void setProperty(
393             const std::string& path,
394             const std::string& interface,
395             const std::string& property,
396             Property&& value)
397         {
398             return setProperty(
399                     getBus(),
400                     path,
401                     interface,
402                     property,
403                     std::forward<Property>(value));
404         }
405 
406         /** @brief Invoke method with mapper lookup. */
407         template <typename ...Args>
408         static auto lookupAndCallMethod(
409             sdbusplus::bus::bus& bus,
410             const std::string& path,
411             const std::string& interface,
412             const std::string& method,
413             Args&& ... args)
414         {
415             return callMethod(
416                     bus,
417                     getService(bus, path, interface),
418                     path,
419                     interface,
420                     method,
421                     std::forward<Args>(args)...);
422         }
423 
424         /** @brief Invoke method with mapper lookup. */
425         template <typename ...Args>
426         static auto lookupAndCallMethod(
427             const std::string& path,
428             const std::string& interface,
429             const std::string& method,
430             Args&& ... args)
431         {
432             return lookupAndCallMethod(
433                     getBus(),
434                     path,
435                     interface,
436                     method,
437                     std::forward<Args>(args)...);
438         }
439 
440         /** @brief Invoke method and read with mapper lookup. */
441         template <typename Ret, typename ...Args>
442         static auto lookupCallMethodAndRead(
443             sdbusplus::bus::bus& bus,
444             const std::string& path,
445             const std::string& interface,
446             const std::string& method,
447             Args&& ... args)
448         {
449             return callMethodAndRead(
450                     bus,
451                     getService(bus, path, interface),
452                     path,
453                     interface,
454                     method,
455                     std::forward<Args>(args)...);
456         }
457 
458         /** @brief Invoke method and read with mapper lookup. */
459         template <typename Ret, typename ...Args>
460         static auto lookupCallMethodAndRead(
461             const std::string& path,
462             const std::string& interface,
463             const std::string& method,
464             Args&& ... args)
465         {
466             return lookupCallMethodAndRead<Ret>(
467                     getBus(),
468                     path,
469                     interface,
470                     method,
471                     std::forward<Args>(args)...);
472         }
473 };
474 
475 } // namespace util
476 } // namespace fan
477 } // namespace phosphor
478