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