1 #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 11 namespace phosphor 12 { 13 namespace fan 14 { 15 namespace util 16 { 17 namespace detail 18 { 19 namespace errors = sdbusplus::xyz::openbmc_project::Common::Error; 20 } // namespace detail 21 22 /** @brief Alias for PropertiesChanged signal callbacks. */ 23 template <typename ...T> 24 using Properties = std::map<std::string, sdbusplus::message::variant<T...>>; 25 26 /** @class SDBusPlus 27 * @brief DBus access delegate implementation for sdbusplus. 28 */ 29 class SDBusPlus 30 { 31 32 public: 33 /** @brief Get the bus connection. */ 34 static auto& getBus() __attribute__((pure)) 35 { 36 static auto bus = sdbusplus::bus::new_default(); 37 return bus; 38 } 39 40 /** @brief Invoke a method. */ 41 template <typename ...Args> 42 static auto callMethod( 43 sdbusplus::bus::bus& bus, 44 const std::string& busName, 45 const std::string& path, 46 const std::string& interface, 47 const std::string& method, 48 Args&& ... args) 49 { 50 auto reqMsg = bus.new_method_call( 51 busName.c_str(), 52 path.c_str(), 53 interface.c_str(), 54 method.c_str()); 55 reqMsg.append(std::forward<Args>(args)...); 56 auto respMsg = bus.call(reqMsg); 57 58 if (respMsg.is_method_error()) 59 { 60 phosphor::logging::log<phosphor::logging::level::INFO>( 61 "Failed to invoke DBus method.", 62 phosphor::logging::entry("PATH=%s", path.c_str()), 63 phosphor::logging::entry( 64 "INTERFACE=%s", interface.c_str()), 65 phosphor::logging::entry("METHOD=%s", method.c_str())); 66 phosphor::logging::elog<detail::errors::InternalFailure>(); 67 } 68 69 return respMsg; 70 } 71 72 /** @brief Invoke a method. */ 73 template <typename ...Args> 74 static auto callMethod( 75 const std::string& busName, 76 const std::string& path, 77 const std::string& interface, 78 const std::string& method, 79 Args&& ... args) 80 { 81 return callMethod( 82 getBus(), 83 busName, 84 path, 85 interface, 86 method, 87 std::forward<Args>(args)...); 88 } 89 90 /** @brief Invoke a method and read the response. */ 91 template <typename Ret, typename ...Args> 92 static auto callMethodAndRead( 93 sdbusplus::bus::bus& bus, 94 const std::string& busName, 95 const std::string& path, 96 const std::string& interface, 97 const std::string& method, 98 Args&& ... args) 99 { 100 sdbusplus::message::message respMsg = 101 callMethod<Args...>( 102 bus, 103 busName, 104 path, 105 interface, 106 method, 107 std::forward<Args>(args)...); 108 Ret resp; 109 respMsg.read(resp); 110 return resp; 111 } 112 113 /** @brief Invoke a method and read the response. */ 114 template <typename Ret, typename ...Args> 115 static auto callMethodAndRead( 116 const std::string& busName, 117 const std::string& path, 118 const std::string& interface, 119 const std::string& method, 120 Args&& ... args) 121 { 122 return callMethodAndRead<Ret>( 123 getBus(), 124 busName, 125 path, 126 interface, 127 method, 128 std::forward<Args>(args)...); 129 } 130 131 /** @brief Get subtree from the mapper. */ 132 static auto getSubTree( 133 sdbusplus::bus::bus& bus, 134 const std::string& path, 135 const std::string& interface, 136 int32_t depth) 137 { 138 using namespace std::literals::string_literals; 139 140 using Path = std::string; 141 using Intf = std::string; 142 using Serv = std::string; 143 using Intfs = std::vector<Intf>; 144 using Objects = std::map<Path, std::map<Serv, Intfs>>; 145 Intfs intfs = {interface}; 146 147 auto mapperResp = callMethodAndRead<Objects>( 148 bus, 149 "xyz.openbmc_project.ObjectMapper"s, 150 "/xyz/openbmc_project/object_mapper"s, 151 "xyz.openbmc_project.ObjectMapper"s, 152 "GetSubTree"s, 153 path, 154 depth, 155 intfs); 156 157 if (mapperResp.empty()) 158 { 159 phosphor::logging::log<phosphor::logging::level::ERR>( 160 "Empty response from mapper GetSubTree", 161 phosphor::logging::entry("SUBTREE=%s", path.c_str()), 162 phosphor::logging::entry( 163 "INTERFACE=%s", interface.c_str()), 164 phosphor::logging::entry("DEPTH=%u", depth)); 165 phosphor::logging::elog<detail::errors::InternalFailure>(); 166 } 167 return mapperResp; 168 } 169 170 /** @brief Get service from the mapper. */ 171 static auto getService( 172 sdbusplus::bus::bus& bus, 173 const std::string& path, 174 const std::string& interface) 175 { 176 using namespace std::literals::string_literals; 177 using GetObject = std::map<std::string, std::vector<std::string>>; 178 179 auto mapperResp = callMethodAndRead<GetObject>( 180 bus, 181 "xyz.openbmc_project.ObjectMapper"s, 182 "/xyz/openbmc_project/object_mapper"s, 183 "xyz.openbmc_project.ObjectMapper"s, 184 "GetObject"s, 185 path, 186 GetObject::mapped_type{interface}); 187 188 if (mapperResp.empty()) 189 { 190 phosphor::logging::log<phosphor::logging::level::INFO>( 191 "Object not found.", 192 phosphor::logging::entry("PATH=%s", path.c_str()), 193 phosphor::logging::entry( 194 "INTERFACE=%s", interface.c_str())); 195 phosphor::logging::elog<detail::errors::InternalFailure>(); 196 } 197 return mapperResp.begin()->first; 198 } 199 200 /** @brief Get service from the mapper. */ 201 static auto getService( 202 const std::string& path, 203 const std::string& interface) 204 { 205 return getService( 206 getBus(), 207 path, 208 interface); 209 } 210 211 /** @brief Get a property with mapper lookup. */ 212 template <typename Property> 213 static auto getProperty( 214 sdbusplus::bus::bus& bus, 215 const std::string& path, 216 const std::string& interface, 217 const std::string& property) 218 { 219 using namespace std::literals::string_literals; 220 221 auto msg = callMethod( 222 bus, 223 getService(bus, path, interface), 224 path, 225 "org.freedesktop.DBus.Properties"s, 226 "Get"s, 227 interface, 228 property); 229 sdbusplus::message::variant<Property> value; 230 msg.read(value); 231 return value.template get<Property>(); 232 } 233 234 /** @brief Get a property with mapper lookup. */ 235 template <typename Property> 236 static auto getProperty( 237 const std::string& path, 238 const std::string& interface, 239 const std::string& property) 240 { 241 return getProperty<Property>( 242 getBus(), 243 path, 244 interface, 245 property); 246 } 247 248 /** @brief Get a property variant with mapper lookup. */ 249 template <typename Variant> 250 static auto getPropertyVariant( 251 sdbusplus::bus::bus& bus, 252 const std::string& path, 253 const std::string& interface, 254 const std::string& property) 255 { 256 using namespace std::literals::string_literals; 257 258 auto msg = callMethod( 259 bus, 260 getService(bus, path, interface), 261 path, 262 "org.freedesktop.DBus.Properties"s, 263 "Get"s, 264 interface, 265 property); 266 Variant value; 267 msg.read(value); 268 return value; 269 } 270 271 /** @brief Get a property variant with mapper lookup. */ 272 template <typename Variant> 273 static auto getPropertyVariant( 274 const std::string& path, 275 const std::string& interface, 276 const std::string& property) 277 { 278 return getPropertyVariant<Variant>( 279 getBus(), 280 path, 281 interface, 282 property); 283 } 284 285 /** @brief Get a property without mapper lookup. */ 286 template <typename Property> 287 static auto getProperty( 288 sdbusplus::bus::bus& bus, 289 const std::string& service, 290 const std::string& path, 291 const std::string& interface, 292 const std::string& property) 293 { 294 using namespace std::literals::string_literals; 295 296 auto msg = callMethod( 297 bus, 298 service, 299 path, 300 "org.freedesktop.DBus.Properties"s, 301 "Get"s, 302 interface, 303 property); 304 sdbusplus::message::variant<Property> value; 305 msg.read(value); 306 return value.template get<Property>(); 307 } 308 309 /** @brief Get a property without mapper lookup. */ 310 template <typename Property> 311 static auto getProperty( 312 const std::string& service, 313 const std::string& path, 314 const std::string& interface, 315 const std::string& property) 316 { 317 return getProperty<Property>( 318 getBus(), 319 service, 320 path, 321 interface, 322 property); 323 } 324 325 /** @brief Get a property variant without mapper lookup. */ 326 template <typename Variant> 327 static auto getPropertyVariant( 328 sdbusplus::bus::bus& bus, 329 const std::string& service, 330 const std::string& path, 331 const std::string& interface, 332 const std::string& property) 333 { 334 using namespace std::literals::string_literals; 335 336 auto msg = callMethod( 337 bus, 338 service, 339 path, 340 "org.freedesktop.DBus.Properties"s, 341 "Get"s, 342 interface, 343 property); 344 Variant value; 345 msg.read(value); 346 return value; 347 } 348 349 /** @brief Get a property variant without mapper lookup. */ 350 template <typename Variant> 351 static auto getPropertyVariant( 352 const std::string& service, 353 const std::string& path, 354 const std::string& interface, 355 const std::string& property) 356 { 357 return getPropertyVariant<Variant>( 358 getBus(), 359 service, 360 path, 361 interface, 362 property); 363 } 364 365 /** @brief Set a property with mapper lookup. */ 366 template <typename Property> 367 static void setProperty( 368 sdbusplus::bus::bus& bus, 369 const std::string& path, 370 const std::string& interface, 371 const std::string& property, 372 Property&& value) 373 { 374 using namespace std::literals::string_literals; 375 376 sdbusplus::message::variant<Property> varValue( 377 std::forward<Property>(value)); 378 379 callMethod( 380 bus, 381 getService(bus, path, interface), 382 path, 383 "org.freedesktop.DBus.Properties"s, 384 "Set"s, 385 interface, 386 property, 387 varValue); 388 } 389 390 /** @brief Set a property with mapper lookup. */ 391 template <typename Property> 392 static void setProperty( 393 const std::string& path, 394 const std::string& interface, 395 const std::string& property, 396 Property&& value) 397 { 398 return setProperty( 399 getBus(), 400 path, 401 interface, 402 property, 403 std::forward<Property>(value)); 404 } 405 406 /** @brief Invoke method with mapper lookup. */ 407 template <typename ...Args> 408 static auto lookupAndCallMethod( 409 sdbusplus::bus::bus& bus, 410 const std::string& path, 411 const std::string& interface, 412 const std::string& method, 413 Args&& ... args) 414 { 415 return callMethod( 416 bus, 417 getService(bus, path, interface), 418 path, 419 interface, 420 method, 421 std::forward<Args>(args)...); 422 } 423 424 /** @brief Invoke method with mapper lookup. */ 425 template <typename ...Args> 426 static auto lookupAndCallMethod( 427 const std::string& path, 428 const std::string& interface, 429 const std::string& method, 430 Args&& ... args) 431 { 432 return lookupAndCallMethod( 433 getBus(), 434 path, 435 interface, 436 method, 437 std::forward<Args>(args)...); 438 } 439 440 /** @brief Invoke method and read with mapper lookup. */ 441 template <typename Ret, typename ...Args> 442 static auto lookupCallMethodAndRead( 443 sdbusplus::bus::bus& bus, 444 const std::string& path, 445 const std::string& interface, 446 const std::string& method, 447 Args&& ... args) 448 { 449 return callMethodAndRead( 450 bus, 451 getService(bus, path, interface), 452 path, 453 interface, 454 method, 455 std::forward<Args>(args)...); 456 } 457 458 /** @brief Invoke method and read with mapper lookup. */ 459 template <typename Ret, typename ...Args> 460 static auto lookupCallMethodAndRead( 461 const std::string& path, 462 const std::string& interface, 463 const std::string& method, 464 Args&& ... args) 465 { 466 return lookupCallMethodAndRead<Ret>( 467 getBus(), 468 path, 469 interface, 470 method, 471 std::forward<Args>(args)...); 472 } 473 }; 474 475 } // namespace util 476 } // namespace fan 477 } // namespace phosphor 478