blob: 58421338673ff71abcc6a9bc9bfb9c7974c39d82 [file] [log] [blame]
Brad Bishop6e9cfdb2017-06-08 11:59:58 -04001#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
11namespace phosphor
12{
13namespace fan
14{
15namespace util
16{
17namespace detail
18{
19namespace errors = sdbusplus::xyz::openbmc_project::Common::Error;
20} // namespace detail
21
Matt Spinlerba7b5fe2018-04-25 15:26:10 -050022/**
23 * @class DBusError
24 *
25 * The base class for the exceptions thrown on fails in the various
26 * SDBusPlus calls. Used so that a single catch statement can catch
27 * any type of these exceptions.
28 *
29 * None of these exceptions will log anything when they are created,
30 * it is up to the handler to do that if desired.
31 */
32class DBusError : public std::runtime_error
33{
34 public:
35 DBusError(const char* msg) :
36 std::runtime_error(msg)
37 {
38 }
39};
40
41/**
42 * @class DBusMethodError
43 *
44 * Thrown on a DBus Method call failure
45 */
46class DBusMethodError : public DBusError
47{
48 public:
49 DBusMethodError(
50 const std::string& busName,
51 const std::string& path,
52 const std::string& interface,
53 const std::string& method) :
54 DBusError("DBus method call failed"),
55 busName(busName),
56 path(path),
57 interface(interface),
58 method(method)
59 {
60 }
61
62 const std::string busName;
63 const std::string path;
64 const std::string interface;
65 const std::string method;
66};
67
68/**
69 * @class DBusServiceError
70 *
71 * Thrown when a service lookup fails. Usually this points to
72 * the object path not being present in D-Bus.
73 */
74class DBusServiceError : public DBusError
75{
76 public:
77 DBusServiceError(
78 const std::string& path,
79 const std::string& interface) :
80 DBusError("DBus service lookup failed"),
81 path(path),
82 interface(interface)
83 {
84 }
85
86 const std::string path;
87 const std::string interface;
88};
89
Brad Bishop1e4922a2017-07-12 22:56:49 -040090/** @brief Alias for PropertiesChanged signal callbacks. */
91template <typename ...T>
92using Properties = std::map<std::string, sdbusplus::message::variant<T...>>;
93
Brad Bishop6e9cfdb2017-06-08 11:59:58 -040094/** @class SDBusPlus
95 * @brief DBus access delegate implementation for sdbusplus.
96 */
97class SDBusPlus
98{
99
100 public:
101 /** @brief Get the bus connection. */
102 static auto& getBus() __attribute__((pure))
103 {
104 static auto bus = sdbusplus::bus::new_default();
105 return bus;
106 }
107
108 /** @brief Invoke a method. */
109 template <typename ...Args>
110 static auto callMethod(
Brad Bishopf2238ae2017-07-30 13:32:23 -0400111 sdbusplus::bus::bus& bus,
Brad Bishop6e9cfdb2017-06-08 11:59:58 -0400112 const std::string& busName,
113 const std::string& path,
114 const std::string& interface,
115 const std::string& method,
116 Args&& ... args)
117 {
Brad Bishopf2238ae2017-07-30 13:32:23 -0400118 auto reqMsg = bus.new_method_call(
Brad Bishope67b41b2017-07-30 13:20:37 -0400119 busName.c_str(),
120 path.c_str(),
121 interface.c_str(),
122 method.c_str());
Brad Bishop6e9cfdb2017-06-08 11:59:58 -0400123 reqMsg.append(std::forward<Args>(args)...);
Brad Bishopf2238ae2017-07-30 13:32:23 -0400124 auto respMsg = bus.call(reqMsg);
Brad Bishop6e9cfdb2017-06-08 11:59:58 -0400125
126 if (respMsg.is_method_error())
127 {
Matt Spinlerba7b5fe2018-04-25 15:26:10 -0500128 throw DBusMethodError{busName, path, interface, method};
Brad Bishop6e9cfdb2017-06-08 11:59:58 -0400129 }
130
131 return respMsg;
132 }
133
Brad Bishopf2238ae2017-07-30 13:32:23 -0400134 /** @brief Invoke a method. */
135 template <typename ...Args>
136 static auto callMethod(
137 const std::string& busName,
138 const std::string& path,
139 const std::string& interface,
140 const std::string& method,
141 Args&& ... args)
142 {
143 return callMethod(
144 getBus(),
145 busName,
146 path,
147 interface,
148 method,
149 std::forward<Args>(args)...);
150 }
151
Brad Bishop6e9cfdb2017-06-08 11:59:58 -0400152 /** @brief Invoke a method and read the response. */
153 template <typename Ret, typename ...Args>
154 static auto callMethodAndRead(
Brad Bishopf2238ae2017-07-30 13:32:23 -0400155 sdbusplus::bus::bus& bus,
Brad Bishop6e9cfdb2017-06-08 11:59:58 -0400156 const std::string& busName,
157 const std::string& path,
158 const std::string& interface,
159 const std::string& method,
160 Args&& ... args)
161 {
162 sdbusplus::message::message respMsg =
Brad Bishope67b41b2017-07-30 13:20:37 -0400163 callMethod<Args...>(
Brad Bishopf2238ae2017-07-30 13:32:23 -0400164 bus,
Brad Bishope67b41b2017-07-30 13:20:37 -0400165 busName,
166 path,
167 interface,
168 method,
169 std::forward<Args>(args)...);
Brad Bishop6e9cfdb2017-06-08 11:59:58 -0400170 Ret resp;
171 respMsg.read(resp);
172 return resp;
173 }
174
Brad Bishopf2238ae2017-07-30 13:32:23 -0400175 /** @brief Invoke a method and read the response. */
176 template <typename Ret, typename ...Args>
177 static auto callMethodAndRead(
178 const std::string& busName,
179 const std::string& path,
180 const std::string& interface,
181 const std::string& method,
182 Args&& ... args)
183 {
184 return callMethodAndRead<Ret>(
185 getBus(),
186 busName,
187 path,
188 interface,
189 method,
190 std::forward<Args>(args)...);
191 }
192
Matthew Bartheca94df2018-01-19 16:42:49 -0600193 /** @brief Get subtree from the mapper. */
194 static auto getSubTree(
195 sdbusplus::bus::bus& bus,
196 const std::string& path,
197 const std::string& interface,
198 int32_t depth)
199 {
200 using namespace std::literals::string_literals;
201
202 using Path = std::string;
203 using Intf = std::string;
204 using Serv = std::string;
205 using Intfs = std::vector<Intf>;
206 using Objects = std::map<Path, std::map<Serv, Intfs>>;
207 Intfs intfs = {interface};
208
209 auto mapperResp = callMethodAndRead<Objects>(
210 bus,
211 "xyz.openbmc_project.ObjectMapper"s,
212 "/xyz/openbmc_project/object_mapper"s,
213 "xyz.openbmc_project.ObjectMapper"s,
214 "GetSubTree"s,
215 path,
216 depth,
217 intfs);
218
219 if (mapperResp.empty())
220 {
221 phosphor::logging::log<phosphor::logging::level::ERR>(
222 "Empty response from mapper GetSubTree",
223 phosphor::logging::entry("SUBTREE=%s", path.c_str()),
224 phosphor::logging::entry(
225 "INTERFACE=%s", interface.c_str()),
226 phosphor::logging::entry("DEPTH=%u", depth));
227 phosphor::logging::elog<detail::errors::InternalFailure>();
228 }
229 return mapperResp;
230 }
Brad Bishopf2238ae2017-07-30 13:32:23 -0400231
Brad Bishop6e9cfdb2017-06-08 11:59:58 -0400232 /** @brief Get service from the mapper. */
233 static auto getService(
Brad Bishopf2238ae2017-07-30 13:32:23 -0400234 sdbusplus::bus::bus& bus,
Brad Bishop6e9cfdb2017-06-08 11:59:58 -0400235 const std::string& path,
236 const std::string& interface)
237 {
238 using namespace std::literals::string_literals;
239 using GetObject = std::map<std::string, std::vector<std::string>>;
240
Matt Spinlerba7b5fe2018-04-25 15:26:10 -0500241 try
Brad Bishop6e9cfdb2017-06-08 11:59:58 -0400242 {
Matt Spinlerba7b5fe2018-04-25 15:26:10 -0500243 auto mapperResp = callMethodAndRead<GetObject>(
244 bus,
245 "xyz.openbmc_project.ObjectMapper"s,
246 "/xyz/openbmc_project/object_mapper"s,
247 "xyz.openbmc_project.ObjectMapper"s,
248 "GetObject"s,
249 path,
250 GetObject::mapped_type{interface});
251
252 if (mapperResp.empty())
253 {
254 //Should never happen. A missing object would fail
255 //in callMethodAndRead()
256 phosphor::logging::log<phosphor::logging::level::ERR>(
257 "Empty mapper response on service lookup");
258 throw DBusServiceError{path, interface};
259 }
260 return mapperResp.begin()->first;
Brad Bishop6e9cfdb2017-06-08 11:59:58 -0400261 }
Matt Spinlerba7b5fe2018-04-25 15:26:10 -0500262 catch (DBusMethodError& e)
263 {
264 throw DBusServiceError{path, interface};
265 }
Brad Bishop6e9cfdb2017-06-08 11:59:58 -0400266 }
267
Brad Bishopf2238ae2017-07-30 13:32:23 -0400268 /** @brief Get service from the mapper. */
269 static auto getService(
270 const std::string& path,
271 const std::string& interface)
272 {
273 return getService(
274 getBus(),
275 path,
276 interface);
277 }
278
Brad Bishop6e9cfdb2017-06-08 11:59:58 -0400279 /** @brief Get a property with mapper lookup. */
280 template <typename Property>
281 static auto getProperty(
Brad Bishopf2238ae2017-07-30 13:32:23 -0400282 sdbusplus::bus::bus& bus,
Brad Bishop6e9cfdb2017-06-08 11:59:58 -0400283 const std::string& path,
284 const std::string& interface,
285 const std::string& property)
286 {
287 using namespace std::literals::string_literals;
288
289 auto msg = callMethod(
Brad Bishopf2238ae2017-07-30 13:32:23 -0400290 bus,
291 getService(bus, path, interface),
Brad Bishope67b41b2017-07-30 13:20:37 -0400292 path,
293 "org.freedesktop.DBus.Properties"s,
294 "Get"s,
295 interface,
296 property);
Brad Bishop6e9cfdb2017-06-08 11:59:58 -0400297 sdbusplus::message::variant<Property> value;
298 msg.read(value);
299 return value.template get<Property>();
300 }
301
Brad Bishopf2238ae2017-07-30 13:32:23 -0400302 /** @brief Get a property with mapper lookup. */
303 template <typename Property>
304 static auto getProperty(
305 const std::string& path,
306 const std::string& interface,
307 const std::string& property)
308 {
309 return getProperty<Property>(
310 getBus(),
311 path,
312 interface,
313 property);
314 }
315
Matthew Barth7311c392018-05-03 16:50:47 -0500316 /** @brief Get a property variant with mapper lookup. */
317 template <typename Variant>
318 static auto getPropertyVariant(
319 sdbusplus::bus::bus& bus,
320 const std::string& path,
321 const std::string& interface,
322 const std::string& property)
323 {
324 using namespace std::literals::string_literals;
325
326 auto msg = callMethod(
327 bus,
328 getService(bus, path, interface),
329 path,
330 "org.freedesktop.DBus.Properties"s,
331 "Get"s,
332 interface,
333 property);
334 Variant value;
335 msg.read(value);
336 return value;
337 }
338
339 /** @brief Get a property variant with mapper lookup. */
340 template <typename Variant>
341 static auto getPropertyVariant(
342 const std::string& path,
343 const std::string& interface,
344 const std::string& property)
345 {
346 return getPropertyVariant<Variant>(
347 getBus(),
348 path,
349 interface,
350 property);
351 }
352
Matthew Barth5a796e62018-01-19 17:14:08 -0600353 /** @brief Get a property without mapper lookup. */
354 template <typename Property>
355 static auto getProperty(
356 sdbusplus::bus::bus& bus,
357 const std::string& service,
358 const std::string& path,
359 const std::string& interface,
360 const std::string& property)
361 {
362 using namespace std::literals::string_literals;
363
364 auto msg = callMethod(
365 bus,
366 service,
367 path,
368 "org.freedesktop.DBus.Properties"s,
369 "Get"s,
370 interface,
371 property);
372 sdbusplus::message::variant<Property> value;
373 msg.read(value);
374 return value.template get<Property>();
375 }
376
377 /** @brief Get a property without mapper lookup. */
378 template <typename Property>
379 static auto getProperty(
380 const std::string& service,
381 const std::string& path,
382 const std::string& interface,
383 const std::string& property)
384 {
385 return getProperty<Property>(
386 getBus(),
387 service,
388 path,
389 interface,
390 property);
391 }
392
Matthew Barth7311c392018-05-03 16:50:47 -0500393 /** @brief Get a property variant without mapper lookup. */
394 template <typename Variant>
395 static auto getPropertyVariant(
396 sdbusplus::bus::bus& bus,
397 const std::string& service,
398 const std::string& path,
399 const std::string& interface,
400 const std::string& property)
401 {
402 using namespace std::literals::string_literals;
403
404 auto msg = callMethod(
405 bus,
406 service,
407 path,
408 "org.freedesktop.DBus.Properties"s,
409 "Get"s,
410 interface,
411 property);
412 Variant value;
413 msg.read(value);
414 return value;
415 }
416
417 /** @brief Get a property variant without mapper lookup. */
418 template <typename Variant>
419 static auto getPropertyVariant(
420 const std::string& service,
421 const std::string& path,
422 const std::string& interface,
423 const std::string& property)
424 {
425 return getPropertyVariant<Variant>(
426 getBus(),
427 service,
428 path,
429 interface,
430 property);
431 }
432
Brad Bishop6e9cfdb2017-06-08 11:59:58 -0400433 /** @brief Set a property with mapper lookup. */
434 template <typename Property>
435 static void setProperty(
Brad Bishopf2238ae2017-07-30 13:32:23 -0400436 sdbusplus::bus::bus& bus,
Brad Bishop6e9cfdb2017-06-08 11:59:58 -0400437 const std::string& path,
438 const std::string& interface,
439 const std::string& property,
440 Property&& value)
441 {
442 using namespace std::literals::string_literals;
443
444 sdbusplus::message::variant<Property> varValue(
Brad Bishope67b41b2017-07-30 13:20:37 -0400445 std::forward<Property>(value));
Brad Bishop6e9cfdb2017-06-08 11:59:58 -0400446
447 callMethod(
Brad Bishopf2238ae2017-07-30 13:32:23 -0400448 bus,
449 getService(bus, path, interface),
Brad Bishope67b41b2017-07-30 13:20:37 -0400450 path,
451 "org.freedesktop.DBus.Properties"s,
452 "Set"s,
453 interface,
454 property,
455 varValue);
Brad Bishop6e9cfdb2017-06-08 11:59:58 -0400456 }
457
Brad Bishopf2238ae2017-07-30 13:32:23 -0400458 /** @brief Set a property with mapper lookup. */
459 template <typename Property>
460 static void setProperty(
461 const std::string& path,
462 const std::string& interface,
463 const std::string& property,
464 Property&& value)
465 {
466 return setProperty(
467 getBus(),
468 path,
469 interface,
470 property,
471 std::forward<Property>(value));
472 }
473
Matthew Barth6f30fd62018-05-11 09:38:29 -0500474 /** @brief Set a property without mapper lookup. */
475 template <typename Property>
476 static void setProperty(
477 sdbusplus::bus::bus& bus,
478 const std::string& service,
479 const std::string& path,
480 const std::string& interface,
481 const std::string& property,
482 Property&& value)
483 {
484 using namespace std::literals::string_literals;
485
486 sdbusplus::message::variant<Property> varValue(
487 std::forward<Property>(value));
488
489 callMethod(
490 bus,
491 service,
492 path,
493 "org.freedesktop.DBus.Properties"s,
494 "Set"s,
495 interface,
496 property,
497 varValue);
498 }
499
500 /** @brief Set a property without mapper lookup. */
501 template <typename Property>
502 static void setProperty(
503 const std::string& service,
504 const std::string& path,
505 const std::string& interface,
506 const std::string& property,
507 Property&& value)
508 {
509 return setProperty(
510 getBus(),
511 service,
512 path,
513 interface,
514 property,
515 std::forward<Property>(value));
516 }
517
Brad Bishopf2238ae2017-07-30 13:32:23 -0400518 /** @brief Invoke method with mapper lookup. */
519 template <typename ...Args>
520 static auto lookupAndCallMethod(
521 sdbusplus::bus::bus& bus,
522 const std::string& path,
523 const std::string& interface,
524 const std::string& method,
525 Args&& ... args)
526 {
527 return callMethod(
528 bus,
529 getService(bus, path, interface),
530 path,
531 interface,
532 method,
533 std::forward<Args>(args)...);
534 }
535
Brad Bishop6e9cfdb2017-06-08 11:59:58 -0400536 /** @brief Invoke method with mapper lookup. */
537 template <typename ...Args>
538 static auto lookupAndCallMethod(
539 const std::string& path,
540 const std::string& interface,
541 const std::string& method,
542 Args&& ... args)
543 {
Brad Bishopf2238ae2017-07-30 13:32:23 -0400544 return lookupAndCallMethod(
545 getBus(),
546 path,
547 interface,
548 method,
549 std::forward<Args>(args)...);
550 }
551
552 /** @brief Invoke method and read with mapper lookup. */
553 template <typename Ret, typename ...Args>
554 static auto lookupCallMethodAndRead(
555 sdbusplus::bus::bus& bus,
556 const std::string& path,
557 const std::string& interface,
558 const std::string& method,
559 Args&& ... args)
560 {
561 return callMethodAndRead(
562 bus,
563 getService(bus, path, interface),
Brad Bishope67b41b2017-07-30 13:20:37 -0400564 path,
565 interface,
566 method,
567 std::forward<Args>(args)...);
Brad Bishop6e9cfdb2017-06-08 11:59:58 -0400568 }
569
570 /** @brief Invoke method and read with mapper lookup. */
571 template <typename Ret, typename ...Args>
572 static auto lookupCallMethodAndRead(
573 const std::string& path,
574 const std::string& interface,
575 const std::string& method,
576 Args&& ... args)
577 {
Brad Bishopf2238ae2017-07-30 13:32:23 -0400578 return lookupCallMethodAndRead<Ret>(
579 getBus(),
Brad Bishope67b41b2017-07-30 13:20:37 -0400580 path,
581 interface,
582 method,
583 std::forward<Args>(args)...);
Brad Bishop6e9cfdb2017-06-08 11:59:58 -0400584 }
Matthew Barth7c48d102018-05-09 14:52:36 -0500585
586 /** @brief Invoke a method and return without checking for error. */
587 template <typename ...Args>
588 static auto callMethodAndReturn(
589 sdbusplus::bus::bus& bus,
590 const std::string& busName,
591 const std::string& path,
592 const std::string& interface,
593 const std::string& method,
594 Args&& ... args)
595 {
596 auto reqMsg = bus.new_method_call(
597 busName.c_str(),
598 path.c_str(),
599 interface.c_str(),
600 method.c_str());
601 reqMsg.append(std::forward<Args>(args)...);
602 auto respMsg = bus.call(reqMsg);
603
604 return respMsg;
605 }
Brad Bishop6e9cfdb2017-06-08 11:59:58 -0400606};
607
608} // namespace util
609} // namespace fan
610} // namespace phosphor