| #ifndef THIRD_PARTY_GBMCWEB_REDFISH_CORE_INCLUDE_UTILS_DBUS_UTILS_H_ |
| #define THIRD_PARTY_GBMCWEB_REDFISH_CORE_INCLUDE_UTILS_DBUS_UTILS_H_ |
| |
| #include <algorithm> |
| #include <cstdint> |
| #include <functional> |
| #include <set> |
| #include <span> // NOLINT |
| #include <string> |
| #include <string_view> |
| #include <type_traits> |
| #include <unordered_map> |
| #include <utility> |
| #include <variant> |
| #include <vector> |
| |
| #include "logging.hpp" |
| #include "dbus_utility.hpp" |
| #include "managed_store.hpp" |
| #include "managed_store_types.hpp" |
| #include "sdbusplus/exception.hpp" |
| #include "sdbusplus/message/native_types.hpp" |
| // Remove unpack_properties header. Have to have this header |
| // now since there are other files indirectly depending on this header and they |
| // haven't been ported to g3 yet. |
| #include "sdbusplus/unpack_properties.hpp" // NOLINT |
| |
| #ifdef UNIT_TEST_BUILD |
| #include "test/g3/mock_managed_store.hpp" // NOLINT |
| #endif |
| |
| namespace redfish { |
| namespace dbus_utils { |
| |
| struct UnpackErrorPrinter { |
| void operator()(const sdbusplus::UnpackErrorReason reason, |
| const std::string& property) const noexcept { |
| BMCWEB_LOG_ERROR |
| << "DBUS property error in property: " << property << ", reason: " |
| << static_cast<std::underlying_type_t<sdbusplus::UnpackErrorReason>>( |
| reason); |
| } |
| }; |
| |
| inline void getPropertiesFromManagedObjects( |
| const dbus::utility::ManagedObjectType& managedObjects, |
| const std::string& objPath, const std::string& interface, |
| dbus::utility::DBusPropertiesMap& properties) { |
| for (const auto& object : managedObjects) { |
| if (object.first.str != objPath) { |
| continue; |
| } |
| |
| for (const auto& interface_map : object.second) { |
| if (interface_map.first != interface) { |
| continue; |
| } |
| properties = interface_map.second; |
| } |
| } |
| } |
| |
| // Populates |serviceNames| list with unique services found in the given |
| // subtree. |
| inline std::vector<std::string> getServiceNamesFromSubtree( |
| const dbus::utility::MapperGetSubTreeResponse& subtree) { |
| std::set<std::string> unique_service_names; |
| for (const auto& [_, serviceMap] : subtree) { |
| for (const auto& service_pair : serviceMap) { |
| unique_service_names.insert(service_pair.first); |
| } |
| } |
| return {unique_service_names.begin(), unique_service_names.end()}; |
| } |
| |
| // Checks if any one of given interfaces is present in the service map. |
| inline bool findInterfacesInServiceMap( |
| const dbus::utility::MapperServiceMap& serviceMap, |
| std::span<const std::string_view> interfaces) { |
| for (const auto& [service_name, interfaceList] : serviceMap) { // NOLINT |
| if (std::find_first_of(interfaceList.begin(), interfaceList.end(), |
| interfaces.begin(), |
| interfaces.end()) != interfaceList.end()) { |
| return true; |
| } |
| } |
| return false; |
| } |
| |
| /** |
| * Recursively gets managed objects under given object path from each service in |
| * the given list of service names and maps objects to the service name they |
| * originate from. |
| * |
| * @param[in] serviceList Mutable list of unique service names. |
| * @param[in] objPath Managed objects are requested relative |
| * to this path. |
| * @param[in,out] managed_objects_by_service Service name to managed objects |
| * map. |
| * @param[in] callback Callback to execute after getting |
| * managed objects from all service names |
| * in the list. |
| */ |
| template <typename Callback> |
| inline void getManagedObjectsInEachServiceCallback( |
| std::vector<std::string>&& serviceList, |
| const sdbusplus::message::object_path& objPath, |
| std::unordered_map<std::string, dbus::utility::ManagedObjectType>&& |
| managed_objects_by_service, |
| const managedStore::ManagedObjectStoreContext& context, |
| Callback&& callback) { |
| BMCWEB_LOG_DEBUG << "GetManagedObjects from next service in list."; |
| if (serviceList.empty()) { |
| BMCWEB_LOG_DEBUG << "Recieved managed objects from all services."; |
| callback(managed_objects_by_service); |
| return; |
| } |
| std::string service_name = serviceList.back(); |
| serviceList.pop_back(); |
| |
| managedStore::GetManagedObjectStore()->getManagedObjectsWithContext( |
| service_name, objPath, context, |
| [serviceList{std::move(serviceList)}, service_name, objPath, |
| managed_objects_by_service{std::move(managed_objects_by_service)}, |
| context = context, callback{std::forward<Callback>(callback)}]( |
| const boost::system::error_code& ec, |
| const dbus::utility::ManagedObjectType& managedObjects) mutable { |
| if (!ec) { |
| managed_objects_by_service[service_name] = managedObjects; |
| } |
| getManagedObjectsInEachServiceCallback( |
| std::move(serviceList), objPath, |
| std::move(managed_objects_by_service), context, |
| std::forward<decltype(callback)>(callback)); |
| }); |
| } |
| |
| /** |
| * Gets managed objects under given object path from each service in the given |
| * list of service names. |
| * |
| * @param[in] serviceList Mutable list of unique service names. |
| * @param[in] objPath Managed objects are requested relative |
| * to this path. |
| * @param[in] callback Callback to execute after getting |
| * managed objects from all service names |
| * in the list. |
| */ |
| template <typename Callback> |
| inline void getManagedObjectsInEachService( |
| std::vector<std::string>&& serviceList, |
| const sdbusplus::message::object_path& objPath, |
| const managedStore::ManagedObjectStoreContext& context, |
| Callback&& callback) { |
| BMCWEB_LOG_DEBUG << "Requesting managed objects from given list of " |
| << "services "; |
| std::unordered_map<std::string, dbus::utility::ManagedObjectType> |
| managed_objects_by_service; |
| if (serviceList.empty()) { |
| BMCWEB_LOG_ERROR << "Service list is empty"; |
| callback(managed_objects_by_service); |
| return; |
| } |
| std::string service_name = serviceList.back(); |
| serviceList.pop_back(); |
| |
| managedStore::GetManagedObjectStore()->getManagedObjectsWithContext( |
| service_name, objPath, context, |
| [serviceList{std::move(serviceList)}, service_name, objPath, |
| managed_objects_by_service{std::move(managed_objects_by_service)}, |
| context = context, callback{std::forward<Callback>(callback)}]( |
| const boost::system::error_code& ec, |
| const dbus::utility::ManagedObjectType& managedObjects) mutable { |
| if (!ec) { |
| managed_objects_by_service[service_name] = managedObjects; |
| } |
| getManagedObjectsInEachServiceCallback( |
| std::move(serviceList), objPath, |
| std::move(managed_objects_by_service), context, |
| std::forward<decltype(callback)>(callback)); |
| }); |
| } |
| |
| template <typename PropertyType> |
| void getProperty(const std::string& service, const std::string& path, |
| const std::string& interface, const std::string& property, |
| const managedStore::ManagedObjectStoreContext& requestContext, |
| std::function<void(const boost::system::error_code&, |
| const PropertyType&)>&& callback) { |
| managedStore::KeyType key_type(managedStore::ManagedType::kManagedProperty, |
| service, {path}, interface, property); |
| BMCWEB_LOG_STATEFUL_DEBUG << "getProperty: Key " << key_type.toString() |
| << " requestContext " << requestContext.toString(); |
| |
| managedStore::GetManagedObjectStore()->getProperty( |
| key_type, requestContext, |
| [callback{std::move(callback)}]( |
| const boost::system::error_code& ec, |
| const dbus::utility::DbusVariantType& managedProperty, |
| [[maybe_unused]] uint64_t age_ms) { |
| if (ec) { |
| callback(ec, {}); |
| return; |
| } |
| const PropertyType* propertyValue = |
| std::get_if<PropertyType>(&managedProperty); |
| if (propertyValue) { |
| callback(ec, *propertyValue); |
| return; |
| } |
| callback(boost::system::errc::make_error_code( |
| boost::system::errc::invalid_argument), |
| {}); |
| }); |
| } |
| |
| template <typename PropertyType> |
| void getProperty( |
| const std::string& service, const std::string& path, |
| const std::string& interface, const std::string& property, |
| const managedStore::ManagedObjectStoreContext& requestContext, |
| std::function<void(const boost::system::error_code&, const PropertyType&, |
| uint64_t)>&& callback) { |
| managedStore::KeyType key_type(managedStore::ManagedType::kManagedProperty, |
| service, {path}, interface, property); |
| BMCWEB_LOG_STATEFUL_DEBUG << "getProperty: Key " << key_type.toString() |
| << " requestContext " << requestContext.toString(); |
| |
| managedStore::GetManagedObjectStore()->getProperty( |
| key_type, requestContext, |
| [callback{std::move(callback)}]( |
| const boost::system::error_code& ec, |
| const dbus::utility::DbusVariantType& managedProperty, |
| uint64_t age_ms) { |
| if (ec) { |
| callback(ec, {}, 0); |
| return; |
| } |
| const PropertyType* propertyValue = |
| std::get_if<PropertyType>(&managedProperty); |
| if (propertyValue) { |
| callback(ec, *propertyValue, age_ms); |
| return; |
| } |
| callback(boost::system::errc::make_error_code( |
| boost::system::errc::invalid_argument), |
| {}, 0); |
| }); |
| } |
| |
| inline void getAssociationEndPoints( |
| const std::string& path, |
| const managedStore::ManagedObjectStoreContext& requestContext, |
| std::function<void(const boost::system::error_code&, |
| const dbus::utility::MapperEndPoints&)>&& callback) { |
| getProperty<dbus::utility::MapperEndPoints>( |
| "xyz.openbmc_project.ObjectMapper", {path}, |
| "xyz.openbmc_project.Association", "endpoints", requestContext, |
| std::move(callback)); |
| } |
| |
| template <typename Callback> |
| inline void checkDbusPathExists( |
| const std::string& path, |
| const managedStore::ManagedObjectStoreContext& context, |
| Callback&& callback) { |
| managedStore::GetManagedObjectStore()->getDbusObject( |
| path, {}, context, |
| [callback{std::forward<Callback>(callback)}]( |
| const boost::system::error_code& ec, |
| const dbus::utility::MapperGetObject& objectNames) { |
| callback(!ec && !objectNames.empty()); |
| }); |
| } |
| |
| template <typename Callback> |
| inline void getAssociatedSubTree( |
| const sdbusplus::message::object_path& associatedPath, |
| const sdbusplus::message::object_path& path, int32_t depth, |
| std::span<const std::string_view> interfaces, |
| const managedStore::ManagedObjectStoreContext& context, |
| Callback&& callback) { |
| managedStore::GetManagedObjectStore()->getAssociatedSubTree( |
| associatedPath, path, depth, interfaces, context, |
| std::forward<Callback>(callback)); |
| } |
| |
| template <typename Callback> |
| inline void getAssociatedSubTreePaths( |
| const sdbusplus::message::object_path& associatedPath, |
| const sdbusplus::message::object_path& path, int32_t depth, |
| std::span<const std::string_view> interfaces, |
| const managedStore::ManagedObjectStoreContext& context, |
| Callback&& callback) { |
| managedStore::GetManagedObjectStore()->getAssociatedSubTreePaths( |
| associatedPath, path, depth, interfaces, context, |
| std::forward<Callback>(callback)); |
| } |
| |
| template <typename Callback> |
| inline void getSubTree(const std::string& path, int32_t depth, |
| std::span<const std::string_view> interfaces, |
| const managedStore::ManagedObjectStoreContext& context, |
| Callback&& callback) { |
| managedStore::GetManagedObjectStore()->getSubTree( |
| path, depth, interfaces, context, std::forward<Callback>(callback)); |
| } |
| |
| // Overload to support span of strings for interface names. |
| template <typename Callback> |
| inline void getSubTree(const std::string& path, int32_t depth, |
| std::span<std::string> interfaces, |
| const managedStore::ManagedObjectStoreContext& context, |
| Callback&& callback) { |
| managedStore::GetManagedObjectStore()->getSubTree( |
| path, depth, interfaces, context, std::forward<Callback>(callback)); |
| } |
| |
| template <typename Callback> |
| inline void getSubTreePaths( |
| const std::string& path, int32_t depth, |
| std::span<const std::string_view> interfaces, |
| const managedStore::ManagedObjectStoreContext& context, |
| Callback&& callback) { |
| managedStore::GetManagedObjectStore()->getSubTreePaths( |
| path, depth, interfaces, context, std::forward<Callback>(callback)); |
| } |
| |
| template <typename Callback> |
| inline void getManagedObjects( |
| const std::string& service, const sdbusplus::message::object_path& path, |
| const managedStore::ManagedObjectStoreContext& context, |
| Callback&& callback) { |
| managedStore::GetManagedObjectStore()->getManagedObjectsWithContext( |
| service, path, context, std::forward<Callback>(callback)); |
| } |
| |
| template <typename Callback> |
| inline void getDbusObject( |
| const std::string& path, std::span<const std::string_view> interfaces, |
| const managedStore::ManagedObjectStoreContext& context, |
| Callback&& callback) { |
| managedStore::GetManagedObjectStore()->getDbusObject( |
| path, interfaces, context, std::forward<Callback>(callback)); |
| } |
| |
| } // namespace dbus_utils |
| } // namespace redfish |
| |
| #endif // THIRD_PARTY_GBMCWEB_REDFISH_CORE_INCLUDE_UTILS_DBUS_UTILS_H_ |