1 #include "associations.hpp" 2 3 void removeAssociation(const std::string& sourcePath, const std::string& owner, 4 sdbusplus::asio::object_server& server, 5 AssociationOwnersType& assocOwners, 6 AssociationInterfaces& assocInterfaces) 7 { 8 // Use associationOwners to find the association paths and endpoints 9 // that the passed in object path and service own. Remove all of 10 // these endpoints from the actual association D-Bus objects, and if 11 // the endpoints property is then empty, the whole association object 12 // can be removed. Note there can be multiple services that own an 13 // association, and also that sourcePath is the path of the object 14 // that contains the org.openbmc.Associations interface and not the 15 // association path itself. 16 17 // Find the services that have associations for this object path 18 auto owners = assocOwners.find(sourcePath); 19 if (owners == assocOwners.end()) 20 { 21 return; 22 } 23 24 // Find the association paths and endpoints owned by this object 25 // path for this service. 26 auto assocs = owners->second.find(owner); 27 if (assocs == owners->second.end()) 28 { 29 return; 30 } 31 32 for (const auto& [assocPath, endpointsToRemove] : assocs->second) 33 { 34 removeAssociationEndpoints(server, assocPath, endpointsToRemove, 35 assocInterfaces); 36 } 37 38 // Remove the associationOwners entries for this owning path/service. 39 owners->second.erase(assocs); 40 if (owners->second.empty()) 41 { 42 assocOwners.erase(owners); 43 } 44 } 45 46 void removeAssociationEndpoints( 47 sdbusplus::asio::object_server& objectServer, const std::string& assocPath, 48 const boost::container::flat_set<std::string>& endpointsToRemove, 49 AssociationInterfaces& assocInterfaces) 50 { 51 auto assoc = assocInterfaces.find(assocPath); 52 if (assoc == assocInterfaces.end()) 53 { 54 return; 55 } 56 57 auto& endpointsInDBus = std::get<endpointsPos>(assoc->second); 58 59 for (const auto& endpointToRemove : endpointsToRemove) 60 { 61 auto e = std::find(endpointsInDBus.begin(), endpointsInDBus.end(), 62 endpointToRemove); 63 64 if (e != endpointsInDBus.end()) 65 { 66 endpointsInDBus.erase(e); 67 } 68 } 69 70 if (endpointsInDBus.empty()) 71 { 72 objectServer.remove_interface(std::get<ifacePos>(assoc->second)); 73 std::get<ifacePos>(assoc->second) = nullptr; 74 std::get<endpointsPos>(assoc->second).clear(); 75 } 76 else 77 { 78 std::get<ifacePos>(assoc->second) 79 ->set_property("endpoints", endpointsInDBus); 80 } 81 } 82 83 void checkAssociationEndpointRemoves( 84 const std::string& sourcePath, const std::string& owner, 85 const AssociationPaths& newAssociations, 86 sdbusplus::asio::object_server& objectServer, 87 AssociationOwnersType& assocOwners, AssociationInterfaces& assocInterfaces) 88 { 89 // Find the services that have associations on this path. 90 auto originalOwners = assocOwners.find(sourcePath); 91 if (originalOwners == assocOwners.end()) 92 { 93 return; 94 } 95 96 // Find the associations for this service 97 auto originalAssociations = originalOwners->second.find(owner); 98 if (originalAssociations == originalOwners->second.end()) 99 { 100 return; 101 } 102 103 // Compare the new endpoints versus the original endpoints, and 104 // remove any of the original ones that aren't in the new list. 105 for (const auto& [originalAssocPath, originalEndpoints] : 106 originalAssociations->second) 107 { 108 // Check if this source even still has each association that 109 // was there previously, and if not, remove all of its endpoints 110 // from the D-Bus endpoints property which will cause the whole 111 // association path to be removed if no endpoints remain. 112 auto newEndpoints = newAssociations.find(originalAssocPath); 113 if (newEndpoints == newAssociations.end()) 114 { 115 removeAssociationEndpoints(objectServer, originalAssocPath, 116 originalEndpoints, assocInterfaces); 117 } 118 else 119 { 120 // The association is still there. Check if the endpoints 121 // changed. 122 boost::container::flat_set<std::string> toRemove; 123 124 for (auto& originalEndpoint : originalEndpoints) 125 { 126 if (std::find(newEndpoints->second.begin(), 127 newEndpoints->second.end(), 128 originalEndpoint) == newEndpoints->second.end()) 129 { 130 toRemove.emplace(originalEndpoint); 131 } 132 } 133 if (!toRemove.empty()) 134 { 135 removeAssociationEndpoints(objectServer, originalAssocPath, 136 toRemove, assocInterfaces); 137 } 138 } 139 } 140 } 141