| #pragma once | 
 |  | 
 | #include <boost/system/error_code.hpp> | 
 | #include <ipmid/api-types.hpp> | 
 | #include <ipmid/message.hpp> | 
 | #include <ipmid/types.hpp> | 
 | #include <phosphor-logging/lg2.hpp> | 
 | #include <sdbusplus/server.hpp> | 
 |  | 
 | #include <chrono> | 
 | #include <optional> | 
 |  | 
 | namespace ipmi | 
 | { | 
 |  | 
 | using namespace std::literals::chrono_literals; | 
 |  | 
 | constexpr auto MAPPER_BUS_NAME = "xyz.openbmc_project.ObjectMapper"; | 
 | constexpr auto MAPPER_OBJ = "/xyz/openbmc_project/object_mapper"; | 
 | constexpr auto MAPPER_INTF = "xyz.openbmc_project.ObjectMapper"; | 
 |  | 
 | constexpr auto ROOT = "/"; | 
 | constexpr auto HOST_MATCH = "host0"; | 
 |  | 
 | constexpr auto PROP_INTF = "org.freedesktop.DBus.Properties"; | 
 | constexpr auto DELETE_INTERFACE = "xyz.openbmc_project.Object.Delete"; | 
 |  | 
 | constexpr auto METHOD_GET = "Get"; | 
 | constexpr auto METHOD_GET_ALL = "GetAll"; | 
 | constexpr auto METHOD_SET = "Set"; | 
 |  | 
 | /* Use a value of 5s which aligns with BT/KCS bridged timeouts, rather | 
 |  * than the default 25s D-Bus timeout. */ | 
 | constexpr std::chrono::microseconds IPMI_DBUS_TIMEOUT = 5s; | 
 |  | 
 | /** @class ServiceCache | 
 |  *  @brief Caches lookups of service names from the object mapper. | 
 |  *  @details Most ipmi commands need to talk to other dbus daemons to perform | 
 |  *           their intended actions on the BMC. This usually means they will | 
 |  *           first look up the service name providing the interface they | 
 |  *           require. This class reduces the number of such calls by caching | 
 |  *           the lookup for a specific service. | 
 |  */ | 
 | class ServiceCache | 
 | { | 
 |   public: | 
 |     /** @brief Creates a new service cache for the given interface | 
 |      *         and path. | 
 |      * | 
 |      *  @param[in] intf - The interface used for each lookup | 
 |      *  @param[in] path - The path used for each lookup | 
 |      */ | 
 |     ServiceCache(const std::string& intf, const std::string& path); | 
 |     ServiceCache(std::string&& intf, std::string&& path); | 
 |  | 
 |     /** @brief Gets the service name from the cache or does in a | 
 |      *         lookup when invalid. | 
 |      * | 
 |      *  @param[in] bus - The bus associated with and used for looking | 
 |      *                   up the service. | 
 |      */ | 
 |     const std::string& getService(sdbusplus::bus_t& bus); | 
 |  | 
 |     /** @brief Invalidates the current service name */ | 
 |     void invalidate(); | 
 |  | 
 |     /** @brief A wrapper around sdbusplus bus.new_method_call | 
 |      * | 
 |      *  @param[in] bus - The bus used for calling the method | 
 |      *  @param[in] intf - The interface containing the method | 
 |      *  @param[in] method - The method name | 
 |      *  @return The message containing the method call. | 
 |      */ | 
 |     sdbusplus::message_t newMethodCall(sdbusplus::bus_t& bus, const char* intf, | 
 |                                        const char* method); | 
 |  | 
 |     /** @brief Check to see if the current cache is valid | 
 |      * | 
 |      * @param[in] bus - The bus used for the service lookup | 
 |      * @return True if the cache is valid false otherwise. | 
 |      */ | 
 |     bool isValid(sdbusplus::bus_t& bus) const; | 
 |  | 
 |   private: | 
 |     /** @brief DBUS interface provided by the service */ | 
 |     const std::string intf; | 
 |     /** @brief DBUS path provided by the service */ | 
 |     const std::string path; | 
 |     /** @brief The name of the service if valid */ | 
 |     std::optional<std::string> cachedService; | 
 |     /** @brief The name of the bus used in the service lookup */ | 
 |     std::optional<std::string> cachedBusName; | 
 | }; | 
 |  | 
 | /** | 
 |  * @brief Get the DBUS Service name for the input dbus path | 
 |  * | 
 |  * @param[in] bus - DBUS Bus Object | 
 |  * @param[in] intf - DBUS Interface | 
 |  * @param[in] path - DBUS Object Path | 
 |  * | 
 |  */ | 
 | std::string getService(sdbusplus::bus_t& bus, const std::string& intf, | 
 |                        const std::string& path); | 
 |  | 
 | /** @brief Gets the dbus sub tree implementing the given interface. | 
 |  *  @param[in] bus - DBUS Bus Object. | 
 |  *  @param[in] interfaces - Dbus interface. | 
 |  *  @param[in] subtreePath - subtree from where the search should start. | 
 |  *  @param[in] depth - Search depth | 
 |  *  @return map of object path and service info. | 
 |  */ | 
 | ObjectTree getSubTree(sdbusplus::bus_t& bus, const InterfaceList& interface, | 
 |                       const std::string& subtreePath = ROOT, int32_t depth = 0); | 
 |  | 
 | /** @brief Gets the dbus object info implementing the given interface | 
 |  *         from the given subtree. | 
 |  *  @param[in] bus - DBUS Bus Object. | 
 |  *  @param[in] interface - Dbus interface. | 
 |  *  @param[in] subtreePath - subtree from where the search should start. | 
 |  *  @param[in] match - identifier for object. | 
 |  *  @return On success returns the object having objectpath and servicename. | 
 |  */ | 
 | DbusObjectInfo getDbusObject( | 
 |     sdbusplus::bus_t& bus, const std::string& interface, | 
 |     const std::string& subtreePath = ROOT, const std::string& match = {}); | 
 |  | 
 | /** @brief Gets the value associated with the given object | 
 |  *         and the interface. | 
 |  *  @param[in] bus - DBUS Bus Object. | 
 |  *  @param[in] service - Dbus service name. | 
 |  *  @param[in] objPath - Dbus object path. | 
 |  *  @param[in] interface - Dbus interface. | 
 |  *  @param[in] property - name of the property. | 
 |  *  @return On success returns the value of the property. | 
 |  */ | 
 | Value getDbusProperty(sdbusplus::bus_t& bus, const std::string& service, | 
 |                       const std::string& objPath, const std::string& interface, | 
 |                       const std::string& property, | 
 |                       std::chrono::microseconds timeout = IPMI_DBUS_TIMEOUT); | 
 |  | 
 | /** @brief Gets all the properties associated with the given object | 
 |  *         and the interface. | 
 |  *  @param[in] bus - DBUS Bus Object. | 
 |  *  @param[in] service - Dbus service name. | 
 |  *  @param[in] objPath - Dbus object path. | 
 |  *  @param[in] interface - Dbus interface. | 
 |  *  @return On success returns the map of name value pair. | 
 |  */ | 
 | PropertyMap getAllDbusProperties( | 
 |     sdbusplus::bus_t& bus, const std::string& service, | 
 |     const std::string& objPath, const std::string& interface, | 
 |     std::chrono::microseconds timeout = IPMI_DBUS_TIMEOUT); | 
 |  | 
 | /** @brief Gets all managed objects associated with the given object | 
 |  *         path and service. | 
 |  *  @param[in] bus - D-Bus Bus Object. | 
 |  *  @param[in] service - D-Bus service name. | 
 |  *  @param[in] objPath - D-Bus object path. | 
 |  *  @return On success returns the map of name value pair. | 
 |  */ | 
 | ObjectValueTree getManagedObjects(sdbusplus::bus_t& bus, | 
 |                                   const std::string& service, | 
 |                                   const std::string& objPath); | 
 |  | 
 | /** @brief Sets the property value of the given object. | 
 |  *  @param[in] bus - DBUS Bus Object. | 
 |  *  @param[in] service - Dbus service name. | 
 |  *  @param[in] objPath - Dbus object path. | 
 |  *  @param[in] interface - Dbus interface. | 
 |  *  @param[in] property - name of the property. | 
 |  *  @param[in] value - value which needs to be set. | 
 |  */ | 
 | void setDbusProperty(sdbusplus::bus_t& bus, const std::string& service, | 
 |                      const std::string& objPath, const std::string& interface, | 
 |                      const std::string& property, const Value& value, | 
 |                      std::chrono::microseconds timeout = IPMI_DBUS_TIMEOUT); | 
 |  | 
 | /** @brief  Gets all the dbus objects from the given service root | 
 |  *          which matches the object identifier. | 
 |  *  @param[in] bus - DBUS Bus Object. | 
 |  *  @param[in] serviceRoot - Service root path. | 
 |  *  @param[in] interface - Dbus interface. | 
 |  *  @param[in] match - Identifier for a path. | 
 |  *  @returns map of object path and service info. | 
 |  */ | 
 | ObjectTree getAllDbusObjects( | 
 |     sdbusplus::bus_t& bus, const std::string& serviceRoot, | 
 |     const std::string& interface, const std::string& match = {}); | 
 |  | 
 | /********* Begin co-routine yielding alternatives ***************/ | 
 |  | 
 | /** @brief Get the D-Bus Service name for the input D-Bus path | 
 |  * | 
 |  *  @param[in] ctx - ipmi::Context::ptr | 
 |  *  @param[in] intf - D-Bus Interface | 
 |  *  @param[in] path - D-Bus Object Path | 
 |  *  @param[out] service - requested service name | 
 |  *  @return boost error code | 
 |  * | 
 |  */ | 
 | boost::system::error_code getService(Context::ptr ctx, const std::string& intf, | 
 |                                      const std::string& path, | 
 |                                      std::string& service); | 
 |  | 
 | /** @brief Gets the dbus sub tree implementing the given interface. | 
 |  *  @param[in] ctx - ipmi::Context::ptr | 
 |  *  @param[in] bus - DBUS Bus Object. | 
 |  *  @param[in] interfaces - Dbus interface. | 
 |  *  @param[in] subtreePath - subtree from where the search should start. | 
 |  *  @param[in] depth - Search depth | 
 |  *  @param[out] objectTree - map of object path and service info. | 
 |  *  @return map of object path and service info. | 
 |  */ | 
 | boost::system::error_code getSubTree( | 
 |     Context::ptr ctx, const InterfaceList& interface, | 
 |     const std::string& subtreePath, int32_t depth, ObjectTree& objectTree); | 
 |  | 
 | /** @brief Gets the D-Bus object info implementing the given interface | 
 |  *         from the given subtree. | 
 |  *  @param[in] ctx - ipmi::Context::ptr | 
 |  *  @param[in] interface - D-Bus interface. | 
 |  *  @param[in][optional] subtreePath - subtree from where the search starts. | 
 |  *  @param[in][optional] match - identifier for object. | 
 |  *  @param[out] D-Bus object with path and service name | 
 |  *  @return - boost error code object | 
 |  */ | 
 | boost::system::error_code getDbusObject( | 
 |     Context::ptr ctx, const std::string& interface, | 
 |     const std::string& subtreePath, const std::string& match, | 
 |     DbusObjectInfo& dbusObject); | 
 |  | 
 | // default for ROOT for subtreePath and std::string{} for match | 
 | static inline boost::system::error_code getDbusObject( | 
 |     Context::ptr ctx, const std::string& interface, DbusObjectInfo& dbusObject) | 
 | { | 
 |     return getDbusObject(ctx, interface, ROOT, {}, dbusObject); | 
 | } | 
 |  | 
 | // default std::string{} for match | 
 | static inline boost::system::error_code getDbusObject( | 
 |     Context::ptr ctx, const std::string& interface, | 
 |     const std::string& subtreePath, DbusObjectInfo& dbusObject) | 
 | { | 
 |     return getDbusObject(ctx, interface, subtreePath, {}, dbusObject); | 
 | } | 
 |  | 
 | /** @brief Gets the value associated with the given object | 
 |  *         and the interface. | 
 |  *  @param[in] ctx - ipmi::Context::ptr | 
 |  *  @param[in] service - D-Bus service name. | 
 |  *  @param[in] objPath - D-Bus object path. | 
 |  *  @param[in] interface - D-Bus interface. | 
 |  *  @param[in] property - name of the property. | 
 |  *  @param[out] propertyValue - value of the D-Bus property. | 
 |  *  @return - boost error code object | 
 |  */ | 
 | template <typename Type> | 
 | boost::system::error_code getDbusProperty( | 
 |     Context::ptr ctx, const std::string& service, const std::string& objPath, | 
 |     const std::string& interface, const std::string& property, | 
 |     Type& propertyValue) | 
 | { | 
 |     boost::system::error_code ec; | 
 |     auto variant = ctx->bus->yield_method_call<std::variant<Type>>( | 
 |         ctx->yield, ec, service.c_str(), objPath.c_str(), PROP_INTF, METHOD_GET, | 
 |         interface, property); | 
 |     if (!ec) | 
 |     { | 
 |         Type* tmp = std::get_if<Type>(&variant); | 
 |         if (tmp) | 
 |         { | 
 |             propertyValue = *tmp; | 
 |             return ec; | 
 |         } | 
 |         // user requested incorrect type; make an error code for them | 
 |         ec = boost::system::errc::make_error_code( | 
 |             boost::system::errc::invalid_argument); | 
 |     } | 
 |     return ec; | 
 | } | 
 |  | 
 | /** @brief Gets all the properties associated with the given object | 
 |  *         and the interface. | 
 |  *  @param[in] ctx - ipmi::Context::ptr | 
 |  *  @param[in] service - D-Bus service name. | 
 |  *  @param[in] objPath - D-Bus object path. | 
 |  *  @param[in] interface - D-Bus interface. | 
 |  *  @param[out] properties - map of name value pair. | 
 |  *  @return - boost error code object | 
 |  */ | 
 | boost::system::error_code getAllDbusProperties( | 
 |     Context::ptr ctx, const std::string& service, const std::string& objPath, | 
 |     const std::string& interface, PropertyMap& properties); | 
 |  | 
 | /** @brief Sets the property value of the given object. | 
 |  *  @param[in] ctx - ipmi::Context::ptr | 
 |  *  @param[in] service - D-Bus service name. | 
 |  *  @param[in] objPath - D-Bus object path. | 
 |  *  @param[in] interface - D-Bus interface. | 
 |  *  @param[in] property - name of the property. | 
 |  *  @param[in] value - value which needs to be set. | 
 |  *  @return - boost error code object | 
 |  */ | 
 | boost::system::error_code setDbusProperty( | 
 |     Context::ptr ctx, const std::string& service, const std::string& objPath, | 
 |     const std::string& interface, const std::string& property, | 
 |     const Value& value); | 
 |  | 
 | /** @brief  Gets all the D-Bus objects from the given service root | 
 |  *          which matches the object identifier. | 
 |  *  @param[in] ctx - ipmi::Context::ptr | 
 |  *  @param[in] serviceRoot - Service root path. | 
 |  *  @param[in] interface - D-Bus interface. | 
 |  *  @param[in][optional] match - Identifier for a path. | 
 |  *  @param[out] objectree - map of object path and service info. | 
 |  *  @return - boost error code object | 
 |  */ | 
 | boost::system::error_code getAllDbusObjects( | 
 |     Context::ptr ctx, const std::string& serviceRoot, | 
 |     const std::string& interface, const std::string& match, | 
 |     ObjectTree& objectTree); | 
 |  | 
 | // default std::string{} for match | 
 | static inline boost::system::error_code getAllDbusObjects( | 
 |     Context::ptr ctx, const std::string& serviceRoot, | 
 |     const std::string& interface, ObjectTree& objectTree) | 
 | { | 
 |     return getAllDbusObjects(ctx, serviceRoot, interface, {}, objectTree); | 
 | } | 
 |  | 
 | /** @brief Gets all managed objects associated with the given object | 
 |  *         path and service. | 
 |  *  @param[in] ctx - ipmi::Context::ptr | 
 |  *  @param[in] service - D-Bus service name. | 
 |  *  @param[in] objPath - D-Bus object path. | 
 |  *  @param[out] objects - map of name value pair. | 
 |  *  @return - boost error code object | 
 |  */ | 
 | boost::system::error_code getManagedObjects( | 
 |     Context::ptr ctx, const std::string& service, const std::string& objPath, | 
 |     ObjectValueTree& objects); | 
 |  | 
 | /** @brief Gets the value associated with the given object | 
 |  *         and the interface. | 
 |  *  @param[in] ctx - ipmi::Context::ptr | 
 |  *  @param[in] service - D-Bus service name. | 
 |  *  @param[in] objPath - D-Bus object path. | 
 |  *  @param[in] interface - D-Bus interface. | 
 |  *  @param[in] method - name of the method. | 
 |  *  @return - boost error code object | 
 |  */ | 
 |  | 
 | boost::system::error_code callDbusMethod( | 
 |     Context::ptr ctx, const std::string& service, const std::string& objPath, | 
 |     const std::string& interface, const std::string& method); | 
 |  | 
 | /********* End co-routine yielding alternatives ***************/ | 
 |  | 
 | /** @brief Retrieve the value from map of variants, | 
 |  *         returning a default if the key does not exist or the | 
 |  *         type of the value does not match the expected type | 
 |  * | 
 |  *  @tparam T - type of expected value to return | 
 |  *  @param[in] props - D-Bus propery map (Map of variants) | 
 |  *  @param[in] name - key name of property to fetch | 
 |  *  @param[in] defaultValue - default value to return on error | 
 |  *  @return - value from propery map at name, or defaultValue | 
 |  */ | 
 | template <typename T> | 
 | T mappedVariant(const ipmi::PropertyMap& props, const std::string& name, | 
 |                 const T& defaultValue) | 
 | { | 
 |     auto item = props.find(name); | 
 |     if (item == props.end()) | 
 |     { | 
 |         return defaultValue; | 
 |     } | 
 |     const T* prop = std::get_if<T>(&item->second); | 
 |     if (!prop) | 
 |     { | 
 |         return defaultValue; | 
 |     } | 
 |     return *prop; | 
 | } | 
 |  | 
 | /** @struct VariantToDoubleVisitor | 
 |  *  @brief Visitor to convert variants to doubles | 
 |  *  @details Performs a static cast on the underlying type | 
 |  */ | 
 | struct VariantToDoubleVisitor | 
 | { | 
 |     template <typename T> | 
 |     std::enable_if_t<std::is_arithmetic<T>::value, double> operator()( | 
 |         const T& t) const | 
 |     { | 
 |         return static_cast<double>(t); | 
 |     } | 
 |  | 
 |     template <typename T> | 
 |     std::enable_if_t<!std::is_arithmetic<T>::value, double> operator()( | 
 |         const T&) const | 
 |     { | 
 |         throw std::invalid_argument("Cannot translate type to double"); | 
 |     } | 
 | }; | 
 |  | 
 | namespace method_no_args | 
 | { | 
 |  | 
 | /** @brief Calls the Dbus method which waits for response. | 
 |  *  @param[in] bus - DBUS Bus Object. | 
 |  *  @param[in] service - Dbus service name. | 
 |  *  @param[in] objPath - Dbus object path. | 
 |  *  @param[in] interface - Dbus interface. | 
 |  *  @param[in] method - Dbus method. | 
 |  */ | 
 | void callDbusMethod(sdbusplus::bus_t& bus, const std::string& service, | 
 |                     const std::string& objPath, const std::string& interface, | 
 |                     const std::string& method); | 
 |  | 
 | } // namespace method_no_args | 
 |  | 
 | template <typename... InputArgs> | 
 | boost::system::error_code callDbusMethod( | 
 |     ipmi::Context::ptr ctx, const std::string& service, | 
 |     const std::string& objPath, const std::string& interface, | 
 |     const std::string& method, const InputArgs&... args) | 
 | { | 
 |     boost::system::error_code ec; | 
 |     ctx->bus->yield_method_call(ctx->yield, ec, service, objPath, interface, | 
 |                                 method, args...); | 
 |  | 
 |     return ec; | 
 | } | 
 |  | 
 | template <typename RetType, typename... InputArgs> | 
 | RetType callDbusMethod(ipmi::Context::ptr ctx, boost::system::error_code& ec, | 
 |                        const std::string& service, const std::string& objPath, | 
 |                        const std::string& interface, const std::string& method, | 
 |                        const InputArgs&... args) | 
 | { | 
 |     auto rc = ctx->bus->yield_method_call<RetType>( | 
 |         ctx->yield, ec, service, objPath, interface, method, args...); | 
 |  | 
 |     return rc; | 
 | } | 
 |  | 
 | /** @brief Perform the low-level i2c bus write-read. | 
 |  *  @param[in] i2cBus - i2c bus device node name, such as /dev/i2c-2. | 
 |  *  @param[in] targetAddr - i2c device target address. | 
 |  *  @param[in] writeData - The data written to i2c device. | 
 |  *  @param[out] readBuf - Data read from the i2c device. | 
 |  */ | 
 | ipmi::Cc i2cWriteRead(std::string i2cBus, const uint8_t targetAddr, | 
 |                       std::vector<uint8_t> writeData, | 
 |                       std::vector<uint8_t>& readBuf); | 
 | } // namespace ipmi |