blob: 5f437675b4c67c9d7437c015ff085fd7fea8a4f3 [file] [log] [blame]
Andrew Geisslera80a3af2019-02-04 14:01:49 -06001#include "associations.hpp"
Willy Tuaba14d32023-01-31 14:19:59 -08002#include "handler.hpp"
Andrew Geissler3b025e62019-02-01 10:33:54 -06003#include "processing.hpp"
Matt Spinler35396c12019-04-05 11:46:57 -05004#include "types.hpp"
Matt Spinlerdd945862018-09-07 12:41:05 -05005
Ed Tanous60520632018-06-11 17:46:52 -07006#include <tinyxml2.h>
7
Ed Tanous21c60592020-08-17 23:43:46 -07008#include <boost/asio/io_context.hpp>
9#include <boost/asio/signal_set.hpp>
Ed Tanous60520632018-06-11 17:46:52 -070010#include <boost/container/flat_map.hpp>
Ed Tanous60520632018-06-11 17:46:52 -070011#include <sdbusplus/asio/connection.hpp>
12#include <sdbusplus/asio/object_server.hpp>
Konstantin Aladyshevb15df6b2022-01-11 14:50:55 +030013#include <xyz/openbmc_project/Common/error.hpp>
Ed Tanous60520632018-06-11 17:46:52 -070014
Brad Bishop23520882022-05-26 21:39:53 -040015#include <atomic>
16#include <chrono>
Brad Bishopea119462022-05-31 20:32:04 -040017#include <exception>
Brad Bishop23520882022-05-26 21:39:53 -040018#include <iomanip>
19#include <iostream>
Brandon Kimf6ebfc72022-07-07 12:53:44 -070020#include <string>
21#include <string_view>
Brad Bishop1f623802022-05-31 18:22:10 -040022#include <utility>
Brad Bishop23520882022-05-26 21:39:53 -040023
Matt Spinlere2359fb2019-04-05 14:11:33 -050024AssociationMaps associationMaps;
Matt Spinler937a2322019-01-23 13:54:22 -060025
Brad Bishopa098a372022-05-05 15:19:04 -040026void updateOwners(sdbusplus::asio::connection* conn,
27 boost::container::flat_map<std::string, std::string>& owners,
28 const std::string& newObject)
Ed Tanous60520632018-06-11 17:46:52 -070029{
Brad Bishop86d28802022-07-11 15:49:31 -040030 if (newObject.starts_with(":"))
Ed Tanous60520632018-06-11 17:46:52 -070031 {
32 return;
33 }
34 conn->async_method_call(
Brad Bishopa098a372022-05-05 15:19:04 -040035 [&, newObject](const boost::system::error_code ec,
36 const std::string& nameOwner) {
Ed Tanous60520632018-06-11 17:46:52 -070037 if (ec)
38 {
Brad Bishopa098a372022-05-05 15:19:04 -040039 std::cerr << "Error getting owner of " << newObject << " : "
Ed Tanous60520632018-06-11 17:46:52 -070040 << ec << "\n";
41 return;
42 }
Brad Bishopa098a372022-05-05 15:19:04 -040043 owners[nameOwner] = newObject;
Ed Tanous60520632018-06-11 17:46:52 -070044 },
45 "org.freedesktop.DBus", "/", "org.freedesktop.DBus", "GetNameOwner",
Brad Bishopa098a372022-05-05 15:19:04 -040046 newObject);
Ed Tanous60520632018-06-11 17:46:52 -070047}
48
Brad Bishopa098a372022-05-05 15:19:04 -040049void sendIntrospectionCompleteSignal(sdbusplus::asio::connection* systemBus,
50 const std::string& processName)
Ed Tanous60520632018-06-11 17:46:52 -070051{
52 // TODO(ed) This signal doesn't get exposed properly in the
53 // introspect right now. Find out how to register signals in
54 // sdbusplus
Patrick Williamscc8070b2022-07-22 19:26:55 -050055 sdbusplus::message_t m = systemBus->new_signal(
Brad Bishopa02cd542021-10-12 19:12:42 -040056 "/xyz/openbmc_project/object_mapper",
57 "xyz.openbmc_project.ObjectMapper.Private", "IntrospectionComplete");
Brad Bishopa098a372022-05-05 15:19:04 -040058 m.append(processName);
Ed Tanous60520632018-06-11 17:46:52 -070059 m.signal_send();
60}
61
62struct InProgressIntrospect
63{
Brad Bishop1f623802022-05-31 18:22:10 -040064 InProgressIntrospect() = delete;
65 InProgressIntrospect(const InProgressIntrospect&) = delete;
66 InProgressIntrospect(InProgressIntrospect&&) = delete;
67 InProgressIntrospect& operator=(const InProgressIntrospect&) = delete;
68 InProgressIntrospect& operator=(InProgressIntrospect&&) = delete;
Ed Tanous60520632018-06-11 17:46:52 -070069 InProgressIntrospect(
Brad Bishopa098a372022-05-05 15:19:04 -040070 sdbusplus::asio::connection* systemBus, boost::asio::io_context& io,
71 const std::string& processName, AssociationMaps& am
Brad Bishopd6aa5522022-05-31 19:23:48 -040072#ifdef MAPPER_ENABLE_DEBUG
Matt Spinleraecabe82018-09-19 13:25:42 -050073 ,
Ed Tanous60520632018-06-11 17:46:52 -070074 std::shared_ptr<std::chrono::time_point<std::chrono::steady_clock>>
Brad Bishopa098a372022-05-05 15:19:04 -040075 globalStartTime
Matt Spinleraecabe82018-09-19 13:25:42 -050076#endif
77 ) :
Brad Bishopa098a372022-05-05 15:19:04 -040078 systemBus(systemBus),
79 io(io), processName(processName), assocMaps(am)
Brad Bishopd6aa5522022-05-31 19:23:48 -040080#ifdef MAPPER_ENABLE_DEBUG
Matt Spinleraecabe82018-09-19 13:25:42 -050081 ,
Brad Bishop1f623802022-05-31 18:22:10 -040082 globalStartTime(std::move(globalStartTime)),
Brad Bishopa098a372022-05-05 15:19:04 -040083 processStartTime(std::chrono::steady_clock::now())
Matt Spinleraecabe82018-09-19 13:25:42 -050084#endif
Brad Bishop23520882022-05-26 21:39:53 -040085 {}
Ed Tanous60520632018-06-11 17:46:52 -070086 ~InProgressIntrospect()
87 {
Brad Bishopea119462022-05-31 20:32:04 -040088 try
Ed Tanous60520632018-06-11 17:46:52 -070089 {
Brad Bishopea119462022-05-31 20:32:04 -040090 sendIntrospectionCompleteSignal(systemBus, processName);
Brad Bishopd6aa5522022-05-31 19:23:48 -040091#ifdef MAPPER_ENABLE_DEBUG
Brad Bishopea119462022-05-31 20:32:04 -040092 std::chrono::duration<float> diff =
93 std::chrono::steady_clock::now() - processStartTime;
94 std::cout << std::setw(50) << processName << " scan took "
95 << diff.count() << " seconds\n";
96
97 // If we're the last outstanding caller globally, calculate the
98 // time it took
99 if (globalStartTime != nullptr && globalStartTime.use_count() == 1)
100 {
101 diff = std::chrono::steady_clock::now() - *globalStartTime;
102 std::cout << "Total scan took " << diff.count()
103 << " seconds to complete\n";
104 }
Matt Spinleraecabe82018-09-19 13:25:42 -0500105#endif
Brad Bishopea119462022-05-31 20:32:04 -0400106 }
107 catch (const std::exception& e)
108 {
109 std::cerr
110 << "Terminating, unhandled exception while introspecting: "
111 << e.what() << "\n";
112 std::terminate();
113 }
114 catch (...)
115 {
116 std::cerr
117 << "Terminating, unhandled exception while introspecting\n";
118 std::terminate();
119 }
Ed Tanous60520632018-06-11 17:46:52 -0700120 }
Brad Bishopa098a372022-05-05 15:19:04 -0400121 sdbusplus::asio::connection* systemBus;
Ed Tanous21c60592020-08-17 23:43:46 -0700122 boost::asio::io_context& io;
Brad Bishopa098a372022-05-05 15:19:04 -0400123 std::string processName;
Matt Spinler11401e22019-04-08 13:13:25 -0500124 AssociationMaps& assocMaps;
Brad Bishopd6aa5522022-05-31 19:23:48 -0400125#ifdef MAPPER_ENABLE_DEBUG
Ed Tanous60520632018-06-11 17:46:52 -0700126 std::shared_ptr<std::chrono::time_point<std::chrono::steady_clock>>
Brad Bishopa098a372022-05-05 15:19:04 -0400127 globalStartTime;
128 std::chrono::time_point<std::chrono::steady_clock> processStartTime;
Matt Spinleraecabe82018-09-19 13:25:42 -0500129#endif
Ed Tanous60520632018-06-11 17:46:52 -0700130};
131
Kallas, Pawel5b4357d2022-10-12 15:36:37 +0200132void doAssociations(boost::asio::io_context& io,
133 sdbusplus::asio::connection* systemBus,
Brad Bishopa098a372022-05-05 15:19:04 -0400134 InterfaceMapType& interfaceMap,
135 sdbusplus::asio::object_server& objectServer,
136 const std::string& processName, const std::string& path,
137 int timeoutRetries = 0)
Ed Tanous60520632018-06-11 17:46:52 -0700138{
Adrian Ambrożewiczbb40bd32021-02-12 13:36:26 +0100139 constexpr int maxTimeoutRetries = 3;
Brad Bishopa098a372022-05-05 15:19:04 -0400140 systemBus->async_method_call(
Kallas, Pawel5b4357d2022-10-12 15:36:37 +0200141 [&io, &objectServer, path, processName, &interfaceMap, systemBus,
Adrian Ambrożewiczbb40bd32021-02-12 13:36:26 +0100142 timeoutRetries](
Matt Spinler937a2322019-01-23 13:54:22 -0600143 const boost::system::error_code ec,
Patrick Williams2bb2d6b2020-05-13 17:59:02 -0500144 const std::variant<std::vector<Association>>& variantAssociations) {
Ed Tanous60520632018-06-11 17:46:52 -0700145 if (ec)
146 {
Adrian Ambrożewiczbb40bd32021-02-12 13:36:26 +0100147 if (ec.value() == boost::system::errc::timed_out &&
148 timeoutRetries < maxTimeoutRetries)
149 {
Kallas, Pawel5b4357d2022-10-12 15:36:37 +0200150 doAssociations(io, systemBus, interfaceMap, objectServer,
Brad Bishopa098a372022-05-05 15:19:04 -0400151 processName, path, timeoutRetries + 1);
Adrian Ambrożewiczbb40bd32021-02-12 13:36:26 +0100152 return;
153 }
Ed Tanous60520632018-06-11 17:46:52 -0700154 std::cerr << "Error getting associations from " << path << "\n";
155 }
156 std::vector<Association> associations =
Patrick Williamsb05bc122020-05-13 12:21:00 -0500157 std::get<std::vector<Association>>(variantAssociations);
Kallas, Pawel5b4357d2022-10-12 15:36:37 +0200158 associationChanged(io, objectServer, associations, path,
159 processName, interfaceMap, associationMaps);
Ed Tanous60520632018-06-11 17:46:52 -0700160 },
161 processName, path, "org.freedesktop.DBus.Properties", "Get",
John Wangd0cf9422019-09-17 16:01:34 +0800162 assocDefsInterface, assocDefsProperty);
Ed Tanous60520632018-06-11 17:46:52 -0700163}
164
Kallas, Pawel5b4357d2022-10-12 15:36:37 +0200165void doIntrospect(boost::asio::io_context& io,
166 sdbusplus::asio::connection* systemBus,
Brad Bishop1f623802022-05-31 18:22:10 -0400167 const std::shared_ptr<InProgressIntrospect>& transaction,
Brad Bishopa098a372022-05-05 15:19:04 -0400168 InterfaceMapType& interfaceMap,
169 sdbusplus::asio::object_server& objectServer,
Brad Bishop1f623802022-05-31 18:22:10 -0400170 const std::string& path, int timeoutRetries = 0)
Ed Tanous60520632018-06-11 17:46:52 -0700171{
Vernon Maueryc52be0d2020-01-14 11:14:25 -0800172 constexpr int maxTimeoutRetries = 3;
Brad Bishopa098a372022-05-05 15:19:04 -0400173 systemBus->async_method_call(
Kallas, Pawel5b4357d2022-10-12 15:36:37 +0200174 [&io, &interfaceMap, &objectServer, transaction, path, systemBus,
Vernon Maueryc52be0d2020-01-14 11:14:25 -0800175 timeoutRetries](const boost::system::error_code ec,
Brad Bishopa098a372022-05-05 15:19:04 -0400176 const std::string& introspectXml) {
Ed Tanous60520632018-06-11 17:46:52 -0700177 if (ec)
178 {
Vernon Maueryc52be0d2020-01-14 11:14:25 -0800179 if (ec.value() == boost::system::errc::timed_out &&
180 timeoutRetries < maxTimeoutRetries)
181 {
Kallas, Pawel5b4357d2022-10-12 15:36:37 +0200182 doIntrospect(io, systemBus, transaction, interfaceMap,
Brad Bishopa098a372022-05-05 15:19:04 -0400183 objectServer, path, timeoutRetries + 1);
Vernon Maueryc52be0d2020-01-14 11:14:25 -0800184 return;
185 }
Ed Tanous60520632018-06-11 17:46:52 -0700186 std::cerr << "Introspect call failed with error: " << ec << ", "
187 << ec.message()
Brad Bishopa098a372022-05-05 15:19:04 -0400188 << " on process: " << transaction->processName
Ed Tanous60520632018-06-11 17:46:52 -0700189 << " path: " << path << "\n";
190 return;
191 }
192
193 tinyxml2::XMLDocument doc;
194
Brad Bishopa098a372022-05-05 15:19:04 -0400195 tinyxml2::XMLError e = doc.Parse(introspectXml.c_str());
Ed Tanous60520632018-06-11 17:46:52 -0700196 if (e != tinyxml2::XMLError::XML_SUCCESS)
197 {
198 std::cerr << "XML parsing failed\n";
199 return;
200 }
201
202 tinyxml2::XMLNode* pRoot = doc.FirstChildElement("node");
203 if (pRoot == nullptr)
204 {
205 std::cerr << "XML document did not contain any data\n";
206 return;
207 }
Brad Bishopa098a372022-05-05 15:19:04 -0400208 auto& thisPathMap = interfaceMap[path];
Ed Tanous60520632018-06-11 17:46:52 -0700209 tinyxml2::XMLElement* pElement =
210 pRoot->FirstChildElement("interface");
211 while (pElement != nullptr)
212 {
Brad Bishopa098a372022-05-05 15:19:04 -0400213 const char* ifaceName = pElement->Attribute("name");
214 if (ifaceName == nullptr)
Ed Tanous60520632018-06-11 17:46:52 -0700215 {
216 continue;
217 }
218
Brad Bishopa098a372022-05-05 15:19:04 -0400219 thisPathMap[transaction->processName].emplace(ifaceName);
Ed Tanousd4dd96a2018-11-12 11:37:44 -0800220
Brad Bishopa098a372022-05-05 15:19:04 -0400221 if (std::strcmp(ifaceName, assocDefsInterface) == 0)
Ed Tanous60520632018-06-11 17:46:52 -0700222 {
Kallas, Pawel5b4357d2022-10-12 15:36:37 +0200223 doAssociations(io, systemBus, interfaceMap, objectServer,
Brad Bishopa098a372022-05-05 15:19:04 -0400224 transaction->processName, path);
Ed Tanous60520632018-06-11 17:46:52 -0700225 }
Ed Tanous60520632018-06-11 17:46:52 -0700226
227 pElement = pElement->NextSiblingElement("interface");
228 }
229
Matt Spinler11401e22019-04-08 13:13:25 -0500230 // Check if this new path has a pending association that can
231 // now be completed.
Kallas, Pawel5b4357d2022-10-12 15:36:37 +0200232 checkIfPendingAssociation(io, path, interfaceMap,
Matt Spinler11401e22019-04-08 13:13:25 -0500233 transaction->assocMaps, objectServer);
234
Ed Tanous50232cd2018-11-12 11:34:43 -0800235 pElement = pRoot->FirstChildElement("node");
236 while (pElement != nullptr)
Ed Tanous60520632018-06-11 17:46:52 -0700237 {
Brad Bishopa098a372022-05-05 15:19:04 -0400238 const char* childPath = pElement->Attribute("name");
239 if (childPath != nullptr)
Ed Tanous60520632018-06-11 17:46:52 -0700240 {
Brad Bishopa098a372022-05-05 15:19:04 -0400241 std::string parentPath(path);
242 if (parentPath == "/")
Ed Tanous60520632018-06-11 17:46:52 -0700243 {
Brad Bishopa098a372022-05-05 15:19:04 -0400244 parentPath.clear();
Ed Tanous60520632018-06-11 17:46:52 -0700245 }
Ed Tanous50232cd2018-11-12 11:34:43 -0800246
Kallas, Pawel5b4357d2022-10-12 15:36:37 +0200247 doIntrospect(io, systemBus, transaction, interfaceMap,
Brad Bishopa098a372022-05-05 15:19:04 -0400248 objectServer, parentPath + "/" + childPath);
Ed Tanous60520632018-06-11 17:46:52 -0700249 }
Ed Tanous50232cd2018-11-12 11:34:43 -0800250 pElement = pElement->NextSiblingElement("node");
Ed Tanous60520632018-06-11 17:46:52 -0700251 }
252 },
Brad Bishopa098a372022-05-05 15:19:04 -0400253 transaction->processName, path, "org.freedesktop.DBus.Introspectable",
Ed Tanous60520632018-06-11 17:46:52 -0700254 "Introspect");
255}
256
Brad Bishopa098a372022-05-05 15:19:04 -0400257void startNewIntrospect(
258 sdbusplus::asio::connection* systemBus, boost::asio::io_context& io,
259 InterfaceMapType& interfaceMap, const std::string& processName,
Matt Spinler11401e22019-04-08 13:13:25 -0500260 AssociationMaps& assocMaps,
Brad Bishopd6aa5522022-05-31 19:23:48 -0400261#ifdef MAPPER_ENABLE_DEBUG
Ed Tanous60520632018-06-11 17:46:52 -0700262 std::shared_ptr<std::chrono::time_point<std::chrono::steady_clock>>
Brad Bishopa098a372022-05-05 15:19:04 -0400263 globalStartTime,
Matt Spinleraecabe82018-09-19 13:25:42 -0500264#endif
Ed Tanous60520632018-06-11 17:46:52 -0700265 sdbusplus::asio::object_server& objectServer)
266{
Brad Bishop1e94e602022-06-02 19:47:53 -0400267 if (needToIntrospect(processName))
Ed Tanous60520632018-06-11 17:46:52 -0700268 {
Ed Tanous60520632018-06-11 17:46:52 -0700269 std::shared_ptr<InProgressIntrospect> transaction =
Brad Bishopa098a372022-05-05 15:19:04 -0400270 std::make_shared<InProgressIntrospect>(systemBus, io, processName,
Matt Spinler11401e22019-04-08 13:13:25 -0500271 assocMaps
Brad Bishopd6aa5522022-05-31 19:23:48 -0400272#ifdef MAPPER_ENABLE_DEBUG
Matt Spinleraecabe82018-09-19 13:25:42 -0500273 ,
Brad Bishopa098a372022-05-05 15:19:04 -0400274 globalStartTime
Matt Spinleraecabe82018-09-19 13:25:42 -0500275#endif
276 );
Ed Tanous60520632018-06-11 17:46:52 -0700277
Kallas, Pawel5b4357d2022-10-12 15:36:37 +0200278 doIntrospect(io, systemBus, transaction, interfaceMap, objectServer,
279 "/");
Ed Tanous60520632018-06-11 17:46:52 -0700280 }
281}
282
Ed Tanous60520632018-06-11 17:46:52 -0700283void doListNames(
Brad Bishopa098a372022-05-05 15:19:04 -0400284 boost::asio::io_context& io, InterfaceMapType& interfaceMap,
285 sdbusplus::asio::connection* systemBus,
286 boost::container::flat_map<std::string, std::string>& nameOwners,
Matt Spinler11401e22019-04-08 13:13:25 -0500287 AssociationMaps& assocMaps, sdbusplus::asio::object_server& objectServer)
Ed Tanous60520632018-06-11 17:46:52 -0700288{
Brad Bishopa098a372022-05-05 15:19:04 -0400289 systemBus->async_method_call(
290 [&io, &interfaceMap, &nameOwners, &objectServer, systemBus,
Matt Spinler11401e22019-04-08 13:13:25 -0500291 &assocMaps](const boost::system::error_code ec,
Brad Bishopa098a372022-05-05 15:19:04 -0400292 std::vector<std::string> processNames) {
Ed Tanous60520632018-06-11 17:46:52 -0700293 if (ec)
294 {
295 std::cerr << "Error getting names: " << ec << "\n";
296 std::exit(EXIT_FAILURE);
297 return;
298 }
Ed Tanous60520632018-06-11 17:46:52 -0700299 // Try to make startup consistent
Brad Bishopa098a372022-05-05 15:19:04 -0400300 std::sort(processNames.begin(), processNames.end());
Brad Bishopd6aa5522022-05-31 19:23:48 -0400301#ifdef MAPPER_ENABLE_DEBUG
Ed Tanous60520632018-06-11 17:46:52 -0700302 std::shared_ptr<std::chrono::time_point<std::chrono::steady_clock>>
Brad Bishopa098a372022-05-05 15:19:04 -0400303 globalStartTime = std::make_shared<
Ed Tanous60520632018-06-11 17:46:52 -0700304 std::chrono::time_point<std::chrono::steady_clock>>(
305 std::chrono::steady_clock::now());
Matt Spinleraecabe82018-09-19 13:25:42 -0500306#endif
Brad Bishopa098a372022-05-05 15:19:04 -0400307 for (const std::string& processName : processNames)
Ed Tanous60520632018-06-11 17:46:52 -0700308 {
Brad Bishop1e94e602022-06-02 19:47:53 -0400309 if (needToIntrospect(processName))
Ed Tanous60520632018-06-11 17:46:52 -0700310 {
Brad Bishopa098a372022-05-05 15:19:04 -0400311 startNewIntrospect(systemBus, io, interfaceMap, processName,
312 assocMaps,
Brad Bishopd6aa5522022-05-31 19:23:48 -0400313#ifdef MAPPER_ENABLE_DEBUG
Brad Bishopa098a372022-05-05 15:19:04 -0400314 globalStartTime,
Matt Spinleraecabe82018-09-19 13:25:42 -0500315#endif
Brad Bishopa098a372022-05-05 15:19:04 -0400316 objectServer);
317 updateOwners(systemBus, nameOwners, processName);
Ed Tanous60520632018-06-11 17:46:52 -0700318 }
319 }
320 },
321 "org.freedesktop.DBus", "/org/freedesktop/DBus", "org.freedesktop.DBus",
322 "ListNames");
323}
324
Matt Spinlera82779f2019-01-09 12:39:42 -0600325// Remove parents of the passed in path that:
326// 1) Only have the 3 default interfaces on them
327// - Means D-Bus created these, not application code,
328// with the Properties, Introspectable, and Peer ifaces
329// 2) Have no other child for this owner
330void removeUnneededParents(const std::string& objectPath,
331 const std::string& owner,
Brad Bishopa098a372022-05-05 15:19:04 -0400332 InterfaceMapType& interfaceMap)
Matt Spinlera82779f2019-01-09 12:39:42 -0600333{
334 auto parent = objectPath;
335
336 while (true)
337 {
338 auto pos = parent.find_last_of('/');
339 if ((pos == std::string::npos) || (pos == 0))
340 {
341 break;
342 }
343 parent = parent.substr(0, pos);
344
Brad Bishopa098a372022-05-05 15:19:04 -0400345 auto parentIt = interfaceMap.find(parent);
346 if (parentIt == interfaceMap.end())
Matt Spinlera82779f2019-01-09 12:39:42 -0600347 {
348 break;
349 }
350
Brad Bishopa098a372022-05-05 15:19:04 -0400351 auto ifacesIt = parentIt->second.find(owner);
352 if (ifacesIt == parentIt->second.end())
Matt Spinlera82779f2019-01-09 12:39:42 -0600353 {
354 break;
355 }
356
Brad Bishopa098a372022-05-05 15:19:04 -0400357 if (ifacesIt->second.size() != 3)
Matt Spinlera82779f2019-01-09 12:39:42 -0600358 {
359 break;
360 }
361
Brad Bishopa098a372022-05-05 15:19:04 -0400362 auto childPath = parent + '/';
Matt Spinlera82779f2019-01-09 12:39:42 -0600363
364 // Remove this parent if there isn't a remaining child on this owner
365 auto child = std::find_if(
Brad Bishopa098a372022-05-05 15:19:04 -0400366 interfaceMap.begin(), interfaceMap.end(),
367 [&owner, &childPath](const auto& entry) {
Brad Bishop86d28802022-07-11 15:49:31 -0400368 return entry.first.starts_with(childPath) &&
Matt Spinlera82779f2019-01-09 12:39:42 -0600369 (entry.second.find(owner) != entry.second.end());
370 });
371
Brad Bishopa098a372022-05-05 15:19:04 -0400372 if (child == interfaceMap.end())
Matt Spinlera82779f2019-01-09 12:39:42 -0600373 {
Brad Bishopa098a372022-05-05 15:19:04 -0400374 parentIt->second.erase(ifacesIt);
375 if (parentIt->second.empty())
Matt Spinlera82779f2019-01-09 12:39:42 -0600376 {
Brad Bishopa098a372022-05-05 15:19:04 -0400377 interfaceMap.erase(parentIt);
Matt Spinlera82779f2019-01-09 12:39:42 -0600378 }
379 }
380 else
381 {
382 break;
383 }
384 }
385}
386
Brad Bishop1e94e602022-06-02 19:47:53 -0400387int main()
Ed Tanous60520632018-06-11 17:46:52 -0700388{
Ed Tanous21c60592020-08-17 23:43:46 -0700389 boost::asio::io_context io;
Brad Bishopa098a372022-05-05 15:19:04 -0400390 std::shared_ptr<sdbusplus::asio::connection> systemBus =
Ed Tanous60520632018-06-11 17:46:52 -0700391 std::make_shared<sdbusplus::asio::connection>(io);
392
Brad Bishopa098a372022-05-05 15:19:04 -0400393 sdbusplus::asio::object_server server(systemBus);
Ed Tanous60520632018-06-11 17:46:52 -0700394
395 // Construct a signal set registered for process termination.
396 boost::asio::signal_set signals(io, SIGINT, SIGTERM);
Brad Bishop2d41d6a2021-08-03 08:14:45 -0400397 signals.async_wait(
398 [&io](const boost::system::error_code&, int) { io.stop(); });
Ed Tanous60520632018-06-11 17:46:52 -0700399
Brad Bishopa098a372022-05-05 15:19:04 -0400400 InterfaceMapType interfaceMap;
401 boost::container::flat_map<std::string, std::string> nameOwners;
Ed Tanous60520632018-06-11 17:46:52 -0700402
William A. Kennington III60ffc242022-12-02 19:36:01 -0800403 auto nameChangeHandler = [&interfaceMap, &io, &nameOwners, &server,
404 systemBus](sdbusplus::message_t& message) {
405 std::string name; // well-known
406 std::string oldOwner; // unique-name
407 std::string newOwner; // unique-name
Ed Tanous60520632018-06-11 17:46:52 -0700408
William A. Kennington III60ffc242022-12-02 19:36:01 -0800409 message.read(name, oldOwner, newOwner);
Ed Tanous60520632018-06-11 17:46:52 -0700410
William A. Kennington III60ffc242022-12-02 19:36:01 -0800411 if (name.starts_with(':'))
412 {
413 // We should do nothing with unique-name connections.
414 return;
415 }
Patrick Williams48248202022-10-10 10:26:47 -0500416
William A. Kennington III60ffc242022-12-02 19:36:01 -0800417 if (!oldOwner.empty())
418 {
419 processNameChangeDelete(io, nameOwners, name, oldOwner,
420 interfaceMap, associationMaps, server);
421 }
Ed Tanous60520632018-06-11 17:46:52 -0700422
William A. Kennington III60ffc242022-12-02 19:36:01 -0800423 if (!newOwner.empty())
424 {
Brad Bishopd6aa5522022-05-31 19:23:48 -0400425#ifdef MAPPER_ENABLE_DEBUG
William A. Kennington III60ffc242022-12-02 19:36:01 -0800426 auto transaction = std::make_shared<
427 std::chrono::time_point<std::chrono::steady_clock>>(
428 std::chrono::steady_clock::now());
Matt Spinleraecabe82018-09-19 13:25:42 -0500429#endif
William A. Kennington III60ffc242022-12-02 19:36:01 -0800430 // New daemon added
431 if (needToIntrospect(name))
432 {
433 nameOwners[newOwner] = name;
434 startNewIntrospect(systemBus.get(), io, interfaceMap, name,
435 associationMaps,
Brad Bishopd6aa5522022-05-31 19:23:48 -0400436#ifdef MAPPER_ENABLE_DEBUG
William A. Kennington III60ffc242022-12-02 19:36:01 -0800437 transaction,
Matt Spinleraecabe82018-09-19 13:25:42 -0500438#endif
William A. Kennington III60ffc242022-12-02 19:36:01 -0800439 server);
Ed Tanous60520632018-06-11 17:46:52 -0700440 }
William A. Kennington III60ffc242022-12-02 19:36:01 -0800441 }
442 };
Ed Tanous60520632018-06-11 17:46:52 -0700443
Patrick Williamscc8070b2022-07-22 19:26:55 -0500444 sdbusplus::bus::match_t nameOwnerChanged(
445 static_cast<sdbusplus::bus_t&>(*systemBus),
William A. Kennington III60ffc242022-12-02 19:36:01 -0800446 sdbusplus::bus::match::rules::nameOwnerChanged(),
447 std::move(nameChangeHandler));
Ed Tanous60520632018-06-11 17:46:52 -0700448
William A. Kennington III60ffc242022-12-02 19:36:01 -0800449 auto interfacesAddedHandler = [&io, &interfaceMap, &nameOwners,
450 &server](sdbusplus::message_t& message) {
451 sdbusplus::message::object_path objPath;
452 InterfacesAdded interfacesAdded;
453 message.read(objPath, interfacesAdded);
454 std::string wellKnown;
455 if (!getWellKnown(nameOwners, message.get_sender(), wellKnown))
456 {
457 return; // only introspect well-known
458 }
459 if (needToIntrospect(wellKnown))
460 {
461 processInterfaceAdded(io, interfaceMap, objPath, interfacesAdded,
462 wellKnown, associationMaps, server);
463 }
464 };
Ed Tanous60520632018-06-11 17:46:52 -0700465
Patrick Williamscc8070b2022-07-22 19:26:55 -0500466 sdbusplus::bus::match_t interfacesAdded(
467 static_cast<sdbusplus::bus_t&>(*systemBus),
Ed Tanous60520632018-06-11 17:46:52 -0700468 sdbusplus::bus::match::rules::interfacesAdded(),
William A. Kennington III60ffc242022-12-02 19:36:01 -0800469 std::move(interfacesAddedHandler));
Ed Tanous60520632018-06-11 17:46:52 -0700470
William A. Kennington III60ffc242022-12-02 19:36:01 -0800471 auto interfacesRemovedHandler = [&io, &interfaceMap, &nameOwners,
472 &server](sdbusplus::message_t& message) {
473 sdbusplus::message::object_path objPath;
474 std::vector<std::string> interfacesRemoved;
475 message.read(objPath, interfacesRemoved);
476 auto connectionMap = interfaceMap.find(objPath.str);
477 if (connectionMap == interfaceMap.end())
478 {
479 return;
480 }
481
482 std::string sender;
483 if (!getWellKnown(nameOwners, message.get_sender(), sender))
484 {
485 return;
486 }
487 for (const std::string& interface : interfacesRemoved)
488 {
489 auto interfaceSet = connectionMap->second.find(sender);
490 if (interfaceSet == connectionMap->second.end())
Ed Tanous60520632018-06-11 17:46:52 -0700491 {
William A. Kennington III60ffc242022-12-02 19:36:01 -0800492 continue;
Ed Tanous60520632018-06-11 17:46:52 -0700493 }
494
William A. Kennington III60ffc242022-12-02 19:36:01 -0800495 if (interface == assocDefsInterface)
Ed Tanous60520632018-06-11 17:46:52 -0700496 {
William A. Kennington III60ffc242022-12-02 19:36:01 -0800497 removeAssociation(io, objPath.str, sender, server,
498 associationMaps);
Ed Tanous60520632018-06-11 17:46:52 -0700499 }
William A. Kennington III60ffc242022-12-02 19:36:01 -0800500
501 interfaceSet->second.erase(interface);
502
503 if (interfaceSet->second.empty())
Ed Tanous60520632018-06-11 17:46:52 -0700504 {
William A. Kennington III60ffc242022-12-02 19:36:01 -0800505 // If this was the last interface on this connection,
506 // erase the connection
507 connectionMap->second.erase(interfaceSet);
508
509 // Instead of checking if every single path is the endpoint
510 // of an association that needs to be moved to pending,
511 // only check when the only remaining owner of this path is
512 // ourself, which would be because we still own the
513 // association path.
514 if ((connectionMap->second.size() == 1) &&
515 (connectionMap->second.begin()->first ==
516 "xyz.openbmc_project.ObjectMapper"))
Ed Tanous60520632018-06-11 17:46:52 -0700517 {
William A. Kennington III60ffc242022-12-02 19:36:01 -0800518 // Remove the 2 association D-Bus paths and move the
519 // association to pending.
520 moveAssociationToPending(io, objPath.str, associationMaps,
521 server);
Ed Tanous60520632018-06-11 17:46:52 -0700522 }
523 }
William A. Kennington III60ffc242022-12-02 19:36:01 -0800524 }
525 // If this was the last connection on this object path,
526 // erase the object path
527 if (connectionMap->second.empty())
528 {
529 interfaceMap.erase(connectionMap);
530 }
Matt Spinlera82779f2019-01-09 12:39:42 -0600531
William A. Kennington III60ffc242022-12-02 19:36:01 -0800532 removeUnneededParents(objPath.str, sender, interfaceMap);
533 };
Ed Tanous60520632018-06-11 17:46:52 -0700534
Patrick Williamscc8070b2022-07-22 19:26:55 -0500535 sdbusplus::bus::match_t interfacesRemoved(
536 static_cast<sdbusplus::bus_t&>(*systemBus),
Ed Tanous60520632018-06-11 17:46:52 -0700537 sdbusplus::bus::match::rules::interfacesRemoved(),
William A. Kennington III60ffc242022-12-02 19:36:01 -0800538 std::move(interfacesRemovedHandler));
Ed Tanous60520632018-06-11 17:46:52 -0700539
William A. Kennington III60ffc242022-12-02 19:36:01 -0800540 auto associationChangedHandler = [&io, &server, &nameOwners, &interfaceMap](
541 sdbusplus::message_t& message) {
542 std::string objectName;
543 boost::container::flat_map<std::string,
544 std::variant<std::vector<Association>>>
545 values;
546 message.read(objectName, values);
547 auto prop = values.find(assocDefsProperty);
548 if (prop != values.end())
549 {
550 std::vector<Association> associations =
551 std::get<std::vector<Association>>(prop->second);
552
553 std::string wellKnown;
554 if (!getWellKnown(nameOwners, message.get_sender(), wellKnown))
Matt Spinler8f876a52019-04-15 13:22:50 -0500555 {
William A. Kennington III60ffc242022-12-02 19:36:01 -0800556 return;
Matt Spinler8f876a52019-04-15 13:22:50 -0500557 }
William A. Kennington III60ffc242022-12-02 19:36:01 -0800558 associationChanged(io, server, associations, message.get_path(),
559 wellKnown, interfaceMap, associationMaps);
560 }
561 };
Patrick Williamscc8070b2022-07-22 19:26:55 -0500562 sdbusplus::bus::match_t assocChangedMatch(
563 static_cast<sdbusplus::bus_t&>(*systemBus),
Ed Tanous60520632018-06-11 17:46:52 -0700564 sdbusplus::bus::match::rules::interface(
565 "org.freedesktop.DBus.Properties") +
566 sdbusplus::bus::match::rules::member("PropertiesChanged") +
Matt Spinler8f876a52019-04-15 13:22:50 -0500567 sdbusplus::bus::match::rules::argN(0, assocDefsInterface),
William A. Kennington III60ffc242022-12-02 19:36:01 -0800568 std::move(associationChangedHandler));
Matt Spinler8f876a52019-04-15 13:22:50 -0500569
Ed Tanous60520632018-06-11 17:46:52 -0700570 std::shared_ptr<sdbusplus::asio::dbus_interface> iface =
Brad Bishopa02cd542021-10-12 19:12:42 -0400571 server.add_interface("/xyz/openbmc_project/object_mapper",
572 "xyz.openbmc_project.ObjectMapper");
Ed Tanous60520632018-06-11 17:46:52 -0700573
574 iface->register_method(
Brad Bishopa098a372022-05-05 15:19:04 -0400575 "GetAncestors", [&interfaceMap](std::string& reqPath,
576 std::vector<std::string>& interfaces) {
577 return getAncestors(interfaceMap, reqPath, interfaces);
Ed Tanous60520632018-06-11 17:46:52 -0700578 });
579
580 iface->register_method(
Brad Bishopa098a372022-05-05 15:19:04 -0400581 "GetObject", [&interfaceMap](const std::string& path,
582 std::vector<std::string>& interfaces) {
583 return getObject(interfaceMap, path, interfaces);
584 });
585
586 iface->register_method(
587 "GetSubTree", [&interfaceMap](std::string& reqPath, int32_t depth,
Ed Tanous60520632018-06-11 17:46:52 -0700588 std::vector<std::string>& interfaces) {
Brad Bishopa098a372022-05-05 15:19:04 -0400589 return getSubTree(interfaceMap, reqPath, depth, interfaces);
Ed Tanous60520632018-06-11 17:46:52 -0700590 });
591
592 iface->register_method(
593 "GetSubTreePaths",
Brad Bishopa098a372022-05-05 15:19:04 -0400594 [&interfaceMap](std::string& reqPath, int32_t depth,
595 std::vector<std::string>& interfaces) {
596 return getSubTreePaths(interfaceMap, reqPath, depth, interfaces);
Ed Tanous60520632018-06-11 17:46:52 -0700597 });
598
599 iface->initialize();
600
601 io.post([&]() {
Brad Bishopa098a372022-05-05 15:19:04 -0400602 doListNames(io, interfaceMap, systemBus.get(), nameOwners,
Matt Spinler11401e22019-04-08 13:13:25 -0500603 associationMaps, server);
Ed Tanous60520632018-06-11 17:46:52 -0700604 });
605
Brad Bishopa098a372022-05-05 15:19:04 -0400606 systemBus->request_name("xyz.openbmc_project.ObjectMapper");
Vishwanatha Subbanna64354ef2020-08-21 03:35:26 -0500607
Ed Tanous60520632018-06-11 17:46:52 -0700608 io.run();
609}