1a80a3af0SAndrew Geissler #include "associations.hpp"
2aba14d3dSWilly Tu #include "handler.hpp"
33b025e69SAndrew Geissler #include "processing.hpp"
435396c10SMatt Spinler #include "types.hpp"
5dd945861SMatt Spinler
660520631SEd Tanous #include <tinyxml2.h>
760520631SEd Tanous
821c60595SEd Tanous #include <boost/asio/io_context.hpp>
921c60595SEd Tanous #include <boost/asio/signal_set.hpp>
1060520631SEd Tanous #include <boost/container/flat_map.hpp>
1160520631SEd Tanous #include <sdbusplus/asio/connection.hpp>
1260520631SEd Tanous #include <sdbusplus/asio/object_server.hpp>
13b15df6b2SKonstantin Aladyshev #include <xyz/openbmc_project/Common/error.hpp>
1460520631SEd Tanous
152352088eSBrad Bishop #include <atomic>
162352088eSBrad Bishop #include <chrono>
17ea119463SBrad Bishop #include <exception>
182352088eSBrad Bishop #include <iomanip>
192352088eSBrad Bishop #include <iostream>
20f6ebfc73SBrandon Kim #include <string>
21f6ebfc73SBrandon Kim #include <string_view>
221f62380aSBrad Bishop #include <utility>
232352088eSBrad Bishop
24e2359fb7SMatt Spinler AssociationMaps associationMaps;
25937a232eSMatt Spinler
updateOwners(sdbusplus::asio::connection * conn,boost::container::flat_map<std::string,std::string> & owners,const std::string & newObject)26a098a37aSBrad Bishop void updateOwners(sdbusplus::asio::connection* conn,
2760520631SEd Tanous boost::container::flat_map<std::string, std::string>& owners,
28a098a37aSBrad Bishop const std::string& newObject)
2960520631SEd Tanous {
3086d2880eSBrad Bishop if (newObject.starts_with(":"))
3160520631SEd Tanous {
3260520631SEd Tanous return;
3360520631SEd Tanous }
3460520631SEd Tanous conn->async_method_call(
35a098a37aSBrad Bishop [&, newObject](const boost::system::error_code ec,
3660520631SEd Tanous const std::string& nameOwner) {
3760520631SEd Tanous if (ec)
3860520631SEd Tanous {
399052ebd3SPatrick Williams std::cerr << "Error getting owner of " << newObject << " : "
409052ebd3SPatrick Williams << ec << "\n";
4160520631SEd Tanous return;
4260520631SEd Tanous }
43a098a37aSBrad Bishop owners[nameOwner] = newObject;
4460520631SEd Tanous },
4560520631SEd Tanous "org.freedesktop.DBus", "/", "org.freedesktop.DBus", "GetNameOwner",
46a098a37aSBrad Bishop newObject);
4760520631SEd Tanous }
4860520631SEd Tanous
sendIntrospectionCompleteSignal(sdbusplus::asio::connection * systemBus,const std::string & processName)49a098a37aSBrad Bishop void sendIntrospectionCompleteSignal(sdbusplus::asio::connection* systemBus,
50a098a37aSBrad Bishop const std::string& processName)
5160520631SEd Tanous {
5260520631SEd Tanous // TODO(ed) This signal doesn't get exposed properly in the
5360520631SEd Tanous // introspect right now. Find out how to register signals in
5460520631SEd Tanous // sdbusplus
55cc8070baSPatrick Williams sdbusplus::message_t m = systemBus->new_signal(
56a02cd54cSBrad Bishop "/xyz/openbmc_project/object_mapper",
57a02cd54cSBrad Bishop "xyz.openbmc_project.ObjectMapper.Private", "IntrospectionComplete");
58a098a37aSBrad Bishop m.append(processName);
5960520631SEd Tanous m.signal_send();
6060520631SEd Tanous }
6160520631SEd Tanous
6260520631SEd Tanous struct InProgressIntrospect
6360520631SEd Tanous {
641f62380aSBrad Bishop InProgressIntrospect() = delete;
651f62380aSBrad Bishop InProgressIntrospect(const InProgressIntrospect&) = delete;
661f62380aSBrad Bishop InProgressIntrospect(InProgressIntrospect&&) = delete;
671f62380aSBrad Bishop InProgressIntrospect& operator=(const InProgressIntrospect&) = delete;
681f62380aSBrad Bishop InProgressIntrospect& operator=(InProgressIntrospect&&) = delete;
InProgressIntrospectInProgressIntrospect6960520631SEd Tanous InProgressIntrospect(
70a098a37aSBrad Bishop sdbusplus::asio::connection* systemBus, boost::asio::io_context& io,
71a098a37aSBrad Bishop const std::string& processName, AssociationMaps& am
72d6aa5525SBrad Bishop #ifdef MAPPER_ENABLE_DEBUG
73aecabe86SMatt Spinler ,
7460520631SEd Tanous std::shared_ptr<std::chrono::time_point<std::chrono::steady_clock>>
75a098a37aSBrad Bishop globalStartTime
76aecabe86SMatt Spinler #endif
77aecabe86SMatt Spinler ) :
789052ebd3SPatrick Williams systemBus(systemBus), io(io), processName(processName), assocMaps(am)
79d6aa5525SBrad Bishop #ifdef MAPPER_ENABLE_DEBUG
80aecabe86SMatt Spinler ,
811f62380aSBrad Bishop globalStartTime(std::move(globalStartTime)),
82a098a37aSBrad Bishop processStartTime(std::chrono::steady_clock::now())
83aecabe86SMatt Spinler #endif
842352088eSBrad Bishop {}
~InProgressIntrospectInProgressIntrospect8560520631SEd Tanous ~InProgressIntrospect()
8660520631SEd Tanous {
87ea119463SBrad Bishop try
88ea119463SBrad Bishop {
89a098a37aSBrad Bishop sendIntrospectionCompleteSignal(systemBus, processName);
90d6aa5525SBrad Bishop #ifdef MAPPER_ENABLE_DEBUG
9160520631SEd Tanous std::chrono::duration<float> diff =
92a098a37aSBrad Bishop std::chrono::steady_clock::now() - processStartTime;
93a098a37aSBrad Bishop std::cout << std::setw(50) << processName << " scan took "
9460520631SEd Tanous << diff.count() << " seconds\n";
9560520631SEd Tanous
9660520631SEd Tanous // If we're the last outstanding caller globally, calculate the
9760520631SEd Tanous // time it took
98a098a37aSBrad Bishop if (globalStartTime != nullptr && globalStartTime.use_count() == 1)
9960520631SEd Tanous {
100a098a37aSBrad Bishop diff = std::chrono::steady_clock::now() - *globalStartTime;
10160520631SEd Tanous std::cout << "Total scan took " << diff.count()
10260520631SEd Tanous << " seconds to complete\n";
10360520631SEd Tanous }
104aecabe86SMatt Spinler #endif
10560520631SEd Tanous }
106ea119463SBrad Bishop catch (const std::exception& e)
107ea119463SBrad Bishop {
108ea119463SBrad Bishop std::cerr
109ea119463SBrad Bishop << "Terminating, unhandled exception while introspecting: "
110ea119463SBrad Bishop << e.what() << "\n";
111ea119463SBrad Bishop std::terminate();
112ea119463SBrad Bishop }
113ea119463SBrad Bishop catch (...)
114ea119463SBrad Bishop {
115ea119463SBrad Bishop std::cerr
116ea119463SBrad Bishop << "Terminating, unhandled exception while introspecting\n";
117ea119463SBrad Bishop std::terminate();
118ea119463SBrad Bishop }
119ea119463SBrad Bishop }
120a098a37aSBrad Bishop sdbusplus::asio::connection* systemBus;
12121c60595SEd Tanous boost::asio::io_context& io;
122a098a37aSBrad Bishop std::string processName;
12311401e2eSMatt Spinler AssociationMaps& assocMaps;
124d6aa5525SBrad Bishop #ifdef MAPPER_ENABLE_DEBUG
12560520631SEd Tanous std::shared_ptr<std::chrono::time_point<std::chrono::steady_clock>>
126a098a37aSBrad Bishop globalStartTime;
127a098a37aSBrad Bishop std::chrono::time_point<std::chrono::steady_clock> processStartTime;
128aecabe86SMatt Spinler #endif
12960520631SEd Tanous };
13060520631SEd Tanous
doAssociations(boost::asio::io_context & io,sdbusplus::asio::connection * systemBus,InterfaceMapType & interfaceMap,sdbusplus::asio::object_server & objectServer,const std::string & processName,const std::string & path,int timeoutRetries=0)1315b4357daSKallas, Pawel void doAssociations(boost::asio::io_context& io,
1325b4357daSKallas, Pawel sdbusplus::asio::connection* systemBus,
133a098a37aSBrad Bishop InterfaceMapType& interfaceMap,
13460520631SEd Tanous sdbusplus::asio::object_server& objectServer,
135bb40bd36SAdrian Ambrożewicz const std::string& processName, const std::string& path,
136bb40bd36SAdrian Ambrożewicz int timeoutRetries = 0)
13760520631SEd Tanous {
138bb40bd36SAdrian Ambrożewicz constexpr int maxTimeoutRetries = 3;
139a098a37aSBrad Bishop systemBus->async_method_call(
1405b4357daSKallas, Pawel [&io, &objectServer, path, processName, &interfaceMap, systemBus,
141bb40bd36SAdrian Ambrożewicz timeoutRetries](
142937a232eSMatt Spinler const boost::system::error_code ec,
1432bb2d6baSPatrick Williams const std::variant<std::vector<Association>>& variantAssociations) {
14460520631SEd Tanous if (ec)
14560520631SEd Tanous {
146bb40bd36SAdrian Ambrożewicz if (ec.value() == boost::system::errc::timed_out &&
147bb40bd36SAdrian Ambrożewicz timeoutRetries < maxTimeoutRetries)
148bb40bd36SAdrian Ambrożewicz {
1495b4357daSKallas, Pawel doAssociations(io, systemBus, interfaceMap, objectServer,
150bb40bd36SAdrian Ambrożewicz processName, path, timeoutRetries + 1);
151bb40bd36SAdrian Ambrożewicz return;
152bb40bd36SAdrian Ambrożewicz }
15360520631SEd Tanous std::cerr << "Error getting associations from " << path << "\n";
15460520631SEd Tanous }
15560520631SEd Tanous std::vector<Association> associations =
156b05bc12cSPatrick Williams std::get<std::vector<Association>>(variantAssociations);
1579052ebd3SPatrick Williams associationChanged(io, objectServer, associations, path,
1589052ebd3SPatrick Williams processName, interfaceMap, associationMaps);
15960520631SEd Tanous },
16060520631SEd Tanous processName, path, "org.freedesktop.DBus.Properties", "Get",
161d0cf9428SJohn Wang assocDefsInterface, assocDefsProperty);
16260520631SEd Tanous }
16360520631SEd Tanous
doIntrospect(boost::asio::io_context & io,sdbusplus::asio::connection * systemBus,const std::shared_ptr<InProgressIntrospect> & transaction,InterfaceMapType & interfaceMap,sdbusplus::asio::object_server & objectServer,const std::string & path,int timeoutRetries=0)1645b4357daSKallas, Pawel void doIntrospect(boost::asio::io_context& io,
1655b4357daSKallas, Pawel sdbusplus::asio::connection* systemBus,
1661f62380aSBrad Bishop const std::shared_ptr<InProgressIntrospect>& transaction,
167a098a37aSBrad Bishop InterfaceMapType& interfaceMap,
16860520631SEd Tanous sdbusplus::asio::object_server& objectServer,
1691f62380aSBrad Bishop const std::string& path, int timeoutRetries = 0)
17060520631SEd Tanous {
171c52be0d2SVernon Mauery constexpr int maxTimeoutRetries = 3;
172a098a37aSBrad Bishop systemBus->async_method_call(
1735b4357daSKallas, Pawel [&io, &interfaceMap, &objectServer, transaction, path, systemBus,
174c52be0d2SVernon Mauery timeoutRetries](const boost::system::error_code ec,
175a098a37aSBrad Bishop const std::string& introspectXml) {
17660520631SEd Tanous if (ec)
17760520631SEd Tanous {
178c52be0d2SVernon Mauery if (ec.value() == boost::system::errc::timed_out &&
179c52be0d2SVernon Mauery timeoutRetries < maxTimeoutRetries)
180c52be0d2SVernon Mauery {
1815b4357daSKallas, Pawel doIntrospect(io, systemBus, transaction, interfaceMap,
182c52be0d2SVernon Mauery objectServer, path, timeoutRetries + 1);
183c52be0d2SVernon Mauery return;
184c52be0d2SVernon Mauery }
18560520631SEd Tanous std::cerr << "Introspect call failed with error: " << ec << ", "
18660520631SEd Tanous << ec.message()
187a098a37aSBrad Bishop << " on process: " << transaction->processName
18860520631SEd Tanous << " path: " << path << "\n";
18960520631SEd Tanous return;
19060520631SEd Tanous }
19160520631SEd Tanous
19260520631SEd Tanous tinyxml2::XMLDocument doc;
19360520631SEd Tanous
194a098a37aSBrad Bishop tinyxml2::XMLError e = doc.Parse(introspectXml.c_str());
19560520631SEd Tanous if (e != tinyxml2::XMLError::XML_SUCCESS)
19660520631SEd Tanous {
19760520631SEd Tanous std::cerr << "XML parsing failed\n";
19860520631SEd Tanous return;
19960520631SEd Tanous }
20060520631SEd Tanous
20160520631SEd Tanous tinyxml2::XMLNode* pRoot = doc.FirstChildElement("node");
20260520631SEd Tanous if (pRoot == nullptr)
20360520631SEd Tanous {
20460520631SEd Tanous std::cerr << "XML document did not contain any data\n";
20560520631SEd Tanous return;
20660520631SEd Tanous }
207a098a37aSBrad Bishop auto& thisPathMap = interfaceMap[path];
2089052ebd3SPatrick Williams tinyxml2::XMLElement* pElement =
2099052ebd3SPatrick Williams pRoot->FirstChildElement("interface");
21060520631SEd Tanous while (pElement != nullptr)
21160520631SEd Tanous {
212a098a37aSBrad Bishop const char* ifaceName = pElement->Attribute("name");
213a098a37aSBrad Bishop if (ifaceName == nullptr)
21460520631SEd Tanous {
21560520631SEd Tanous continue;
21660520631SEd Tanous }
21760520631SEd Tanous
218a098a37aSBrad Bishop thisPathMap[transaction->processName].emplace(ifaceName);
219d4dd96a0SEd Tanous
220a098a37aSBrad Bishop if (std::strcmp(ifaceName, assocDefsInterface) == 0)
22160520631SEd Tanous {
2225b4357daSKallas, Pawel doAssociations(io, systemBus, interfaceMap, objectServer,
223a098a37aSBrad Bishop transaction->processName, path);
22460520631SEd Tanous }
22560520631SEd Tanous
22660520631SEd Tanous pElement = pElement->NextSiblingElement("interface");
22760520631SEd Tanous }
22860520631SEd Tanous
22911401e2eSMatt Spinler // Check if this new path has a pending association that can
23011401e2eSMatt Spinler // now be completed.
2315b4357daSKallas, Pawel checkIfPendingAssociation(io, path, interfaceMap,
23211401e2eSMatt Spinler transaction->assocMaps, objectServer);
23311401e2eSMatt Spinler
23460520631SEd Tanous pElement = pRoot->FirstChildElement("node");
23560520631SEd Tanous while (pElement != nullptr)
23660520631SEd Tanous {
237a098a37aSBrad Bishop const char* childPath = pElement->Attribute("name");
238a098a37aSBrad Bishop if (childPath != nullptr)
23960520631SEd Tanous {
240a098a37aSBrad Bishop std::string parentPath(path);
241a098a37aSBrad Bishop if (parentPath == "/")
24260520631SEd Tanous {
243a098a37aSBrad Bishop parentPath.clear();
24460520631SEd Tanous }
24560520631SEd Tanous
2465b4357daSKallas, Pawel doIntrospect(io, systemBus, transaction, interfaceMap,
247a098a37aSBrad Bishop objectServer, parentPath + "/" + childPath);
24860520631SEd Tanous }
24960520631SEd Tanous pElement = pElement->NextSiblingElement("node");
25060520631SEd Tanous }
25160520631SEd Tanous },
252a098a37aSBrad Bishop transaction->processName, path, "org.freedesktop.DBus.Introspectable",
25360520631SEd Tanous "Introspect");
25460520631SEd Tanous }
25560520631SEd Tanous
startNewIntrospect(sdbusplus::asio::connection * systemBus,boost::asio::io_context & io,InterfaceMapType & interfaceMap,const std::string & processName,AssociationMaps & assocMaps,std::shared_ptr<std::chrono::time_point<std::chrono::steady_clock>> globalStartTime,sdbusplus::asio::object_server & objectServer)256a098a37aSBrad Bishop void startNewIntrospect(
257a098a37aSBrad Bishop sdbusplus::asio::connection* systemBus, boost::asio::io_context& io,
258a098a37aSBrad Bishop InterfaceMapType& interfaceMap, const std::string& processName,
25911401e2eSMatt Spinler AssociationMaps& assocMaps,
260d6aa5525SBrad Bishop #ifdef MAPPER_ENABLE_DEBUG
26160520631SEd Tanous std::shared_ptr<std::chrono::time_point<std::chrono::steady_clock>>
262a098a37aSBrad Bishop globalStartTime,
263aecabe86SMatt Spinler #endif
26460520631SEd Tanous sdbusplus::asio::object_server& objectServer)
26560520631SEd Tanous {
2661e94e60bSBrad Bishop if (needToIntrospect(processName))
26760520631SEd Tanous {
26860520631SEd Tanous std::shared_ptr<InProgressIntrospect> transaction =
2699052ebd3SPatrick Williams std::make_shared<InProgressIntrospect>(
2709052ebd3SPatrick Williams systemBus, io, processName, assocMaps
271d6aa5525SBrad Bishop #ifdef MAPPER_ENABLE_DEBUG
272aecabe86SMatt Spinler ,
273a098a37aSBrad Bishop globalStartTime
274aecabe86SMatt Spinler #endif
275aecabe86SMatt Spinler );
27660520631SEd Tanous
2775b4357daSKallas, Pawel doIntrospect(io, systemBus, transaction, interfaceMap, objectServer,
2785b4357daSKallas, Pawel "/");
27960520631SEd Tanous }
28060520631SEd Tanous }
28160520631SEd Tanous
doListNames(boost::asio::io_context & io,InterfaceMapType & interfaceMap,sdbusplus::asio::connection * systemBus,boost::container::flat_map<std::string,std::string> & nameOwners,AssociationMaps & assocMaps,sdbusplus::asio::object_server & objectServer)28260520631SEd Tanous void doListNames(
283a098a37aSBrad Bishop boost::asio::io_context& io, InterfaceMapType& interfaceMap,
284a098a37aSBrad Bishop sdbusplus::asio::connection* systemBus,
285a098a37aSBrad Bishop boost::container::flat_map<std::string, std::string>& nameOwners,
28611401e2eSMatt Spinler AssociationMaps& assocMaps, sdbusplus::asio::object_server& objectServer)
28760520631SEd Tanous {
288a098a37aSBrad Bishop systemBus->async_method_call(
289a098a37aSBrad Bishop [&io, &interfaceMap, &nameOwners, &objectServer, systemBus,
29011401e2eSMatt Spinler &assocMaps](const boost::system::error_code ec,
291a098a37aSBrad Bishop std::vector<std::string> processNames) {
29260520631SEd Tanous if (ec)
29360520631SEd Tanous {
29460520631SEd Tanous std::cerr << "Error getting names: " << ec << "\n";
29560520631SEd Tanous std::exit(EXIT_FAILURE);
29660520631SEd Tanous return;
29760520631SEd Tanous }
29860520631SEd Tanous // Try to make startup consistent
299a098a37aSBrad Bishop std::sort(processNames.begin(), processNames.end());
300d6aa5525SBrad Bishop #ifdef MAPPER_ENABLE_DEBUG
30160520631SEd Tanous std::shared_ptr<std::chrono::time_point<std::chrono::steady_clock>>
302a098a37aSBrad Bishop globalStartTime = std::make_shared<
30360520631SEd Tanous std::chrono::time_point<std::chrono::steady_clock>>(
30460520631SEd Tanous std::chrono::steady_clock::now());
305aecabe86SMatt Spinler #endif
306a098a37aSBrad Bishop for (const std::string& processName : processNames)
30760520631SEd Tanous {
3081e94e60bSBrad Bishop if (needToIntrospect(processName))
30960520631SEd Tanous {
310a098a37aSBrad Bishop startNewIntrospect(systemBus, io, interfaceMap, processName,
311a098a37aSBrad Bishop assocMaps,
312d6aa5525SBrad Bishop #ifdef MAPPER_ENABLE_DEBUG
313a098a37aSBrad Bishop globalStartTime,
314aecabe86SMatt Spinler #endif
31560520631SEd Tanous objectServer);
316a098a37aSBrad Bishop updateOwners(systemBus, nameOwners, processName);
31760520631SEd Tanous }
31860520631SEd Tanous }
31960520631SEd Tanous },
32060520631SEd Tanous "org.freedesktop.DBus", "/org/freedesktop/DBus", "org.freedesktop.DBus",
32160520631SEd Tanous "ListNames");
32260520631SEd Tanous }
32360520631SEd Tanous
324a82779fbSMatt Spinler // Remove parents of the passed in path that:
325a82779fbSMatt Spinler // 1) Only have the 3 default interfaces on them
326a82779fbSMatt Spinler // - Means D-Bus created these, not application code,
327a82779fbSMatt Spinler // with the Properties, Introspectable, and Peer ifaces
328a82779fbSMatt Spinler // 2) Have no other child for this owner
removeUnneededParents(const std::string & objectPath,const std::string & owner,InterfaceMapType & interfaceMap)329a82779fbSMatt Spinler void removeUnneededParents(const std::string& objectPath,
330a82779fbSMatt Spinler const std::string& owner,
331a098a37aSBrad Bishop InterfaceMapType& interfaceMap)
332a82779fbSMatt Spinler {
333a82779fbSMatt Spinler auto parent = objectPath;
334a82779fbSMatt Spinler
335a82779fbSMatt Spinler while (true)
336a82779fbSMatt Spinler {
337a82779fbSMatt Spinler auto pos = parent.find_last_of('/');
338a82779fbSMatt Spinler if ((pos == std::string::npos) || (pos == 0))
339a82779fbSMatt Spinler {
340a82779fbSMatt Spinler break;
341a82779fbSMatt Spinler }
342a82779fbSMatt Spinler parent = parent.substr(0, pos);
343a82779fbSMatt Spinler
344a098a37aSBrad Bishop auto parentIt = interfaceMap.find(parent);
345a098a37aSBrad Bishop if (parentIt == interfaceMap.end())
346a82779fbSMatt Spinler {
347a82779fbSMatt Spinler break;
348a82779fbSMatt Spinler }
349a82779fbSMatt Spinler
350a098a37aSBrad Bishop auto ifacesIt = parentIt->second.find(owner);
351a098a37aSBrad Bishop if (ifacesIt == parentIt->second.end())
352a82779fbSMatt Spinler {
353a82779fbSMatt Spinler break;
354a82779fbSMatt Spinler }
355a82779fbSMatt Spinler
356a098a37aSBrad Bishop if (ifacesIt->second.size() != 3)
357a82779fbSMatt Spinler {
358a82779fbSMatt Spinler break;
359a82779fbSMatt Spinler }
360a82779fbSMatt Spinler
361a098a37aSBrad Bishop auto childPath = parent + '/';
362a82779fbSMatt Spinler
363a82779fbSMatt Spinler // Remove this parent if there isn't a remaining child on this owner
3649052ebd3SPatrick Williams auto child = std::find_if(
3659052ebd3SPatrick Williams interfaceMap.begin(), interfaceMap.end(),
366a098a37aSBrad Bishop [&owner, &childPath](const auto& entry) {
36786d2880eSBrad Bishop return entry.first.starts_with(childPath) &&
368a82779fbSMatt Spinler (entry.second.find(owner) != entry.second.end());
369a82779fbSMatt Spinler });
370a82779fbSMatt Spinler
371a098a37aSBrad Bishop if (child == interfaceMap.end())
372a82779fbSMatt Spinler {
373a098a37aSBrad Bishop parentIt->second.erase(ifacesIt);
374a098a37aSBrad Bishop if (parentIt->second.empty())
375a82779fbSMatt Spinler {
376a098a37aSBrad Bishop interfaceMap.erase(parentIt);
377a82779fbSMatt Spinler }
378a82779fbSMatt Spinler }
379a82779fbSMatt Spinler else
380a82779fbSMatt Spinler {
381a82779fbSMatt Spinler break;
382a82779fbSMatt Spinler }
383a82779fbSMatt Spinler }
384a82779fbSMatt Spinler }
385a82779fbSMatt Spinler
main()3861e94e60bSBrad Bishop int main()
38760520631SEd Tanous {
38821c60595SEd Tanous boost::asio::io_context io;
389a098a37aSBrad Bishop std::shared_ptr<sdbusplus::asio::connection> systemBus =
39060520631SEd Tanous std::make_shared<sdbusplus::asio::connection>(io);
39160520631SEd Tanous
392a098a37aSBrad Bishop sdbusplus::asio::object_server server(systemBus);
39360520631SEd Tanous
39460520631SEd Tanous // Construct a signal set registered for process termination.
39560520631SEd Tanous boost::asio::signal_set signals(io, SIGINT, SIGTERM);
3969052ebd3SPatrick Williams signals.async_wait([&io](const boost::system::error_code&, int) {
3979052ebd3SPatrick Williams io.stop();
3989052ebd3SPatrick Williams });
39960520631SEd Tanous
400a098a37aSBrad Bishop InterfaceMapType interfaceMap;
401a098a37aSBrad Bishop boost::container::flat_map<std::string, std::string> nameOwners;
40260520631SEd Tanous
40360ffc244SWilliam A. Kennington III auto nameChangeHandler = [&interfaceMap, &io, &nameOwners, &server,
404cc8070baSPatrick Williams systemBus](sdbusplus::message_t& message) {
4052067926aSAndrew Geissler std::string name; // well-known
406a098a37aSBrad Bishop std::string oldOwner; // unique-name
407a098a37aSBrad Bishop std::string newOwner; // unique-name
40860520631SEd Tanous
409a098a37aSBrad Bishop message.read(name, oldOwner, newOwner);
41060520631SEd Tanous
41148248203SPatrick Williams if (name.starts_with(':'))
41248248203SPatrick Williams {
41348248203SPatrick Williams // We should do nothing with unique-name connections.
41448248203SPatrick Williams return;
41548248203SPatrick Williams }
41648248203SPatrick Williams
417a098a37aSBrad Bishop if (!oldOwner.empty())
41860520631SEd Tanous {
4195b4357daSKallas, Pawel processNameChangeDelete(io, nameOwners, name, oldOwner,
420a098a37aSBrad Bishop interfaceMap, associationMaps, server);
42160520631SEd Tanous }
42260520631SEd Tanous
423a098a37aSBrad Bishop if (!newOwner.empty())
42460520631SEd Tanous {
425d6aa5525SBrad Bishop #ifdef MAPPER_ENABLE_DEBUG
42660520631SEd Tanous auto transaction = std::make_shared<
42760520631SEd Tanous std::chrono::time_point<std::chrono::steady_clock>>(
42860520631SEd Tanous std::chrono::steady_clock::now());
429aecabe86SMatt Spinler #endif
43060520631SEd Tanous // New daemon added
4311e94e60bSBrad Bishop if (needToIntrospect(name))
43260520631SEd Tanous {
433a098a37aSBrad Bishop nameOwners[newOwner] = name;
434a098a37aSBrad Bishop startNewIntrospect(systemBus.get(), io, interfaceMap, name,
435a098a37aSBrad Bishop associationMaps,
436d6aa5525SBrad Bishop #ifdef MAPPER_ENABLE_DEBUG
437aecabe86SMatt Spinler transaction,
438aecabe86SMatt Spinler #endif
439aecabe86SMatt Spinler server);
44060520631SEd Tanous }
44160520631SEd Tanous }
44260520631SEd Tanous };
44360520631SEd Tanous
444cc8070baSPatrick Williams sdbusplus::bus::match_t nameOwnerChanged(
445cc8070baSPatrick Williams static_cast<sdbusplus::bus_t&>(*systemBus),
44660ffc244SWilliam A. Kennington III sdbusplus::bus::match::rules::nameOwnerChanged(),
44760ffc244SWilliam A. Kennington III std::move(nameChangeHandler));
44860520631SEd Tanous
44960ffc244SWilliam A. Kennington III auto interfacesAddedHandler = [&io, &interfaceMap, &nameOwners,
4505b4357daSKallas, Pawel &server](sdbusplus::message_t& message) {
451a098a37aSBrad Bishop sdbusplus::message::object_path objPath;
452a098a37aSBrad Bishop InterfacesAdded interfacesAdded;
453a098a37aSBrad Bishop message.read(objPath, interfacesAdded);
454a098a37aSBrad Bishop std::string wellKnown;
455a098a37aSBrad Bishop if (!getWellKnown(nameOwners, message.get_sender(), wellKnown))
45660520631SEd Tanous {
45760520631SEd Tanous return; // only introspect well-known
45860520631SEd Tanous }
4591e94e60bSBrad Bishop if (needToIntrospect(wellKnown))
46060520631SEd Tanous {
46160ffc244SWilliam A. Kennington III processInterfaceAdded(io, interfaceMap, objPath, interfacesAdded,
46260ffc244SWilliam A. Kennington III wellKnown, associationMaps, server);
46360520631SEd Tanous }
46460520631SEd Tanous };
46560520631SEd Tanous
466cc8070baSPatrick Williams sdbusplus::bus::match_t interfacesAdded(
467cc8070baSPatrick Williams static_cast<sdbusplus::bus_t&>(*systemBus),
46860520631SEd Tanous sdbusplus::bus::match::rules::interfacesAdded(),
46960ffc244SWilliam A. Kennington III std::move(interfacesAddedHandler));
47060520631SEd Tanous
47160ffc244SWilliam A. Kennington III auto interfacesRemovedHandler = [&io, &interfaceMap, &nameOwners,
472cc8070baSPatrick Williams &server](sdbusplus::message_t& message) {
473a098a37aSBrad Bishop sdbusplus::message::object_path objPath;
474a098a37aSBrad Bishop std::vector<std::string> interfacesRemoved;
475a098a37aSBrad Bishop message.read(objPath, interfacesRemoved);
476a098a37aSBrad Bishop auto connectionMap = interfaceMap.find(objPath.str);
477a098a37aSBrad Bishop if (connectionMap == interfaceMap.end())
47860520631SEd Tanous {
47960520631SEd Tanous return;
48060520631SEd Tanous }
48160520631SEd Tanous
48260520631SEd Tanous std::string sender;
483a098a37aSBrad Bishop if (!getWellKnown(nameOwners, message.get_sender(), sender))
48460520631SEd Tanous {
48560520631SEd Tanous return;
48660520631SEd Tanous }
487a098a37aSBrad Bishop for (const std::string& interface : interfacesRemoved)
48860520631SEd Tanous {
489a098a37aSBrad Bishop auto interfaceSet = connectionMap->second.find(sender);
490a098a37aSBrad Bishop if (interfaceSet == connectionMap->second.end())
49160520631SEd Tanous {
49260520631SEd Tanous continue;
49360520631SEd Tanous }
49460520631SEd Tanous
495d0cf9428SJohn Wang if (interface == assocDefsInterface)
49660520631SEd Tanous {
4975b4357daSKallas, Pawel removeAssociation(io, objPath.str, sender, server,
498e2359fb7SMatt Spinler associationMaps);
49960520631SEd Tanous }
50060520631SEd Tanous
501a098a37aSBrad Bishop interfaceSet->second.erase(interface);
5029c3d2859SMatt Spinler
503a098a37aSBrad Bishop if (interfaceSet->second.empty())
50460520631SEd Tanous {
5059c3d2859SMatt Spinler // If this was the last interface on this connection,
5069c3d2859SMatt Spinler // erase the connection
507a098a37aSBrad Bishop connectionMap->second.erase(interfaceSet);
5089c3d2859SMatt Spinler
5099c3d2859SMatt Spinler // Instead of checking if every single path is the endpoint
5109c3d2859SMatt Spinler // of an association that needs to be moved to pending,
5119c3d2859SMatt Spinler // only check when the only remaining owner of this path is
5129c3d2859SMatt Spinler // ourself, which would be because we still own the
5139c3d2859SMatt Spinler // association path.
514a098a37aSBrad Bishop if ((connectionMap->second.size() == 1) &&
515a098a37aSBrad Bishop (connectionMap->second.begin()->first ==
516a02cd54cSBrad Bishop "xyz.openbmc_project.ObjectMapper"))
5179c3d2859SMatt Spinler {
5189c3d2859SMatt Spinler // Remove the 2 association D-Bus paths and move the
5199c3d2859SMatt Spinler // association to pending.
52060ffc244SWilliam A. Kennington III moveAssociationToPending(io, objPath.str, associationMaps,
52160ffc244SWilliam A. Kennington III server);
5229c3d2859SMatt Spinler }
52360520631SEd Tanous }
52460520631SEd Tanous }
52560520631SEd Tanous // If this was the last connection on this object path,
52660520631SEd Tanous // erase the object path
527a098a37aSBrad Bishop if (connectionMap->second.empty())
52860520631SEd Tanous {
529a098a37aSBrad Bishop interfaceMap.erase(connectionMap);
53060520631SEd Tanous }
531a82779fbSMatt Spinler
532a098a37aSBrad Bishop removeUnneededParents(objPath.str, sender, interfaceMap);
53360520631SEd Tanous };
53460520631SEd Tanous
535cc8070baSPatrick Williams sdbusplus::bus::match_t interfacesRemoved(
536cc8070baSPatrick Williams static_cast<sdbusplus::bus_t&>(*systemBus),
53760520631SEd Tanous sdbusplus::bus::match::rules::interfacesRemoved(),
53860ffc244SWilliam A. Kennington III std::move(interfacesRemovedHandler));
53960520631SEd Tanous
54060ffc244SWilliam A. Kennington III auto associationChangedHandler = [&io, &server, &nameOwners, &interfaceMap](
541cc8070baSPatrick Williams sdbusplus::message_t& message) {
54260520631SEd Tanous std::string objectName;
5432bb2d6baSPatrick Williams boost::container::flat_map<std::string,
5442bb2d6baSPatrick Williams std::variant<std::vector<Association>>>
54560520631SEd Tanous values;
54660520631SEd Tanous message.read(objectName, values);
547d0cf9428SJohn Wang auto prop = values.find(assocDefsProperty);
5488f876a5aSMatt Spinler if (prop != values.end())
54960520631SEd Tanous {
55060520631SEd Tanous std::vector<Association> associations =
551b05bc12cSPatrick Williams std::get<std::vector<Association>>(prop->second);
552937a232eSMatt Spinler
553a098a37aSBrad Bishop std::string wellKnown;
554a098a37aSBrad Bishop if (!getWellKnown(nameOwners, message.get_sender(), wellKnown))
555937a232eSMatt Spinler {
556937a232eSMatt Spinler return;
557937a232eSMatt Spinler }
5585b4357daSKallas, Pawel associationChanged(io, server, associations, message.get_path(),
559a098a37aSBrad Bishop wellKnown, interfaceMap, associationMaps);
56060520631SEd Tanous }
56160520631SEd Tanous };
562cc8070baSPatrick Williams sdbusplus::bus::match_t assocChangedMatch(
563cc8070baSPatrick Williams static_cast<sdbusplus::bus_t&>(*systemBus),
56460520631SEd Tanous sdbusplus::bus::match::rules::interface(
56560520631SEd Tanous "org.freedesktop.DBus.Properties") +
56660520631SEd Tanous sdbusplus::bus::match::rules::member("PropertiesChanged") +
5678f876a5aSMatt Spinler sdbusplus::bus::match::rules::argN(0, assocDefsInterface),
56860ffc244SWilliam A. Kennington III std::move(associationChangedHandler));
5698f876a5aSMatt Spinler
57060520631SEd Tanous std::shared_ptr<sdbusplus::asio::dbus_interface> iface =
571a02cd54cSBrad Bishop server.add_interface("/xyz/openbmc_project/object_mapper",
572a02cd54cSBrad Bishop "xyz.openbmc_project.ObjectMapper");
57360520631SEd Tanous
57460520631SEd Tanous iface->register_method(
575a098a37aSBrad Bishop "GetAncestors", [&interfaceMap](std::string& reqPath,
57660520631SEd Tanous std::vector<std::string>& interfaces) {
577a098a37aSBrad Bishop return getAncestors(interfaceMap, reqPath, interfaces);
57860520631SEd Tanous });
57960520631SEd Tanous
58060520631SEd Tanous iface->register_method(
581a098a37aSBrad Bishop "GetObject", [&interfaceMap](const std::string& path,
58260520631SEd Tanous std::vector<std::string>& interfaces) {
583a098a37aSBrad Bishop return getObject(interfaceMap, path, interfaces);
58460520631SEd Tanous });
58560520631SEd Tanous
58660520631SEd Tanous iface->register_method(
587a098a37aSBrad Bishop "GetSubTree", [&interfaceMap](std::string& reqPath, int32_t depth,
58860520631SEd Tanous std::vector<std::string>& interfaces) {
589a098a37aSBrad Bishop return getSubTree(interfaceMap, reqPath, depth, interfaces);
59060520631SEd Tanous });
59160520631SEd Tanous
59260520631SEd Tanous iface->register_method(
59360520631SEd Tanous "GetSubTreePaths",
594a098a37aSBrad Bishop [&interfaceMap](std::string& reqPath, int32_t depth,
59560520631SEd Tanous std::vector<std::string>& interfaces) {
596a098a37aSBrad Bishop return getSubTreePaths(interfaceMap, reqPath, depth, interfaces);
59760520631SEd Tanous });
59860520631SEd Tanous
59958881d0bSWilly Tu iface->register_method(
60058881d0bSWilly Tu "GetAssociatedSubTree",
60158881d0bSWilly Tu [&interfaceMap](const sdbusplus::message::object_path& associationPath,
60258881d0bSWilly Tu const sdbusplus::message::object_path& reqPath,
60358881d0bSWilly Tu int32_t depth, std::vector<std::string>& interfaces) {
60458881d0bSWilly Tu return getAssociatedSubTree(interfaceMap, associationMaps,
60558881d0bSWilly Tu associationPath, reqPath, depth,
60658881d0bSWilly Tu interfaces);
60758881d0bSWilly Tu });
60858881d0bSWilly Tu
60958881d0bSWilly Tu iface->register_method(
61058881d0bSWilly Tu "GetAssociatedSubTreePaths",
61158881d0bSWilly Tu [&interfaceMap](const sdbusplus::message::object_path& associationPath,
61258881d0bSWilly Tu const sdbusplus::message::object_path& reqPath,
61358881d0bSWilly Tu int32_t depth, std::vector<std::string>& interfaces) {
61458881d0bSWilly Tu return getAssociatedSubTreePaths(interfaceMap, associationMaps,
61558881d0bSWilly Tu associationPath, reqPath, depth,
61658881d0bSWilly Tu interfaces);
61758881d0bSWilly Tu });
61858881d0bSWilly Tu
619c363323eSLakshmi Yadlapati iface->register_method(
620c363323eSLakshmi Yadlapati "GetAssociatedSubTreeById",
621c363323eSLakshmi Yadlapati [&interfaceMap](const std::string& id, const std::string& objectPath,
622c363323eSLakshmi Yadlapati std::vector<std::string>& subtreeInterfaces,
623c363323eSLakshmi Yadlapati const std::string& association,
624c363323eSLakshmi Yadlapati std::vector<std::string>& endpointInterfaces) {
625c363323eSLakshmi Yadlapati return getAssociatedSubTreeById(interfaceMap, associationMaps, id,
626c363323eSLakshmi Yadlapati objectPath, subtreeInterfaces,
627c363323eSLakshmi Yadlapati association, endpointInterfaces);
628c363323eSLakshmi Yadlapati });
629c363323eSLakshmi Yadlapati
630c363323eSLakshmi Yadlapati iface->register_method(
631c363323eSLakshmi Yadlapati "GetAssociatedSubTreePathsById",
632c363323eSLakshmi Yadlapati [&interfaceMap](const std::string& id, const std::string& objectPath,
633c363323eSLakshmi Yadlapati std::vector<std::string>& subtreeInterfaces,
634c363323eSLakshmi Yadlapati const std::string& association,
635c363323eSLakshmi Yadlapati std::vector<std::string>& endpointInterfaces) {
636c363323eSLakshmi Yadlapati return getAssociatedSubTreePathsById(
637c363323eSLakshmi Yadlapati interfaceMap, associationMaps, id, objectPath,
638c363323eSLakshmi Yadlapati subtreeInterfaces, association, endpointInterfaces);
639c363323eSLakshmi Yadlapati });
640c363323eSLakshmi Yadlapati
64160520631SEd Tanous iface->initialize();
64260520631SEd Tanous
643*41ad8380SEd Tanous boost::asio::post(io, [&]() {
644a098a37aSBrad Bishop doListNames(io, interfaceMap, systemBus.get(), nameOwners,
64511401e2eSMatt Spinler associationMaps, server);
64660520631SEd Tanous });
64760520631SEd Tanous
648a098a37aSBrad Bishop systemBus->request_name("xyz.openbmc_project.ObjectMapper");
64964354ef2SVishwanatha Subbanna
65060520631SEd Tanous io.run();
65160520631SEd Tanous }
652