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)); 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> 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> 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 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> 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. */ 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> 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 = 122 callMethod(bus, busName, path, "org.freedesktop.DBus.Properties"s, 123 "Get"s, interface, 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> 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> 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> 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