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