blob: 3a6cd658229c649e0cbe37ff1264750e1bb24020 [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)...);
Brad Bishopf2238ae2017-07-30 13:32:23 -0400152 auto respMsg = bus.call(reqMsg);
Brad Bishop6e9cfdb2017-06-08 11:59:58 -0400153
154 if (respMsg.is_method_error())
155 {
Matt Spinlerba7b5fe2018-04-25 15:26:10 -0500156 throw DBusMethodError{busName, path, interface, method};
Brad Bishop6e9cfdb2017-06-08 11:59:58 -0400157 }
158
159 return respMsg;
160 }
161
Brad Bishopf2238ae2017-07-30 13:32:23 -0400162 /** @brief Invoke a method. */
163 template <typename ...Args>
164 static auto callMethod(
165 const std::string& busName,
166 const std::string& path,
167 const std::string& interface,
168 const std::string& method,
169 Args&& ... args)
170 {
171 return callMethod(
172 getBus(),
173 busName,
174 path,
175 interface,
176 method,
177 std::forward<Args>(args)...);
178 }
179
Brad Bishop6e9cfdb2017-06-08 11:59:58 -0400180 /** @brief Invoke a method and read the response. */
181 template <typename Ret, typename ...Args>
182 static auto callMethodAndRead(
Brad Bishopf2238ae2017-07-30 13:32:23 -0400183 sdbusplus::bus::bus& bus,
Brad Bishop6e9cfdb2017-06-08 11:59:58 -0400184 const std::string& busName,
185 const std::string& path,
186 const std::string& interface,
187 const std::string& method,
188 Args&& ... args)
189 {
190 sdbusplus::message::message respMsg =
Brad Bishope67b41b2017-07-30 13:20:37 -0400191 callMethod<Args...>(
Brad Bishopf2238ae2017-07-30 13:32:23 -0400192 bus,
Brad Bishope67b41b2017-07-30 13:20:37 -0400193 busName,
194 path,
195 interface,
196 method,
197 std::forward<Args>(args)...);
Brad Bishop6e9cfdb2017-06-08 11:59:58 -0400198 Ret resp;
199 respMsg.read(resp);
200 return resp;
201 }
202
Brad Bishopf2238ae2017-07-30 13:32:23 -0400203 /** @brief Invoke a method and read the response. */
204 template <typename Ret, typename ...Args>
205 static auto callMethodAndRead(
206 const std::string& busName,
207 const std::string& path,
208 const std::string& interface,
209 const std::string& method,
210 Args&& ... args)
211 {
212 return callMethodAndRead<Ret>(
213 getBus(),
214 busName,
215 path,
216 interface,
217 method,
218 std::forward<Args>(args)...);
219 }
220
Matthew Bartheca94df2018-01-19 16:42:49 -0600221 /** @brief Get subtree from the mapper. */
222 static auto getSubTree(
223 sdbusplus::bus::bus& bus,
224 const std::string& path,
225 const std::string& interface,
226 int32_t depth)
227 {
228 using namespace std::literals::string_literals;
229
230 using Path = std::string;
231 using Intf = std::string;
232 using Serv = std::string;
233 using Intfs = std::vector<Intf>;
234 using Objects = std::map<Path, std::map<Serv, Intfs>>;
235 Intfs intfs = {interface};
236
237 auto mapperResp = callMethodAndRead<Objects>(
238 bus,
239 "xyz.openbmc_project.ObjectMapper"s,
240 "/xyz/openbmc_project/object_mapper"s,
241 "xyz.openbmc_project.ObjectMapper"s,
242 "GetSubTree"s,
243 path,
244 depth,
245 intfs);
246
247 if (mapperResp.empty())
248 {
249 phosphor::logging::log<phosphor::logging::level::ERR>(
250 "Empty response from mapper GetSubTree",
251 phosphor::logging::entry("SUBTREE=%s", path.c_str()),
252 phosphor::logging::entry(
253 "INTERFACE=%s", interface.c_str()),
254 phosphor::logging::entry("DEPTH=%u", depth));
255 phosphor::logging::elog<detail::errors::InternalFailure>();
256 }
257 return mapperResp;
258 }
Brad Bishopf2238ae2017-07-30 13:32:23 -0400259
Brad Bishop6e9cfdb2017-06-08 11:59:58 -0400260 /** @brief Get service from the mapper. */
261 static auto getService(
Brad Bishopf2238ae2017-07-30 13:32:23 -0400262 sdbusplus::bus::bus& bus,
Brad Bishop6e9cfdb2017-06-08 11:59:58 -0400263 const std::string& path,
264 const std::string& interface)
265 {
266 using namespace std::literals::string_literals;
267 using GetObject = std::map<std::string, std::vector<std::string>>;
268
Matt Spinlerba7b5fe2018-04-25 15:26:10 -0500269 try
Brad Bishop6e9cfdb2017-06-08 11:59:58 -0400270 {
Matt Spinlerba7b5fe2018-04-25 15:26:10 -0500271 auto mapperResp = callMethodAndRead<GetObject>(
272 bus,
273 "xyz.openbmc_project.ObjectMapper"s,
274 "/xyz/openbmc_project/object_mapper"s,
275 "xyz.openbmc_project.ObjectMapper"s,
276 "GetObject"s,
277 path,
278 GetObject::mapped_type{interface});
279
280 if (mapperResp.empty())
281 {
282 //Should never happen. A missing object would fail
283 //in callMethodAndRead()
284 phosphor::logging::log<phosphor::logging::level::ERR>(
285 "Empty mapper response on service lookup");
286 throw DBusServiceError{path, interface};
287 }
288 return mapperResp.begin()->first;
Brad Bishop6e9cfdb2017-06-08 11:59:58 -0400289 }
Matt Spinlerba7b5fe2018-04-25 15:26:10 -0500290 catch (DBusMethodError& e)
291 {
292 throw DBusServiceError{path, interface};
293 }
Brad Bishop6e9cfdb2017-06-08 11:59:58 -0400294 }
295
Brad Bishopf2238ae2017-07-30 13:32:23 -0400296 /** @brief Get service from the mapper. */
297 static auto getService(
298 const std::string& path,
299 const std::string& interface)
300 {
301 return getService(
302 getBus(),
303 path,
304 interface);
305 }
306
Brad Bishop6e9cfdb2017-06-08 11:59:58 -0400307 /** @brief Get a property with mapper lookup. */
308 template <typename Property>
309 static auto getProperty(
Brad Bishopf2238ae2017-07-30 13:32:23 -0400310 sdbusplus::bus::bus& bus,
Brad Bishop6e9cfdb2017-06-08 11:59:58 -0400311 const std::string& path,
312 const std::string& interface,
313 const std::string& property)
314 {
315 using namespace std::literals::string_literals;
316
Matthew Barth88923a02018-05-11 10:14:44 -0500317 auto service = getService(bus, path, interface);
Brad Bishop6e9cfdb2017-06-08 11:59:58 -0400318 auto msg = callMethod(
Brad Bishopf2238ae2017-07-30 13:32:23 -0400319 bus,
Matthew Barth88923a02018-05-11 10:14:44 -0500320 service,
Brad Bishope67b41b2017-07-30 13:20:37 -0400321 path,
322 "org.freedesktop.DBus.Properties"s,
323 "Get"s,
324 interface,
325 property);
Matthew Barth88923a02018-05-11 10:14:44 -0500326 if (msg.is_method_error())
327 {
328 throw DBusPropertyError{
329 "DBus get property failed",
330 service,
331 path,
332 interface,
333 property};
334 }
Brad Bishop6e9cfdb2017-06-08 11:59:58 -0400335 sdbusplus::message::variant<Property> value;
336 msg.read(value);
337 return value.template get<Property>();
338 }
339
Brad Bishopf2238ae2017-07-30 13:32:23 -0400340 /** @brief Get a property with mapper lookup. */
341 template <typename Property>
342 static auto getProperty(
343 const std::string& path,
344 const std::string& interface,
345 const std::string& property)
346 {
347 return getProperty<Property>(
348 getBus(),
349 path,
350 interface,
351 property);
352 }
353
Matthew Barth7311c392018-05-03 16:50:47 -0500354 /** @brief Get a property variant with mapper lookup. */
355 template <typename Variant>
356 static auto getPropertyVariant(
357 sdbusplus::bus::bus& bus,
358 const std::string& path,
359 const std::string& interface,
360 const std::string& property)
361 {
362 using namespace std::literals::string_literals;
363
Matthew Barth88923a02018-05-11 10:14:44 -0500364 auto service = getService(bus, path, interface);
Matthew Barth7311c392018-05-03 16:50:47 -0500365 auto msg = callMethod(
366 bus,
Matthew Barth88923a02018-05-11 10:14:44 -0500367 service,
Matthew Barth7311c392018-05-03 16:50:47 -0500368 path,
369 "org.freedesktop.DBus.Properties"s,
370 "Get"s,
371 interface,
372 property);
Matthew Barth88923a02018-05-11 10:14:44 -0500373 if (msg.is_method_error())
374 {
375 throw DBusPropertyError{
376 "DBus get property variant failed",
377 service,
378 path,
379 interface,
380 property};
381 }
Matthew Barth7311c392018-05-03 16:50:47 -0500382 Variant value;
383 msg.read(value);
384 return value;
385 }
386
387 /** @brief Get a property variant with mapper lookup. */
388 template <typename Variant>
389 static auto getPropertyVariant(
390 const std::string& path,
391 const std::string& interface,
392 const std::string& property)
393 {
394 return getPropertyVariant<Variant>(
395 getBus(),
396 path,
397 interface,
398 property);
399 }
400
Matthew Barth5a796e62018-01-19 17:14:08 -0600401 /** @brief Get a property without mapper lookup. */
402 template <typename Property>
403 static auto getProperty(
404 sdbusplus::bus::bus& bus,
405 const std::string& service,
406 const std::string& path,
407 const std::string& interface,
408 const std::string& property)
409 {
410 using namespace std::literals::string_literals;
411
Matthew Barth88923a02018-05-11 10:14:44 -0500412 auto msg = callMethodAndReturn(
Matthew Barth5a796e62018-01-19 17:14:08 -0600413 bus,
414 service,
415 path,
416 "org.freedesktop.DBus.Properties"s,
417 "Get"s,
418 interface,
419 property);
Matthew Barth88923a02018-05-11 10:14:44 -0500420 if (msg.is_method_error())
421 {
422 throw DBusPropertyError{
423 "DBus get property failed",
424 service,
425 path,
426 interface,
427 property};
428 }
Matthew Barth5a796e62018-01-19 17:14:08 -0600429 sdbusplus::message::variant<Property> value;
430 msg.read(value);
431 return value.template get<Property>();
432 }
433
434 /** @brief Get a property without mapper lookup. */
435 template <typename Property>
436 static auto getProperty(
437 const std::string& service,
438 const std::string& path,
439 const std::string& interface,
440 const std::string& property)
441 {
442 return getProperty<Property>(
443 getBus(),
444 service,
445 path,
446 interface,
447 property);
448 }
449
Matthew Barth7311c392018-05-03 16:50:47 -0500450 /** @brief Get a property variant without mapper lookup. */
451 template <typename Variant>
452 static auto getPropertyVariant(
453 sdbusplus::bus::bus& bus,
454 const std::string& service,
455 const std::string& path,
456 const std::string& interface,
457 const std::string& property)
458 {
459 using namespace std::literals::string_literals;
460
Matthew Barth88923a02018-05-11 10:14:44 -0500461 auto msg = callMethodAndReturn(
Matthew Barth7311c392018-05-03 16:50:47 -0500462 bus,
463 service,
464 path,
465 "org.freedesktop.DBus.Properties"s,
466 "Get"s,
467 interface,
468 property);
Matthew Barth88923a02018-05-11 10:14:44 -0500469 if (msg.is_method_error())
470 {
471 throw DBusPropertyError{
472 "DBus get property variant failed",
473 service,
474 path,
475 interface,
476 property};
477 }
Matthew Barth7311c392018-05-03 16:50:47 -0500478 Variant value;
479 msg.read(value);
480 return value;
481 }
482
483 /** @brief Get a property variant without mapper lookup. */
484 template <typename Variant>
485 static auto getPropertyVariant(
486 const std::string& service,
487 const std::string& path,
488 const std::string& interface,
489 const std::string& property)
490 {
491 return getPropertyVariant<Variant>(
492 getBus(),
493 service,
494 path,
495 interface,
496 property);
497 }
498
Brad Bishop6e9cfdb2017-06-08 11:59:58 -0400499 /** @brief Set a property with mapper lookup. */
500 template <typename Property>
501 static void setProperty(
Brad Bishopf2238ae2017-07-30 13:32:23 -0400502 sdbusplus::bus::bus& bus,
Brad Bishop6e9cfdb2017-06-08 11:59:58 -0400503 const std::string& path,
504 const std::string& interface,
505 const std::string& property,
506 Property&& value)
507 {
508 using namespace std::literals::string_literals;
509
510 sdbusplus::message::variant<Property> varValue(
Brad Bishope67b41b2017-07-30 13:20:37 -0400511 std::forward<Property>(value));
Brad Bishop6e9cfdb2017-06-08 11:59:58 -0400512
Matthew Barth88923a02018-05-11 10:14:44 -0500513 auto service = getService(bus, path, interface);
514 auto msg = callMethodAndReturn(
Brad Bishopf2238ae2017-07-30 13:32:23 -0400515 bus,
Matthew Barth88923a02018-05-11 10:14:44 -0500516 service,
Brad Bishope67b41b2017-07-30 13:20:37 -0400517 path,
518 "org.freedesktop.DBus.Properties"s,
519 "Set"s,
520 interface,
521 property,
522 varValue);
Matthew Barth88923a02018-05-11 10:14:44 -0500523 if (msg.is_method_error())
524 {
525 throw DBusPropertyError{
526 "DBus set property failed",
527 service,
528 path,
529 interface,
530 property};
531 }
Brad Bishop6e9cfdb2017-06-08 11:59:58 -0400532 }
533
Brad Bishopf2238ae2017-07-30 13:32:23 -0400534 /** @brief Set a property with mapper lookup. */
535 template <typename Property>
536 static void setProperty(
537 const std::string& path,
538 const std::string& interface,
539 const std::string& property,
540 Property&& value)
541 {
542 return setProperty(
543 getBus(),
544 path,
545 interface,
546 property,
547 std::forward<Property>(value));
548 }
549
Matthew Barth6f30fd62018-05-11 09:38:29 -0500550 /** @brief Set a property without mapper lookup. */
551 template <typename Property>
552 static void setProperty(
553 sdbusplus::bus::bus& bus,
554 const std::string& service,
555 const std::string& path,
556 const std::string& interface,
557 const std::string& property,
558 Property&& value)
559 {
560 using namespace std::literals::string_literals;
561
562 sdbusplus::message::variant<Property> varValue(
563 std::forward<Property>(value));
564
Matthew Barth88923a02018-05-11 10:14:44 -0500565 auto msg = callMethodAndReturn(
Matthew Barth6f30fd62018-05-11 09:38:29 -0500566 bus,
567 service,
568 path,
569 "org.freedesktop.DBus.Properties"s,
570 "Set"s,
571 interface,
572 property,
573 varValue);
Matthew Barth88923a02018-05-11 10:14:44 -0500574 if (msg.is_method_error())
575 {
576 throw DBusPropertyError{
577 "DBus set property failed",
578 service,
579 path,
580 interface,
581 property};
582 }
Matthew Barth6f30fd62018-05-11 09:38:29 -0500583 }
584
585 /** @brief Set a property without mapper lookup. */
586 template <typename Property>
587 static void setProperty(
588 const std::string& service,
589 const std::string& path,
590 const std::string& interface,
591 const std::string& property,
592 Property&& value)
593 {
594 return setProperty(
595 getBus(),
596 service,
597 path,
598 interface,
599 property,
600 std::forward<Property>(value));
601 }
602
Brad Bishopf2238ae2017-07-30 13:32:23 -0400603 /** @brief Invoke method with mapper lookup. */
604 template <typename ...Args>
605 static auto lookupAndCallMethod(
606 sdbusplus::bus::bus& bus,
607 const std::string& path,
608 const std::string& interface,
609 const std::string& method,
610 Args&& ... args)
611 {
612 return callMethod(
613 bus,
614 getService(bus, path, interface),
615 path,
616 interface,
617 method,
618 std::forward<Args>(args)...);
619 }
620
Brad Bishop6e9cfdb2017-06-08 11:59:58 -0400621 /** @brief Invoke method with mapper lookup. */
622 template <typename ...Args>
623 static auto lookupAndCallMethod(
624 const std::string& path,
625 const std::string& interface,
626 const std::string& method,
627 Args&& ... args)
628 {
Brad Bishopf2238ae2017-07-30 13:32:23 -0400629 return lookupAndCallMethod(
630 getBus(),
631 path,
632 interface,
633 method,
634 std::forward<Args>(args)...);
635 }
636
637 /** @brief Invoke method and read with mapper lookup. */
638 template <typename Ret, typename ...Args>
639 static auto lookupCallMethodAndRead(
640 sdbusplus::bus::bus& bus,
641 const std::string& path,
642 const std::string& interface,
643 const std::string& method,
644 Args&& ... args)
645 {
646 return callMethodAndRead(
647 bus,
648 getService(bus, path, interface),
Brad Bishope67b41b2017-07-30 13:20:37 -0400649 path,
650 interface,
651 method,
652 std::forward<Args>(args)...);
Brad Bishop6e9cfdb2017-06-08 11:59:58 -0400653 }
654
655 /** @brief Invoke method and read with mapper lookup. */
656 template <typename Ret, typename ...Args>
657 static auto lookupCallMethodAndRead(
658 const std::string& path,
659 const std::string& interface,
660 const std::string& method,
661 Args&& ... args)
662 {
Brad Bishopf2238ae2017-07-30 13:32:23 -0400663 return lookupCallMethodAndRead<Ret>(
664 getBus(),
Brad Bishope67b41b2017-07-30 13:20:37 -0400665 path,
666 interface,
667 method,
668 std::forward<Args>(args)...);
Brad Bishop6e9cfdb2017-06-08 11:59:58 -0400669 }
Matthew Barth7c48d102018-05-09 14:52:36 -0500670
671 /** @brief Invoke a method and return without checking for error. */
672 template <typename ...Args>
673 static auto callMethodAndReturn(
674 sdbusplus::bus::bus& bus,
675 const std::string& busName,
676 const std::string& path,
677 const std::string& interface,
678 const std::string& method,
679 Args&& ... args)
680 {
681 auto reqMsg = bus.new_method_call(
682 busName.c_str(),
683 path.c_str(),
684 interface.c_str(),
685 method.c_str());
686 reqMsg.append(std::forward<Args>(args)...);
687 auto respMsg = bus.call(reqMsg);
688
689 return respMsg;
690 }
Brad Bishop6e9cfdb2017-06-08 11:59:58 -0400691};
692
693} // namespace util
694} // namespace fan
695} // namespace phosphor