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