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 
132         /** @brief Get service from the mapper. */
133         static auto getService(
134             sdbusplus::bus::bus& bus,
135             const std::string& path,
136             const std::string& interface)
137         {
138             using namespace std::literals::string_literals;
139             using GetObject = std::map<std::string, std::vector<std::string>>;
140 
141             auto mapperResp = callMethodAndRead<GetObject>(
142                     bus,
143                     "xyz.openbmc_project.ObjectMapper"s,
144                     "/xyz/openbmc_project/object_mapper"s,
145                     "xyz.openbmc_project.ObjectMapper"s,
146                     "GetObject"s,
147                     path,
148                     GetObject::mapped_type{interface});
149 
150             if (mapperResp.empty())
151             {
152                 phosphor::logging::log<phosphor::logging::level::INFO>(
153                         "Object not found.",
154                         phosphor::logging::entry("PATH=%s", path.c_str()),
155                         phosphor::logging::entry(
156                                 "INTERFACE=%s", interface.c_str()));
157                 phosphor::logging::elog<detail::errors::InternalFailure>();
158             }
159             return mapperResp.begin()->first;
160         }
161 
162         /** @brief Get service from the mapper. */
163         static auto getService(
164             const std::string& path,
165             const std::string& interface)
166         {
167             return getService(
168                     getBus(),
169                     path,
170                     interface);
171         }
172 
173         /** @brief Get a property with mapper lookup. */
174         template <typename Property>
175         static auto getProperty(
176             sdbusplus::bus::bus& bus,
177             const std::string& path,
178             const std::string& interface,
179             const std::string& property)
180         {
181             using namespace std::literals::string_literals;
182 
183             auto msg = callMethod(
184                     bus,
185                     getService(bus, path, interface),
186                     path,
187                     "org.freedesktop.DBus.Properties"s,
188                     "Get"s,
189                     interface,
190                     property);
191             sdbusplus::message::variant<Property> value;
192             msg.read(value);
193             return value.template get<Property>();
194         }
195 
196         /** @brief Get a property with mapper lookup. */
197         template <typename Property>
198         static auto getProperty(
199             const std::string& path,
200             const std::string& interface,
201             const std::string& property)
202         {
203             return getProperty<Property>(
204                     getBus(),
205                     path,
206                     interface,
207                     property);
208         }
209 
210         /** @brief Set a property with mapper lookup. */
211         template <typename Property>
212         static void setProperty(
213             sdbusplus::bus::bus& bus,
214             const std::string& path,
215             const std::string& interface,
216             const std::string& property,
217             Property&& value)
218         {
219             using namespace std::literals::string_literals;
220 
221             sdbusplus::message::variant<Property> varValue(
222                     std::forward<Property>(value));
223 
224             callMethod(
225                     bus,
226                     getService(bus, path, interface),
227                     path,
228                     "org.freedesktop.DBus.Properties"s,
229                     "Set"s,
230                     interface,
231                     property,
232                     varValue);
233         }
234 
235         /** @brief Set a property with mapper lookup. */
236         template <typename Property>
237         static void setProperty(
238             const std::string& path,
239             const std::string& interface,
240             const std::string& property,
241             Property&& value)
242         {
243             return setProperty(
244                     getBus(),
245                     path,
246                     interface,
247                     property,
248                     std::forward<Property>(value));
249         }
250 
251         /** @brief Invoke method with mapper lookup. */
252         template <typename ...Args>
253         static auto lookupAndCallMethod(
254             sdbusplus::bus::bus& bus,
255             const std::string& path,
256             const std::string& interface,
257             const std::string& method,
258             Args&& ... args)
259         {
260             return callMethod(
261                     bus,
262                     getService(bus, path, interface),
263                     path,
264                     interface,
265                     method,
266                     std::forward<Args>(args)...);
267         }
268 
269         /** @brief Invoke method with mapper lookup. */
270         template <typename ...Args>
271         static auto lookupAndCallMethod(
272             const std::string& path,
273             const std::string& interface,
274             const std::string& method,
275             Args&& ... args)
276         {
277             return lookupAndCallMethod(
278                     getBus(),
279                     path,
280                     interface,
281                     method,
282                     std::forward<Args>(args)...);
283         }
284 
285         /** @brief Invoke method and read with mapper lookup. */
286         template <typename Ret, typename ...Args>
287         static auto lookupCallMethodAndRead(
288             sdbusplus::bus::bus& bus,
289             const std::string& path,
290             const std::string& interface,
291             const std::string& method,
292             Args&& ... args)
293         {
294             return callMethodAndRead(
295                     bus,
296                     getService(bus, path, interface),
297                     path,
298                     interface,
299                     method,
300                     std::forward<Args>(args)...);
301         }
302 
303         /** @brief Invoke method and read with mapper lookup. */
304         template <typename Ret, typename ...Args>
305         static auto lookupCallMethodAndRead(
306             const std::string& path,
307             const std::string& interface,
308             const std::string& method,
309             Args&& ... args)
310         {
311             return lookupCallMethodAndRead<Ret>(
312                     getBus(),
313                     path,
314                     interface,
315                     method,
316                     std::forward<Args>(args)...);
317         }
318 };
319 
320 } // namespace util
321 } // namespace fan
322 } // namespace phosphor
323