| #include "processing.hpp" |
| |
| #include <boost/algorithm/string/predicate.hpp> |
| |
| #include <iostream> |
| |
| bool getWellKnown( |
| const boost::container::flat_map<std::string, std::string>& owners, |
| const std::string& request, std::string& wellKnown) |
| { |
| // If it's already a well known name, just return |
| if (!boost::starts_with(request, ":")) |
| { |
| wellKnown = request; |
| return true; |
| } |
| |
| auto it = owners.find(request); |
| if (it == owners.end()) |
| { |
| return false; |
| } |
| wellKnown = it->second; |
| return true; |
| } |
| |
| bool needToIntrospect(const std::string& processName, |
| const AllowDenyList& allowList) |
| { |
| auto inAllowList = |
| std::find_if(allowList.begin(), allowList.end(), |
| [&processName](const auto& prefix) { |
| return boost::starts_with(processName, prefix); |
| }) != allowList.end(); |
| |
| return inAllowList; |
| } |
| |
| void processNameChangeDelete( |
| boost::container::flat_map<std::string, std::string>& nameOwners, |
| const std::string& wellKnown, const std::string& oldOwner, |
| InterfaceMapType& interfaceMap, AssociationMaps& assocMaps, |
| sdbusplus::asio::object_server& server) |
| { |
| if (boost::starts_with(oldOwner, ":")) |
| { |
| auto it = nameOwners.find(oldOwner); |
| if (it != nameOwners.end()) |
| { |
| nameOwners.erase(it); |
| } |
| } |
| // Connection removed |
| InterfaceMapType::iterator pathIt = interfaceMap.begin(); |
| while (pathIt != interfaceMap.end()) |
| { |
| // If an associations interface is being removed, |
| // also need to remove the corresponding associations |
| // objects and properties. |
| auto ifaces = pathIt->second.find(wellKnown); |
| if (ifaces != pathIt->second.end()) |
| { |
| auto assoc = std::find(ifaces->second.begin(), ifaces->second.end(), |
| assocDefsInterface); |
| if (assoc != ifaces->second.end()) |
| { |
| removeAssociation(pathIt->first, wellKnown, server, assocMaps); |
| } |
| |
| // Instead of checking if every single path is the endpoint of an |
| // association that needs to be moved to pending, only check when |
| // we own this path as well, which would be because of an |
| // association. |
| if ((pathIt->second.size() == 2) && |
| (pathIt->second.find("xyz.openbmc_project.ObjectMapper") != |
| pathIt->second.end())) |
| { |
| // Remove the 2 association D-Bus paths and move the |
| // association to pending. |
| moveAssociationToPending(pathIt->first, assocMaps, server); |
| } |
| } |
| pathIt->second.erase(wellKnown); |
| if (pathIt->second.empty()) |
| { |
| // If the last connection to the object is gone, |
| // delete the top level object |
| pathIt = interfaceMap.erase(pathIt); |
| continue; |
| } |
| pathIt++; |
| } |
| } |
| |
| void processInterfaceAdded(InterfaceMapType& interfaceMap, |
| const sdbusplus::message::object_path& objPath, |
| const InterfacesAdded& intfAdded, |
| const std::string& wellKnown, |
| AssociationMaps& assocMaps, |
| sdbusplus::asio::object_server& server) |
| { |
| auto& ifaceList = interfaceMap[objPath.str]; |
| |
| for (const auto& interfacePair : intfAdded) |
| { |
| ifaceList[wellKnown].emplace(interfacePair.first); |
| |
| if (interfacePair.first == assocDefsInterface) |
| { |
| const std::variant<std::vector<Association>>* variantAssociations = |
| nullptr; |
| for (const auto& interface : interfacePair.second) |
| { |
| if (interface.first == assocDefsProperty) |
| { |
| variantAssociations = &(interface.second); |
| } |
| } |
| if (variantAssociations == nullptr) |
| { |
| std::cerr << "Illegal association found on " << wellKnown |
| << "\n"; |
| continue; |
| } |
| std::vector<Association> associations = |
| std::get<std::vector<Association>>(*variantAssociations); |
| associationChanged(server, associations, objPath.str, wellKnown, |
| interfaceMap, assocMaps); |
| } |
| } |
| |
| // To handle the case where an object path is being created |
| // with 2 or more new path segments, check if the parent paths |
| // of this path are already in the interface map, and add them |
| // if they aren't with just the default freedesktop interfaces. |
| // This would be done via introspection if they would have |
| // already existed at startup. While we could also introspect |
| // them now to do the work, we know there aren't any other |
| // interfaces or we would have gotten signals for them as well, |
| // so take a shortcut to speed things up. |
| // |
| // This is all needed so that mapper operations can be done |
| // on the new parent paths. |
| using iface_map_iterator = InterfaceMapType::iterator; |
| using name_map_iterator = InterfaceMapType::mapped_type::iterator; |
| |
| static const InterfaceNames defaultIfaces{ |
| "org.freedesktop.DBus.Introspectable", "org.freedesktop.DBus.Peer", |
| "org.freedesktop.DBus.Properties"}; |
| |
| std::string parent = objPath.str; |
| auto pos = parent.find_last_of('/'); |
| |
| while (pos != std::string::npos) |
| { |
| parent = parent.substr(0, pos); |
| |
| std::pair<iface_map_iterator, bool> parentEntry = |
| interfaceMap.try_emplace(parent); |
| |
| std::pair<name_map_iterator, bool> ifaceEntry = |
| parentEntry.first->second.try_emplace(wellKnown, defaultIfaces); |
| |
| if (!ifaceEntry.second) |
| { |
| // Entry was already there for this name so done. |
| break; |
| } |
| |
| pos = parent.find_last_of('/'); |
| } |
| |
| // The new interface might have an association pending |
| checkIfPendingAssociation(objPath.str, interfaceMap, assocMaps, server); |
| } |