blob: b441d80643fefd72f529fd4190257e44805675d1 [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
Matthew Barth88923a02018-05-11 10:14:44 -050090/**
91 * @class DBusPropertyError
92 *
93 * Thrown when a set/get property fails.
94 */
95class DBusPropertyError : public DBusError
96{
97 public:
98 DBusPropertyError(
99 const char* msg,
100 const std::string& busName,
101 const std::string& path,
102 const std::string& interface,
103 const std::string& property) :
104 DBusError(msg),
105 busName(busName),
106 path(path),
107 interface(interface),
108 property(property)
109 {
110 }
111
112 const std::string busName;
113 const std::string path;
114 const std::string interface;
115 const std::string property;
116};
117
Brad Bishop1e4922a2017-07-12 22:56:49 -0400118/** @brief Alias for PropertiesChanged signal callbacks. */
119template <typename ...T>
120using Properties = std::map<std::string, sdbusplus::message::variant<T...>>;
121
Brad Bishop6e9cfdb2017-06-08 11:59:58 -0400122/** @class SDBusPlus
123 * @brief DBus access delegate implementation for sdbusplus.
124 */
125class SDBusPlus
126{
127
128 public:
129 /** @brief Get the bus connection. */
130 static auto& getBus() __attribute__((pure))
131 {
132 static auto bus = sdbusplus::bus::new_default();
133 return bus;
134 }
135
136 /** @brief Invoke a method. */
137 template <typename ...Args>
138 static auto callMethod(
Brad Bishopf2238ae2017-07-30 13:32:23 -0400139 sdbusplus::bus::bus& bus,
Brad Bishop6e9cfdb2017-06-08 11:59:58 -0400140 const std::string& busName,
141 const std::string& path,
142 const std::string& interface,
143 const std::string& method,
144 Args&& ... args)
145 {
Brad Bishopf2238ae2017-07-30 13:32:23 -0400146 auto reqMsg = bus.new_method_call(
Brad Bishope67b41b2017-07-30 13:20:37 -0400147 busName.c_str(),
148 path.c_str(),
149 interface.c_str(),
150 method.c_str());
Brad Bishop6e9cfdb2017-06-08 11:59:58 -0400151 reqMsg.append(std::forward<Args>(args)...);
Matthew Barth86be4762018-07-17 10:51:36 -0500152 try
153 {
154 auto respMsg = bus.call(reqMsg);
155 if (respMsg.is_method_error())
156 {
157 throw DBusMethodError{busName, path, interface, method};
158 }
159 return respMsg;
160 }
161 catch (const sdbusplus::exception::SdBusError&)
Brad Bishop6e9cfdb2017-06-08 11:59:58 -0400162 {
Matt Spinlerba7b5fe2018-04-25 15:26:10 -0500163 throw DBusMethodError{busName, path, interface, method};
Brad Bishop6e9cfdb2017-06-08 11:59:58 -0400164 }
Brad Bishop6e9cfdb2017-06-08 11:59:58 -0400165 }
166
Brad Bishopf2238ae2017-07-30 13:32:23 -0400167 /** @brief Invoke a method. */
168 template <typename ...Args>
169 static auto callMethod(
170 const std::string& busName,
171 const std::string& path,
172 const std::string& interface,
173 const std::string& method,
174 Args&& ... args)
175 {
176 return callMethod(
177 getBus(),
178 busName,
179 path,
180 interface,
181 method,
182 std::forward<Args>(args)...);
183 }
184
Brad Bishop6e9cfdb2017-06-08 11:59:58 -0400185 /** @brief Invoke a method and read the response. */
186 template <typename Ret, typename ...Args>
187 static auto callMethodAndRead(
Brad Bishopf2238ae2017-07-30 13:32:23 -0400188 sdbusplus::bus::bus& bus,
Brad Bishop6e9cfdb2017-06-08 11:59:58 -0400189 const std::string& busName,
190 const std::string& path,
191 const std::string& interface,
192 const std::string& method,
193 Args&& ... args)
194 {
195 sdbusplus::message::message respMsg =
Brad Bishope67b41b2017-07-30 13:20:37 -0400196 callMethod<Args...>(
Brad Bishopf2238ae2017-07-30 13:32:23 -0400197 bus,
Brad Bishope67b41b2017-07-30 13:20:37 -0400198 busName,
199 path,
200 interface,
201 method,
202 std::forward<Args>(args)...);
Brad Bishop6e9cfdb2017-06-08 11:59:58 -0400203 Ret resp;
204 respMsg.read(resp);
205 return resp;
206 }
207
Brad Bishopf2238ae2017-07-30 13:32:23 -0400208 /** @brief Invoke a method and read the response. */
209 template <typename Ret, typename ...Args>
210 static auto callMethodAndRead(
211 const std::string& busName,
212 const std::string& path,
213 const std::string& interface,
214 const std::string& method,
215 Args&& ... args)
216 {
217 return callMethodAndRead<Ret>(
218 getBus(),
219 busName,
220 path,
221 interface,
222 method,
223 std::forward<Args>(args)...);
224 }
225
Matthew Barthd74df092019-12-13 11:36:20 -0600226 /** @brief Get subtree from the mapper without checking response. */
227 static auto getSubTreeRaw(
Matthew Bartheca94df2018-01-19 16:42:49 -0600228 sdbusplus::bus::bus& bus,
229 const std::string& path,
230 const std::string& interface,
231 int32_t depth)
232 {
233 using namespace std::literals::string_literals;
234
235 using Path = std::string;
236 using Intf = std::string;
237 using Serv = std::string;
238 using Intfs = std::vector<Intf>;
239 using Objects = std::map<Path, std::map<Serv, Intfs>>;
240 Intfs intfs = {interface};
241
Matthew Barthd74df092019-12-13 11:36:20 -0600242 return callMethodAndRead<Objects>(
Matthew Bartheca94df2018-01-19 16:42:49 -0600243 bus,
244 "xyz.openbmc_project.ObjectMapper"s,
245 "/xyz/openbmc_project/object_mapper"s,
246 "xyz.openbmc_project.ObjectMapper"s,
247 "GetSubTree"s,
248 path,
249 depth,
250 intfs);
Matthew Barthd74df092019-12-13 11:36:20 -0600251 }
Matthew Bartheca94df2018-01-19 16:42:49 -0600252
Matthew Barthd74df092019-12-13 11:36:20 -0600253 /** @brief Get subtree from the mapper. */
254 static auto getSubTree(
255 sdbusplus::bus::bus& bus,
256 const std::string& path,
257 const std::string& interface,
258 int32_t depth)
259 {
260 auto mapperResp = getSubTreeRaw(bus, path, interface, depth);
Matthew Bartheca94df2018-01-19 16:42:49 -0600261 if (mapperResp.empty())
262 {
263 phosphor::logging::log<phosphor::logging::level::ERR>(
264 "Empty response from mapper GetSubTree",
265 phosphor::logging::entry("SUBTREE=%s", path.c_str()),
266 phosphor::logging::entry(
267 "INTERFACE=%s", interface.c_str()),
268 phosphor::logging::entry("DEPTH=%u", depth));
269 phosphor::logging::elog<detail::errors::InternalFailure>();
270 }
271 return mapperResp;
272 }
Brad Bishopf2238ae2017-07-30 13:32:23 -0400273
Brad Bishop6e9cfdb2017-06-08 11:59:58 -0400274 /** @brief Get service from the mapper. */
275 static auto getService(
Brad Bishopf2238ae2017-07-30 13:32:23 -0400276 sdbusplus::bus::bus& bus,
Brad Bishop6e9cfdb2017-06-08 11:59:58 -0400277 const std::string& path,
278 const std::string& interface)
279 {
280 using namespace std::literals::string_literals;
281 using GetObject = std::map<std::string, std::vector<std::string>>;
282
Matt Spinlerba7b5fe2018-04-25 15:26:10 -0500283 try
Brad Bishop6e9cfdb2017-06-08 11:59:58 -0400284 {
Matt Spinlerba7b5fe2018-04-25 15:26:10 -0500285 auto mapperResp = callMethodAndRead<GetObject>(
286 bus,
287 "xyz.openbmc_project.ObjectMapper"s,
288 "/xyz/openbmc_project/object_mapper"s,
289 "xyz.openbmc_project.ObjectMapper"s,
290 "GetObject"s,
291 path,
292 GetObject::mapped_type{interface});
293
294 if (mapperResp.empty())
295 {
296 //Should never happen. A missing object would fail
297 //in callMethodAndRead()
298 phosphor::logging::log<phosphor::logging::level::ERR>(
299 "Empty mapper response on service lookup");
300 throw DBusServiceError{path, interface};
301 }
302 return mapperResp.begin()->first;
Brad Bishop6e9cfdb2017-06-08 11:59:58 -0400303 }
Matt Spinlerba7b5fe2018-04-25 15:26:10 -0500304 catch (DBusMethodError& e)
305 {
306 throw DBusServiceError{path, interface};
307 }
Brad Bishop6e9cfdb2017-06-08 11:59:58 -0400308 }
309
Brad Bishopf2238ae2017-07-30 13:32:23 -0400310 /** @brief Get service from the mapper. */
311 static auto getService(
312 const std::string& path,
313 const std::string& interface)
314 {
315 return getService(
316 getBus(),
317 path,
318 interface);
319 }
320
Brad Bishop6e9cfdb2017-06-08 11:59:58 -0400321 /** @brief Get a property with mapper lookup. */
322 template <typename Property>
323 static auto getProperty(
Brad Bishopf2238ae2017-07-30 13:32:23 -0400324 sdbusplus::bus::bus& bus,
Brad Bishop6e9cfdb2017-06-08 11:59:58 -0400325 const std::string& path,
326 const std::string& interface,
327 const std::string& property)
328 {
329 using namespace std::literals::string_literals;
330
Matthew Barth88923a02018-05-11 10:14:44 -0500331 auto service = getService(bus, path, interface);
Brad Bishop6e9cfdb2017-06-08 11:59:58 -0400332 auto msg = callMethod(
Brad Bishopf2238ae2017-07-30 13:32:23 -0400333 bus,
Matthew Barth88923a02018-05-11 10:14:44 -0500334 service,
Brad Bishope67b41b2017-07-30 13:20:37 -0400335 path,
336 "org.freedesktop.DBus.Properties"s,
337 "Get"s,
338 interface,
339 property);
Matthew Barth88923a02018-05-11 10:14:44 -0500340 if (msg.is_method_error())
341 {
342 throw DBusPropertyError{
343 "DBus get property failed",
344 service,
345 path,
346 interface,
347 property};
348 }
Brad Bishop6e9cfdb2017-06-08 11:59:58 -0400349 sdbusplus::message::variant<Property> value;
350 msg.read(value);
William A. Kennington III52fbe0d2018-11-06 16:28:18 -0800351 return sdbusplus::message::variant_ns::get<Property>(value);
Brad Bishop6e9cfdb2017-06-08 11:59:58 -0400352 }
353
Brad Bishopf2238ae2017-07-30 13:32:23 -0400354 /** @brief Get a property with mapper lookup. */
355 template <typename Property>
356 static auto getProperty(
357 const std::string& path,
358 const std::string& interface,
359 const std::string& property)
360 {
361 return getProperty<Property>(
362 getBus(),
363 path,
364 interface,
365 property);
366 }
367
Matthew Barth7311c392018-05-03 16:50:47 -0500368 /** @brief Get a property variant with mapper lookup. */
369 template <typename Variant>
370 static auto getPropertyVariant(
371 sdbusplus::bus::bus& bus,
372 const std::string& path,
373 const std::string& interface,
374 const std::string& property)
375 {
376 using namespace std::literals::string_literals;
377
Matthew Barth88923a02018-05-11 10:14:44 -0500378 auto service = getService(bus, path, interface);
Matthew Barth7311c392018-05-03 16:50:47 -0500379 auto msg = callMethod(
380 bus,
Matthew Barth88923a02018-05-11 10:14:44 -0500381 service,
Matthew Barth7311c392018-05-03 16:50:47 -0500382 path,
383 "org.freedesktop.DBus.Properties"s,
384 "Get"s,
385 interface,
386 property);
Matthew Barth88923a02018-05-11 10:14:44 -0500387 if (msg.is_method_error())
388 {
389 throw DBusPropertyError{
390 "DBus get property variant failed",
391 service,
392 path,
393 interface,
394 property};
395 }
Matthew Barth7311c392018-05-03 16:50:47 -0500396 Variant value;
397 msg.read(value);
398 return value;
399 }
400
401 /** @brief Get a property variant with mapper lookup. */
402 template <typename Variant>
403 static auto getPropertyVariant(
404 const std::string& path,
405 const std::string& interface,
406 const std::string& property)
407 {
408 return getPropertyVariant<Variant>(
409 getBus(),
410 path,
411 interface,
412 property);
413 }
414
Matthew Barth5a796e62018-01-19 17:14:08 -0600415 /** @brief Get a property without mapper lookup. */
416 template <typename Property>
417 static auto getProperty(
418 sdbusplus::bus::bus& bus,
419 const std::string& service,
420 const std::string& path,
421 const std::string& interface,
422 const std::string& property)
423 {
424 using namespace std::literals::string_literals;
425
Matthew Barth88923a02018-05-11 10:14:44 -0500426 auto msg = callMethodAndReturn(
Matthew Barth5a796e62018-01-19 17:14:08 -0600427 bus,
428 service,
429 path,
430 "org.freedesktop.DBus.Properties"s,
431 "Get"s,
432 interface,
433 property);
Matthew Barth88923a02018-05-11 10:14:44 -0500434 if (msg.is_method_error())
435 {
436 throw DBusPropertyError{
437 "DBus get property failed",
438 service,
439 path,
440 interface,
441 property};
442 }
Matthew Barth5a796e62018-01-19 17:14:08 -0600443 sdbusplus::message::variant<Property> value;
444 msg.read(value);
William A. Kennington III52fbe0d2018-11-06 16:28:18 -0800445 return sdbusplus::message::variant_ns::get<Property>(value);
Matthew Barth5a796e62018-01-19 17:14:08 -0600446 }
447
448 /** @brief Get a property without mapper lookup. */
449 template <typename Property>
450 static auto getProperty(
451 const std::string& service,
452 const std::string& path,
453 const std::string& interface,
454 const std::string& property)
455 {
456 return getProperty<Property>(
457 getBus(),
458 service,
459 path,
460 interface,
461 property);
462 }
463
Matthew Barth7311c392018-05-03 16:50:47 -0500464 /** @brief Get a property variant without mapper lookup. */
465 template <typename Variant>
466 static auto getPropertyVariant(
467 sdbusplus::bus::bus& bus,
468 const std::string& service,
469 const std::string& path,
470 const std::string& interface,
471 const std::string& property)
472 {
473 using namespace std::literals::string_literals;
474
Matthew Barth88923a02018-05-11 10:14:44 -0500475 auto msg = callMethodAndReturn(
Matthew Barth7311c392018-05-03 16:50:47 -0500476 bus,
477 service,
478 path,
479 "org.freedesktop.DBus.Properties"s,
480 "Get"s,
481 interface,
482 property);
Matthew Barth88923a02018-05-11 10:14:44 -0500483 if (msg.is_method_error())
484 {
485 throw DBusPropertyError{
486 "DBus get property variant failed",
487 service,
488 path,
489 interface,
490 property};
491 }
Matthew Barth7311c392018-05-03 16:50:47 -0500492 Variant value;
493 msg.read(value);
494 return value;
495 }
496
497 /** @brief Get a property variant without mapper lookup. */
498 template <typename Variant>
499 static auto getPropertyVariant(
500 const std::string& service,
501 const std::string& path,
502 const std::string& interface,
503 const std::string& property)
504 {
505 return getPropertyVariant<Variant>(
506 getBus(),
507 service,
508 path,
509 interface,
510 property);
511 }
512
Brad Bishop6e9cfdb2017-06-08 11:59:58 -0400513 /** @brief Set a property with mapper lookup. */
514 template <typename Property>
515 static void setProperty(
Brad Bishopf2238ae2017-07-30 13:32:23 -0400516 sdbusplus::bus::bus& bus,
Brad Bishop6e9cfdb2017-06-08 11:59:58 -0400517 const std::string& path,
518 const std::string& interface,
519 const std::string& property,
520 Property&& value)
521 {
522 using namespace std::literals::string_literals;
523
524 sdbusplus::message::variant<Property> varValue(
Brad Bishope67b41b2017-07-30 13:20:37 -0400525 std::forward<Property>(value));
Brad Bishop6e9cfdb2017-06-08 11:59:58 -0400526
Matthew Barth88923a02018-05-11 10:14:44 -0500527 auto service = getService(bus, path, interface);
528 auto msg = callMethodAndReturn(
Brad Bishopf2238ae2017-07-30 13:32:23 -0400529 bus,
Matthew Barth88923a02018-05-11 10:14:44 -0500530 service,
Brad Bishope67b41b2017-07-30 13:20:37 -0400531 path,
532 "org.freedesktop.DBus.Properties"s,
533 "Set"s,
534 interface,
535 property,
536 varValue);
Matthew Barth88923a02018-05-11 10:14:44 -0500537 if (msg.is_method_error())
538 {
539 throw DBusPropertyError{
540 "DBus set property failed",
541 service,
542 path,
543 interface,
544 property};
545 }
Brad Bishop6e9cfdb2017-06-08 11:59:58 -0400546 }
547
Brad Bishopf2238ae2017-07-30 13:32:23 -0400548 /** @brief Set a property with mapper lookup. */
549 template <typename Property>
550 static void setProperty(
551 const std::string& path,
552 const std::string& interface,
553 const std::string& property,
554 Property&& value)
555 {
556 return setProperty(
557 getBus(),
558 path,
559 interface,
560 property,
561 std::forward<Property>(value));
562 }
563
Matthew Barth6f30fd62018-05-11 09:38:29 -0500564 /** @brief Set a property without mapper lookup. */
565 template <typename Property>
566 static void setProperty(
567 sdbusplus::bus::bus& bus,
568 const std::string& service,
569 const std::string& path,
570 const std::string& interface,
571 const std::string& property,
572 Property&& value)
573 {
574 using namespace std::literals::string_literals;
575
576 sdbusplus::message::variant<Property> varValue(
577 std::forward<Property>(value));
578
Matthew Barth88923a02018-05-11 10:14:44 -0500579 auto msg = callMethodAndReturn(
Matthew Barth6f30fd62018-05-11 09:38:29 -0500580 bus,
581 service,
582 path,
583 "org.freedesktop.DBus.Properties"s,
584 "Set"s,
585 interface,
586 property,
587 varValue);
Matthew Barth88923a02018-05-11 10:14:44 -0500588 if (msg.is_method_error())
589 {
590 throw DBusPropertyError{
591 "DBus set property failed",
592 service,
593 path,
594 interface,
595 property};
596 }
Matthew Barth6f30fd62018-05-11 09:38:29 -0500597 }
598
599 /** @brief Set a property without mapper lookup. */
600 template <typename Property>
601 static void setProperty(
602 const std::string& service,
603 const std::string& path,
604 const std::string& interface,
605 const std::string& property,
606 Property&& value)
607 {
608 return setProperty(
609 getBus(),
610 service,
611 path,
612 interface,
613 property,
614 std::forward<Property>(value));
615 }
616
Brad Bishopf2238ae2017-07-30 13:32:23 -0400617 /** @brief Invoke method with mapper lookup. */
618 template <typename ...Args>
619 static auto lookupAndCallMethod(
620 sdbusplus::bus::bus& bus,
621 const std::string& path,
622 const std::string& interface,
623 const std::string& method,
624 Args&& ... args)
625 {
626 return callMethod(
627 bus,
628 getService(bus, path, interface),
629 path,
630 interface,
631 method,
632 std::forward<Args>(args)...);
633 }
634
Brad Bishop6e9cfdb2017-06-08 11:59:58 -0400635 /** @brief Invoke method with mapper lookup. */
636 template <typename ...Args>
637 static auto lookupAndCallMethod(
638 const std::string& path,
639 const std::string& interface,
640 const std::string& method,
641 Args&& ... args)
642 {
Brad Bishopf2238ae2017-07-30 13:32:23 -0400643 return lookupAndCallMethod(
644 getBus(),
645 path,
646 interface,
647 method,
648 std::forward<Args>(args)...);
649 }
650
651 /** @brief Invoke method and read with mapper lookup. */
652 template <typename Ret, typename ...Args>
653 static auto lookupCallMethodAndRead(
654 sdbusplus::bus::bus& bus,
655 const std::string& path,
656 const std::string& interface,
657 const std::string& method,
658 Args&& ... args)
659 {
660 return callMethodAndRead(
661 bus,
662 getService(bus, path, interface),
Brad Bishope67b41b2017-07-30 13:20:37 -0400663 path,
664 interface,
665 method,
666 std::forward<Args>(args)...);
Brad Bishop6e9cfdb2017-06-08 11:59:58 -0400667 }
668
669 /** @brief Invoke method and read with mapper lookup. */
670 template <typename Ret, typename ...Args>
671 static auto lookupCallMethodAndRead(
672 const std::string& path,
673 const std::string& interface,
674 const std::string& method,
675 Args&& ... args)
676 {
Brad Bishopf2238ae2017-07-30 13:32:23 -0400677 return lookupCallMethodAndRead<Ret>(
678 getBus(),
Brad Bishope67b41b2017-07-30 13:20:37 -0400679 path,
680 interface,
681 method,
682 std::forward<Args>(args)...);
Brad Bishop6e9cfdb2017-06-08 11:59:58 -0400683 }
Matthew Barth7c48d102018-05-09 14:52:36 -0500684
685 /** @brief Invoke a method and return without checking for error. */
686 template <typename ...Args>
687 static auto callMethodAndReturn(
688 sdbusplus::bus::bus& bus,
689 const std::string& busName,
690 const std::string& path,
691 const std::string& interface,
692 const std::string& method,
693 Args&& ... args)
694 {
695 auto reqMsg = bus.new_method_call(
696 busName.c_str(),
697 path.c_str(),
698 interface.c_str(),
699 method.c_str());
700 reqMsg.append(std::forward<Args>(args)...);
701 auto respMsg = bus.call(reqMsg);
702
703 return respMsg;
704 }
Brad Bishop6e9cfdb2017-06-08 11:59:58 -0400705};
706
707} // namespace util
708} // namespace fan
709} // namespace phosphor