xref: /openbmc/phosphor-dbus-monitor/mslverify/util.hpp (revision 13e3df602acb51a4505fce2fab1cedd04f010e7b)
1 #pragma once
2 
3 #include <phosphor-logging/elog-errors.hpp>
4 #include <phosphor-logging/elog.hpp>
5 #include <phosphor-logging/lg2.hpp>
6 #include <sdbusplus/bus.hpp>
7 #include <sdbusplus/message.hpp>
8 #include <xyz/openbmc_project/Common/error.hpp>
9 
10 #include <string>
11 
12 namespace util
13 {
14 namespace detail
15 {
16 namespace errors = sdbusplus::xyz::openbmc_project::Common::Error;
17 } // namespace detail
18 
19 /** @brief Alias for PropertiesChanged signal callbacks. */
20 template <typename... T>
21 using Properties = std::map<std::string, std::variant<T...>>;
22 
23 namespace sdbusplus
24 {
25 
26 /** @brief Get the bus connection. */
27 static auto& getBus() __attribute__((pure));
28 static auto& getBus()
29 {
30     static auto bus = ::sdbusplus::bus::new_default();
31     return bus;
32 }
33 
34 /** @brief Invoke a method. */
35 template <typename... Args>
36 static auto callMethod(::sdbusplus::bus::bus& bus, const std::string& busName,
37                        const std::string& path, const std::string& interface,
38                        const std::string& method, Args&&... args)
39 {
40     auto reqMsg = bus.new_method_call(busName.c_str(), path.c_str(),
41                                       interface.c_str(), method.c_str());
42     reqMsg.append(std::forward<Args>(args)...);
43     auto respMsg = bus.call(reqMsg);
44 
45     if (respMsg.is_method_error())
46     {
47         lg2::error("Failed to invoke DBus method. {PATH}, {INTF}, {METHOD}",
48                    "PATH", path, "INTF", interface, "METHOD", method);
49         phosphor::logging::elog<detail::errors::InternalFailure>();
50     }
51 
52     return respMsg;
53 }
54 
55 /** @brief Invoke a method. */
56 template <typename... Args>
57 static auto callMethod(const std::string& busName, const std::string& path,
58                        const std::string& interface, const std::string& method,
59                        Args&&... args)
60 {
61     return callMethod(getBus(), busName, path, interface, method,
62                       std::forward<Args>(args)...);
63 }
64 
65 /** @brief Invoke a method and read the response. */
66 template <typename Ret, typename... Args>
67 static auto
68     callMethodAndRead(::sdbusplus::bus::bus& bus, const std::string& busName,
69                       const std::string& path, const std::string& interface,
70                       const std::string& method, Args&&... args)
71 {
72     ::sdbusplus::message::message respMsg = callMethod<Args...>(
73         bus, busName, path, interface, method, std::forward<Args>(args)...);
74     Ret resp;
75     respMsg.read(resp);
76     return resp;
77 }
78 
79 /** @brief Invoke a method and read the response. */
80 template <typename Ret, typename... Args>
81 static auto callMethodAndRead(const std::string& busName,
82                               const std::string& path,
83                               const std::string& interface,
84                               const std::string& method, Args&&... args)
85 {
86     return callMethodAndRead<Ret>(getBus(), busName, path, interface, method,
87                                   std::forward<Args>(args)...);
88 }
89 
90 /** @brief Get service from the mapper. */
91 static auto getService(::sdbusplus::bus::bus& bus, const std::string& path,
92                        const std::string& interface)
93 {
94     using namespace std::literals::string_literals;
95     using GetObject = std::map<std::string, std::vector<std::string>>;
96 
97     auto mapperResp = callMethodAndRead<GetObject>(
98         bus, "xyz.openbmc_project.ObjectMapper"s,
99         "/xyz/openbmc_project/object_mapper"s,
100         "xyz.openbmc_project.ObjectMapper"s, "GetObject"s, path,
101         GetObject::mapped_type{interface});
102 
103     if (mapperResp.empty())
104     {
105         lg2::error("Object not found. {PATH}, {INTF}", "PATH", path, "INTF",
106                    interface);
107         phosphor::logging::elog<detail::errors::InternalFailure>();
108     }
109     return mapperResp.begin()->first;
110 }
111 
112 /** @brief Get a property without mapper lookup. */
113 template <typename Property>
114 static auto getProperty(::sdbusplus::bus::bus& bus, const std::string& busName,
115                         const std::string& path, const std::string& interface,
116                         const std::string& property)
117 {
118     using namespace std::literals::string_literals;
119 
120     auto msg =
121         callMethod(bus, busName, path, "org.freedesktop.DBus.Properties"s,
122                    "Get"s, interface, property);
123     ::std::variant<Property> value;
124     msg.read(value);
125     return std::get<Property>(value);
126 }
127 
128 /** @brief Get a property without mapper lookup. */
129 template <typename Property>
130 static auto getProperty(const std::string& busName, const std::string& path,
131                         const std::string& interface,
132                         const std::string& property)
133 {
134     return getProperty<Property>(getBus(), busName, path, interface, property);
135 }
136 
137 /** @brief Get a property with mapper lookup. */
138 template <typename Property>
139 static auto getProperty(::sdbusplus::bus::bus& bus, const std::string& path,
140                         const std::string& interface,
141                         const std::string& property)
142 {
143     return getProperty<Property>(bus, getService(bus, path, interface), path,
144                                  interface, property);
145 }
146 
147 /** @brief Get a property with mapper lookup. */
148 template <typename Property>
149 static auto getProperty(const std::string& path, const std::string& interface,
150                         const std::string& property)
151 {
152     return getProperty<Property>(getBus(), path, interface, property);
153 }
154 
155 } // namespace sdbusplus
156 } // namespace util
157