blob: 8a5b2f4a146d0c3cbc1e84d536215344b09eaed2 [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 Bartheca94df2018-01-19 16:42:49 -0600226 /** @brief Get subtree from the mapper. */
227 static auto getSubTree(
228 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
242 auto mapperResp = callMethodAndRead<Objects>(
243 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);
251
252 if (mapperResp.empty())
253 {
254 phosphor::logging::log<phosphor::logging::level::ERR>(
255 "Empty response from mapper GetSubTree",
256 phosphor::logging::entry("SUBTREE=%s", path.c_str()),
257 phosphor::logging::entry(
258 "INTERFACE=%s", interface.c_str()),
259 phosphor::logging::entry("DEPTH=%u", depth));
260 phosphor::logging::elog<detail::errors::InternalFailure>();
261 }
262 return mapperResp;
263 }
Brad Bishopf2238ae2017-07-30 13:32:23 -0400264
Brad Bishop6e9cfdb2017-06-08 11:59:58 -0400265 /** @brief Get service from the mapper. */
266 static auto getService(
Brad Bishopf2238ae2017-07-30 13:32:23 -0400267 sdbusplus::bus::bus& bus,
Brad Bishop6e9cfdb2017-06-08 11:59:58 -0400268 const std::string& path,
269 const std::string& interface)
270 {
271 using namespace std::literals::string_literals;
272 using GetObject = std::map<std::string, std::vector<std::string>>;
273
Matt Spinlerba7b5fe2018-04-25 15:26:10 -0500274 try
Brad Bishop6e9cfdb2017-06-08 11:59:58 -0400275 {
Matt Spinlerba7b5fe2018-04-25 15:26:10 -0500276 auto mapperResp = callMethodAndRead<GetObject>(
277 bus,
278 "xyz.openbmc_project.ObjectMapper"s,
279 "/xyz/openbmc_project/object_mapper"s,
280 "xyz.openbmc_project.ObjectMapper"s,
281 "GetObject"s,
282 path,
283 GetObject::mapped_type{interface});
284
285 if (mapperResp.empty())
286 {
287 //Should never happen. A missing object would fail
288 //in callMethodAndRead()
289 phosphor::logging::log<phosphor::logging::level::ERR>(
290 "Empty mapper response on service lookup");
291 throw DBusServiceError{path, interface};
292 }
293 return mapperResp.begin()->first;
Brad Bishop6e9cfdb2017-06-08 11:59:58 -0400294 }
Matt Spinlerba7b5fe2018-04-25 15:26:10 -0500295 catch (DBusMethodError& e)
296 {
297 throw DBusServiceError{path, interface};
298 }
Brad Bishop6e9cfdb2017-06-08 11:59:58 -0400299 }
300
Brad Bishopf2238ae2017-07-30 13:32:23 -0400301 /** @brief Get service from the mapper. */
302 static auto getService(
303 const std::string& path,
304 const std::string& interface)
305 {
306 return getService(
307 getBus(),
308 path,
309 interface);
310 }
311
Brad Bishop6e9cfdb2017-06-08 11:59:58 -0400312 /** @brief Get a property with mapper lookup. */
313 template <typename Property>
314 static auto getProperty(
Brad Bishopf2238ae2017-07-30 13:32:23 -0400315 sdbusplus::bus::bus& bus,
Brad Bishop6e9cfdb2017-06-08 11:59:58 -0400316 const std::string& path,
317 const std::string& interface,
318 const std::string& property)
319 {
320 using namespace std::literals::string_literals;
321
Matthew Barth88923a02018-05-11 10:14:44 -0500322 auto service = getService(bus, path, interface);
Brad Bishop6e9cfdb2017-06-08 11:59:58 -0400323 auto msg = callMethod(
Brad Bishopf2238ae2017-07-30 13:32:23 -0400324 bus,
Matthew Barth88923a02018-05-11 10:14:44 -0500325 service,
Brad Bishope67b41b2017-07-30 13:20:37 -0400326 path,
327 "org.freedesktop.DBus.Properties"s,
328 "Get"s,
329 interface,
330 property);
Matthew Barth88923a02018-05-11 10:14:44 -0500331 if (msg.is_method_error())
332 {
333 throw DBusPropertyError{
334 "DBus get property failed",
335 service,
336 path,
337 interface,
338 property};
339 }
Brad Bishop6e9cfdb2017-06-08 11:59:58 -0400340 sdbusplus::message::variant<Property> value;
341 msg.read(value);
William A. Kennington III52fbe0d2018-11-06 16:28:18 -0800342 return sdbusplus::message::variant_ns::get<Property>(value);
Brad Bishop6e9cfdb2017-06-08 11:59:58 -0400343 }
344
Brad Bishopf2238ae2017-07-30 13:32:23 -0400345 /** @brief Get a property with mapper lookup. */
346 template <typename Property>
347 static auto getProperty(
348 const std::string& path,
349 const std::string& interface,
350 const std::string& property)
351 {
352 return getProperty<Property>(
353 getBus(),
354 path,
355 interface,
356 property);
357 }
358
Matthew Barth7311c392018-05-03 16:50:47 -0500359 /** @brief Get a property variant with mapper lookup. */
360 template <typename Variant>
361 static auto getPropertyVariant(
362 sdbusplus::bus::bus& bus,
363 const std::string& path,
364 const std::string& interface,
365 const std::string& property)
366 {
367 using namespace std::literals::string_literals;
368
Matthew Barth88923a02018-05-11 10:14:44 -0500369 auto service = getService(bus, path, interface);
Matthew Barth7311c392018-05-03 16:50:47 -0500370 auto msg = callMethod(
371 bus,
Matthew Barth88923a02018-05-11 10:14:44 -0500372 service,
Matthew Barth7311c392018-05-03 16:50:47 -0500373 path,
374 "org.freedesktop.DBus.Properties"s,
375 "Get"s,
376 interface,
377 property);
Matthew Barth88923a02018-05-11 10:14:44 -0500378 if (msg.is_method_error())
379 {
380 throw DBusPropertyError{
381 "DBus get property variant failed",
382 service,
383 path,
384 interface,
385 property};
386 }
Matthew Barth7311c392018-05-03 16:50:47 -0500387 Variant value;
388 msg.read(value);
389 return value;
390 }
391
392 /** @brief Get a property variant with mapper lookup. */
393 template <typename Variant>
394 static auto getPropertyVariant(
395 const std::string& path,
396 const std::string& interface,
397 const std::string& property)
398 {
399 return getPropertyVariant<Variant>(
400 getBus(),
401 path,
402 interface,
403 property);
404 }
405
Matthew Barth5a796e62018-01-19 17:14:08 -0600406 /** @brief Get a property without mapper lookup. */
407 template <typename Property>
408 static auto getProperty(
409 sdbusplus::bus::bus& bus,
410 const std::string& service,
411 const std::string& path,
412 const std::string& interface,
413 const std::string& property)
414 {
415 using namespace std::literals::string_literals;
416
Matthew Barth88923a02018-05-11 10:14:44 -0500417 auto msg = callMethodAndReturn(
Matthew Barth5a796e62018-01-19 17:14:08 -0600418 bus,
419 service,
420 path,
421 "org.freedesktop.DBus.Properties"s,
422 "Get"s,
423 interface,
424 property);
Matthew Barth88923a02018-05-11 10:14:44 -0500425 if (msg.is_method_error())
426 {
427 throw DBusPropertyError{
428 "DBus get property failed",
429 service,
430 path,
431 interface,
432 property};
433 }
Matthew Barth5a796e62018-01-19 17:14:08 -0600434 sdbusplus::message::variant<Property> value;
435 msg.read(value);
William A. Kennington III52fbe0d2018-11-06 16:28:18 -0800436 return sdbusplus::message::variant_ns::get<Property>(value);
Matthew Barth5a796e62018-01-19 17:14:08 -0600437 }
438
439 /** @brief Get a property without mapper lookup. */
440 template <typename Property>
441 static auto getProperty(
442 const std::string& service,
443 const std::string& path,
444 const std::string& interface,
445 const std::string& property)
446 {
447 return getProperty<Property>(
448 getBus(),
449 service,
450 path,
451 interface,
452 property);
453 }
454
Matthew Barth7311c392018-05-03 16:50:47 -0500455 /** @brief Get a property variant without mapper lookup. */
456 template <typename Variant>
457 static auto getPropertyVariant(
458 sdbusplus::bus::bus& bus,
459 const std::string& service,
460 const std::string& path,
461 const std::string& interface,
462 const std::string& property)
463 {
464 using namespace std::literals::string_literals;
465
Matthew Barth88923a02018-05-11 10:14:44 -0500466 auto msg = callMethodAndReturn(
Matthew Barth7311c392018-05-03 16:50:47 -0500467 bus,
468 service,
469 path,
470 "org.freedesktop.DBus.Properties"s,
471 "Get"s,
472 interface,
473 property);
Matthew Barth88923a02018-05-11 10:14:44 -0500474 if (msg.is_method_error())
475 {
476 throw DBusPropertyError{
477 "DBus get property variant failed",
478 service,
479 path,
480 interface,
481 property};
482 }
Matthew Barth7311c392018-05-03 16:50:47 -0500483 Variant value;
484 msg.read(value);
485 return value;
486 }
487
488 /** @brief Get a property variant without mapper lookup. */
489 template <typename Variant>
490 static auto getPropertyVariant(
491 const std::string& service,
492 const std::string& path,
493 const std::string& interface,
494 const std::string& property)
495 {
496 return getPropertyVariant<Variant>(
497 getBus(),
498 service,
499 path,
500 interface,
501 property);
502 }
503
Brad Bishop6e9cfdb2017-06-08 11:59:58 -0400504 /** @brief Set a property with mapper lookup. */
505 template <typename Property>
506 static void setProperty(
Brad Bishopf2238ae2017-07-30 13:32:23 -0400507 sdbusplus::bus::bus& bus,
Brad Bishop6e9cfdb2017-06-08 11:59:58 -0400508 const std::string& path,
509 const std::string& interface,
510 const std::string& property,
511 Property&& value)
512 {
513 using namespace std::literals::string_literals;
514
515 sdbusplus::message::variant<Property> varValue(
Brad Bishope67b41b2017-07-30 13:20:37 -0400516 std::forward<Property>(value));
Brad Bishop6e9cfdb2017-06-08 11:59:58 -0400517
Matthew Barth88923a02018-05-11 10:14:44 -0500518 auto service = getService(bus, path, interface);
519 auto msg = callMethodAndReturn(
Brad Bishopf2238ae2017-07-30 13:32:23 -0400520 bus,
Matthew Barth88923a02018-05-11 10:14:44 -0500521 service,
Brad Bishope67b41b2017-07-30 13:20:37 -0400522 path,
523 "org.freedesktop.DBus.Properties"s,
524 "Set"s,
525 interface,
526 property,
527 varValue);
Matthew Barth88923a02018-05-11 10:14:44 -0500528 if (msg.is_method_error())
529 {
530 throw DBusPropertyError{
531 "DBus set property failed",
532 service,
533 path,
534 interface,
535 property};
536 }
Brad Bishop6e9cfdb2017-06-08 11:59:58 -0400537 }
538
Brad Bishopf2238ae2017-07-30 13:32:23 -0400539 /** @brief Set a property with mapper lookup. */
540 template <typename Property>
541 static void setProperty(
542 const std::string& path,
543 const std::string& interface,
544 const std::string& property,
545 Property&& value)
546 {
547 return setProperty(
548 getBus(),
549 path,
550 interface,
551 property,
552 std::forward<Property>(value));
553 }
554
Matthew Barth6f30fd62018-05-11 09:38:29 -0500555 /** @brief Set a property without mapper lookup. */
556 template <typename Property>
557 static void setProperty(
558 sdbusplus::bus::bus& bus,
559 const std::string& service,
560 const std::string& path,
561 const std::string& interface,
562 const std::string& property,
563 Property&& value)
564 {
565 using namespace std::literals::string_literals;
566
567 sdbusplus::message::variant<Property> varValue(
568 std::forward<Property>(value));
569
Matthew Barth88923a02018-05-11 10:14:44 -0500570 auto msg = callMethodAndReturn(
Matthew Barth6f30fd62018-05-11 09:38:29 -0500571 bus,
572 service,
573 path,
574 "org.freedesktop.DBus.Properties"s,
575 "Set"s,
576 interface,
577 property,
578 varValue);
Matthew Barth88923a02018-05-11 10:14:44 -0500579 if (msg.is_method_error())
580 {
581 throw DBusPropertyError{
582 "DBus set property failed",
583 service,
584 path,
585 interface,
586 property};
587 }
Matthew Barth6f30fd62018-05-11 09:38:29 -0500588 }
589
590 /** @brief Set a property without mapper lookup. */
591 template <typename Property>
592 static void setProperty(
593 const std::string& service,
594 const std::string& path,
595 const std::string& interface,
596 const std::string& property,
597 Property&& value)
598 {
599 return setProperty(
600 getBus(),
601 service,
602 path,
603 interface,
604 property,
605 std::forward<Property>(value));
606 }
607
Brad Bishopf2238ae2017-07-30 13:32:23 -0400608 /** @brief Invoke method with mapper lookup. */
609 template <typename ...Args>
610 static auto lookupAndCallMethod(
611 sdbusplus::bus::bus& bus,
612 const std::string& path,
613 const std::string& interface,
614 const std::string& method,
615 Args&& ... args)
616 {
617 return callMethod(
618 bus,
619 getService(bus, path, interface),
620 path,
621 interface,
622 method,
623 std::forward<Args>(args)...);
624 }
625
Brad Bishop6e9cfdb2017-06-08 11:59:58 -0400626 /** @brief Invoke method with mapper lookup. */
627 template <typename ...Args>
628 static auto lookupAndCallMethod(
629 const std::string& path,
630 const std::string& interface,
631 const std::string& method,
632 Args&& ... args)
633 {
Brad Bishopf2238ae2017-07-30 13:32:23 -0400634 return lookupAndCallMethod(
635 getBus(),
636 path,
637 interface,
638 method,
639 std::forward<Args>(args)...);
640 }
641
642 /** @brief Invoke method and read with mapper lookup. */
643 template <typename Ret, typename ...Args>
644 static auto lookupCallMethodAndRead(
645 sdbusplus::bus::bus& bus,
646 const std::string& path,
647 const std::string& interface,
648 const std::string& method,
649 Args&& ... args)
650 {
651 return callMethodAndRead(
652 bus,
653 getService(bus, path, interface),
Brad Bishope67b41b2017-07-30 13:20:37 -0400654 path,
655 interface,
656 method,
657 std::forward<Args>(args)...);
Brad Bishop6e9cfdb2017-06-08 11:59:58 -0400658 }
659
660 /** @brief Invoke method and read with mapper lookup. */
661 template <typename Ret, typename ...Args>
662 static auto lookupCallMethodAndRead(
663 const std::string& path,
664 const std::string& interface,
665 const std::string& method,
666 Args&& ... args)
667 {
Brad Bishopf2238ae2017-07-30 13:32:23 -0400668 return lookupCallMethodAndRead<Ret>(
669 getBus(),
Brad Bishope67b41b2017-07-30 13:20:37 -0400670 path,
671 interface,
672 method,
673 std::forward<Args>(args)...);
Brad Bishop6e9cfdb2017-06-08 11:59:58 -0400674 }
Matthew Barth7c48d102018-05-09 14:52:36 -0500675
676 /** @brief Invoke a method and return without checking for error. */
677 template <typename ...Args>
678 static auto callMethodAndReturn(
679 sdbusplus::bus::bus& bus,
680 const std::string& busName,
681 const std::string& path,
682 const std::string& interface,
683 const std::string& method,
684 Args&& ... args)
685 {
686 auto reqMsg = bus.new_method_call(
687 busName.c_str(),
688 path.c_str(),
689 interface.c_str(),
690 method.c_str());
691 reqMsg.append(std::forward<Args>(args)...);
692 auto respMsg = bus.call(reqMsg);
693
694 return respMsg;
695 }
Brad Bishop6e9cfdb2017-06-08 11:59:58 -0400696};
697
698} // namespace util
699} // namespace fan
700} // namespace phosphor