blob: 242903b94c67b7786e3374b0c4562f35b8d9abc2 [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 Williams670edd12023-02-15 15:06:52 -060037 if (ec)
38 {
39 std::cerr << "Error getting owner of " << newObject << " : " << ec
40 << "\n";
41 return;
42 }
43 owners[nameOwner] = newObject;
Ed Tanous60520632018-06-11 17:46:52 -070044 },
45 "org.freedesktop.DBus", "/", "org.freedesktop.DBus", "GetNameOwner",
Brad Bishopa098a372022-05-05 15:19:04 -040046 newObject);
Ed Tanous60520632018-06-11 17:46:52 -070047}
48
Brad Bishopa098a372022-05-05 15:19:04 -040049void sendIntrospectionCompleteSignal(sdbusplus::asio::connection* systemBus,
50 const std::string& processName)
Ed Tanous60520632018-06-11 17:46:52 -070051{
52 // TODO(ed) This signal doesn't get exposed properly in the
53 // introspect right now. Find out how to register signals in
54 // sdbusplus
Patrick Williamscc8070b2022-07-22 19:26:55 -050055 sdbusplus::message_t m = systemBus->new_signal(
Brad Bishopa02cd542021-10-12 19:12:42 -040056 "/xyz/openbmc_project/object_mapper",
57 "xyz.openbmc_project.ObjectMapper.Private", "IntrospectionComplete");
Brad Bishopa098a372022-05-05 15:19:04 -040058 m.append(processName);
Ed Tanous60520632018-06-11 17:46:52 -070059 m.signal_send();
60}
61
62struct InProgressIntrospect
63{
Brad Bishop1f623802022-05-31 18:22:10 -040064 InProgressIntrospect() = delete;
65 InProgressIntrospect(const InProgressIntrospect&) = delete;
66 InProgressIntrospect(InProgressIntrospect&&) = delete;
67 InProgressIntrospect& operator=(const InProgressIntrospect&) = delete;
68 InProgressIntrospect& operator=(InProgressIntrospect&&) = delete;
Ed Tanous60520632018-06-11 17:46:52 -070069 InProgressIntrospect(
Brad Bishopa098a372022-05-05 15:19:04 -040070 sdbusplus::asio::connection* systemBus, boost::asio::io_context& io,
71 const std::string& processName, AssociationMaps& am
Brad Bishopd6aa5522022-05-31 19:23:48 -040072#ifdef MAPPER_ENABLE_DEBUG
Matt Spinleraecabe82018-09-19 13:25:42 -050073 ,
Ed Tanous60520632018-06-11 17:46:52 -070074 std::shared_ptr<std::chrono::time_point<std::chrono::steady_clock>>
Brad Bishopa098a372022-05-05 15:19:04 -040075 globalStartTime
Matt Spinleraecabe82018-09-19 13:25:42 -050076#endif
77 ) :
Brad Bishopa098a372022-05-05 15:19:04 -040078 systemBus(systemBus),
79 io(io), processName(processName), assocMaps(am)
Brad Bishopd6aa5522022-05-31 19:23:48 -040080#ifdef MAPPER_ENABLE_DEBUG
Matt Spinleraecabe82018-09-19 13:25:42 -050081 ,
Brad Bishop1f623802022-05-31 18:22:10 -040082 globalStartTime(std::move(globalStartTime)),
Brad Bishopa098a372022-05-05 15:19:04 -040083 processStartTime(std::chrono::steady_clock::now())
Matt Spinleraecabe82018-09-19 13:25:42 -050084#endif
Brad Bishop23520882022-05-26 21:39:53 -040085 {}
Ed Tanous60520632018-06-11 17:46:52 -070086 ~InProgressIntrospect()
87 {
Brad Bishopea119462022-05-31 20:32:04 -040088 try
Ed Tanous60520632018-06-11 17:46:52 -070089 {
Brad Bishopea119462022-05-31 20:32:04 -040090 sendIntrospectionCompleteSignal(systemBus, processName);
Brad Bishopd6aa5522022-05-31 19:23:48 -040091#ifdef MAPPER_ENABLE_DEBUG
Brad Bishopea119462022-05-31 20:32:04 -040092 std::chrono::duration<float> diff =
93 std::chrono::steady_clock::now() - processStartTime;
94 std::cout << std::setw(50) << processName << " scan took "
95 << diff.count() << " seconds\n";
96
97 // If we're the last outstanding caller globally, calculate the
98 // time it took
99 if (globalStartTime != nullptr && globalStartTime.use_count() == 1)
100 {
101 diff = std::chrono::steady_clock::now() - *globalStartTime;
102 std::cout << "Total scan took " << diff.count()
103 << " seconds to complete\n";
104 }
Matt Spinleraecabe82018-09-19 13:25:42 -0500105#endif
Brad Bishopea119462022-05-31 20:32:04 -0400106 }
107 catch (const std::exception& e)
108 {
109 std::cerr
110 << "Terminating, unhandled exception while introspecting: "
111 << e.what() << "\n";
112 std::terminate();
113 }
114 catch (...)
115 {
116 std::cerr
117 << "Terminating, unhandled exception while introspecting\n";
118 std::terminate();
119 }
Ed Tanous60520632018-06-11 17:46:52 -0700120 }
Brad Bishopa098a372022-05-05 15:19:04 -0400121 sdbusplus::asio::connection* systemBus;
Ed Tanous21c60592020-08-17 23:43:46 -0700122 boost::asio::io_context& io;
Brad Bishopa098a372022-05-05 15:19:04 -0400123 std::string processName;
Matt Spinler11401e22019-04-08 13:13:25 -0500124 AssociationMaps& assocMaps;
Brad Bishopd6aa5522022-05-31 19:23:48 -0400125#ifdef MAPPER_ENABLE_DEBUG
Ed Tanous60520632018-06-11 17:46:52 -0700126 std::shared_ptr<std::chrono::time_point<std::chrono::steady_clock>>
Brad Bishopa098a372022-05-05 15:19:04 -0400127 globalStartTime;
128 std::chrono::time_point<std::chrono::steady_clock> processStartTime;
Matt Spinleraecabe82018-09-19 13:25:42 -0500129#endif
Ed Tanous60520632018-06-11 17:46:52 -0700130};
131
Kallas, Pawel5b4357d2022-10-12 15:36:37 +0200132void doAssociations(boost::asio::io_context& io,
133 sdbusplus::asio::connection* systemBus,
Brad Bishopa098a372022-05-05 15:19:04 -0400134 InterfaceMapType& interfaceMap,
135 sdbusplus::asio::object_server& objectServer,
136 const std::string& processName, const std::string& path,
137 int timeoutRetries = 0)
Ed Tanous60520632018-06-11 17:46:52 -0700138{
Adrian Ambrożewiczbb40bd32021-02-12 13:36:26 +0100139 constexpr int maxTimeoutRetries = 3;
Brad Bishopa098a372022-05-05 15:19:04 -0400140 systemBus->async_method_call(
Kallas, Pawel5b4357d2022-10-12 15:36:37 +0200141 [&io, &objectServer, path, processName, &interfaceMap, systemBus,
Adrian Ambrożewiczbb40bd32021-02-12 13:36:26 +0100142 timeoutRetries](
Matt Spinler937a2322019-01-23 13:54:22 -0600143 const boost::system::error_code ec,
Patrick Williams2bb2d6b2020-05-13 17:59:02 -0500144 const std::variant<std::vector<Association>>& variantAssociations) {
Patrick Williams670edd12023-02-15 15:06:52 -0600145 if (ec)
146 {
147 if (ec.value() == boost::system::errc::timed_out &&
148 timeoutRetries < maxTimeoutRetries)
Ed Tanous60520632018-06-11 17:46:52 -0700149 {
Patrick Williams670edd12023-02-15 15:06:52 -0600150 doAssociations(io, systemBus, interfaceMap, objectServer,
151 processName, path, timeoutRetries + 1);
152 return;
Ed Tanous60520632018-06-11 17:46:52 -0700153 }
Patrick Williams670edd12023-02-15 15:06:52 -0600154 std::cerr << "Error getting associations from " << path << "\n";
155 }
156 std::vector<Association> associations =
157 std::get<std::vector<Association>>(variantAssociations);
158 associationChanged(io, objectServer, associations, path, processName,
159 interfaceMap, associationMaps);
Ed Tanous60520632018-06-11 17:46:52 -0700160 },
161 processName, path, "org.freedesktop.DBus.Properties", "Get",
John Wangd0cf9422019-09-17 16:01:34 +0800162 assocDefsInterface, assocDefsProperty);
Ed Tanous60520632018-06-11 17:46:52 -0700163}
164
Kallas, Pawel5b4357d2022-10-12 15:36:37 +0200165void doIntrospect(boost::asio::io_context& io,
166 sdbusplus::asio::connection* systemBus,
Brad Bishop1f623802022-05-31 18:22:10 -0400167 const std::shared_ptr<InProgressIntrospect>& transaction,
Brad Bishopa098a372022-05-05 15:19:04 -0400168 InterfaceMapType& interfaceMap,
169 sdbusplus::asio::object_server& objectServer,
Brad Bishop1f623802022-05-31 18:22:10 -0400170 const std::string& path, int timeoutRetries = 0)
Ed Tanous60520632018-06-11 17:46:52 -0700171{
Vernon Maueryc52be0d2020-01-14 11:14:25 -0800172 constexpr int maxTimeoutRetries = 3;
Brad Bishopa098a372022-05-05 15:19:04 -0400173 systemBus->async_method_call(
Kallas, Pawel5b4357d2022-10-12 15:36:37 +0200174 [&io, &interfaceMap, &objectServer, transaction, path, systemBus,
Vernon Maueryc52be0d2020-01-14 11:14:25 -0800175 timeoutRetries](const boost::system::error_code ec,
Brad Bishopa098a372022-05-05 15:19:04 -0400176 const std::string& introspectXml) {
Patrick Williams670edd12023-02-15 15:06:52 -0600177 if (ec)
178 {
179 if (ec.value() == boost::system::errc::timed_out &&
180 timeoutRetries < maxTimeoutRetries)
Ed Tanous60520632018-06-11 17:46:52 -0700181 {
Patrick Williams670edd12023-02-15 15:06:52 -0600182 doIntrospect(io, systemBus, transaction, interfaceMap,
183 objectServer, path, timeoutRetries + 1);
Ed Tanous60520632018-06-11 17:46:52 -0700184 return;
185 }
Patrick Williams670edd12023-02-15 15:06:52 -0600186 std::cerr << "Introspect call failed with error: " << ec << ", "
187 << ec.message()
188 << " on process: " << transaction->processName
189 << " path: " << path << "\n";
190 return;
191 }
Ed Tanous60520632018-06-11 17:46:52 -0700192
Patrick Williams670edd12023-02-15 15:06:52 -0600193 tinyxml2::XMLDocument doc;
Ed Tanous60520632018-06-11 17:46:52 -0700194
Patrick Williams670edd12023-02-15 15:06:52 -0600195 tinyxml2::XMLError e = doc.Parse(introspectXml.c_str());
196 if (e != tinyxml2::XMLError::XML_SUCCESS)
197 {
198 std::cerr << "XML parsing failed\n";
199 return;
200 }
201
202 tinyxml2::XMLNode* pRoot = doc.FirstChildElement("node");
203 if (pRoot == nullptr)
204 {
205 std::cerr << "XML document did not contain any data\n";
206 return;
207 }
208 auto& thisPathMap = interfaceMap[path];
209 tinyxml2::XMLElement* pElement = pRoot->FirstChildElement("interface");
210 while (pElement != nullptr)
211 {
212 const char* ifaceName = pElement->Attribute("name");
213 if (ifaceName == nullptr)
Ed Tanous60520632018-06-11 17:46:52 -0700214 {
Patrick Williams670edd12023-02-15 15:06:52 -0600215 continue;
Ed Tanous60520632018-06-11 17:46:52 -0700216 }
217
Patrick Williams670edd12023-02-15 15:06:52 -0600218 thisPathMap[transaction->processName].emplace(ifaceName);
219
220 if (std::strcmp(ifaceName, assocDefsInterface) == 0)
Ed Tanous60520632018-06-11 17:46:52 -0700221 {
Patrick Williams670edd12023-02-15 15:06:52 -0600222 doAssociations(io, systemBus, interfaceMap, objectServer,
223 transaction->processName, path);
Ed Tanous60520632018-06-11 17:46:52 -0700224 }
Patrick Williams670edd12023-02-15 15:06:52 -0600225
226 pElement = pElement->NextSiblingElement("interface");
227 }
228
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)
Ed Tanous60520632018-06-11 17:46:52 -0700239 {
Patrick Williams670edd12023-02-15 15:06:52 -0600240 std::string parentPath(path);
241 if (parentPath == "/")
Ed Tanous60520632018-06-11 17:46:52 -0700242 {
Patrick Williams670edd12023-02-15 15:06:52 -0600243 parentPath.clear();
Ed Tanous60520632018-06-11 17:46:52 -0700244 }
245
Patrick Williams670edd12023-02-15 15:06:52 -0600246 doIntrospect(io, systemBus, transaction, interfaceMap,
247 objectServer, parentPath + "/" + childPath);
Ed Tanous60520632018-06-11 17:46:52 -0700248 }
Patrick Williams670edd12023-02-15 15:06:52 -0600249 pElement = pElement->NextSiblingElement("node");
250 }
Ed Tanous60520632018-06-11 17:46:52 -0700251 },
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 =
Brad Bishopa098a372022-05-05 15:19:04 -0400269 std::make_shared<InProgressIntrospect>(systemBus, io, processName,
Matt Spinler11401e22019-04-08 13:13:25 -0500270 assocMaps
Brad Bishopd6aa5522022-05-31 19:23:48 -0400271#ifdef MAPPER_ENABLE_DEBUG
Matt Spinleraecabe82018-09-19 13:25:42 -0500272 ,
Brad Bishopa098a372022-05-05 15:19:04 -0400273 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 Williams670edd12023-02-15 15:06:52 -0600292 if (ec)
293 {
294 std::cerr << "Error getting names: " << ec << "\n";
295 std::exit(EXIT_FAILURE);
296 return;
297 }
298 // Try to make startup consistent
299 std::sort(processNames.begin(), processNames.end());
Brad Bishopd6aa5522022-05-31 19:23:48 -0400300#ifdef MAPPER_ENABLE_DEBUG
Patrick Williams670edd12023-02-15 15:06:52 -0600301 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());
Matt Spinleraecabe82018-09-19 13:25:42 -0500305#endif
Patrick Williams670edd12023-02-15 15:06:52 -0600306 for (const std::string& processName : processNames)
307 {
308 if (needToIntrospect(processName))
Ed Tanous60520632018-06-11 17:46:52 -0700309 {
Patrick Williams670edd12023-02-15 15:06:52 -0600310 startNewIntrospect(systemBus, io, interfaceMap, processName,
311 assocMaps,
Brad Bishopd6aa5522022-05-31 19:23:48 -0400312#ifdef MAPPER_ENABLE_DEBUG
Patrick Williams670edd12023-02-15 15:06:52 -0600313 globalStartTime,
Matt Spinleraecabe82018-09-19 13:25:42 -0500314#endif
Patrick Williams670edd12023-02-15 15:06:52 -0600315 objectServer);
316 updateOwners(systemBus, nameOwners, processName);
Ed Tanous60520632018-06-11 17:46:52 -0700317 }
Patrick Williams670edd12023-02-15 15:06:52 -0600318 }
Ed Tanous60520632018-06-11 17:46:52 -0700319 },
320 "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 Williams670edd12023-02-15 15:06:52 -0600364 auto child = std::find_if(interfaceMap.begin(), interfaceMap.end(),
365 [&owner, &childPath](const auto& entry) {
366 return entry.first.starts_with(childPath) &&
367 (entry.second.find(owner) != entry.second.end());
368 });
Matt Spinlera82779f2019-01-09 12:39:42 -0600369
Brad Bishopa098a372022-05-05 15:19:04 -0400370 if (child == interfaceMap.end())
Matt Spinlera82779f2019-01-09 12:39:42 -0600371 {
Brad Bishopa098a372022-05-05 15:19:04 -0400372 parentIt->second.erase(ifacesIt);
373 if (parentIt->second.empty())
Matt Spinlera82779f2019-01-09 12:39:42 -0600374 {
Brad Bishopa098a372022-05-05 15:19:04 -0400375 interfaceMap.erase(parentIt);
Matt Spinlera82779f2019-01-09 12:39:42 -0600376 }
377 }
378 else
379 {
380 break;
381 }
382 }
383}
384
Brad Bishop1e94e602022-06-02 19:47:53 -0400385int main()
Ed Tanous60520632018-06-11 17:46:52 -0700386{
Ed Tanous21c60592020-08-17 23:43:46 -0700387 boost::asio::io_context io;
Brad Bishopa098a372022-05-05 15:19:04 -0400388 std::shared_ptr<sdbusplus::asio::connection> systemBus =
Ed Tanous60520632018-06-11 17:46:52 -0700389 std::make_shared<sdbusplus::asio::connection>(io);
390
Brad Bishopa098a372022-05-05 15:19:04 -0400391 sdbusplus::asio::object_server server(systemBus);
Ed Tanous60520632018-06-11 17:46:52 -0700392
393 // Construct a signal set registered for process termination.
394 boost::asio::signal_set signals(io, SIGINT, SIGTERM);
Brad Bishop2d41d6a2021-08-03 08:14:45 -0400395 signals.async_wait(
396 [&io](const boost::system::error_code&, int) { io.stop(); });
Ed Tanous60520632018-06-11 17:46:52 -0700397
Brad Bishopa098a372022-05-05 15:19:04 -0400398 InterfaceMapType interfaceMap;
399 boost::container::flat_map<std::string, std::string> nameOwners;
Ed Tanous60520632018-06-11 17:46:52 -0700400
William A. Kennington III60ffc242022-12-02 19:36:01 -0800401 auto nameChangeHandler = [&interfaceMap, &io, &nameOwners, &server,
402 systemBus](sdbusplus::message_t& message) {
403 std::string name; // well-known
404 std::string oldOwner; // unique-name
405 std::string newOwner; // unique-name
Ed Tanous60520632018-06-11 17:46:52 -0700406
William A. Kennington III60ffc242022-12-02 19:36:01 -0800407 message.read(name, oldOwner, newOwner);
Ed Tanous60520632018-06-11 17:46:52 -0700408
William A. Kennington III60ffc242022-12-02 19:36:01 -0800409 if (name.starts_with(':'))
410 {
411 // We should do nothing with unique-name connections.
412 return;
413 }
Patrick Williams48248202022-10-10 10:26:47 -0500414
William A. Kennington III60ffc242022-12-02 19:36:01 -0800415 if (!oldOwner.empty())
416 {
417 processNameChangeDelete(io, nameOwners, name, oldOwner,
418 interfaceMap, associationMaps, server);
419 }
Ed Tanous60520632018-06-11 17:46:52 -0700420
William A. Kennington III60ffc242022-12-02 19:36:01 -0800421 if (!newOwner.empty())
422 {
Brad Bishopd6aa5522022-05-31 19:23:48 -0400423#ifdef MAPPER_ENABLE_DEBUG
William A. Kennington III60ffc242022-12-02 19:36:01 -0800424 auto transaction = std::make_shared<
425 std::chrono::time_point<std::chrono::steady_clock>>(
426 std::chrono::steady_clock::now());
Matt Spinleraecabe82018-09-19 13:25:42 -0500427#endif
William A. Kennington III60ffc242022-12-02 19:36:01 -0800428 // New daemon added
429 if (needToIntrospect(name))
430 {
431 nameOwners[newOwner] = name;
432 startNewIntrospect(systemBus.get(), io, interfaceMap, name,
433 associationMaps,
Brad Bishopd6aa5522022-05-31 19:23:48 -0400434#ifdef MAPPER_ENABLE_DEBUG
William A. Kennington III60ffc242022-12-02 19:36:01 -0800435 transaction,
Matt Spinleraecabe82018-09-19 13:25:42 -0500436#endif
William A. Kennington III60ffc242022-12-02 19:36:01 -0800437 server);
Ed Tanous60520632018-06-11 17:46:52 -0700438 }
William A. Kennington III60ffc242022-12-02 19:36:01 -0800439 }
440 };
Ed Tanous60520632018-06-11 17:46:52 -0700441
Patrick Williamscc8070b2022-07-22 19:26:55 -0500442 sdbusplus::bus::match_t nameOwnerChanged(
443 static_cast<sdbusplus::bus_t&>(*systemBus),
William A. Kennington III60ffc242022-12-02 19:36:01 -0800444 sdbusplus::bus::match::rules::nameOwnerChanged(),
445 std::move(nameChangeHandler));
Ed Tanous60520632018-06-11 17:46:52 -0700446
William A. Kennington III60ffc242022-12-02 19:36:01 -0800447 auto interfacesAddedHandler = [&io, &interfaceMap, &nameOwners,
448 &server](sdbusplus::message_t& message) {
449 sdbusplus::message::object_path objPath;
450 InterfacesAdded interfacesAdded;
451 message.read(objPath, interfacesAdded);
452 std::string wellKnown;
453 if (!getWellKnown(nameOwners, message.get_sender(), wellKnown))
454 {
455 return; // only introspect well-known
456 }
457 if (needToIntrospect(wellKnown))
458 {
459 processInterfaceAdded(io, interfaceMap, objPath, interfacesAdded,
460 wellKnown, associationMaps, server);
461 }
462 };
Ed Tanous60520632018-06-11 17:46:52 -0700463
Patrick Williamscc8070b2022-07-22 19:26:55 -0500464 sdbusplus::bus::match_t interfacesAdded(
465 static_cast<sdbusplus::bus_t&>(*systemBus),
Ed Tanous60520632018-06-11 17:46:52 -0700466 sdbusplus::bus::match::rules::interfacesAdded(),
William A. Kennington III60ffc242022-12-02 19:36:01 -0800467 std::move(interfacesAddedHandler));
Ed Tanous60520632018-06-11 17:46:52 -0700468
William A. Kennington III60ffc242022-12-02 19:36:01 -0800469 auto interfacesRemovedHandler = [&io, &interfaceMap, &nameOwners,
470 &server](sdbusplus::message_t& message) {
471 sdbusplus::message::object_path objPath;
472 std::vector<std::string> interfacesRemoved;
473 message.read(objPath, interfacesRemoved);
474 auto connectionMap = interfaceMap.find(objPath.str);
475 if (connectionMap == interfaceMap.end())
476 {
477 return;
478 }
479
480 std::string sender;
481 if (!getWellKnown(nameOwners, message.get_sender(), sender))
482 {
483 return;
484 }
485 for (const std::string& interface : interfacesRemoved)
486 {
487 auto interfaceSet = connectionMap->second.find(sender);
488 if (interfaceSet == connectionMap->second.end())
Ed Tanous60520632018-06-11 17:46:52 -0700489 {
William A. Kennington III60ffc242022-12-02 19:36:01 -0800490 continue;
Ed Tanous60520632018-06-11 17:46:52 -0700491 }
492
William A. Kennington III60ffc242022-12-02 19:36:01 -0800493 if (interface == assocDefsInterface)
Ed Tanous60520632018-06-11 17:46:52 -0700494 {
William A. Kennington III60ffc242022-12-02 19:36:01 -0800495 removeAssociation(io, objPath.str, sender, server,
496 associationMaps);
Ed Tanous60520632018-06-11 17:46:52 -0700497 }
William A. Kennington III60ffc242022-12-02 19:36:01 -0800498
499 interfaceSet->second.erase(interface);
500
501 if (interfaceSet->second.empty())
Ed Tanous60520632018-06-11 17:46:52 -0700502 {
William A. Kennington III60ffc242022-12-02 19:36:01 -0800503 // If this was the last interface on this connection,
504 // erase the connection
505 connectionMap->second.erase(interfaceSet);
506
507 // Instead of checking if every single path is the endpoint
508 // of an association that needs to be moved to pending,
509 // only check when the only remaining owner of this path is
510 // ourself, which would be because we still own the
511 // association path.
512 if ((connectionMap->second.size() == 1) &&
513 (connectionMap->second.begin()->first ==
514 "xyz.openbmc_project.ObjectMapper"))
Ed Tanous60520632018-06-11 17:46:52 -0700515 {
William A. Kennington III60ffc242022-12-02 19:36:01 -0800516 // Remove the 2 association D-Bus paths and move the
517 // association to pending.
518 moveAssociationToPending(io, objPath.str, associationMaps,
519 server);
Ed Tanous60520632018-06-11 17:46:52 -0700520 }
521 }
William A. Kennington III60ffc242022-12-02 19:36:01 -0800522 }
523 // If this was the last connection on this object path,
524 // erase the object path
525 if (connectionMap->second.empty())
526 {
527 interfaceMap.erase(connectionMap);
528 }
Matt Spinlera82779f2019-01-09 12:39:42 -0600529
William A. Kennington III60ffc242022-12-02 19:36:01 -0800530 removeUnneededParents(objPath.str, sender, interfaceMap);
531 };
Ed Tanous60520632018-06-11 17:46:52 -0700532
Patrick Williamscc8070b2022-07-22 19:26:55 -0500533 sdbusplus::bus::match_t interfacesRemoved(
534 static_cast<sdbusplus::bus_t&>(*systemBus),
Ed Tanous60520632018-06-11 17:46:52 -0700535 sdbusplus::bus::match::rules::interfacesRemoved(),
William A. Kennington III60ffc242022-12-02 19:36:01 -0800536 std::move(interfacesRemovedHandler));
Ed Tanous60520632018-06-11 17:46:52 -0700537
William A. Kennington III60ffc242022-12-02 19:36:01 -0800538 auto associationChangedHandler = [&io, &server, &nameOwners, &interfaceMap](
539 sdbusplus::message_t& message) {
540 std::string objectName;
541 boost::container::flat_map<std::string,
542 std::variant<std::vector<Association>>>
543 values;
544 message.read(objectName, values);
545 auto prop = values.find(assocDefsProperty);
546 if (prop != values.end())
547 {
548 std::vector<Association> associations =
549 std::get<std::vector<Association>>(prop->second);
550
551 std::string wellKnown;
552 if (!getWellKnown(nameOwners, message.get_sender(), wellKnown))
Matt Spinler8f876a52019-04-15 13:22:50 -0500553 {
William A. Kennington III60ffc242022-12-02 19:36:01 -0800554 return;
Matt Spinler8f876a52019-04-15 13:22:50 -0500555 }
William A. Kennington III60ffc242022-12-02 19:36:01 -0800556 associationChanged(io, server, associations, message.get_path(),
557 wellKnown, interfaceMap, associationMaps);
558 }
559 };
Patrick Williamscc8070b2022-07-22 19:26:55 -0500560 sdbusplus::bus::match_t assocChangedMatch(
561 static_cast<sdbusplus::bus_t&>(*systemBus),
Ed Tanous60520632018-06-11 17:46:52 -0700562 sdbusplus::bus::match::rules::interface(
563 "org.freedesktop.DBus.Properties") +
564 sdbusplus::bus::match::rules::member("PropertiesChanged") +
Matt Spinler8f876a52019-04-15 13:22:50 -0500565 sdbusplus::bus::match::rules::argN(0, assocDefsInterface),
William A. Kennington III60ffc242022-12-02 19:36:01 -0800566 std::move(associationChangedHandler));
Matt Spinler8f876a52019-04-15 13:22:50 -0500567
Ed Tanous60520632018-06-11 17:46:52 -0700568 std::shared_ptr<sdbusplus::asio::dbus_interface> iface =
Brad Bishopa02cd542021-10-12 19:12:42 -0400569 server.add_interface("/xyz/openbmc_project/object_mapper",
570 "xyz.openbmc_project.ObjectMapper");
Ed Tanous60520632018-06-11 17:46:52 -0700571
572 iface->register_method(
Brad Bishopa098a372022-05-05 15:19:04 -0400573 "GetAncestors", [&interfaceMap](std::string& reqPath,
574 std::vector<std::string>& interfaces) {
575 return getAncestors(interfaceMap, reqPath, interfaces);
Ed Tanous60520632018-06-11 17:46:52 -0700576 });
577
578 iface->register_method(
Brad Bishopa098a372022-05-05 15:19:04 -0400579 "GetObject", [&interfaceMap](const std::string& path,
580 std::vector<std::string>& interfaces) {
581 return getObject(interfaceMap, path, interfaces);
582 });
583
584 iface->register_method(
585 "GetSubTree", [&interfaceMap](std::string& reqPath, int32_t depth,
Ed Tanous60520632018-06-11 17:46:52 -0700586 std::vector<std::string>& interfaces) {
Brad Bishopa098a372022-05-05 15:19:04 -0400587 return getSubTree(interfaceMap, reqPath, depth, interfaces);
Ed Tanous60520632018-06-11 17:46:52 -0700588 });
589
590 iface->register_method(
591 "GetSubTreePaths",
Brad Bishopa098a372022-05-05 15:19:04 -0400592 [&interfaceMap](std::string& reqPath, int32_t depth,
593 std::vector<std::string>& interfaces) {
Patrick Williams670edd12023-02-15 15:06:52 -0600594 return getSubTreePaths(interfaceMap, reqPath, depth, interfaces);
Ed Tanous60520632018-06-11 17:46:52 -0700595 });
596
Willy Tu58881d02022-10-02 20:46:45 +0000597 iface->register_method(
598 "GetAssociatedSubTree",
599 [&interfaceMap](const sdbusplus::message::object_path& associationPath,
600 const sdbusplus::message::object_path& reqPath,
601 int32_t depth, std::vector<std::string>& interfaces) {
Patrick Williams670edd12023-02-15 15:06:52 -0600602 return getAssociatedSubTree(interfaceMap, associationMaps,
603 associationPath, reqPath, depth,
604 interfaces);
Willy Tu58881d02022-10-02 20:46:45 +0000605 });
606
607 iface->register_method(
608 "GetAssociatedSubTreePaths",
609 [&interfaceMap](const sdbusplus::message::object_path& associationPath,
610 const sdbusplus::message::object_path& reqPath,
611 int32_t depth, std::vector<std::string>& interfaces) {
Patrick Williams670edd12023-02-15 15:06:52 -0600612 return getAssociatedSubTreePaths(interfaceMap, associationMaps,
613 associationPath, reqPath, depth,
614 interfaces);
Willy Tu58881d02022-10-02 20:46:45 +0000615 });
616
Ed Tanous60520632018-06-11 17:46:52 -0700617 iface->initialize();
618
619 io.post([&]() {
Brad Bishopa098a372022-05-05 15:19:04 -0400620 doListNames(io, interfaceMap, systemBus.get(), nameOwners,
Matt Spinler11401e22019-04-08 13:13:25 -0500621 associationMaps, server);
Ed Tanous60520632018-06-11 17:46:52 -0700622 });
623
Brad Bishopa098a372022-05-05 15:19:04 -0400624 systemBus->request_name("xyz.openbmc_project.ObjectMapper");
Vishwanatha Subbanna64354ef2020-08-21 03:35:26 -0500625
Ed Tanous60520632018-06-11 17:46:52 -0700626 io.run();
627}