1 #pragma once 2 3 #include <sdbusplus/bus.hpp> 4 #include <sdbusplus/message.hpp> 5 #include <phosphor-logging/log.hpp> 6 #include <phosphor-logging/elog.hpp> 7 #include <phosphor-logging/elog-errors.hpp> 8 #include <xyz/openbmc_project/Common/error.hpp> 9 10 namespace util 11 { 12 namespace detail 13 { 14 namespace errors = sdbusplus::xyz::openbmc_project::Common::Error; 15 } // namespace detail 16 17 /** @brief Alias for PropertiesChanged signal callbacks. */ 18 template <typename ...T> 19 using Properties = std::map<std::string, sdbusplus::message::variant<T...>>; 20 21 namespace sdbusplus 22 { 23 24 /** @brief Get the bus connection. */ 25 static auto& getBus() __attribute__((pure)); 26 static auto& getBus() 27 { 28 static auto bus = ::sdbusplus::bus::new_default(); 29 return bus; 30 } 31 32 /** @brief Invoke a method. */ 33 template <typename ...Args> 34 static auto callMethod( 35 ::sdbusplus::bus::bus& bus, 36 const std::string& busName, 37 const std::string& path, 38 const std::string& interface, 39 const std::string& method, 40 Args&& ... args) 41 { 42 auto reqMsg = bus.new_method_call( 43 busName.c_str(), 44 path.c_str(), 45 interface.c_str(), 46 method.c_str()); 47 reqMsg.append(std::forward<Args>(args)...); 48 auto respMsg = bus.call(reqMsg); 49 50 if (respMsg.is_method_error()) 51 { 52 phosphor::logging::log<phosphor::logging::level::INFO>( 53 "Failed to invoke DBus method.", 54 phosphor::logging::entry("PATH=%s", path.c_str()), 55 phosphor::logging::entry( 56 "INTERFACE=%s", interface.c_str()), 57 phosphor::logging::entry("METHOD=%s", method.c_str())); 58 phosphor::logging::elog<detail::errors::InternalFailure>(); 59 } 60 61 return respMsg; 62 } 63 64 /** @brief Invoke a method. */ 65 template <typename ...Args> 66 static auto callMethod( 67 const std::string& busName, 68 const std::string& path, 69 const std::string& interface, 70 const std::string& method, 71 Args&& ... args) 72 { 73 return callMethod( 74 getBus(), 75 busName, 76 path, 77 interface, 78 method, 79 std::forward<Args>(args)...); 80 } 81 82 /** @brief Invoke a method and read the response. */ 83 template <typename Ret, typename ...Args> 84 static auto callMethodAndRead( 85 ::sdbusplus::bus::bus& bus, 86 const std::string& busName, 87 const std::string& path, 88 const std::string& interface, 89 const std::string& method, 90 Args&& ... args) 91 { 92 ::sdbusplus::message::message respMsg = 93 callMethod<Args...>( 94 bus, 95 busName, 96 path, 97 interface, 98 method, 99 std::forward<Args>(args)...); 100 Ret resp; 101 respMsg.read(resp); 102 return resp; 103 } 104 105 /** @brief Invoke a method and read the response. */ 106 template <typename Ret, typename ...Args> 107 static auto callMethodAndRead( 108 const std::string& busName, 109 const std::string& path, 110 const std::string& interface, 111 const std::string& method, 112 Args&& ... args) 113 { 114 return callMethodAndRead<Ret>( 115 getBus(), 116 busName, 117 path, 118 interface, 119 method, 120 std::forward<Args>(args)...); 121 } 122 123 124 /** @brief Get service from the mapper. */ 125 static auto getService( 126 ::sdbusplus::bus::bus& bus, 127 const std::string& path, 128 const std::string& interface) 129 { 130 using namespace std::literals::string_literals; 131 using GetObject = std::map<std::string, std::vector<std::string>>; 132 133 auto mapperResp = callMethodAndRead<GetObject>( 134 bus, 135 "xyz.openbmc_project.ObjectMapper"s, 136 "/xyz/openbmc_project/object_mapper"s, 137 "xyz.openbmc_project.ObjectMapper"s, 138 "GetObject"s, 139 path, 140 GetObject::mapped_type{interface}); 141 142 if (mapperResp.empty()) 143 { 144 phosphor::logging::log<phosphor::logging::level::INFO>( 145 "Object not found.", 146 phosphor::logging::entry("PATH=%s", path.c_str()), 147 phosphor::logging::entry( 148 "INTERFACE=%s", interface.c_str())); 149 phosphor::logging::elog<detail::errors::InternalFailure>(); 150 } 151 return mapperResp.begin()->first; 152 } 153 154 /** @brief Get a property without mapper lookup. */ 155 template <typename Property> 156 static auto getProperty( 157 ::sdbusplus::bus::bus& bus, 158 const std::string& busName, 159 const std::string& path, 160 const std::string& interface, 161 const std::string& property) 162 { 163 using namespace std::literals::string_literals; 164 165 auto msg = callMethod( 166 bus, 167 busName, 168 path, 169 "org.freedesktop.DBus.Properties"s, 170 "Get"s, 171 interface, 172 property); 173 ::sdbusplus::message::variant<Property> value; 174 msg.read(value); 175 return value.template get<Property>(); 176 } 177 178 /** @brief Get a property without mapper lookup. */ 179 template <typename Property> 180 static auto getProperty( 181 const std::string& busName, 182 const std::string& path, 183 const std::string& interface, 184 const std::string& property) 185 { 186 return getProperty<Property>( 187 getBus(), 188 busName, 189 path, 190 interface, 191 property); 192 } 193 194 /** @brief Get a property with mapper lookup. */ 195 template <typename Property> 196 static auto getProperty( 197 ::sdbusplus::bus::bus& bus, 198 const std::string& path, 199 const std::string& interface, 200 const std::string& property) 201 { 202 return getProperty<Property>( 203 bus, 204 getService(bus, path, interface), 205 path, 206 interface, 207 property); 208 } 209 210 /** @brief Get a property with mapper lookup. */ 211 template <typename Property> 212 static auto getProperty( 213 const std::string& path, 214 const std::string& interface, 215 const std::string& property) 216 { 217 return getProperty<Property>( 218 getBus(), 219 path, 220 interface, 221 property); 222 } 223 224 } // namespace sdbusplus 225 } // namespace util 226