blob: 3bd529a2dba5b953db8e92cd2c74ca54e09e2678 [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 <chrono>
Brad Bishopea119462022-05-31 20:32:04 -040016#include <exception>
Brad Bishop23520882022-05-26 21:39:53 -040017#include <iomanip>
18#include <iostream>
Brandon Kimf6ebfc72022-07-07 12:53:44 -070019#include <string>
20#include <string_view>
Brad Bishop1f623802022-05-31 18:22:10 -040021#include <utility>
Brad Bishop23520882022-05-26 21:39:53 -040022
Matt Spinlere2359fb2019-04-05 14:11:33 -050023AssociationMaps associationMaps;
Matt Spinler937a2322019-01-23 13:54:22 -060024
Brad Bishopa098a372022-05-05 15:19:04 -040025void updateOwners(sdbusplus::asio::connection* conn,
26 boost::container::flat_map<std::string, std::string>& owners,
27 const std::string& newObject)
Ed Tanous60520632018-06-11 17:46:52 -070028{
Brad Bishop86d28802022-07-11 15:49:31 -040029 if (newObject.starts_with(":"))
Ed Tanous60520632018-06-11 17:46:52 -070030 {
31 return;
32 }
33 conn->async_method_call(
Brad Bishopa098a372022-05-05 15:19:04 -040034 [&, newObject](const boost::system::error_code ec,
35 const std::string& nameOwner) {
Patrick Williams9052ebd2024-08-16 15:22:16 -040036 if (ec)
37 {
38 std::cerr << "Error getting owner of " << newObject << " : "
39 << ec << "\n";
40 return;
41 }
42 owners[nameOwner] = newObject;
43 },
Ed Tanous60520632018-06-11 17:46:52 -070044 "org.freedesktop.DBus", "/", "org.freedesktop.DBus", "GetNameOwner",
Brad Bishopa098a372022-05-05 15:19:04 -040045 newObject);
Ed Tanous60520632018-06-11 17:46:52 -070046}
47
Brad Bishopa098a372022-05-05 15:19:04 -040048void sendIntrospectionCompleteSignal(sdbusplus::asio::connection* systemBus,
49 const std::string& processName)
Ed Tanous60520632018-06-11 17:46:52 -070050{
51 // TODO(ed) This signal doesn't get exposed properly in the
52 // introspect right now. Find out how to register signals in
53 // sdbusplus
Patrick Williamscc8070b2022-07-22 19:26:55 -050054 sdbusplus::message_t m = systemBus->new_signal(
Brad Bishopa02cd542021-10-12 19:12:42 -040055 "/xyz/openbmc_project/object_mapper",
56 "xyz.openbmc_project.ObjectMapper.Private", "IntrospectionComplete");
Brad Bishopa098a372022-05-05 15:19:04 -040057 m.append(processName);
Ed Tanous60520632018-06-11 17:46:52 -070058 m.signal_send();
59}
60
61struct InProgressIntrospect
62{
Brad Bishop1f623802022-05-31 18:22:10 -040063 InProgressIntrospect() = delete;
64 InProgressIntrospect(const InProgressIntrospect&) = delete;
65 InProgressIntrospect(InProgressIntrospect&&) = delete;
66 InProgressIntrospect& operator=(const InProgressIntrospect&) = delete;
67 InProgressIntrospect& operator=(InProgressIntrospect&&) = delete;
Ed Tanous60520632018-06-11 17:46:52 -070068 InProgressIntrospect(
Brad Bishop11c0cc32025-07-08 16:04:25 -040069 sdbusplus::asio::connection* systemBusConnection,
70 boost::asio::io_context& ioContext,
71 const std::string& introspectProcessName, 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 Bishop11c0cc32025-07-08 16:04:25 -040075 globalIntrospectStartTime
Matt Spinleraecabe82018-09-19 13:25:42 -050076#endif
77 ) :
Brad Bishop11c0cc32025-07-08 16:04:25 -040078 systemBus(systemBusConnection), io(ioContext),
79 processName(introspectProcessName), assocMaps(am)
Brad Bishopd6aa5522022-05-31 19:23:48 -040080#ifdef MAPPER_ENABLE_DEBUG
Matt Spinleraecabe82018-09-19 13:25:42 -050081 ,
Brad Bishop11c0cc32025-07-08 16:04:25 -040082 globalStartTime(std::move(globalIntrospectStartTime)),
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) {
Patrick Williams9052ebd2024-08-16 15:22:16 -0400145 if (ec)
Ed Tanous60520632018-06-11 17:46:52 -0700146 {
Patrick Williams9052ebd2024-08-16 15:22:16 -0400147 if (ec.value() == boost::system::errc::timed_out &&
148 timeoutRetries < maxTimeoutRetries)
149 {
150 doAssociations(io, systemBus, interfaceMap, objectServer,
151 processName, path, timeoutRetries + 1);
152 return;
153 }
154 std::cerr << "Error getting associations from " << path << "\n";
Ed Tanous60520632018-06-11 17:46:52 -0700155 }
Patrick Williams9052ebd2024-08-16 15:22:16 -0400156 std::vector<Association> associations =
157 std::get<std::vector<Association>>(variantAssociations);
158 associationChanged(io, objectServer, associations, path,
159 processName, interfaceMap, associationMaps);
160 },
Ed Tanous60520632018-06-11 17:46:52 -0700161 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) {
Patrick Williams9052ebd2024-08-16 15:22:16 -0400177 if (ec)
Ed Tanous60520632018-06-11 17:46:52 -0700178 {
Patrick Williams9052ebd2024-08-16 15:22:16 -0400179 if (ec.value() == boost::system::errc::timed_out &&
180 timeoutRetries < maxTimeoutRetries)
181 {
182 doIntrospect(io, systemBus, transaction, interfaceMap,
183 objectServer, path, timeoutRetries + 1);
184 return;
185 }
186 std::cerr << "Introspect call failed with error: " << ec << ", "
187 << ec.message()
188 << " on process: " << transaction->processName
189 << " path: " << path << "\n";
Ed Tanous60520632018-06-11 17:46:52 -0700190 return;
191 }
192
Patrick Williams9052ebd2024-08-16 15:22:16 -0400193 tinyxml2::XMLDocument doc;
Ed Tanous60520632018-06-11 17:46:52 -0700194
Patrick Williams9052ebd2024-08-16 15:22:16 -0400195 tinyxml2::XMLError e = doc.Parse(introspectXml.c_str());
196 if (e != tinyxml2::XMLError::XML_SUCCESS)
Ed Tanous60520632018-06-11 17:46:52 -0700197 {
Patrick Williams9052ebd2024-08-16 15:22:16 -0400198 std::cerr << "XML parsing failed\n";
199 return;
Ed Tanous60520632018-06-11 17:46:52 -0700200 }
201
Patrick Williams9052ebd2024-08-16 15:22:16 -0400202 tinyxml2::XMLNode* pRoot = doc.FirstChildElement("node");
203 if (pRoot == nullptr)
Ed Tanous60520632018-06-11 17:46:52 -0700204 {
Patrick Williams9052ebd2024-08-16 15:22:16 -0400205 std::cerr << "XML document did not contain any data\n";
206 return;
Ed Tanous60520632018-06-11 17:46:52 -0700207 }
Patrick Williams9052ebd2024-08-16 15:22:16 -0400208 auto& thisPathMap = interfaceMap[path];
209 tinyxml2::XMLElement* pElement =
210 pRoot->FirstChildElement("interface");
211 while (pElement != nullptr)
Ed Tanous60520632018-06-11 17:46:52 -0700212 {
Patrick Williams9052ebd2024-08-16 15:22:16 -0400213 const char* ifaceName = pElement->Attribute("name");
214 if (ifaceName == nullptr)
Ed Tanous60520632018-06-11 17:46:52 -0700215 {
Patrick Williams9052ebd2024-08-16 15:22:16 -0400216 continue;
Ed Tanous60520632018-06-11 17:46:52 -0700217 }
218
Patrick Williams9052ebd2024-08-16 15:22:16 -0400219 thisPathMap[transaction->processName].emplace(ifaceName);
220
221 if (std::strcmp(ifaceName, assocDefsInterface) == 0)
222 {
223 doAssociations(io, systemBus, interfaceMap, objectServer,
224 transaction->processName, path);
225 }
226
227 pElement = pElement->NextSiblingElement("interface");
Ed Tanous60520632018-06-11 17:46:52 -0700228 }
Patrick Williams9052ebd2024-08-16 15:22:16 -0400229
230 // Check if this new path has a pending association that can
231 // now be completed.
232 checkIfPendingAssociation(io, path, interfaceMap,
233 transaction->assocMaps, objectServer);
234
235 pElement = pRoot->FirstChildElement("node");
236 while (pElement != nullptr)
237 {
238 const char* childPath = pElement->Attribute("name");
239 if (childPath != nullptr)
240 {
241 std::string parentPath(path);
242 if (parentPath == "/")
243 {
244 parentPath.clear();
245 }
246
247 doIntrospect(io, systemBus, transaction, interfaceMap,
248 objectServer, parentPath + "/" + childPath);
249 }
250 pElement = pElement->NextSiblingElement("node");
251 }
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 =
Patrick Williams9052ebd2024-08-16 15:22:16 -0400270 std::make_shared<InProgressIntrospect>(
271 systemBus, io, processName, assocMaps
Brad Bishopd6aa5522022-05-31 19:23:48 -0400272#ifdef MAPPER_ENABLE_DEBUG
Patrick Williams9052ebd2024-08-16 15:22:16 -0400273 ,
274 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) {
Patrick Williams9052ebd2024-08-16 15:22:16 -0400293 if (ec)
Ed Tanous60520632018-06-11 17:46:52 -0700294 {
Patrick Williams9052ebd2024-08-16 15:22:16 -0400295 std::cerr << "Error getting names: " << ec << "\n";
296 std::exit(EXIT_FAILURE);
297 return;
Ed Tanous60520632018-06-11 17:46:52 -0700298 }
Patrick Williams9052ebd2024-08-16 15:22:16 -0400299 // Try to make startup consistent
300 std::sort(processNames.begin(), processNames.end());
301#ifdef MAPPER_ENABLE_DEBUG
302 std::shared_ptr<std::chrono::time_point<std::chrono::steady_clock>>
303 globalStartTime = std::make_shared<
304 std::chrono::time_point<std::chrono::steady_clock>>(
305 std::chrono::steady_clock::now());
306#endif
307 for (const std::string& processName : processNames)
308 {
309 if (needToIntrospect(processName))
310 {
311 startNewIntrospect(systemBus, io, interfaceMap, processName,
312 assocMaps,
313#ifdef MAPPER_ENABLE_DEBUG
314 globalStartTime,
315#endif
316 objectServer);
317 updateOwners(systemBus, nameOwners, processName);
318 }
319 }
320 },
Ed Tanous60520632018-06-11 17:46:52 -0700321 "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
Patrick Williams9052ebd2024-08-16 15:22:16 -0400365 auto child = std::find_if(
366 interfaceMap.begin(), interfaceMap.end(),
367 [&owner, &childPath](const auto& entry) {
368 return entry.first.starts_with(childPath) &&
369 (entry.second.find(owner) != entry.second.end());
370 });
Matt Spinlera82779f2019-01-09 12:39:42 -0600371
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);
Patrick Williams9052ebd2024-08-16 15:22:16 -0400397 signals.async_wait([&io](const boost::system::error_code&, int) {
398 io.stop();
399 });
Ed Tanous60520632018-06-11 17:46:52 -0700400
Brad Bishopa098a372022-05-05 15:19:04 -0400401 InterfaceMapType interfaceMap;
402 boost::container::flat_map<std::string, std::string> nameOwners;
Ed Tanous60520632018-06-11 17:46:52 -0700403
William A. Kennington III60ffc242022-12-02 19:36:01 -0800404 auto nameChangeHandler = [&interfaceMap, &io, &nameOwners, &server,
405 systemBus](sdbusplus::message_t& message) {
406 std::string name; // well-known
407 std::string oldOwner; // unique-name
408 std::string newOwner; // unique-name
Ed Tanous60520632018-06-11 17:46:52 -0700409
William A. Kennington III60ffc242022-12-02 19:36:01 -0800410 message.read(name, oldOwner, newOwner);
Ed Tanous60520632018-06-11 17:46:52 -0700411
William A. Kennington III60ffc242022-12-02 19:36:01 -0800412 if (name.starts_with(':'))
413 {
414 // We should do nothing with unique-name connections.
415 return;
416 }
Patrick Williams48248202022-10-10 10:26:47 -0500417
William A. Kennington III60ffc242022-12-02 19:36:01 -0800418 if (!oldOwner.empty())
419 {
420 processNameChangeDelete(io, nameOwners, name, oldOwner,
421 interfaceMap, associationMaps, server);
422 }
Ed Tanous60520632018-06-11 17:46:52 -0700423
William A. Kennington III60ffc242022-12-02 19:36:01 -0800424 if (!newOwner.empty())
425 {
Brad Bishopd6aa5522022-05-31 19:23:48 -0400426#ifdef MAPPER_ENABLE_DEBUG
William A. Kennington III60ffc242022-12-02 19:36:01 -0800427 auto transaction = std::make_shared<
428 std::chrono::time_point<std::chrono::steady_clock>>(
429 std::chrono::steady_clock::now());
Matt Spinleraecabe82018-09-19 13:25:42 -0500430#endif
William A. Kennington III60ffc242022-12-02 19:36:01 -0800431 // New daemon added
432 if (needToIntrospect(name))
433 {
434 nameOwners[newOwner] = name;
435 startNewIntrospect(systemBus.get(), io, interfaceMap, name,
436 associationMaps,
Brad Bishopd6aa5522022-05-31 19:23:48 -0400437#ifdef MAPPER_ENABLE_DEBUG
William A. Kennington III60ffc242022-12-02 19:36:01 -0800438 transaction,
Matt Spinleraecabe82018-09-19 13:25:42 -0500439#endif
William A. Kennington III60ffc242022-12-02 19:36:01 -0800440 server);
Ed Tanous60520632018-06-11 17:46:52 -0700441 }
William A. Kennington III60ffc242022-12-02 19:36:01 -0800442 }
443 };
Ed Tanous60520632018-06-11 17:46:52 -0700444
Patrick Williamscc8070b2022-07-22 19:26:55 -0500445 sdbusplus::bus::match_t nameOwnerChanged(
446 static_cast<sdbusplus::bus_t&>(*systemBus),
William A. Kennington III60ffc242022-12-02 19:36:01 -0800447 sdbusplus::bus::match::rules::nameOwnerChanged(),
448 std::move(nameChangeHandler));
Ed Tanous60520632018-06-11 17:46:52 -0700449
William A. Kennington III60ffc242022-12-02 19:36:01 -0800450 auto interfacesAddedHandler = [&io, &interfaceMap, &nameOwners,
451 &server](sdbusplus::message_t& message) {
452 sdbusplus::message::object_path objPath;
453 InterfacesAdded interfacesAdded;
454 message.read(objPath, interfacesAdded);
455 std::string wellKnown;
456 if (!getWellKnown(nameOwners, message.get_sender(), wellKnown))
457 {
458 return; // only introspect well-known
459 }
460 if (needToIntrospect(wellKnown))
461 {
462 processInterfaceAdded(io, interfaceMap, objPath, interfacesAdded,
463 wellKnown, associationMaps, server);
464 }
465 };
Ed Tanous60520632018-06-11 17:46:52 -0700466
Patrick Williamscc8070b2022-07-22 19:26:55 -0500467 sdbusplus::bus::match_t interfacesAdded(
468 static_cast<sdbusplus::bus_t&>(*systemBus),
Ed Tanous60520632018-06-11 17:46:52 -0700469 sdbusplus::bus::match::rules::interfacesAdded(),
William A. Kennington III60ffc242022-12-02 19:36:01 -0800470 std::move(interfacesAddedHandler));
Ed Tanous60520632018-06-11 17:46:52 -0700471
William A. Kennington III60ffc242022-12-02 19:36:01 -0800472 auto interfacesRemovedHandler = [&io, &interfaceMap, &nameOwners,
473 &server](sdbusplus::message_t& message) {
474 sdbusplus::message::object_path objPath;
475 std::vector<std::string> interfacesRemoved;
476 message.read(objPath, interfacesRemoved);
477 auto connectionMap = interfaceMap.find(objPath.str);
478 if (connectionMap == interfaceMap.end())
479 {
480 return;
481 }
482
483 std::string sender;
484 if (!getWellKnown(nameOwners, message.get_sender(), sender))
485 {
486 return;
487 }
488 for (const std::string& interface : interfacesRemoved)
489 {
490 auto interfaceSet = connectionMap->second.find(sender);
491 if (interfaceSet == connectionMap->second.end())
Ed Tanous60520632018-06-11 17:46:52 -0700492 {
William A. Kennington III60ffc242022-12-02 19:36:01 -0800493 continue;
Ed Tanous60520632018-06-11 17:46:52 -0700494 }
495
William A. Kennington III60ffc242022-12-02 19:36:01 -0800496 if (interface == assocDefsInterface)
Ed Tanous60520632018-06-11 17:46:52 -0700497 {
William A. Kennington III60ffc242022-12-02 19:36:01 -0800498 removeAssociation(io, objPath.str, sender, server,
499 associationMaps);
Ed Tanous60520632018-06-11 17:46:52 -0700500 }
William A. Kennington III60ffc242022-12-02 19:36:01 -0800501
502 interfaceSet->second.erase(interface);
503
504 if (interfaceSet->second.empty())
Ed Tanous60520632018-06-11 17:46:52 -0700505 {
William A. Kennington III60ffc242022-12-02 19:36:01 -0800506 // If this was the last interface on this connection,
507 // erase the connection
508 connectionMap->second.erase(interfaceSet);
509
510 // Instead of checking if every single path is the endpoint
511 // of an association that needs to be moved to pending,
512 // only check when the only remaining owner of this path is
513 // ourself, which would be because we still own the
514 // association path.
515 if ((connectionMap->second.size() == 1) &&
516 (connectionMap->second.begin()->first ==
517 "xyz.openbmc_project.ObjectMapper"))
Ed Tanous60520632018-06-11 17:46:52 -0700518 {
William A. Kennington III60ffc242022-12-02 19:36:01 -0800519 // Remove the 2 association D-Bus paths and move the
520 // association to pending.
521 moveAssociationToPending(io, objPath.str, associationMaps,
522 server);
Ed Tanous60520632018-06-11 17:46:52 -0700523 }
524 }
William A. Kennington III60ffc242022-12-02 19:36:01 -0800525 }
526 // If this was the last connection on this object path,
527 // erase the object path
528 if (connectionMap->second.empty())
529 {
530 interfaceMap.erase(connectionMap);
531 }
Matt Spinlera82779f2019-01-09 12:39:42 -0600532
William A. Kennington III60ffc242022-12-02 19:36:01 -0800533 removeUnneededParents(objPath.str, sender, interfaceMap);
534 };
Ed Tanous60520632018-06-11 17:46:52 -0700535
Patrick Williamscc8070b2022-07-22 19:26:55 -0500536 sdbusplus::bus::match_t interfacesRemoved(
537 static_cast<sdbusplus::bus_t&>(*systemBus),
Ed Tanous60520632018-06-11 17:46:52 -0700538 sdbusplus::bus::match::rules::interfacesRemoved(),
William A. Kennington III60ffc242022-12-02 19:36:01 -0800539 std::move(interfacesRemovedHandler));
Ed Tanous60520632018-06-11 17:46:52 -0700540
William A. Kennington III60ffc242022-12-02 19:36:01 -0800541 auto associationChangedHandler = [&io, &server, &nameOwners, &interfaceMap](
542 sdbusplus::message_t& message) {
543 std::string objectName;
544 boost::container::flat_map<std::string,
545 std::variant<std::vector<Association>>>
546 values;
547 message.read(objectName, values);
548 auto prop = values.find(assocDefsProperty);
549 if (prop != values.end())
550 {
551 std::vector<Association> associations =
552 std::get<std::vector<Association>>(prop->second);
553
554 std::string wellKnown;
555 if (!getWellKnown(nameOwners, message.get_sender(), wellKnown))
Matt Spinler8f876a52019-04-15 13:22:50 -0500556 {
William A. Kennington III60ffc242022-12-02 19:36:01 -0800557 return;
Matt Spinler8f876a52019-04-15 13:22:50 -0500558 }
William A. Kennington III60ffc242022-12-02 19:36:01 -0800559 associationChanged(io, server, associations, message.get_path(),
560 wellKnown, interfaceMap, associationMaps);
561 }
562 };
Patrick Williamscc8070b2022-07-22 19:26:55 -0500563 sdbusplus::bus::match_t assocChangedMatch(
564 static_cast<sdbusplus::bus_t&>(*systemBus),
Ed Tanous60520632018-06-11 17:46:52 -0700565 sdbusplus::bus::match::rules::interface(
566 "org.freedesktop.DBus.Properties") +
567 sdbusplus::bus::match::rules::member("PropertiesChanged") +
Matt Spinler8f876a52019-04-15 13:22:50 -0500568 sdbusplus::bus::match::rules::argN(0, assocDefsInterface),
William A. Kennington III60ffc242022-12-02 19:36:01 -0800569 std::move(associationChangedHandler));
Matt Spinler8f876a52019-04-15 13:22:50 -0500570
Ed Tanous60520632018-06-11 17:46:52 -0700571 std::shared_ptr<sdbusplus::asio::dbus_interface> iface =
Brad Bishopa02cd542021-10-12 19:12:42 -0400572 server.add_interface("/xyz/openbmc_project/object_mapper",
573 "xyz.openbmc_project.ObjectMapper");
Ed Tanous60520632018-06-11 17:46:52 -0700574
575 iface->register_method(
Brad Bishopa098a372022-05-05 15:19:04 -0400576 "GetAncestors", [&interfaceMap](std::string& reqPath,
577 std::vector<std::string>& interfaces) {
Patrick Williams9052ebd2024-08-16 15:22:16 -0400578 return getAncestors(interfaceMap, reqPath, interfaces);
579 });
Ed Tanous60520632018-06-11 17:46:52 -0700580
581 iface->register_method(
Brad Bishopa098a372022-05-05 15:19:04 -0400582 "GetObject", [&interfaceMap](const std::string& path,
583 std::vector<std::string>& interfaces) {
Patrick Williams9052ebd2024-08-16 15:22:16 -0400584 return getObject(interfaceMap, path, interfaces);
585 });
Brad Bishopa098a372022-05-05 15:19:04 -0400586
587 iface->register_method(
588 "GetSubTree", [&interfaceMap](std::string& reqPath, int32_t depth,
Ed Tanous60520632018-06-11 17:46:52 -0700589 std::vector<std::string>& interfaces) {
Patrick Williams9052ebd2024-08-16 15:22:16 -0400590 return getSubTree(interfaceMap, reqPath, depth, interfaces);
591 });
Ed Tanous60520632018-06-11 17:46:52 -0700592
593 iface->register_method(
594 "GetSubTreePaths",
Brad Bishopa098a372022-05-05 15:19:04 -0400595 [&interfaceMap](std::string& reqPath, int32_t depth,
596 std::vector<std::string>& interfaces) {
Patrick Williams9052ebd2024-08-16 15:22:16 -0400597 return getSubTreePaths(interfaceMap, reqPath, depth, interfaces);
598 });
Ed Tanous60520632018-06-11 17:46:52 -0700599
Willy Tu58881d02022-10-02 20:46:45 +0000600 iface->register_method(
601 "GetAssociatedSubTree",
602 [&interfaceMap](const sdbusplus::message::object_path& associationPath,
603 const sdbusplus::message::object_path& reqPath,
604 int32_t depth, std::vector<std::string>& interfaces) {
Patrick Williams9052ebd2024-08-16 15:22:16 -0400605 return getAssociatedSubTree(interfaceMap, associationMaps,
606 associationPath, reqPath, depth,
607 interfaces);
608 });
Willy Tu58881d02022-10-02 20:46:45 +0000609
610 iface->register_method(
611 "GetAssociatedSubTreePaths",
612 [&interfaceMap](const sdbusplus::message::object_path& associationPath,
613 const sdbusplus::message::object_path& reqPath,
614 int32_t depth, std::vector<std::string>& interfaces) {
Patrick Williams9052ebd2024-08-16 15:22:16 -0400615 return getAssociatedSubTreePaths(interfaceMap, associationMaps,
616 associationPath, reqPath, depth,
617 interfaces);
618 });
Willy Tu58881d02022-10-02 20:46:45 +0000619
Lakshmi Yadlapatic3633232024-04-09 10:47:29 -0500620 iface->register_method(
621 "GetAssociatedSubTreeById",
622 [&interfaceMap](const std::string& id, const std::string& objectPath,
623 std::vector<std::string>& subtreeInterfaces,
624 const std::string& association,
625 std::vector<std::string>& endpointInterfaces) {
626 return getAssociatedSubTreeById(interfaceMap, associationMaps, id,
627 objectPath, subtreeInterfaces,
628 association, endpointInterfaces);
629 });
630
631 iface->register_method(
632 "GetAssociatedSubTreePathsById",
633 [&interfaceMap](const std::string& id, const std::string& objectPath,
634 std::vector<std::string>& subtreeInterfaces,
635 const std::string& association,
636 std::vector<std::string>& endpointInterfaces) {
637 return getAssociatedSubTreePathsById(
638 interfaceMap, associationMaps, id, objectPath,
639 subtreeInterfaces, association, endpointInterfaces);
640 });
641
Ed Tanous60520632018-06-11 17:46:52 -0700642 iface->initialize();
643
Ed Tanous41ad8382025-02-13 17:00:14 -0800644 boost::asio::post(io, [&]() {
Brad Bishopa098a372022-05-05 15:19:04 -0400645 doListNames(io, interfaceMap, systemBus.get(), nameOwners,
Matt Spinler11401e22019-04-08 13:13:25 -0500646 associationMaps, server);
Ed Tanous60520632018-06-11 17:46:52 -0700647 });
648
Brad Bishopa098a372022-05-05 15:19:04 -0400649 systemBus->request_name("xyz.openbmc_project.ObjectMapper");
Vishwanatha Subbanna64354ef2020-08-21 03:35:26 -0500650
Ed Tanous60520632018-06-11 17:46:52 -0700651 io.run();
652}