blob: 3c7e7fbbd6b80796ea60da8180bd753b01a2405a [file] [log] [blame]
Andrew Geissler3b025e62019-02-01 10:33:54 -06001#include "processing.hpp"
2
3#include <boost/algorithm/string/predicate.hpp>
Andrew Geissler70461892019-02-27 09:57:37 -06004#include <iostream>
Andrew Geissler3b025e62019-02-01 10:33:54 -06005
6bool getWellKnown(
7 const boost::container::flat_map<std::string, std::string>& owners,
8 const std::string& request, std::string& wellKnown)
9{
10 // If it's already a well known name, just return
11 if (!boost::starts_with(request, ":"))
12 {
13 wellKnown = request;
14 return true;
15 }
16
17 auto it = owners.find(request);
18 if (it == owners.end())
19 {
20 return false;
21 }
22 wellKnown = it->second;
23 return true;
24}
Andrew Geissler82815da2019-02-04 12:19:41 -060025
26bool needToIntrospect(const std::string& processName,
27 const WhiteBlackList& whiteList,
28 const WhiteBlackList& blackList)
29{
30 auto inWhitelist =
31 std::find_if(whiteList.begin(), whiteList.end(),
32 [&processName](const auto& prefix) {
33 return boost::starts_with(processName, prefix);
34 }) != whiteList.end();
35
36 // This holds full service names, not prefixes
37 auto inBlacklist = blackList.find(processName) != blackList.end();
38
39 return inWhitelist && !inBlacklist;
40}
Andrew Geissler20679262019-02-11 20:20:40 -060041
42void processNameChangeDelete(
43 boost::container::flat_map<std::string, std::string>& nameOwners,
44 const std::string& wellKnown, const std::string& oldOwner,
45 interface_map_type& interfaceMap, AssociationOwnersType& assocOwners,
46 AssociationInterfaces& assocInterfaces,
47 sdbusplus::asio::object_server& server)
48{
49 if (boost::starts_with(oldOwner, ":"))
50 {
51 auto it = nameOwners.find(oldOwner);
52 if (it != nameOwners.end())
53 {
54 nameOwners.erase(it);
55 }
56 }
57 // Connection removed
58 interface_map_type::iterator pathIt = interfaceMap.begin();
59 while (pathIt != interfaceMap.end())
60 {
61 // If an associations interface is being removed,
62 // also need to remove the corresponding associations
63 // objects and properties.
64 auto ifaces = pathIt->second.find(wellKnown);
65 if (ifaces != pathIt->second.end())
66 {
Matt Spinler8f876a52019-04-15 13:22:50 -050067 auto assoc = std::find_if(
68 ifaces->second.begin(), ifaces->second.end(),
69 [](const auto& iface) { return isAssocDefIface(iface); });
Andrew Geissler20679262019-02-11 20:20:40 -060070 if (assoc != ifaces->second.end())
71 {
72 removeAssociation(pathIt->first, wellKnown, server, assocOwners,
73 assocInterfaces);
74 }
75 }
76 pathIt->second.erase(wellKnown);
77 if (pathIt->second.empty())
78 {
79 // If the last connection to the object is gone,
80 // delete the top level object
81 pathIt = interfaceMap.erase(pathIt);
82 continue;
83 }
84 pathIt++;
85 }
86}
Andrew Geissler70461892019-02-27 09:57:37 -060087
88void processInterfaceAdded(interface_map_type& interfaceMap,
89 const sdbusplus::message::object_path& objPath,
90 const InterfacesAdded& intfAdded,
91 const std::string& wellKnown,
92 AssociationOwnersType& assocOwners,
93 AssociationInterfaces& assocInterfaces,
94 sdbusplus::asio::object_server& server)
95{
96 auto& ifaceList = interfaceMap[objPath.str];
97
98 for (const auto& interfacePair : intfAdded)
99 {
100 ifaceList[wellKnown].emplace(interfacePair.first);
101
Matt Spinler8f876a52019-04-15 13:22:50 -0500102 if (isAssocDefIface(interfacePair.first))
Andrew Geissler70461892019-02-27 09:57:37 -0600103 {
104 const sdbusplus::message::variant<std::vector<Association>>*
105 variantAssociations = nullptr;
106 for (const auto& interface : interfacePair.second)
107 {
Matt Spinler8f876a52019-04-15 13:22:50 -0500108 if (interface.first == getAssocDefPropName(interfacePair.first))
Andrew Geissler70461892019-02-27 09:57:37 -0600109 {
110 variantAssociations = &(interface.second);
111 }
112 }
113 if (variantAssociations == nullptr)
114 {
115 std::cerr << "Illegal association found on " << wellKnown
116 << "\n";
117 continue;
118 }
119 std::vector<Association> associations =
120 sdbusplus::message::variant_ns::get<std::vector<Association>>(
121 *variantAssociations);
122 associationChanged(server, associations, objPath.str, wellKnown,
123 assocOwners, assocInterfaces);
124 }
125 }
126
127 // To handle the case where an object path is being created
128 // with 2 or more new path segments, check if the parent paths
129 // of this path are already in the interface map, and add them
130 // if they aren't with just the default freedesktop interfaces.
131 // This would be done via introspection if they would have
132 // already existed at startup. While we could also introspect
133 // them now to do the work, we know there aren't any other
134 // interfaces or we would have gotten signals for them as well,
135 // so take a shortcut to speed things up.
136 //
137 // This is all needed so that mapper operations can be done
138 // on the new parent paths.
139 using iface_map_iterator = interface_map_type::iterator;
140 using iface_map_value_type =
141 boost::container::flat_map<std::string,
142 boost::container::flat_set<std::string>>;
143 using name_map_iterator = iface_map_value_type::iterator;
144
145 static const boost::container::flat_set<std::string> defaultIfaces{
146 "org.freedesktop.DBus.Introspectable", "org.freedesktop.DBus.Peer",
147 "org.freedesktop.DBus.Properties"};
148
149 std::string parent = objPath.str;
150 auto pos = parent.find_last_of('/');
151
152 while (pos != std::string::npos)
153 {
154 parent = parent.substr(0, pos);
155
156 std::pair<iface_map_iterator, bool> parentEntry =
157 interfaceMap.insert(std::make_pair(parent, iface_map_value_type{}));
158
159 std::pair<name_map_iterator, bool> ifaceEntry =
160 parentEntry.first->second.insert(
161 std::make_pair(wellKnown, defaultIfaces));
162
163 if (!ifaceEntry.second)
164 {
165 // Entry was already there for this name so done.
166 break;
167 }
168
169 pos = parent.find_last_of('/');
170 }
171}