#include "associations.hpp" void removeAssociation(const std::string& sourcePath, const std::string& owner, sdbusplus::asio::object_server& server, AssociationOwnersType& assocOwners, AssociationInterfaces& assocInterfaces) { // Use associationOwners to find the association paths and endpoints // that the passed in object path and service own. Remove all of // these endpoints from the actual association D-Bus objects, and if // the endpoints property is then empty, the whole association object // can be removed. Note there can be multiple services that own an // association, and also that sourcePath is the path of the object // that contains the org.openbmc.Associations interface and not the // association path itself. // Find the services that have associations for this object path auto owners = assocOwners.find(sourcePath); if (owners == assocOwners.end()) { return; } // Find the association paths and endpoints owned by this object // path for this service. auto assocs = owners->second.find(owner); if (assocs == owners->second.end()) { return; } for (const auto& [assocPath, endpointsToRemove] : assocs->second) { removeAssociationEndpoints(server, assocPath, endpointsToRemove, assocInterfaces); } // Remove the associationOwners entries for this owning path/service. owners->second.erase(assocs); if (owners->second.empty()) { assocOwners.erase(owners); } } void removeAssociationEndpoints( sdbusplus::asio::object_server& objectServer, const std::string& assocPath, const boost::container::flat_set& endpointsToRemove, AssociationInterfaces& assocInterfaces) { auto assoc = assocInterfaces.find(assocPath); if (assoc == assocInterfaces.end()) { return; } auto& endpointsInDBus = std::get(assoc->second); for (const auto& endpointToRemove : endpointsToRemove) { auto e = std::find(endpointsInDBus.begin(), endpointsInDBus.end(), endpointToRemove); if (e != endpointsInDBus.end()) { endpointsInDBus.erase(e); } } if (endpointsInDBus.empty()) { objectServer.remove_interface(std::get(assoc->second)); std::get(assoc->second) = nullptr; std::get(assoc->second).clear(); } else { std::get(assoc->second) ->set_property("endpoints", endpointsInDBus); } } void checkAssociationEndpointRemoves( const std::string& sourcePath, const std::string& owner, const AssociationPaths& newAssociations, sdbusplus::asio::object_server& objectServer, AssociationOwnersType& assocOwners, AssociationInterfaces& assocInterfaces) { // Find the services that have associations on this path. auto originalOwners = assocOwners.find(sourcePath); if (originalOwners == assocOwners.end()) { return; } // Find the associations for this service auto originalAssociations = originalOwners->second.find(owner); if (originalAssociations == originalOwners->second.end()) { return; } // Compare the new endpoints versus the original endpoints, and // remove any of the original ones that aren't in the new list. for (const auto& [originalAssocPath, originalEndpoints] : originalAssociations->second) { // Check if this source even still has each association that // was there previously, and if not, remove all of its endpoints // from the D-Bus endpoints property which will cause the whole // association path to be removed if no endpoints remain. auto newEndpoints = newAssociations.find(originalAssocPath); if (newEndpoints == newAssociations.end()) { removeAssociationEndpoints(objectServer, originalAssocPath, originalEndpoints, assocInterfaces); } else { // The association is still there. Check if the endpoints // changed. boost::container::flat_set toRemove; for (auto& originalEndpoint : originalEndpoints) { if (std::find(newEndpoints->second.begin(), newEndpoints->second.end(), originalEndpoint) == newEndpoints->second.end()) { toRemove.emplace(originalEndpoint); } } if (!toRemove.empty()) { removeAssociationEndpoints(objectServer, originalAssocPath, toRemove, assocInterfaces); } } } }