blob: ebaf1abdc229c02eb2b8722ddbb7f10a6a95bbd5 [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) {
Patrick Williams9052ebd2024-08-16 15:22:16 -040037 if (ec)
38 {
39 std::cerr << "Error getting owner of " << newObject << " : "
40 << ec << "\n";
41 return;
42 }
43 owners[nameOwner] = newObject;
44 },
Ed Tanous60520632018-06-11 17:46:52 -070045 "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 ) :
Patrick Williams9052ebd2024-08-16 15:22:16 -040078 systemBus(systemBus), io(io), processName(processName), assocMaps(am)
Brad Bishopd6aa5522022-05-31 19:23:48 -040079#ifdef MAPPER_ENABLE_DEBUG
Matt Spinleraecabe82018-09-19 13:25:42 -050080 ,
Brad Bishop1f623802022-05-31 18:22:10 -040081 globalStartTime(std::move(globalStartTime)),
Brad Bishopa098a372022-05-05 15:19:04 -040082 processStartTime(std::chrono::steady_clock::now())
Matt Spinleraecabe82018-09-19 13:25:42 -050083#endif
Brad Bishop23520882022-05-26 21:39:53 -040084 {}
Ed Tanous60520632018-06-11 17:46:52 -070085 ~InProgressIntrospect()
86 {
Brad Bishopea119462022-05-31 20:32:04 -040087 try
Ed Tanous60520632018-06-11 17:46:52 -070088 {
Brad Bishopea119462022-05-31 20:32:04 -040089 sendIntrospectionCompleteSignal(systemBus, processName);
Brad Bishopd6aa5522022-05-31 19:23:48 -040090#ifdef MAPPER_ENABLE_DEBUG
Brad Bishopea119462022-05-31 20:32:04 -040091 std::chrono::duration<float> diff =
92 std::chrono::steady_clock::now() - processStartTime;
93 std::cout << std::setw(50) << processName << " scan took "
94 << diff.count() << " seconds\n";
95
96 // If we're the last outstanding caller globally, calculate the
97 // time it took
98 if (globalStartTime != nullptr && globalStartTime.use_count() == 1)
99 {
100 diff = std::chrono::steady_clock::now() - *globalStartTime;
101 std::cout << "Total scan took " << diff.count()
102 << " seconds to complete\n";
103 }
Matt Spinleraecabe82018-09-19 13:25:42 -0500104#endif
Brad Bishopea119462022-05-31 20:32:04 -0400105 }
106 catch (const std::exception& e)
107 {
108 std::cerr
109 << "Terminating, unhandled exception while introspecting: "
110 << e.what() << "\n";
111 std::terminate();
112 }
113 catch (...)
114 {
115 std::cerr
116 << "Terminating, unhandled exception while introspecting\n";
117 std::terminate();
118 }
Ed Tanous60520632018-06-11 17:46:52 -0700119 }
Brad Bishopa098a372022-05-05 15:19:04 -0400120 sdbusplus::asio::connection* systemBus;
Ed Tanous21c60592020-08-17 23:43:46 -0700121 boost::asio::io_context& io;
Brad Bishopa098a372022-05-05 15:19:04 -0400122 std::string processName;
Matt Spinler11401e22019-04-08 13:13:25 -0500123 AssociationMaps& assocMaps;
Brad Bishopd6aa5522022-05-31 19:23:48 -0400124#ifdef MAPPER_ENABLE_DEBUG
Ed Tanous60520632018-06-11 17:46:52 -0700125 std::shared_ptr<std::chrono::time_point<std::chrono::steady_clock>>
Brad Bishopa098a372022-05-05 15:19:04 -0400126 globalStartTime;
127 std::chrono::time_point<std::chrono::steady_clock> processStartTime;
Matt Spinleraecabe82018-09-19 13:25:42 -0500128#endif
Ed Tanous60520632018-06-11 17:46:52 -0700129};
130
Kallas, Pawel5b4357d2022-10-12 15:36:37 +0200131void doAssociations(boost::asio::io_context& io,
132 sdbusplus::asio::connection* systemBus,
Brad Bishopa098a372022-05-05 15:19:04 -0400133 InterfaceMapType& interfaceMap,
134 sdbusplus::asio::object_server& objectServer,
135 const std::string& processName, const std::string& path,
136 int timeoutRetries = 0)
Ed Tanous60520632018-06-11 17:46:52 -0700137{
Adrian Ambrożewiczbb40bd32021-02-12 13:36:26 +0100138 constexpr int maxTimeoutRetries = 3;
Brad Bishopa098a372022-05-05 15:19:04 -0400139 systemBus->async_method_call(
Kallas, Pawel5b4357d2022-10-12 15:36:37 +0200140 [&io, &objectServer, path, processName, &interfaceMap, systemBus,
Adrian Ambrożewiczbb40bd32021-02-12 13:36:26 +0100141 timeoutRetries](
Matt Spinler937a2322019-01-23 13:54:22 -0600142 const boost::system::error_code ec,
Patrick Williams2bb2d6b2020-05-13 17:59:02 -0500143 const std::variant<std::vector<Association>>& variantAssociations) {
Patrick Williams9052ebd2024-08-16 15:22:16 -0400144 if (ec)
Ed Tanous60520632018-06-11 17:46:52 -0700145 {
Patrick Williams9052ebd2024-08-16 15:22:16 -0400146 if (ec.value() == boost::system::errc::timed_out &&
147 timeoutRetries < maxTimeoutRetries)
148 {
149 doAssociations(io, systemBus, interfaceMap, objectServer,
150 processName, path, timeoutRetries + 1);
151 return;
152 }
153 std::cerr << "Error getting associations from " << path << "\n";
Ed Tanous60520632018-06-11 17:46:52 -0700154 }
Patrick Williams9052ebd2024-08-16 15:22:16 -0400155 std::vector<Association> associations =
156 std::get<std::vector<Association>>(variantAssociations);
157 associationChanged(io, objectServer, associations, path,
158 processName, interfaceMap, associationMaps);
159 },
Ed Tanous60520632018-06-11 17:46:52 -0700160 processName, path, "org.freedesktop.DBus.Properties", "Get",
John Wangd0cf9422019-09-17 16:01:34 +0800161 assocDefsInterface, assocDefsProperty);
Ed Tanous60520632018-06-11 17:46:52 -0700162}
163
Kallas, Pawel5b4357d2022-10-12 15:36:37 +0200164void doIntrospect(boost::asio::io_context& io,
165 sdbusplus::asio::connection* systemBus,
Brad Bishop1f623802022-05-31 18:22:10 -0400166 const std::shared_ptr<InProgressIntrospect>& transaction,
Brad Bishopa098a372022-05-05 15:19:04 -0400167 InterfaceMapType& interfaceMap,
168 sdbusplus::asio::object_server& objectServer,
Brad Bishop1f623802022-05-31 18:22:10 -0400169 const std::string& path, int timeoutRetries = 0)
Ed Tanous60520632018-06-11 17:46:52 -0700170{
Vernon Maueryc52be0d2020-01-14 11:14:25 -0800171 constexpr int maxTimeoutRetries = 3;
Brad Bishopa098a372022-05-05 15:19:04 -0400172 systemBus->async_method_call(
Kallas, Pawel5b4357d2022-10-12 15:36:37 +0200173 [&io, &interfaceMap, &objectServer, transaction, path, systemBus,
Vernon Maueryc52be0d2020-01-14 11:14:25 -0800174 timeoutRetries](const boost::system::error_code ec,
Brad Bishopa098a372022-05-05 15:19:04 -0400175 const std::string& introspectXml) {
Patrick Williams9052ebd2024-08-16 15:22:16 -0400176 if (ec)
Ed Tanous60520632018-06-11 17:46:52 -0700177 {
Patrick Williams9052ebd2024-08-16 15:22:16 -0400178 if (ec.value() == boost::system::errc::timed_out &&
179 timeoutRetries < maxTimeoutRetries)
180 {
181 doIntrospect(io, systemBus, transaction, interfaceMap,
182 objectServer, path, timeoutRetries + 1);
183 return;
184 }
185 std::cerr << "Introspect call failed with error: " << ec << ", "
186 << ec.message()
187 << " on process: " << transaction->processName
188 << " path: " << path << "\n";
Ed Tanous60520632018-06-11 17:46:52 -0700189 return;
190 }
191
Patrick Williams9052ebd2024-08-16 15:22:16 -0400192 tinyxml2::XMLDocument doc;
Ed Tanous60520632018-06-11 17:46:52 -0700193
Patrick Williams9052ebd2024-08-16 15:22:16 -0400194 tinyxml2::XMLError e = doc.Parse(introspectXml.c_str());
195 if (e != tinyxml2::XMLError::XML_SUCCESS)
Ed Tanous60520632018-06-11 17:46:52 -0700196 {
Patrick Williams9052ebd2024-08-16 15:22:16 -0400197 std::cerr << "XML parsing failed\n";
198 return;
Ed Tanous60520632018-06-11 17:46:52 -0700199 }
200
Patrick Williams9052ebd2024-08-16 15:22:16 -0400201 tinyxml2::XMLNode* pRoot = doc.FirstChildElement("node");
202 if (pRoot == nullptr)
Ed Tanous60520632018-06-11 17:46:52 -0700203 {
Patrick Williams9052ebd2024-08-16 15:22:16 -0400204 std::cerr << "XML document did not contain any data\n";
205 return;
Ed Tanous60520632018-06-11 17:46:52 -0700206 }
Patrick Williams9052ebd2024-08-16 15:22:16 -0400207 auto& thisPathMap = interfaceMap[path];
208 tinyxml2::XMLElement* pElement =
209 pRoot->FirstChildElement("interface");
210 while (pElement != nullptr)
Ed Tanous60520632018-06-11 17:46:52 -0700211 {
Patrick Williams9052ebd2024-08-16 15:22:16 -0400212 const char* ifaceName = pElement->Attribute("name");
213 if (ifaceName == nullptr)
Ed Tanous60520632018-06-11 17:46:52 -0700214 {
Patrick Williams9052ebd2024-08-16 15:22:16 -0400215 continue;
Ed Tanous60520632018-06-11 17:46:52 -0700216 }
217
Patrick Williams9052ebd2024-08-16 15:22:16 -0400218 thisPathMap[transaction->processName].emplace(ifaceName);
219
220 if (std::strcmp(ifaceName, assocDefsInterface) == 0)
221 {
222 doAssociations(io, systemBus, interfaceMap, objectServer,
223 transaction->processName, path);
224 }
225
226 pElement = pElement->NextSiblingElement("interface");
Ed Tanous60520632018-06-11 17:46:52 -0700227 }
Patrick Williams9052ebd2024-08-16 15:22:16 -0400228
229 // Check if this new path has a pending association that can
230 // now be completed.
231 checkIfPendingAssociation(io, path, interfaceMap,
232 transaction->assocMaps, objectServer);
233
234 pElement = pRoot->FirstChildElement("node");
235 while (pElement != nullptr)
236 {
237 const char* childPath = pElement->Attribute("name");
238 if (childPath != nullptr)
239 {
240 std::string parentPath(path);
241 if (parentPath == "/")
242 {
243 parentPath.clear();
244 }
245
246 doIntrospect(io, systemBus, transaction, interfaceMap,
247 objectServer, parentPath + "/" + childPath);
248 }
249 pElement = pElement->NextSiblingElement("node");
250 }
251 },
Brad Bishopa098a372022-05-05 15:19:04 -0400252 transaction->processName, path, "org.freedesktop.DBus.Introspectable",
Ed Tanous60520632018-06-11 17:46:52 -0700253 "Introspect");
254}
255
Brad Bishopa098a372022-05-05 15:19:04 -0400256void startNewIntrospect(
257 sdbusplus::asio::connection* systemBus, boost::asio::io_context& io,
258 InterfaceMapType& interfaceMap, const std::string& processName,
Matt Spinler11401e22019-04-08 13:13:25 -0500259 AssociationMaps& assocMaps,
Brad Bishopd6aa5522022-05-31 19:23:48 -0400260#ifdef MAPPER_ENABLE_DEBUG
Ed Tanous60520632018-06-11 17:46:52 -0700261 std::shared_ptr<std::chrono::time_point<std::chrono::steady_clock>>
Brad Bishopa098a372022-05-05 15:19:04 -0400262 globalStartTime,
Matt Spinleraecabe82018-09-19 13:25:42 -0500263#endif
Ed Tanous60520632018-06-11 17:46:52 -0700264 sdbusplus::asio::object_server& objectServer)
265{
Brad Bishop1e94e602022-06-02 19:47:53 -0400266 if (needToIntrospect(processName))
Ed Tanous60520632018-06-11 17:46:52 -0700267 {
Ed Tanous60520632018-06-11 17:46:52 -0700268 std::shared_ptr<InProgressIntrospect> transaction =
Patrick Williams9052ebd2024-08-16 15:22:16 -0400269 std::make_shared<InProgressIntrospect>(
270 systemBus, io, processName, assocMaps
Brad Bishopd6aa5522022-05-31 19:23:48 -0400271#ifdef MAPPER_ENABLE_DEBUG
Patrick Williams9052ebd2024-08-16 15:22:16 -0400272 ,
273 globalStartTime
Matt Spinleraecabe82018-09-19 13:25:42 -0500274#endif
275 );
Ed Tanous60520632018-06-11 17:46:52 -0700276
Kallas, Pawel5b4357d2022-10-12 15:36:37 +0200277 doIntrospect(io, systemBus, transaction, interfaceMap, objectServer,
278 "/");
Ed Tanous60520632018-06-11 17:46:52 -0700279 }
280}
281
Ed Tanous60520632018-06-11 17:46:52 -0700282void doListNames(
Brad Bishopa098a372022-05-05 15:19:04 -0400283 boost::asio::io_context& io, InterfaceMapType& interfaceMap,
284 sdbusplus::asio::connection* systemBus,
285 boost::container::flat_map<std::string, std::string>& nameOwners,
Matt Spinler11401e22019-04-08 13:13:25 -0500286 AssociationMaps& assocMaps, sdbusplus::asio::object_server& objectServer)
Ed Tanous60520632018-06-11 17:46:52 -0700287{
Brad Bishopa098a372022-05-05 15:19:04 -0400288 systemBus->async_method_call(
289 [&io, &interfaceMap, &nameOwners, &objectServer, systemBus,
Matt Spinler11401e22019-04-08 13:13:25 -0500290 &assocMaps](const boost::system::error_code ec,
Brad Bishopa098a372022-05-05 15:19:04 -0400291 std::vector<std::string> processNames) {
Patrick Williams9052ebd2024-08-16 15:22:16 -0400292 if (ec)
Ed Tanous60520632018-06-11 17:46:52 -0700293 {
Patrick Williams9052ebd2024-08-16 15:22:16 -0400294 std::cerr << "Error getting names: " << ec << "\n";
295 std::exit(EXIT_FAILURE);
296 return;
Ed Tanous60520632018-06-11 17:46:52 -0700297 }
Patrick Williams9052ebd2024-08-16 15:22:16 -0400298 // Try to make startup consistent
299 std::sort(processNames.begin(), processNames.end());
300#ifdef MAPPER_ENABLE_DEBUG
301 std::shared_ptr<std::chrono::time_point<std::chrono::steady_clock>>
302 globalStartTime = std::make_shared<
303 std::chrono::time_point<std::chrono::steady_clock>>(
304 std::chrono::steady_clock::now());
305#endif
306 for (const std::string& processName : processNames)
307 {
308 if (needToIntrospect(processName))
309 {
310 startNewIntrospect(systemBus, io, interfaceMap, processName,
311 assocMaps,
312#ifdef MAPPER_ENABLE_DEBUG
313 globalStartTime,
314#endif
315 objectServer);
316 updateOwners(systemBus, nameOwners, processName);
317 }
318 }
319 },
Ed Tanous60520632018-06-11 17:46:52 -0700320 "org.freedesktop.DBus", "/org/freedesktop/DBus", "org.freedesktop.DBus",
321 "ListNames");
322}
323
Matt Spinlera82779f2019-01-09 12:39:42 -0600324// Remove parents of the passed in path that:
325// 1) Only have the 3 default interfaces on them
326// - Means D-Bus created these, not application code,
327// with the Properties, Introspectable, and Peer ifaces
328// 2) Have no other child for this owner
329void removeUnneededParents(const std::string& objectPath,
330 const std::string& owner,
Brad Bishopa098a372022-05-05 15:19:04 -0400331 InterfaceMapType& interfaceMap)
Matt Spinlera82779f2019-01-09 12:39:42 -0600332{
333 auto parent = objectPath;
334
335 while (true)
336 {
337 auto pos = parent.find_last_of('/');
338 if ((pos == std::string::npos) || (pos == 0))
339 {
340 break;
341 }
342 parent = parent.substr(0, pos);
343
Brad Bishopa098a372022-05-05 15:19:04 -0400344 auto parentIt = interfaceMap.find(parent);
345 if (parentIt == interfaceMap.end())
Matt Spinlera82779f2019-01-09 12:39:42 -0600346 {
347 break;
348 }
349
Brad Bishopa098a372022-05-05 15:19:04 -0400350 auto ifacesIt = parentIt->second.find(owner);
351 if (ifacesIt == parentIt->second.end())
Matt Spinlera82779f2019-01-09 12:39:42 -0600352 {
353 break;
354 }
355
Brad Bishopa098a372022-05-05 15:19:04 -0400356 if (ifacesIt->second.size() != 3)
Matt Spinlera82779f2019-01-09 12:39:42 -0600357 {
358 break;
359 }
360
Brad Bishopa098a372022-05-05 15:19:04 -0400361 auto childPath = parent + '/';
Matt Spinlera82779f2019-01-09 12:39:42 -0600362
363 // Remove this parent if there isn't a remaining child on this owner
Patrick Williams9052ebd2024-08-16 15:22:16 -0400364 auto child = std::find_if(
365 interfaceMap.begin(), interfaceMap.end(),
366 [&owner, &childPath](const auto& entry) {
367 return entry.first.starts_with(childPath) &&
368 (entry.second.find(owner) != entry.second.end());
369 });
Matt Spinlera82779f2019-01-09 12:39:42 -0600370
Brad Bishopa098a372022-05-05 15:19:04 -0400371 if (child == interfaceMap.end())
Matt Spinlera82779f2019-01-09 12:39:42 -0600372 {
Brad Bishopa098a372022-05-05 15:19:04 -0400373 parentIt->second.erase(ifacesIt);
374 if (parentIt->second.empty())
Matt Spinlera82779f2019-01-09 12:39:42 -0600375 {
Brad Bishopa098a372022-05-05 15:19:04 -0400376 interfaceMap.erase(parentIt);
Matt Spinlera82779f2019-01-09 12:39:42 -0600377 }
378 }
379 else
380 {
381 break;
382 }
383 }
384}
385
Brad Bishop1e94e602022-06-02 19:47:53 -0400386int main()
Ed Tanous60520632018-06-11 17:46:52 -0700387{
Ed Tanous21c60592020-08-17 23:43:46 -0700388 boost::asio::io_context io;
Brad Bishopa098a372022-05-05 15:19:04 -0400389 std::shared_ptr<sdbusplus::asio::connection> systemBus =
Ed Tanous60520632018-06-11 17:46:52 -0700390 std::make_shared<sdbusplus::asio::connection>(io);
391
Brad Bishopa098a372022-05-05 15:19:04 -0400392 sdbusplus::asio::object_server server(systemBus);
Ed Tanous60520632018-06-11 17:46:52 -0700393
394 // Construct a signal set registered for process termination.
395 boost::asio::signal_set signals(io, SIGINT, SIGTERM);
Patrick Williams9052ebd2024-08-16 15:22:16 -0400396 signals.async_wait([&io](const boost::system::error_code&, int) {
397 io.stop();
398 });
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) {
Patrick Williams9052ebd2024-08-16 15:22:16 -0400577 return getAncestors(interfaceMap, reqPath, interfaces);
578 });
Ed Tanous60520632018-06-11 17:46:52 -0700579
580 iface->register_method(
Brad Bishopa098a372022-05-05 15:19:04 -0400581 "GetObject", [&interfaceMap](const std::string& path,
582 std::vector<std::string>& interfaces) {
Patrick Williams9052ebd2024-08-16 15:22:16 -0400583 return getObject(interfaceMap, path, interfaces);
584 });
Brad Bishopa098a372022-05-05 15:19:04 -0400585
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) {
Patrick Williams9052ebd2024-08-16 15:22:16 -0400589 return getSubTree(interfaceMap, reqPath, depth, interfaces);
590 });
Ed Tanous60520632018-06-11 17:46:52 -0700591
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) {
Patrick Williams9052ebd2024-08-16 15:22:16 -0400596 return getSubTreePaths(interfaceMap, reqPath, depth, interfaces);
597 });
Ed Tanous60520632018-06-11 17:46:52 -0700598
Willy Tu58881d02022-10-02 20:46:45 +0000599 iface->register_method(
600 "GetAssociatedSubTree",
601 [&interfaceMap](const sdbusplus::message::object_path& associationPath,
602 const sdbusplus::message::object_path& reqPath,
603 int32_t depth, std::vector<std::string>& interfaces) {
Patrick Williams9052ebd2024-08-16 15:22:16 -0400604 return getAssociatedSubTree(interfaceMap, associationMaps,
605 associationPath, reqPath, depth,
606 interfaces);
607 });
Willy Tu58881d02022-10-02 20:46:45 +0000608
609 iface->register_method(
610 "GetAssociatedSubTreePaths",
611 [&interfaceMap](const sdbusplus::message::object_path& associationPath,
612 const sdbusplus::message::object_path& reqPath,
613 int32_t depth, std::vector<std::string>& interfaces) {
Patrick Williams9052ebd2024-08-16 15:22:16 -0400614 return getAssociatedSubTreePaths(interfaceMap, associationMaps,
615 associationPath, reqPath, depth,
616 interfaces);
617 });
Willy Tu58881d02022-10-02 20:46:45 +0000618
Lakshmi Yadlapatic3633232024-04-09 10:47:29 -0500619 iface->register_method(
620 "GetAssociatedSubTreeById",
621 [&interfaceMap](const std::string& id, const std::string& objectPath,
622 std::vector<std::string>& subtreeInterfaces,
623 const std::string& association,
624 std::vector<std::string>& endpointInterfaces) {
625 return getAssociatedSubTreeById(interfaceMap, associationMaps, id,
626 objectPath, subtreeInterfaces,
627 association, endpointInterfaces);
628 });
629
630 iface->register_method(
631 "GetAssociatedSubTreePathsById",
632 [&interfaceMap](const std::string& id, const std::string& objectPath,
633 std::vector<std::string>& subtreeInterfaces,
634 const std::string& association,
635 std::vector<std::string>& endpointInterfaces) {
636 return getAssociatedSubTreePathsById(
637 interfaceMap, associationMaps, id, objectPath,
638 subtreeInterfaces, association, endpointInterfaces);
639 });
640
Ed Tanous60520632018-06-11 17:46:52 -0700641 iface->initialize();
642
643 io.post([&]() {
Brad Bishopa098a372022-05-05 15:19:04 -0400644 doListNames(io, interfaceMap, systemBus.get(), nameOwners,
Matt Spinler11401e22019-04-08 13:13:25 -0500645 associationMaps, server);
Ed Tanous60520632018-06-11 17:46:52 -0700646 });
647
Brad Bishopa098a372022-05-05 15:19:04 -0400648 systemBus->request_name("xyz.openbmc_project.ObjectMapper");
Vishwanatha Subbanna64354ef2020-08-21 03:35:26 -0500649
Ed Tanous60520632018-06-11 17:46:52 -0700650 io.run();
651}