blob: 346cebd4e8e6a2144abeab2d365d5db58a387247 [file] [log] [blame]
Andrew Geisslera80a3af2019-02-04 14:01:49 -06001#include "associations.hpp"
2
Kallas, Pawel5b4357d2022-10-12 15:36:37 +02003#include <boost/asio/steady_timer.hpp>
Lei YUb89c6612021-07-22 15:59:52 +08004#include <sdbusplus/exception.hpp>
Andrew Geissler4511b332019-02-21 15:40:40 -06005
Brad Bishop23520882022-05-26 21:39:53 -04006#include <iostream>
Brad Bishop86d28802022-07-11 15:49:31 -04007#include <string>
Brad Bishop23520882022-05-26 21:39:53 -04008
Kallas, Pawel5b4357d2022-10-12 15:36:37 +02009void updateEndpointsOnDbus(sdbusplus::asio::object_server& objectServer,
10 const std::string& assocPath,
11 AssociationMaps& assocMaps)
12{
13 auto& iface = assocMaps.ifaces[assocPath];
14 auto& i = std::get<ifacePos>(iface);
15 auto& endpoints = std::get<endpointsPos>(iface);
16
17 // If the interface already exists, only need to update
18 // the property value, otherwise create it
19 if (i)
20 {
21 if (endpoints.empty())
22 {
23 objectServer.remove_interface(i);
24 i = nullptr;
25 }
26 else
27 {
28 i->set_property("endpoints", endpoints);
29 }
30 }
31 else
32 {
33 if (!endpoints.empty())
34 {
35 i = objectServer.add_interface(assocPath, xyzAssociationInterface);
36 i->register_property("endpoints", endpoints);
37 i->initialize();
38 }
39 }
40}
41
42void scheduleUpdateEndpointsOnDbus(boost::asio::io_context& io,
43 sdbusplus::asio::object_server& objectServer,
44 const std::string& assocPath,
45 AssociationMaps& assocMaps)
46{
47 static std::set<std::string> delayedUpdatePaths;
48
49 if (delayedUpdatePaths.contains(assocPath))
50 {
51 return;
52 }
53
54 auto& iface = assocMaps.ifaces[assocPath];
55 auto& endpoints = std::get<endpointsPos>(iface);
56
57 if (endpoints.size() > endpointsCountTimerThreshold)
58 {
59 delayedUpdatePaths.emplace(assocPath);
60 auto timer = std::make_shared<boost::asio::steady_timer>(
61 io, std::chrono::seconds(endpointUpdateDelaySeconds));
62 timer->async_wait([&objectServer, &assocMaps, timer,
63 assocPath](const boost::system::error_code& ec) {
64 if (!ec)
65 {
66 updateEndpointsOnDbus(objectServer, assocPath, assocMaps);
67 }
68 delayedUpdatePaths.erase(assocPath);
69 });
70 }
71 else
72 {
73 updateEndpointsOnDbus(objectServer, assocPath, assocMaps);
74 }
75}
76
77void removeAssociation(boost::asio::io_context& io,
78 const std::string& sourcePath, const std::string& owner,
Andrew Geisslera80a3af2019-02-04 14:01:49 -060079 sdbusplus::asio::object_server& server,
Matt Spinlere2359fb2019-04-05 14:11:33 -050080 AssociationMaps& assocMaps)
Andrew Geisslera80a3af2019-02-04 14:01:49 -060081{
82 // Use associationOwners to find the association paths and endpoints
83 // that the passed in object path and service own. Remove all of
84 // these endpoints from the actual association D-Bus objects, and if
85 // the endpoints property is then empty, the whole association object
86 // can be removed. Note there can be multiple services that own an
87 // association, and also that sourcePath is the path of the object
88 // that contains the org.openbmc.Associations interface and not the
89 // association path itself.
90
91 // Find the services that have associations for this object path
Matt Spinlere2359fb2019-04-05 14:11:33 -050092 auto owners = assocMaps.owners.find(sourcePath);
93 if (owners == assocMaps.owners.end())
Andrew Geisslera80a3af2019-02-04 14:01:49 -060094 {
95 return;
96 }
97
98 // Find the association paths and endpoints owned by this object
99 // path for this service.
100 auto assocs = owners->second.find(owner);
101 if (assocs == owners->second.end())
102 {
103 return;
104 }
105
106 for (const auto& [assocPath, endpointsToRemove] : assocs->second)
107 {
Kallas, Pawel5b4357d2022-10-12 15:36:37 +0200108 removeAssociationEndpoints(io, server, assocPath, endpointsToRemove,
Matt Spinlere2359fb2019-04-05 14:11:33 -0500109 assocMaps);
Andrew Geisslera80a3af2019-02-04 14:01:49 -0600110 }
111
112 // Remove the associationOwners entries for this owning path/service.
113 owners->second.erase(assocs);
114 if (owners->second.empty())
115 {
Matt Spinlere2359fb2019-04-05 14:11:33 -0500116 assocMaps.owners.erase(owners);
Andrew Geisslera80a3af2019-02-04 14:01:49 -0600117 }
Matt Spinlercb9bcdb2019-04-08 10:58:49 -0500118
119 // If we were still waiting on the other side of this association to
120 // show up, cancel that wait.
121 removeFromPendingAssociations(sourcePath, assocMaps);
Andrew Geisslera80a3af2019-02-04 14:01:49 -0600122}
Andrew Geisslerff5ce922019-02-21 12:43:09 -0600123
124void removeAssociationEndpoints(
Kallas, Pawel5b4357d2022-10-12 15:36:37 +0200125 boost::asio::io_context& io, sdbusplus::asio::object_server& objectServer,
126 const std::string& assocPath,
Andrew Geisslerff5ce922019-02-21 12:43:09 -0600127 const boost::container::flat_set<std::string>& endpointsToRemove,
Matt Spinlere2359fb2019-04-05 14:11:33 -0500128 AssociationMaps& assocMaps)
Andrew Geisslerff5ce922019-02-21 12:43:09 -0600129{
Matt Spinlere2359fb2019-04-05 14:11:33 -0500130 auto assoc = assocMaps.ifaces.find(assocPath);
131 if (assoc == assocMaps.ifaces.end())
Andrew Geisslerff5ce922019-02-21 12:43:09 -0600132 {
133 return;
134 }
135
136 auto& endpointsInDBus = std::get<endpointsPos>(assoc->second);
137
138 for (const auto& endpointToRemove : endpointsToRemove)
139 {
140 auto e = std::find(endpointsInDBus.begin(), endpointsInDBus.end(),
141 endpointToRemove);
142
143 if (e != endpointsInDBus.end())
144 {
145 endpointsInDBus.erase(e);
146 }
147 }
148
Kallas, Pawel5b4357d2022-10-12 15:36:37 +0200149 scheduleUpdateEndpointsOnDbus(io, objectServer, assocPath, assocMaps);
Andrew Geisslerff5ce922019-02-21 12:43:09 -0600150}
Andrew Geissler7f1c44d2019-02-21 13:44:16 -0600151
152void checkAssociationEndpointRemoves(
Kallas, Pawel5b4357d2022-10-12 15:36:37 +0200153 boost::asio::io_context& io, const std::string& sourcePath,
154 const std::string& owner, const AssociationPaths& newAssociations,
Matt Spinlere2359fb2019-04-05 14:11:33 -0500155 sdbusplus::asio::object_server& objectServer, AssociationMaps& assocMaps)
Andrew Geissler7f1c44d2019-02-21 13:44:16 -0600156{
157 // Find the services that have associations on this path.
Matt Spinlere2359fb2019-04-05 14:11:33 -0500158 auto originalOwners = assocMaps.owners.find(sourcePath);
159 if (originalOwners == assocMaps.owners.end())
Andrew Geissler7f1c44d2019-02-21 13:44:16 -0600160 {
161 return;
162 }
163
164 // Find the associations for this service
165 auto originalAssociations = originalOwners->second.find(owner);
166 if (originalAssociations == originalOwners->second.end())
167 {
168 return;
169 }
170
171 // Compare the new endpoints versus the original endpoints, and
172 // remove any of the original ones that aren't in the new list.
173 for (const auto& [originalAssocPath, originalEndpoints] :
174 originalAssociations->second)
175 {
176 // Check if this source even still has each association that
177 // was there previously, and if not, remove all of its endpoints
178 // from the D-Bus endpoints property which will cause the whole
179 // association path to be removed if no endpoints remain.
180 auto newEndpoints = newAssociations.find(originalAssocPath);
181 if (newEndpoints == newAssociations.end())
182 {
Kallas, Pawel5b4357d2022-10-12 15:36:37 +0200183 removeAssociationEndpoints(io, objectServer, originalAssocPath,
Matt Spinlere2359fb2019-04-05 14:11:33 -0500184 originalEndpoints, assocMaps);
Andrew Geissler7f1c44d2019-02-21 13:44:16 -0600185 }
186 else
187 {
188 // The association is still there. Check if the endpoints
189 // changed.
190 boost::container::flat_set<std::string> toRemove;
191
Brad Bishop1f623802022-05-31 18:22:10 -0400192 for (const auto& originalEndpoint : originalEndpoints)
Andrew Geissler7f1c44d2019-02-21 13:44:16 -0600193 {
194 if (std::find(newEndpoints->second.begin(),
195 newEndpoints->second.end(),
196 originalEndpoint) == newEndpoints->second.end())
197 {
198 toRemove.emplace(originalEndpoint);
199 }
200 }
201 if (!toRemove.empty())
202 {
Kallas, Pawel5b4357d2022-10-12 15:36:37 +0200203 removeAssociationEndpoints(io, objectServer, originalAssocPath,
Matt Spinlere2359fb2019-04-05 14:11:33 -0500204 toRemove, assocMaps);
Andrew Geissler7f1c44d2019-02-21 13:44:16 -0600205 }
206 }
207 }
208}
Andrew Geissler4511b332019-02-21 15:40:40 -0600209
Matt Spinler11401e22019-04-08 13:13:25 -0500210void addEndpointsToAssocIfaces(
Kallas, Pawel5b4357d2022-10-12 15:36:37 +0200211 boost::asio::io_context& io, sdbusplus::asio::object_server& objectServer,
212 const std::string& assocPath,
Matt Spinler11401e22019-04-08 13:13:25 -0500213 const boost::container::flat_set<std::string>& endpointPaths,
214 AssociationMaps& assocMaps)
215{
216 auto& iface = assocMaps.ifaces[assocPath];
Matt Spinler11401e22019-04-08 13:13:25 -0500217 auto& endpoints = std::get<endpointsPos>(iface);
218
219 // Only add new endpoints
Brad Bishop1f623802022-05-31 18:22:10 -0400220 for (const auto& e : endpointPaths)
Matt Spinler11401e22019-04-08 13:13:25 -0500221 {
222 if (std::find(endpoints.begin(), endpoints.end(), e) == endpoints.end())
223 {
224 endpoints.push_back(e);
225 }
226 }
Kallas, Pawel5b4357d2022-10-12 15:36:37 +0200227 scheduleUpdateEndpointsOnDbus(io, objectServer, assocPath, assocMaps);
Matt Spinler11401e22019-04-08 13:13:25 -0500228}
229
Kallas, Pawel5b4357d2022-10-12 15:36:37 +0200230void associationChanged(boost::asio::io_context& io,
231 sdbusplus::asio::object_server& objectServer,
Andrew Geissler4511b332019-02-21 15:40:40 -0600232 const std::vector<Association>& associations,
233 const std::string& path, const std::string& owner,
Brad Bishopa098a372022-05-05 15:19:04 -0400234 const InterfaceMapType& interfaceMap,
Matt Spinlere2359fb2019-04-05 14:11:33 -0500235 AssociationMaps& assocMaps)
Andrew Geissler4511b332019-02-21 15:40:40 -0600236{
237 AssociationPaths objects;
238
239 for (const Association& association : associations)
240 {
241 std::string forward;
242 std::string reverse;
Brad Bishop1f623802022-05-31 18:22:10 -0400243 std::string objectPath;
244 std::tie(forward, reverse, objectPath) = association;
Andrew Geissler4511b332019-02-21 15:40:40 -0600245
Brad Bishop1f623802022-05-31 18:22:10 -0400246 if (objectPath.empty())
Andrew Geissler0a560a52019-03-22 10:59:07 -0500247 {
248 std::cerr << "Found invalid association on path " << path << "\n";
249 continue;
250 }
Matt Spinlere0b0e3a2019-04-08 10:39:23 -0500251
252 // Can't create this association if the endpoint isn't on D-Bus.
Brad Bishop1f623802022-05-31 18:22:10 -0400253 if (interfaceMap.find(objectPath) == interfaceMap.end())
Matt Spinlere0b0e3a2019-04-08 10:39:23 -0500254 {
Brad Bishop1f623802022-05-31 18:22:10 -0400255 addPendingAssociation(objectPath, reverse, path, forward, owner,
Matt Spinlere0b0e3a2019-04-08 10:39:23 -0500256 assocMaps);
257 continue;
258 }
259
Brad Bishop1f623802022-05-31 18:22:10 -0400260 if (!forward.empty())
Andrew Geissler4511b332019-02-21 15:40:40 -0600261 {
Brad Bishop1f623802022-05-31 18:22:10 -0400262 objects[path + "/" + forward].emplace(objectPath);
Andrew Geissler4511b332019-02-21 15:40:40 -0600263 }
Brad Bishop1f623802022-05-31 18:22:10 -0400264 if (!reverse.empty())
Andrew Geissler4511b332019-02-21 15:40:40 -0600265 {
Brad Bishop1f623802022-05-31 18:22:10 -0400266 objects[objectPath + "/" + reverse].emplace(path);
Andrew Geissler4511b332019-02-21 15:40:40 -0600267 }
268 }
269 for (const auto& object : objects)
270 {
Kallas, Pawel5b4357d2022-10-12 15:36:37 +0200271 addEndpointsToAssocIfaces(io, objectServer, object.first, object.second,
Matt Spinler11401e22019-04-08 13:13:25 -0500272 assocMaps);
Andrew Geissler4511b332019-02-21 15:40:40 -0600273 }
274
275 // Check for endpoints being removed instead of added
Kallas, Pawel5b4357d2022-10-12 15:36:37 +0200276 checkAssociationEndpointRemoves(io, path, owner, objects, objectServer,
Matt Spinlere2359fb2019-04-05 14:11:33 -0500277 assocMaps);
Andrew Geissler4511b332019-02-21 15:40:40 -0600278
Matt Spinlere0b0e3a2019-04-08 10:39:23 -0500279 if (!objects.empty())
Andrew Geissler4511b332019-02-21 15:40:40 -0600280 {
Matt Spinlere0b0e3a2019-04-08 10:39:23 -0500281 // Update associationOwners with the latest info
282 auto a = assocMaps.owners.find(path);
283 if (a != assocMaps.owners.end())
Andrew Geissler4511b332019-02-21 15:40:40 -0600284 {
Matt Spinlere0b0e3a2019-04-08 10:39:23 -0500285 auto o = a->second.find(owner);
286 if (o != a->second.end())
287 {
288 o->second = std::move(objects);
289 }
290 else
291 {
292 a->second.emplace(owner, std::move(objects));
293 }
Andrew Geissler4511b332019-02-21 15:40:40 -0600294 }
295 else
296 {
Matt Spinlere0b0e3a2019-04-08 10:39:23 -0500297 boost::container::flat_map<std::string, AssociationPaths> owners;
298 owners.emplace(owner, std::move(objects));
299 assocMaps.owners.emplace(path, owners);
Andrew Geissler4511b332019-02-21 15:40:40 -0600300 }
301 }
Matt Spinlere0b0e3a2019-04-08 10:39:23 -0500302}
303
304void addPendingAssociation(const std::string& objectPath,
305 const std::string& type,
306 const std::string& endpointPath,
307 const std::string& endpointType,
308 const std::string& owner, AssociationMaps& assocMaps)
309{
310 Association assoc{type, endpointType, endpointPath};
311
312 auto p = assocMaps.pending.find(objectPath);
313 if (p == assocMaps.pending.end())
314 {
315 ExistingEndpoints ee;
316 ee.emplace_back(owner, std::move(assoc));
317 assocMaps.pending.emplace(objectPath, std::move(ee));
318 }
Andrew Geissler4511b332019-02-21 15:40:40 -0600319 else
320 {
Matt Spinlere0b0e3a2019-04-08 10:39:23 -0500321 // Already waiting on this path for another association,
322 // so just add this endpoint and owner.
323 auto& endpoints = p->second;
324 auto e =
325 std::find_if(endpoints.begin(), endpoints.end(),
326 [&assoc, &owner](const auto& endpoint) {
327 return (std::get<ownerPos>(endpoint) == owner) &&
328 (std::get<assocPos>(endpoint) == assoc);
329 });
330 if (e == endpoints.end())
331 {
332 endpoints.emplace_back(owner, std::move(assoc));
333 }
Andrew Geissler4511b332019-02-21 15:40:40 -0600334 }
335}
Matt Spinlercb9bcdb2019-04-08 10:58:49 -0500336
337void removeFromPendingAssociations(const std::string& endpointPath,
338 AssociationMaps& assocMaps)
339{
340 auto assoc = assocMaps.pending.begin();
341 while (assoc != assocMaps.pending.end())
342 {
343 auto endpoint = assoc->second.begin();
344 while (endpoint != assoc->second.end())
345 {
346 auto& e = std::get<assocPos>(*endpoint);
347 if (std::get<reversePathPos>(e) == endpointPath)
348 {
349 endpoint = assoc->second.erase(endpoint);
350 continue;
351 }
352
353 endpoint++;
354 }
355
356 if (assoc->second.empty())
357 {
358 assoc = assocMaps.pending.erase(assoc);
359 continue;
360 }
361
362 assoc++;
363 }
364}
Matt Spinler11401e22019-04-08 13:13:25 -0500365
Kallas, Pawel5b4357d2022-10-12 15:36:37 +0200366void addSingleAssociation(boost::asio::io_context& io,
367 sdbusplus::asio::object_server& server,
Matt Spinler11401e22019-04-08 13:13:25 -0500368 const std::string& assocPath,
369 const std::string& endpoint, const std::string& owner,
370 const std::string& ownerPath,
371 AssociationMaps& assocMaps)
372{
373 boost::container::flat_set<std::string> endpoints{endpoint};
374
Kallas, Pawel5b4357d2022-10-12 15:36:37 +0200375 addEndpointsToAssocIfaces(io, server, assocPath, endpoints, assocMaps);
Matt Spinler11401e22019-04-08 13:13:25 -0500376
377 AssociationPaths objects;
378 boost::container::flat_set e{endpoint};
379 objects.emplace(assocPath, e);
380
381 auto a = assocMaps.owners.find(ownerPath);
382 if (a != assocMaps.owners.end())
383 {
384 auto o = a->second.find(owner);
385 if (o != a->second.end())
386 {
387 auto p = o->second.find(assocPath);
388 if (p != o->second.end())
389 {
390 p->second.emplace(endpoint);
391 }
392 else
393 {
394 o->second.emplace(assocPath, e);
395 }
396 }
397 else
398 {
399 a->second.emplace(owner, std::move(objects));
400 }
401 }
402 else
403 {
404 boost::container::flat_map<std::string, AssociationPaths> owners;
405 owners.emplace(owner, std::move(objects));
406 assocMaps.owners.emplace(endpoint, owners);
407 }
408}
409
Kallas, Pawel5b4357d2022-10-12 15:36:37 +0200410void checkIfPendingAssociation(boost::asio::io_context& io,
411 const std::string& objectPath,
Brad Bishopa098a372022-05-05 15:19:04 -0400412 const InterfaceMapType& interfaceMap,
Matt Spinler11401e22019-04-08 13:13:25 -0500413 AssociationMaps& assocMaps,
414 sdbusplus::asio::object_server& server)
415{
416 auto pending = assocMaps.pending.find(objectPath);
417 if (pending == assocMaps.pending.end())
418 {
419 return;
420 }
421
422 if (interfaceMap.find(objectPath) == interfaceMap.end())
423 {
424 return;
425 }
426
427 auto endpoint = pending->second.begin();
428
429 while (endpoint != pending->second.end())
430 {
431 const auto& e = std::get<assocPos>(*endpoint);
432
433 // Ensure the other side of the association still exists
434 if (interfaceMap.find(std::get<reversePathPos>(e)) ==
435 interfaceMap.end())
436 {
437 endpoint++;
438 continue;
439 }
440
441 // Add both sides of the association:
442 // objectPath/forwardType and reversePath/reverseType
443 //
444 // The ownerPath is the reversePath - i.e. the endpoint that
445 // is on D-Bus and owns the org.openbmc.Associations iface.
446 //
447 const auto& ownerPath = std::get<reversePathPos>(e);
448 const auto& owner = std::get<ownerPos>(*endpoint);
449
450 auto assocPath = objectPath + '/' + std::get<forwardTypePos>(e);
451 auto endpointPath = ownerPath;
452
Lei YUb89c6612021-07-22 15:59:52 +0800453 try
454 {
Kallas, Pawel5b4357d2022-10-12 15:36:37 +0200455 addSingleAssociation(io, server, assocPath, endpointPath, owner,
Lei YUb89c6612021-07-22 15:59:52 +0800456 ownerPath, assocMaps);
Matt Spinler11401e22019-04-08 13:13:25 -0500457
Lei YUb89c6612021-07-22 15:59:52 +0800458 // Now the reverse direction (still the same owner and ownerPath)
459 assocPath = endpointPath + '/' + std::get<reverseTypePos>(e);
460 endpointPath = objectPath;
Kallas, Pawel5b4357d2022-10-12 15:36:37 +0200461 addSingleAssociation(io, server, assocPath, endpointPath, owner,
Lei YUb89c6612021-07-22 15:59:52 +0800462 ownerPath, assocMaps);
463 }
Patrick Williamscc8070b2022-07-22 19:26:55 -0500464 catch (const sdbusplus::exception_t& e)
Lei YUb89c6612021-07-22 15:59:52 +0800465 {
466 // In some case the interface could not be created on DBus and an
467 // exception is thrown. mapper has no control of the interface/path
468 // of the associations, so it has to catch the error and drop the
469 // association request.
Brad Bishop1f623802022-05-31 18:22:10 -0400470 std::cerr << "Error adding association: assocPath " << assocPath
471 << ", endpointPath " << endpointPath
472 << ", what: " << e.what() << "\n";
Lei YUb89c6612021-07-22 15:59:52 +0800473 }
Matt Spinler11401e22019-04-08 13:13:25 -0500474
475 // Not pending anymore
476 endpoint = pending->second.erase(endpoint);
477 }
478
479 if (pending->second.empty())
480 {
481 assocMaps.pending.erase(objectPath);
482 }
483}
Matt Spinler7f8fd1f2019-04-08 15:21:59 -0500484
485void findAssociations(const std::string& endpointPath,
486 AssociationMaps& assocMaps,
487 FindAssocResults& associationData)
488{
489 for (const auto& [sourcePath, owners] : assocMaps.owners)
490 {
491 for (const auto& [owner, assocs] : owners)
492 {
493 for (const auto& [assocPath, endpoints] : assocs)
494 {
495 if (std::find(endpoints.begin(), endpoints.end(),
496 endpointPath) != endpoints.end())
497 {
498 // assocPath is <path>/<type> which tells us what is on the
499 // other side of the association.
500 auto pos = assocPath.rfind('/');
501 auto otherPath = assocPath.substr(0, pos);
502 auto otherType = assocPath.substr(pos + 1);
503
504 // Now we need to find the endpointPath/<type> ->
505 // [otherPath] entry so that we can get the type for
506 // endpointPath's side of the assoc. Do this by finding
507 // otherPath as an endpoint, and also checking for
508 // 'endpointPath/*' as the key.
509 auto a = std::find_if(
510 assocs.begin(), assocs.end(),
511 [&endpointPath, &otherPath](const auto& ap) {
512 const auto& endpoints = ap.second;
513 auto endpoint = std::find(
514 endpoints.begin(), endpoints.end(), otherPath);
515 if (endpoint != endpoints.end())
516 {
Brad Bishop86d28802022-07-11 15:49:31 -0400517 return ap.first.starts_with(endpointPath + '/');
Matt Spinler7f8fd1f2019-04-08 15:21:59 -0500518 }
519 return false;
520 });
521
522 if (a != assocs.end())
523 {
524 // Pull out the type from endpointPath/<type>
525 pos = a->first.rfind('/');
526 auto thisType = a->first.substr(pos + 1);
527
528 // Now we know the full association:
529 // endpointPath/thisType -> otherPath/otherType
530 Association association{thisType, otherType, otherPath};
531 associationData.emplace_back(owner, association);
532 }
533 }
534 }
535 }
536 }
537}
Matt Spinler9c3d2852019-04-08 15:57:19 -0500538
539/** @brief Remove an endpoint for a particular association from D-Bus.
540 *
541 * If the last endpoint is gone, remove the whole association interface,
542 * otherwise just update the D-Bus endpoints property.
543 *
544 * @param[in] assocPath - the association path
545 * @param[in] endpointPath - the endpoint path to find and remove
546 * @param[in,out] assocMaps - the association maps
547 * @param[in,out] server - sdbus system object
548 */
Kallas, Pawel5b4357d2022-10-12 15:36:37 +0200549void removeAssociationIfacesEntry(boost::asio::io_context& io,
550 const std::string& assocPath,
Matt Spinler9c3d2852019-04-08 15:57:19 -0500551 const std::string& endpointPath,
552 AssociationMaps& assocMaps,
553 sdbusplus::asio::object_server& server)
554{
555 auto assoc = assocMaps.ifaces.find(assocPath);
556 if (assoc != assocMaps.ifaces.end())
557 {
558 auto& endpoints = std::get<endpointsPos>(assoc->second);
559 auto e = std::find(endpoints.begin(), endpoints.end(), endpointPath);
560 if (e != endpoints.end())
561 {
562 endpoints.erase(e);
563
Kallas, Pawel5b4357d2022-10-12 15:36:37 +0200564 scheduleUpdateEndpointsOnDbus(io, server, assocPath, assocMaps);
Matt Spinler9c3d2852019-04-08 15:57:19 -0500565 }
566 }
567}
568
569/** @brief Remove an endpoint from the association owners map.
570 *
571 * For a specific association path and owner, remove the endpoint.
572 * Remove all remaining artifacts of that endpoint in the owners map
573 * based on what frees up after the erase.
574 *
575 * @param[in] assocPath - the association object path
576 * @param[in] endpointPath - the endpoint object path
577 * @param[in] owner - the owner of the association
578 * @param[in,out] assocMaps - the association maps
Matt Spinler9c3d2852019-04-08 15:57:19 -0500579 */
580void removeAssociationOwnersEntry(const std::string& assocPath,
581 const std::string& endpointPath,
582 const std::string& owner,
Brad Bishopa6646902022-06-02 19:05:34 -0400583 AssociationMaps& assocMaps)
Matt Spinler9c3d2852019-04-08 15:57:19 -0500584{
585 auto sources = assocMaps.owners.begin();
586 while (sources != assocMaps.owners.end())
587 {
588 auto owners = sources->second.find(owner);
589 if (owners != sources->second.end())
590 {
591 auto entry = owners->second.find(assocPath);
592 if (entry != owners->second.end())
593 {
594 auto e = std::find(entry->second.begin(), entry->second.end(),
595 endpointPath);
596 if (e != entry->second.end())
597 {
598 entry->second.erase(e);
599 if (entry->second.empty())
600 {
601 owners->second.erase(entry);
602 }
603 }
604 }
605
606 if (owners->second.empty())
607 {
608 sources->second.erase(owners);
609 }
610 }
611
612 if (sources->second.empty())
613 {
614 sources = assocMaps.owners.erase(sources);
615 continue;
616 }
617 sources++;
618 }
619}
620
Kallas, Pawel5b4357d2022-10-12 15:36:37 +0200621void moveAssociationToPending(boost::asio::io_context& io,
622 const std::string& endpointPath,
Matt Spinler9c3d2852019-04-08 15:57:19 -0500623 AssociationMaps& assocMaps,
624 sdbusplus::asio::object_server& server)
625{
626 FindAssocResults associationData;
627
628 // Check which associations this path is an endpoint of, and
629 // then add them to the pending associations map and remove
630 // the associations objects.
631 findAssociations(endpointPath, assocMaps, associationData);
632
633 for (const auto& [owner, association] : associationData)
634 {
635 const auto& forwardPath = endpointPath;
636 const auto& forwardType = std::get<forwardTypePos>(association);
637 const auto& reversePath = std::get<reversePathPos>(association);
638 const auto& reverseType = std::get<reverseTypePos>(association);
639
640 addPendingAssociation(forwardPath, forwardType, reversePath,
641 reverseType, owner, assocMaps);
642
643 // Remove both sides of the association from assocMaps.ifaces
Kallas, Pawel5b4357d2022-10-12 15:36:37 +0200644 removeAssociationIfacesEntry(io, forwardPath + '/' + forwardType,
Matt Spinler9c3d2852019-04-08 15:57:19 -0500645 reversePath, assocMaps, server);
Kallas, Pawel5b4357d2022-10-12 15:36:37 +0200646 removeAssociationIfacesEntry(io, reversePath + '/' + reverseType,
Matt Spinler9c3d2852019-04-08 15:57:19 -0500647 forwardPath, assocMaps, server);
648
649 // Remove both sides of the association from assocMaps.owners
650 removeAssociationOwnersEntry(forwardPath + '/' + forwardType,
Brad Bishopa6646902022-06-02 19:05:34 -0400651 reversePath, owner, assocMaps);
Matt Spinler9c3d2852019-04-08 15:57:19 -0500652 removeAssociationOwnersEntry(reversePath + '/' + reverseType,
Brad Bishopa6646902022-06-02 19:05:34 -0400653 forwardPath, owner, assocMaps);
Matt Spinler9c3d2852019-04-08 15:57:19 -0500654 }
655}