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