blob: b79d7227abe59654c4daea89cf8d5732f7145f13 [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 Bishop11c0cc32025-07-08 16:04:25 -040070 sdbusplus::asio::connection* systemBusConnection,
71 boost::asio::io_context& ioContext,
72 const std::string& introspectProcessName, AssociationMaps& am
Brad Bishopd6aa5522022-05-31 19:23:48 -040073#ifdef MAPPER_ENABLE_DEBUG
Matt Spinleraecabe82018-09-19 13:25:42 -050074 ,
Ed Tanous60520632018-06-11 17:46:52 -070075 std::shared_ptr<std::chrono::time_point<std::chrono::steady_clock>>
Brad Bishop11c0cc32025-07-08 16:04:25 -040076 globalIntrospectStartTime
Matt Spinleraecabe82018-09-19 13:25:42 -050077#endif
78 ) :
Brad Bishop11c0cc32025-07-08 16:04:25 -040079 systemBus(systemBusConnection), io(ioContext),
80 processName(introspectProcessName), assocMaps(am)
Brad Bishopd6aa5522022-05-31 19:23:48 -040081#ifdef MAPPER_ENABLE_DEBUG
Matt Spinleraecabe82018-09-19 13:25:42 -050082 ,
Brad Bishop11c0cc32025-07-08 16:04:25 -040083 globalStartTime(std::move(globalIntrospectStartTime)),
Brad Bishopa098a372022-05-05 15:19:04 -040084 processStartTime(std::chrono::steady_clock::now())
Matt Spinleraecabe82018-09-19 13:25:42 -050085#endif
Brad Bishop23520882022-05-26 21:39:53 -040086 {}
Ed Tanous60520632018-06-11 17:46:52 -070087 ~InProgressIntrospect()
88 {
Brad Bishopea119462022-05-31 20:32:04 -040089 try
Ed Tanous60520632018-06-11 17:46:52 -070090 {
Brad Bishopea119462022-05-31 20:32:04 -040091 sendIntrospectionCompleteSignal(systemBus, processName);
Brad Bishopd6aa5522022-05-31 19:23:48 -040092#ifdef MAPPER_ENABLE_DEBUG
Brad Bishopea119462022-05-31 20:32:04 -040093 std::chrono::duration<float> diff =
94 std::chrono::steady_clock::now() - processStartTime;
95 std::cout << std::setw(50) << processName << " scan took "
96 << diff.count() << " seconds\n";
97
98 // If we're the last outstanding caller globally, calculate the
99 // time it took
100 if (globalStartTime != nullptr && globalStartTime.use_count() == 1)
101 {
102 diff = std::chrono::steady_clock::now() - *globalStartTime;
103 std::cout << "Total scan took " << diff.count()
104 << " seconds to complete\n";
105 }
Matt Spinleraecabe82018-09-19 13:25:42 -0500106#endif
Brad Bishopea119462022-05-31 20:32:04 -0400107 }
108 catch (const std::exception& e)
109 {
110 std::cerr
111 << "Terminating, unhandled exception while introspecting: "
112 << e.what() << "\n";
113 std::terminate();
114 }
115 catch (...)
116 {
117 std::cerr
118 << "Terminating, unhandled exception while introspecting\n";
119 std::terminate();
120 }
Ed Tanous60520632018-06-11 17:46:52 -0700121 }
Brad Bishopa098a372022-05-05 15:19:04 -0400122 sdbusplus::asio::connection* systemBus;
Ed Tanous21c60592020-08-17 23:43:46 -0700123 boost::asio::io_context& io;
Brad Bishopa098a372022-05-05 15:19:04 -0400124 std::string processName;
Matt Spinler11401e22019-04-08 13:13:25 -0500125 AssociationMaps& assocMaps;
Brad Bishopd6aa5522022-05-31 19:23:48 -0400126#ifdef MAPPER_ENABLE_DEBUG
Ed Tanous60520632018-06-11 17:46:52 -0700127 std::shared_ptr<std::chrono::time_point<std::chrono::steady_clock>>
Brad Bishopa098a372022-05-05 15:19:04 -0400128 globalStartTime;
129 std::chrono::time_point<std::chrono::steady_clock> processStartTime;
Matt Spinleraecabe82018-09-19 13:25:42 -0500130#endif
Ed Tanous60520632018-06-11 17:46:52 -0700131};
132
Kallas, Pawel5b4357d2022-10-12 15:36:37 +0200133void doAssociations(boost::asio::io_context& io,
134 sdbusplus::asio::connection* systemBus,
Brad Bishopa098a372022-05-05 15:19:04 -0400135 InterfaceMapType& interfaceMap,
136 sdbusplus::asio::object_server& objectServer,
137 const std::string& processName, const std::string& path,
138 int timeoutRetries = 0)
Ed Tanous60520632018-06-11 17:46:52 -0700139{
Adrian Ambrożewiczbb40bd32021-02-12 13:36:26 +0100140 constexpr int maxTimeoutRetries = 3;
Brad Bishopa098a372022-05-05 15:19:04 -0400141 systemBus->async_method_call(
Kallas, Pawel5b4357d2022-10-12 15:36:37 +0200142 [&io, &objectServer, path, processName, &interfaceMap, systemBus,
Adrian Ambrożewiczbb40bd32021-02-12 13:36:26 +0100143 timeoutRetries](
Matt Spinler937a2322019-01-23 13:54:22 -0600144 const boost::system::error_code ec,
Patrick Williams2bb2d6b2020-05-13 17:59:02 -0500145 const std::variant<std::vector<Association>>& variantAssociations) {
Patrick Williams9052ebd2024-08-16 15:22:16 -0400146 if (ec)
Ed Tanous60520632018-06-11 17:46:52 -0700147 {
Patrick Williams9052ebd2024-08-16 15:22:16 -0400148 if (ec.value() == boost::system::errc::timed_out &&
149 timeoutRetries < maxTimeoutRetries)
150 {
151 doAssociations(io, systemBus, interfaceMap, objectServer,
152 processName, path, timeoutRetries + 1);
153 return;
154 }
155 std::cerr << "Error getting associations from " << path << "\n";
Ed Tanous60520632018-06-11 17:46:52 -0700156 }
Patrick Williams9052ebd2024-08-16 15:22:16 -0400157 std::vector<Association> associations =
158 std::get<std::vector<Association>>(variantAssociations);
159 associationChanged(io, objectServer, associations, path,
160 processName, interfaceMap, associationMaps);
161 },
Ed Tanous60520632018-06-11 17:46:52 -0700162 processName, path, "org.freedesktop.DBus.Properties", "Get",
John Wangd0cf9422019-09-17 16:01:34 +0800163 assocDefsInterface, assocDefsProperty);
Ed Tanous60520632018-06-11 17:46:52 -0700164}
165
Kallas, Pawel5b4357d2022-10-12 15:36:37 +0200166void doIntrospect(boost::asio::io_context& io,
167 sdbusplus::asio::connection* systemBus,
Brad Bishop1f623802022-05-31 18:22:10 -0400168 const std::shared_ptr<InProgressIntrospect>& transaction,
Brad Bishopa098a372022-05-05 15:19:04 -0400169 InterfaceMapType& interfaceMap,
170 sdbusplus::asio::object_server& objectServer,
Brad Bishop1f623802022-05-31 18:22:10 -0400171 const std::string& path, int timeoutRetries = 0)
Ed Tanous60520632018-06-11 17:46:52 -0700172{
Vernon Maueryc52be0d2020-01-14 11:14:25 -0800173 constexpr int maxTimeoutRetries = 3;
Brad Bishopa098a372022-05-05 15:19:04 -0400174 systemBus->async_method_call(
Kallas, Pawel5b4357d2022-10-12 15:36:37 +0200175 [&io, &interfaceMap, &objectServer, transaction, path, systemBus,
Vernon Maueryc52be0d2020-01-14 11:14:25 -0800176 timeoutRetries](const boost::system::error_code ec,
Brad Bishopa098a372022-05-05 15:19:04 -0400177 const std::string& introspectXml) {
Patrick Williams9052ebd2024-08-16 15:22:16 -0400178 if (ec)
Ed Tanous60520632018-06-11 17:46:52 -0700179 {
Patrick Williams9052ebd2024-08-16 15:22:16 -0400180 if (ec.value() == boost::system::errc::timed_out &&
181 timeoutRetries < maxTimeoutRetries)
182 {
183 doIntrospect(io, systemBus, transaction, interfaceMap,
184 objectServer, path, timeoutRetries + 1);
185 return;
186 }
187 std::cerr << "Introspect call failed with error: " << ec << ", "
188 << ec.message()
189 << " on process: " << transaction->processName
190 << " path: " << path << "\n";
Ed Tanous60520632018-06-11 17:46:52 -0700191 return;
192 }
193
Patrick Williams9052ebd2024-08-16 15:22:16 -0400194 tinyxml2::XMLDocument doc;
Ed Tanous60520632018-06-11 17:46:52 -0700195
Patrick Williams9052ebd2024-08-16 15:22:16 -0400196 tinyxml2::XMLError e = doc.Parse(introspectXml.c_str());
197 if (e != tinyxml2::XMLError::XML_SUCCESS)
Ed Tanous60520632018-06-11 17:46:52 -0700198 {
Patrick Williams9052ebd2024-08-16 15:22:16 -0400199 std::cerr << "XML parsing failed\n";
200 return;
Ed Tanous60520632018-06-11 17:46:52 -0700201 }
202
Patrick Williams9052ebd2024-08-16 15:22:16 -0400203 tinyxml2::XMLNode* pRoot = doc.FirstChildElement("node");
204 if (pRoot == nullptr)
Ed Tanous60520632018-06-11 17:46:52 -0700205 {
Patrick Williams9052ebd2024-08-16 15:22:16 -0400206 std::cerr << "XML document did not contain any data\n";
207 return;
Ed Tanous60520632018-06-11 17:46:52 -0700208 }
Patrick Williams9052ebd2024-08-16 15:22:16 -0400209 auto& thisPathMap = interfaceMap[path];
210 tinyxml2::XMLElement* pElement =
211 pRoot->FirstChildElement("interface");
212 while (pElement != nullptr)
Ed Tanous60520632018-06-11 17:46:52 -0700213 {
Patrick Williams9052ebd2024-08-16 15:22:16 -0400214 const char* ifaceName = pElement->Attribute("name");
215 if (ifaceName == nullptr)
Ed Tanous60520632018-06-11 17:46:52 -0700216 {
Patrick Williams9052ebd2024-08-16 15:22:16 -0400217 continue;
Ed Tanous60520632018-06-11 17:46:52 -0700218 }
219
Patrick Williams9052ebd2024-08-16 15:22:16 -0400220 thisPathMap[transaction->processName].emplace(ifaceName);
221
222 if (std::strcmp(ifaceName, assocDefsInterface) == 0)
223 {
224 doAssociations(io, systemBus, interfaceMap, objectServer,
225 transaction->processName, path);
226 }
227
228 pElement = pElement->NextSiblingElement("interface");
Ed Tanous60520632018-06-11 17:46:52 -0700229 }
Patrick Williams9052ebd2024-08-16 15:22:16 -0400230
231 // Check if this new path has a pending association that can
232 // now be completed.
233 checkIfPendingAssociation(io, path, interfaceMap,
234 transaction->assocMaps, objectServer);
235
236 pElement = pRoot->FirstChildElement("node");
237 while (pElement != nullptr)
238 {
239 const char* childPath = pElement->Attribute("name");
240 if (childPath != nullptr)
241 {
242 std::string parentPath(path);
243 if (parentPath == "/")
244 {
245 parentPath.clear();
246 }
247
248 doIntrospect(io, systemBus, transaction, interfaceMap,
249 objectServer, parentPath + "/" + childPath);
250 }
251 pElement = pElement->NextSiblingElement("node");
252 }
253 },
Brad Bishopa098a372022-05-05 15:19:04 -0400254 transaction->processName, path, "org.freedesktop.DBus.Introspectable",
Ed Tanous60520632018-06-11 17:46:52 -0700255 "Introspect");
256}
257
Brad Bishopa098a372022-05-05 15:19:04 -0400258void startNewIntrospect(
259 sdbusplus::asio::connection* systemBus, boost::asio::io_context& io,
260 InterfaceMapType& interfaceMap, const std::string& processName,
Matt Spinler11401e22019-04-08 13:13:25 -0500261 AssociationMaps& assocMaps,
Brad Bishopd6aa5522022-05-31 19:23:48 -0400262#ifdef MAPPER_ENABLE_DEBUG
Ed Tanous60520632018-06-11 17:46:52 -0700263 std::shared_ptr<std::chrono::time_point<std::chrono::steady_clock>>
Brad Bishopa098a372022-05-05 15:19:04 -0400264 globalStartTime,
Matt Spinleraecabe82018-09-19 13:25:42 -0500265#endif
Ed Tanous60520632018-06-11 17:46:52 -0700266 sdbusplus::asio::object_server& objectServer)
267{
Brad Bishop1e94e602022-06-02 19:47:53 -0400268 if (needToIntrospect(processName))
Ed Tanous60520632018-06-11 17:46:52 -0700269 {
Ed Tanous60520632018-06-11 17:46:52 -0700270 std::shared_ptr<InProgressIntrospect> transaction =
Patrick Williams9052ebd2024-08-16 15:22:16 -0400271 std::make_shared<InProgressIntrospect>(
272 systemBus, io, processName, assocMaps
Brad Bishopd6aa5522022-05-31 19:23:48 -0400273#ifdef MAPPER_ENABLE_DEBUG
Patrick Williams9052ebd2024-08-16 15:22:16 -0400274 ,
275 globalStartTime
Matt Spinleraecabe82018-09-19 13:25:42 -0500276#endif
277 );
Ed Tanous60520632018-06-11 17:46:52 -0700278
Kallas, Pawel5b4357d2022-10-12 15:36:37 +0200279 doIntrospect(io, systemBus, transaction, interfaceMap, objectServer,
280 "/");
Ed Tanous60520632018-06-11 17:46:52 -0700281 }
282}
283
Ed Tanous60520632018-06-11 17:46:52 -0700284void doListNames(
Brad Bishopa098a372022-05-05 15:19:04 -0400285 boost::asio::io_context& io, InterfaceMapType& interfaceMap,
286 sdbusplus::asio::connection* systemBus,
287 boost::container::flat_map<std::string, std::string>& nameOwners,
Matt Spinler11401e22019-04-08 13:13:25 -0500288 AssociationMaps& assocMaps, sdbusplus::asio::object_server& objectServer)
Ed Tanous60520632018-06-11 17:46:52 -0700289{
Brad Bishopa098a372022-05-05 15:19:04 -0400290 systemBus->async_method_call(
291 [&io, &interfaceMap, &nameOwners, &objectServer, systemBus,
Matt Spinler11401e22019-04-08 13:13:25 -0500292 &assocMaps](const boost::system::error_code ec,
Brad Bishopa098a372022-05-05 15:19:04 -0400293 std::vector<std::string> processNames) {
Patrick Williams9052ebd2024-08-16 15:22:16 -0400294 if (ec)
Ed Tanous60520632018-06-11 17:46:52 -0700295 {
Patrick Williams9052ebd2024-08-16 15:22:16 -0400296 std::cerr << "Error getting names: " << ec << "\n";
297 std::exit(EXIT_FAILURE);
298 return;
Ed Tanous60520632018-06-11 17:46:52 -0700299 }
Patrick Williams9052ebd2024-08-16 15:22:16 -0400300 // Try to make startup consistent
301 std::sort(processNames.begin(), processNames.end());
302#ifdef MAPPER_ENABLE_DEBUG
303 std::shared_ptr<std::chrono::time_point<std::chrono::steady_clock>>
304 globalStartTime = std::make_shared<
305 std::chrono::time_point<std::chrono::steady_clock>>(
306 std::chrono::steady_clock::now());
307#endif
308 for (const std::string& processName : processNames)
309 {
310 if (needToIntrospect(processName))
311 {
312 startNewIntrospect(systemBus, io, interfaceMap, processName,
313 assocMaps,
314#ifdef MAPPER_ENABLE_DEBUG
315 globalStartTime,
316#endif
317 objectServer);
318 updateOwners(systemBus, nameOwners, processName);
319 }
320 }
321 },
Ed Tanous60520632018-06-11 17:46:52 -0700322 "org.freedesktop.DBus", "/org/freedesktop/DBus", "org.freedesktop.DBus",
323 "ListNames");
324}
325
Matt Spinlera82779f2019-01-09 12:39:42 -0600326// Remove parents of the passed in path that:
327// 1) Only have the 3 default interfaces on them
328// - Means D-Bus created these, not application code,
329// with the Properties, Introspectable, and Peer ifaces
330// 2) Have no other child for this owner
331void removeUnneededParents(const std::string& objectPath,
332 const std::string& owner,
Brad Bishopa098a372022-05-05 15:19:04 -0400333 InterfaceMapType& interfaceMap)
Matt Spinlera82779f2019-01-09 12:39:42 -0600334{
335 auto parent = objectPath;
336
337 while (true)
338 {
339 auto pos = parent.find_last_of('/');
340 if ((pos == std::string::npos) || (pos == 0))
341 {
342 break;
343 }
344 parent = parent.substr(0, pos);
345
Brad Bishopa098a372022-05-05 15:19:04 -0400346 auto parentIt = interfaceMap.find(parent);
347 if (parentIt == interfaceMap.end())
Matt Spinlera82779f2019-01-09 12:39:42 -0600348 {
349 break;
350 }
351
Brad Bishopa098a372022-05-05 15:19:04 -0400352 auto ifacesIt = parentIt->second.find(owner);
353 if (ifacesIt == parentIt->second.end())
Matt Spinlera82779f2019-01-09 12:39:42 -0600354 {
355 break;
356 }
357
Brad Bishopa098a372022-05-05 15:19:04 -0400358 if (ifacesIt->second.size() != 3)
Matt Spinlera82779f2019-01-09 12:39:42 -0600359 {
360 break;
361 }
362
Brad Bishopa098a372022-05-05 15:19:04 -0400363 auto childPath = parent + '/';
Matt Spinlera82779f2019-01-09 12:39:42 -0600364
365 // Remove this parent if there isn't a remaining child on this owner
Patrick Williams9052ebd2024-08-16 15:22:16 -0400366 auto child = std::find_if(
367 interfaceMap.begin(), interfaceMap.end(),
368 [&owner, &childPath](const auto& entry) {
369 return entry.first.starts_with(childPath) &&
370 (entry.second.find(owner) != entry.second.end());
371 });
Matt Spinlera82779f2019-01-09 12:39:42 -0600372
Brad Bishopa098a372022-05-05 15:19:04 -0400373 if (child == interfaceMap.end())
Matt Spinlera82779f2019-01-09 12:39:42 -0600374 {
Brad Bishopa098a372022-05-05 15:19:04 -0400375 parentIt->second.erase(ifacesIt);
376 if (parentIt->second.empty())
Matt Spinlera82779f2019-01-09 12:39:42 -0600377 {
Brad Bishopa098a372022-05-05 15:19:04 -0400378 interfaceMap.erase(parentIt);
Matt Spinlera82779f2019-01-09 12:39:42 -0600379 }
380 }
381 else
382 {
383 break;
384 }
385 }
386}
387
Brad Bishop1e94e602022-06-02 19:47:53 -0400388int main()
Ed Tanous60520632018-06-11 17:46:52 -0700389{
Ed Tanous21c60592020-08-17 23:43:46 -0700390 boost::asio::io_context io;
Brad Bishopa098a372022-05-05 15:19:04 -0400391 std::shared_ptr<sdbusplus::asio::connection> systemBus =
Ed Tanous60520632018-06-11 17:46:52 -0700392 std::make_shared<sdbusplus::asio::connection>(io);
393
Brad Bishopa098a372022-05-05 15:19:04 -0400394 sdbusplus::asio::object_server server(systemBus);
Ed Tanous60520632018-06-11 17:46:52 -0700395
396 // Construct a signal set registered for process termination.
397 boost::asio::signal_set signals(io, SIGINT, SIGTERM);
Patrick Williams9052ebd2024-08-16 15:22:16 -0400398 signals.async_wait([&io](const boost::system::error_code&, int) {
399 io.stop();
400 });
Ed Tanous60520632018-06-11 17:46:52 -0700401
Brad Bishopa098a372022-05-05 15:19:04 -0400402 InterfaceMapType interfaceMap;
403 boost::container::flat_map<std::string, std::string> nameOwners;
Ed Tanous60520632018-06-11 17:46:52 -0700404
William A. Kennington III60ffc242022-12-02 19:36:01 -0800405 auto nameChangeHandler = [&interfaceMap, &io, &nameOwners, &server,
406 systemBus](sdbusplus::message_t& message) {
407 std::string name; // well-known
408 std::string oldOwner; // unique-name
409 std::string newOwner; // unique-name
Ed Tanous60520632018-06-11 17:46:52 -0700410
William A. Kennington III60ffc242022-12-02 19:36:01 -0800411 message.read(name, oldOwner, newOwner);
Ed Tanous60520632018-06-11 17:46:52 -0700412
William A. Kennington III60ffc242022-12-02 19:36:01 -0800413 if (name.starts_with(':'))
414 {
415 // We should do nothing with unique-name connections.
416 return;
417 }
Patrick Williams48248202022-10-10 10:26:47 -0500418
William A. Kennington III60ffc242022-12-02 19:36:01 -0800419 if (!oldOwner.empty())
420 {
421 processNameChangeDelete(io, nameOwners, name, oldOwner,
422 interfaceMap, associationMaps, server);
423 }
Ed Tanous60520632018-06-11 17:46:52 -0700424
William A. Kennington III60ffc242022-12-02 19:36:01 -0800425 if (!newOwner.empty())
426 {
Brad Bishopd6aa5522022-05-31 19:23:48 -0400427#ifdef MAPPER_ENABLE_DEBUG
William A. Kennington III60ffc242022-12-02 19:36:01 -0800428 auto transaction = std::make_shared<
429 std::chrono::time_point<std::chrono::steady_clock>>(
430 std::chrono::steady_clock::now());
Matt Spinleraecabe82018-09-19 13:25:42 -0500431#endif
William A. Kennington III60ffc242022-12-02 19:36:01 -0800432 // New daemon added
433 if (needToIntrospect(name))
434 {
435 nameOwners[newOwner] = name;
436 startNewIntrospect(systemBus.get(), io, interfaceMap, name,
437 associationMaps,
Brad Bishopd6aa5522022-05-31 19:23:48 -0400438#ifdef MAPPER_ENABLE_DEBUG
William A. Kennington III60ffc242022-12-02 19:36:01 -0800439 transaction,
Matt Spinleraecabe82018-09-19 13:25:42 -0500440#endif
William A. Kennington III60ffc242022-12-02 19:36:01 -0800441 server);
Ed Tanous60520632018-06-11 17:46:52 -0700442 }
William A. Kennington III60ffc242022-12-02 19:36:01 -0800443 }
444 };
Ed Tanous60520632018-06-11 17:46:52 -0700445
Patrick Williamscc8070b2022-07-22 19:26:55 -0500446 sdbusplus::bus::match_t nameOwnerChanged(
447 static_cast<sdbusplus::bus_t&>(*systemBus),
William A. Kennington III60ffc242022-12-02 19:36:01 -0800448 sdbusplus::bus::match::rules::nameOwnerChanged(),
449 std::move(nameChangeHandler));
Ed Tanous60520632018-06-11 17:46:52 -0700450
William A. Kennington III60ffc242022-12-02 19:36:01 -0800451 auto interfacesAddedHandler = [&io, &interfaceMap, &nameOwners,
452 &server](sdbusplus::message_t& message) {
453 sdbusplus::message::object_path objPath;
454 InterfacesAdded interfacesAdded;
455 message.read(objPath, interfacesAdded);
456 std::string wellKnown;
457 if (!getWellKnown(nameOwners, message.get_sender(), wellKnown))
458 {
459 return; // only introspect well-known
460 }
461 if (needToIntrospect(wellKnown))
462 {
463 processInterfaceAdded(io, interfaceMap, objPath, interfacesAdded,
464 wellKnown, associationMaps, server);
465 }
466 };
Ed Tanous60520632018-06-11 17:46:52 -0700467
Patrick Williamscc8070b2022-07-22 19:26:55 -0500468 sdbusplus::bus::match_t interfacesAdded(
469 static_cast<sdbusplus::bus_t&>(*systemBus),
Ed Tanous60520632018-06-11 17:46:52 -0700470 sdbusplus::bus::match::rules::interfacesAdded(),
William A. Kennington III60ffc242022-12-02 19:36:01 -0800471 std::move(interfacesAddedHandler));
Ed Tanous60520632018-06-11 17:46:52 -0700472
William A. Kennington III60ffc242022-12-02 19:36:01 -0800473 auto interfacesRemovedHandler = [&io, &interfaceMap, &nameOwners,
474 &server](sdbusplus::message_t& message) {
475 sdbusplus::message::object_path objPath;
476 std::vector<std::string> interfacesRemoved;
477 message.read(objPath, interfacesRemoved);
478 auto connectionMap = interfaceMap.find(objPath.str);
479 if (connectionMap == interfaceMap.end())
480 {
481 return;
482 }
483
484 std::string sender;
485 if (!getWellKnown(nameOwners, message.get_sender(), sender))
486 {
487 return;
488 }
489 for (const std::string& interface : interfacesRemoved)
490 {
491 auto interfaceSet = connectionMap->second.find(sender);
492 if (interfaceSet == connectionMap->second.end())
Ed Tanous60520632018-06-11 17:46:52 -0700493 {
William A. Kennington III60ffc242022-12-02 19:36:01 -0800494 continue;
Ed Tanous60520632018-06-11 17:46:52 -0700495 }
496
William A. Kennington III60ffc242022-12-02 19:36:01 -0800497 if (interface == assocDefsInterface)
Ed Tanous60520632018-06-11 17:46:52 -0700498 {
William A. Kennington III60ffc242022-12-02 19:36:01 -0800499 removeAssociation(io, objPath.str, sender, server,
500 associationMaps);
Ed Tanous60520632018-06-11 17:46:52 -0700501 }
William A. Kennington III60ffc242022-12-02 19:36:01 -0800502
503 interfaceSet->second.erase(interface);
504
505 if (interfaceSet->second.empty())
Ed Tanous60520632018-06-11 17:46:52 -0700506 {
William A. Kennington III60ffc242022-12-02 19:36:01 -0800507 // If this was the last interface on this connection,
508 // erase the connection
509 connectionMap->second.erase(interfaceSet);
510
511 // Instead of checking if every single path is the endpoint
512 // of an association that needs to be moved to pending,
513 // only check when the only remaining owner of this path is
514 // ourself, which would be because we still own the
515 // association path.
516 if ((connectionMap->second.size() == 1) &&
517 (connectionMap->second.begin()->first ==
518 "xyz.openbmc_project.ObjectMapper"))
Ed Tanous60520632018-06-11 17:46:52 -0700519 {
William A. Kennington III60ffc242022-12-02 19:36:01 -0800520 // Remove the 2 association D-Bus paths and move the
521 // association to pending.
522 moveAssociationToPending(io, objPath.str, associationMaps,
523 server);
Ed Tanous60520632018-06-11 17:46:52 -0700524 }
525 }
William A. Kennington III60ffc242022-12-02 19:36:01 -0800526 }
527 // If this was the last connection on this object path,
528 // erase the object path
529 if (connectionMap->second.empty())
530 {
531 interfaceMap.erase(connectionMap);
532 }
Matt Spinlera82779f2019-01-09 12:39:42 -0600533
William A. Kennington III60ffc242022-12-02 19:36:01 -0800534 removeUnneededParents(objPath.str, sender, interfaceMap);
535 };
Ed Tanous60520632018-06-11 17:46:52 -0700536
Patrick Williamscc8070b2022-07-22 19:26:55 -0500537 sdbusplus::bus::match_t interfacesRemoved(
538 static_cast<sdbusplus::bus_t&>(*systemBus),
Ed Tanous60520632018-06-11 17:46:52 -0700539 sdbusplus::bus::match::rules::interfacesRemoved(),
William A. Kennington III60ffc242022-12-02 19:36:01 -0800540 std::move(interfacesRemovedHandler));
Ed Tanous60520632018-06-11 17:46:52 -0700541
William A. Kennington III60ffc242022-12-02 19:36:01 -0800542 auto associationChangedHandler = [&io, &server, &nameOwners, &interfaceMap](
543 sdbusplus::message_t& message) {
544 std::string objectName;
545 boost::container::flat_map<std::string,
546 std::variant<std::vector<Association>>>
547 values;
548 message.read(objectName, values);
549 auto prop = values.find(assocDefsProperty);
550 if (prop != values.end())
551 {
552 std::vector<Association> associations =
553 std::get<std::vector<Association>>(prop->second);
554
555 std::string wellKnown;
556 if (!getWellKnown(nameOwners, message.get_sender(), wellKnown))
Matt Spinler8f876a52019-04-15 13:22:50 -0500557 {
William A. Kennington III60ffc242022-12-02 19:36:01 -0800558 return;
Matt Spinler8f876a52019-04-15 13:22:50 -0500559 }
William A. Kennington III60ffc242022-12-02 19:36:01 -0800560 associationChanged(io, server, associations, message.get_path(),
561 wellKnown, interfaceMap, associationMaps);
562 }
563 };
Patrick Williamscc8070b2022-07-22 19:26:55 -0500564 sdbusplus::bus::match_t assocChangedMatch(
565 static_cast<sdbusplus::bus_t&>(*systemBus),
Ed Tanous60520632018-06-11 17:46:52 -0700566 sdbusplus::bus::match::rules::interface(
567 "org.freedesktop.DBus.Properties") +
568 sdbusplus::bus::match::rules::member("PropertiesChanged") +
Matt Spinler8f876a52019-04-15 13:22:50 -0500569 sdbusplus::bus::match::rules::argN(0, assocDefsInterface),
William A. Kennington III60ffc242022-12-02 19:36:01 -0800570 std::move(associationChangedHandler));
Matt Spinler8f876a52019-04-15 13:22:50 -0500571
Ed Tanous60520632018-06-11 17:46:52 -0700572 std::shared_ptr<sdbusplus::asio::dbus_interface> iface =
Brad Bishopa02cd542021-10-12 19:12:42 -0400573 server.add_interface("/xyz/openbmc_project/object_mapper",
574 "xyz.openbmc_project.ObjectMapper");
Ed Tanous60520632018-06-11 17:46:52 -0700575
576 iface->register_method(
Brad Bishopa098a372022-05-05 15:19:04 -0400577 "GetAncestors", [&interfaceMap](std::string& reqPath,
578 std::vector<std::string>& interfaces) {
Patrick Williams9052ebd2024-08-16 15:22:16 -0400579 return getAncestors(interfaceMap, reqPath, interfaces);
580 });
Ed Tanous60520632018-06-11 17:46:52 -0700581
582 iface->register_method(
Brad Bishopa098a372022-05-05 15:19:04 -0400583 "GetObject", [&interfaceMap](const std::string& path,
584 std::vector<std::string>& interfaces) {
Patrick Williams9052ebd2024-08-16 15:22:16 -0400585 return getObject(interfaceMap, path, interfaces);
586 });
Brad Bishopa098a372022-05-05 15:19:04 -0400587
588 iface->register_method(
589 "GetSubTree", [&interfaceMap](std::string& reqPath, int32_t depth,
Ed Tanous60520632018-06-11 17:46:52 -0700590 std::vector<std::string>& interfaces) {
Patrick Williams9052ebd2024-08-16 15:22:16 -0400591 return getSubTree(interfaceMap, reqPath, depth, interfaces);
592 });
Ed Tanous60520632018-06-11 17:46:52 -0700593
594 iface->register_method(
595 "GetSubTreePaths",
Brad Bishopa098a372022-05-05 15:19:04 -0400596 [&interfaceMap](std::string& reqPath, int32_t depth,
597 std::vector<std::string>& interfaces) {
Patrick Williams9052ebd2024-08-16 15:22:16 -0400598 return getSubTreePaths(interfaceMap, reqPath, depth, interfaces);
599 });
Ed Tanous60520632018-06-11 17:46:52 -0700600
Willy Tu58881d02022-10-02 20:46:45 +0000601 iface->register_method(
602 "GetAssociatedSubTree",
603 [&interfaceMap](const sdbusplus::message::object_path& associationPath,
604 const sdbusplus::message::object_path& reqPath,
605 int32_t depth, std::vector<std::string>& interfaces) {
Patrick Williams9052ebd2024-08-16 15:22:16 -0400606 return getAssociatedSubTree(interfaceMap, associationMaps,
607 associationPath, reqPath, depth,
608 interfaces);
609 });
Willy Tu58881d02022-10-02 20:46:45 +0000610
611 iface->register_method(
612 "GetAssociatedSubTreePaths",
613 [&interfaceMap](const sdbusplus::message::object_path& associationPath,
614 const sdbusplus::message::object_path& reqPath,
615 int32_t depth, std::vector<std::string>& interfaces) {
Patrick Williams9052ebd2024-08-16 15:22:16 -0400616 return getAssociatedSubTreePaths(interfaceMap, associationMaps,
617 associationPath, reqPath, depth,
618 interfaces);
619 });
Willy Tu58881d02022-10-02 20:46:45 +0000620
Lakshmi Yadlapatic3633232024-04-09 10:47:29 -0500621 iface->register_method(
622 "GetAssociatedSubTreeById",
623 [&interfaceMap](const std::string& id, const std::string& objectPath,
624 std::vector<std::string>& subtreeInterfaces,
625 const std::string& association,
626 std::vector<std::string>& endpointInterfaces) {
627 return getAssociatedSubTreeById(interfaceMap, associationMaps, id,
628 objectPath, subtreeInterfaces,
629 association, endpointInterfaces);
630 });
631
632 iface->register_method(
633 "GetAssociatedSubTreePathsById",
634 [&interfaceMap](const std::string& id, const std::string& objectPath,
635 std::vector<std::string>& subtreeInterfaces,
636 const std::string& association,
637 std::vector<std::string>& endpointInterfaces) {
638 return getAssociatedSubTreePathsById(
639 interfaceMap, associationMaps, id, objectPath,
640 subtreeInterfaces, association, endpointInterfaces);
641 });
642
Ed Tanous60520632018-06-11 17:46:52 -0700643 iface->initialize();
644
Ed Tanous41ad8382025-02-13 17:00:14 -0800645 boost::asio::post(io, [&]() {
Brad Bishopa098a372022-05-05 15:19:04 -0400646 doListNames(io, interfaceMap, systemBus.get(), nameOwners,
Matt Spinler11401e22019-04-08 13:13:25 -0500647 associationMaps, server);
Ed Tanous60520632018-06-11 17:46:52 -0700648 });
649
Brad Bishopa098a372022-05-05 15:19:04 -0400650 systemBus->request_name("xyz.openbmc_project.ObjectMapper");
Vishwanatha Subbanna64354ef2020-08-21 03:35:26 -0500651
Ed Tanous60520632018-06-11 17:46:52 -0700652 io.run();
653}