summaryrefslogtreecommitdiffstats
path: root/src/main.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/main.cpp')
-rw-r--r--src/main.cpp837
1 files changed, 837 insertions, 0 deletions
diff --git a/src/main.cpp b/src/main.cpp
new file mode 100644
index 0000000..e00e920
--- /dev/null
+++ b/src/main.cpp
@@ -0,0 +1,837 @@
+#include <tinyxml2.h>
+
+#include <atomic>
+#include <boost/algorithm/string/predicate.hpp>
+#include <boost/container/flat_map.hpp>
+#include <boost/container/flat_set.hpp>
+#include <chrono>
+#include <iomanip>
+#include <iostream>
+#include <sdbusplus/asio/connection.hpp>
+#include <sdbusplus/asio/object_server.hpp>
+
+constexpr const char* OBJECT_MAPPER_DBUS_NAME =
+ "xyz.openbmc_project.ObjectMapper";
+constexpr const char* ASSOCIATIONS_INTERFACE = "org.openbmc.Associations";
+
+// interface_map_type is the underlying datastructure the mapper uses.
+// The 3 levels of map are
+// object paths
+// connection names
+// interface names
+using interface_map_type = boost::container::flat_map<
+ std::string, boost::container::flat_map<
+ std::string, boost::container::flat_set<std::string>>>;
+
+using Association = std::tuple<std::string, std::string, std::string>;
+
+boost::container::flat_map<std::string,
+ std::shared_ptr<sdbusplus::asio::dbus_interface>>
+ associationInterfaces;
+
+/** Exception thrown when a path is not found in the object list. */
+struct NotFoundException final : public sdbusplus::exception_t
+{
+ const char* name() const noexcept override
+ {
+ return "org.freedesktop.DBus.Error.FileNotFound";
+ };
+ const char* description() const noexcept override
+ {
+ return "path or object not found";
+ };
+ const char* what() const noexcept override
+ {
+ return "org.freedesktop.DBus.Error.FileNotFound: "
+ "The requested object was not found";
+ };
+};
+
+bool get_well_known(
+ boost::container::flat_map<std::string, std::string>& owners,
+ const std::string& request, std::string& well_known)
+{
+ // If it's already a well known name, just return
+ if (!boost::starts_with(request, ":"))
+ {
+ well_known = request;
+ return true;
+ }
+
+ auto it = owners.find(request);
+ if (it == owners.end())
+ {
+ return false;
+ }
+ well_known = it->second;
+ return true;
+}
+
+void update_owners(sdbusplus::asio::connection* conn,
+ boost::container::flat_map<std::string, std::string>& owners,
+ const std::string& new_object)
+{
+ if (boost::starts_with(new_object, ":"))
+ {
+ return;
+ }
+ conn->async_method_call(
+ [&, new_object](const boost::system::error_code ec,
+ const std::string& nameOwner) {
+ if (ec)
+ {
+ std::cerr << "Error getting owner of " << new_object << " : "
+ << ec << "\n";
+ return;
+ }
+ owners[nameOwner] = new_object;
+ },
+ "org.freedesktop.DBus", "/", "org.freedesktop.DBus", "GetNameOwner",
+ new_object);
+}
+
+void send_introspection_complete_signal(sdbusplus::asio::connection* system_bus,
+ const std::string& process_name)
+{
+ // TODO(ed) This signal doesn't get exposed properly in the
+ // introspect right now. Find out how to register signals in
+ // sdbusplus
+ sdbusplus::message::message m = system_bus->new_signal(
+ "/xyz/openbmc_project/object_mapper",
+ "xyz.openbmc_project.ObjectMapper.Private", "IntrospectionComplete");
+ m.append(process_name);
+ m.signal_send();
+}
+
+struct InProgressIntrospect
+{
+ InProgressIntrospect(
+ sdbusplus::asio::connection* system_bus, boost::asio::io_service& io,
+ const std::string& process_name,
+ std::shared_ptr<std::chrono::time_point<std::chrono::steady_clock>>
+ global_start_time) :
+ system_bus(system_bus),
+ io(io), process_name(process_name),
+ global_start_time(global_start_time),
+ process_start_time(std::chrono::steady_clock::now())
+ {
+ }
+ ~InProgressIntrospect()
+ {
+ send_introspection_complete_signal(system_bus, process_name);
+ std::chrono::duration<float> diff =
+ std::chrono::steady_clock::now() - process_start_time;
+ std::cout << std::setw(50) << process_name << " scan took "
+ << diff.count() << " seconds\n";
+
+ // If we're the last outstanding caller globally, calculate the
+ // time it took
+ if (global_start_time != nullptr && global_start_time.use_count() == 1)
+ {
+ diff = std::chrono::steady_clock::now() - *global_start_time;
+ std::cout << "Total scan took " << diff.count()
+ << " seconds to complete\n";
+ }
+ }
+ sdbusplus::asio::connection* system_bus;
+ boost::asio::io_service& io;
+ std::string process_name;
+
+ std::shared_ptr<std::chrono::time_point<std::chrono::steady_clock>>
+ global_start_time;
+ std::chrono::time_point<std::chrono::steady_clock> process_start_time;
+};
+
+static const boost::container::flat_set<std::string> ignored_interfaces{
+ "org.freedesktop.DBus.Introspectable", "org.freedesktop.DBus.Peer",
+ "org.freedesktop.DBus.Properties"};
+
+void do_getmanagedobjects(sdbusplus::asio::connection* system_bus,
+ std::shared_ptr<InProgressIntrospect> transaction,
+ interface_map_type& interface_map, std::string path)
+{
+ // note, the variant type doesn't matter, as we don't actually track
+ // property names as of yet. variant<bool> seemed like the most simple.
+ using ManagedObjectType = std::vector<std::pair<
+ sdbusplus::message::object_path,
+ boost::container::flat_map<
+ std::string, boost::container::flat_map<
+ std::string, sdbusplus::message::variant<bool>>>>>;
+
+ system_bus->async_method_call(
+ [&interface_map, system_bus, transaction,
+ path](const boost::system::error_code ec,
+ const ManagedObjectType& objects) {
+ if (ec)
+ {
+ std::cerr << "GetMangedObjects call failed" << ec << "\n";
+ return;
+ }
+
+ interface_map.reserve(interface_map.size() + objects.size());
+ for (const std::pair<
+ sdbusplus::message::object_path,
+ boost::container::flat_map<
+ std::string,
+ boost::container::flat_map<
+ std::string, sdbusplus::message::variant<bool>>>>&
+ object : objects)
+ {
+ const std::string& path_name = object.first.str;
+ auto& this_path_map =
+ interface_map[path_name][transaction->process_name];
+ for (auto& interface_it : object.second)
+ {
+ this_path_map.insert(interface_it.first);
+ }
+ }
+ },
+ transaction->process_name, path, "org.freedesktop.DBus.ObjectManager",
+ "GetManagedObjects");
+}
+
+void addAssociation(sdbusplus::asio::object_server& objectServer,
+ const std::vector<Association>& associations,
+ const std::string& path)
+{
+ boost::container::flat_map<std::string,
+ boost::container::flat_set<std::string>>
+ objects;
+ for (const Association& association : associations)
+ {
+ std::string forward;
+ std::string reverse;
+ std::string endpoint;
+ std::tie(forward, reverse, endpoint) = association;
+
+ if (forward.size())
+ {
+ objects[path + "/" + forward].emplace(endpoint);
+ }
+ if (reverse.size())
+ {
+ if (endpoint.empty())
+ {
+ std::cerr << "Found invalid association on path " << path
+ << "\n";
+ continue;
+ }
+ objects[endpoint + "/" + reverse].emplace(path);
+ }
+ }
+ for (const auto& object : objects)
+ {
+ // the mapper exposes the new association interface but intakes
+ // the old
+
+ auto& iface = associationInterfaces[object.first];
+ iface = objectServer.add_interface(object.first,
+ "xyz.openbmc_project.Association");
+ iface->register_property("endpoints",
+ std::vector<std::string>(object.second.begin(),
+ object.second.end()));
+ iface->initialize();
+ }
+}
+
+void do_associations(sdbusplus::asio::connection* system_bus,
+ sdbusplus::asio::object_server& objectServer,
+ const std::string& processName, const std::string& path)
+{
+ system_bus->async_method_call(
+ [&objectServer,
+ path](const boost::system::error_code ec,
+ const sdbusplus::message::variant<std::vector<Association>>&
+ variantAssociations) {
+ if (ec)
+ {
+ std::cerr << "Error getting associations from " << path << "\n";
+ }
+ std::vector<Association> associations =
+ sdbusplus::message::variant_ns::get<std::vector<Association>>(
+ variantAssociations);
+ addAssociation(objectServer, associations, path);
+ },
+ processName, path, "org.freedesktop.DBus.Properties", "Get",
+ ASSOCIATIONS_INTERFACE, "associations");
+}
+
+void do_introspect(sdbusplus::asio::connection* system_bus,
+ std::shared_ptr<InProgressIntrospect> transaction,
+ interface_map_type& interface_map,
+ sdbusplus::asio::object_server& objectServer,
+ std::string path)
+{
+ system_bus->async_method_call(
+ [&interface_map, &objectServer, transaction, path,
+ system_bus](const boost::system::error_code ec,
+ const std::string& introspect_xml) {
+ if (ec)
+ {
+ std::cerr << "Introspect call failed with error: " << ec << ", "
+ << ec.message()
+ << " on process: " << transaction->process_name
+ << " path: " << path << "\n";
+ return;
+ }
+
+ tinyxml2::XMLDocument doc;
+
+ tinyxml2::XMLError e = doc.Parse(introspect_xml.c_str());
+ if (e != tinyxml2::XMLError::XML_SUCCESS)
+ {
+ std::cerr << "XML parsing failed\n";
+ return;
+ }
+
+ tinyxml2::XMLNode* pRoot = doc.FirstChildElement("node");
+ if (pRoot == nullptr)
+ {
+ std::cerr << "XML document did not contain any data\n";
+ return;
+ }
+ auto& thisPathMap = interface_map[path];
+ bool handling_via_objectmanager = false;
+ tinyxml2::XMLElement* pElement =
+ pRoot->FirstChildElement("interface");
+ while (pElement != nullptr)
+ {
+ const char* iface_name = pElement->Attribute("name");
+ if (iface_name == nullptr)
+ {
+ continue;
+ }
+
+ if (ignored_interfaces.find(std::string(iface_name)) ==
+ ignored_interfaces.end())
+ {
+ thisPathMap[transaction->process_name].emplace(iface_name);
+ }
+ if (std::strcmp(iface_name, ASSOCIATIONS_INTERFACE) == 0)
+ {
+ do_associations(system_bus, objectServer,
+ transaction->process_name, path);
+ }
+ else if (std::strcmp(iface_name,
+ "org.freedesktop.DBus.ObjectManager") == 0)
+ {
+ // TODO(ed) in the current implementation,
+ // introspect is actually faster than
+ // getmanagedObjects, but I suspect it will be
+ // faster when needing to deal with
+ // associations, so leave the code here for now
+
+ // handling_via_objectmanager = true;
+ // do_getmanagedobjects(system_bus, transaction,
+ // interface_map, path);
+ }
+
+ pElement = pElement->NextSiblingElement("interface");
+ }
+
+ if (!handling_via_objectmanager)
+ {
+ pElement = pRoot->FirstChildElement("node");
+ while (pElement != nullptr)
+ {
+ const char* child_path = pElement->Attribute("name");
+ if (child_path != nullptr)
+ {
+ std::string parent_path(path);
+ if (parent_path == "/")
+ {
+ parent_path.clear();
+ }
+
+ do_introspect(system_bus, transaction, interface_map,
+ objectServer,
+ parent_path + "/" + child_path);
+ }
+ pElement = pElement->NextSiblingElement("node");
+ }
+ }
+ },
+ transaction->process_name, path, "org.freedesktop.DBus.Introspectable",
+ "Introspect");
+}
+
+bool need_to_introspect(const std::string& process_name)
+{
+ return boost::starts_with(process_name, "xyz.openbmc_project.") ||
+ boost::starts_with(process_name, "org.openbmc.") ||
+ boost::starts_with(process_name, "com.intel.");
+}
+
+void start_new_introspect(
+ sdbusplus::asio::connection* system_bus, boost::asio::io_service& io,
+ interface_map_type& interface_map, const std::string& process_name,
+ std::shared_ptr<std::chrono::time_point<std::chrono::steady_clock>>
+ global_start_time,
+ sdbusplus::asio::object_server& objectServer)
+{
+ if (need_to_introspect(process_name))
+ {
+
+ std::cerr << "starting introspect on " << process_name << "\n";
+ std::shared_ptr<InProgressIntrospect> transaction =
+ std::make_shared<InProgressIntrospect>(system_bus, io, process_name,
+ global_start_time);
+
+ do_introspect(system_bus, transaction, interface_map, objectServer,
+ "/");
+ }
+}
+
+// TODO(ed) replace with std::set_intersection once c++17 is available
+template <class InputIt1, class InputIt2>
+bool intersect(InputIt1 first1, InputIt1 last1, InputIt2 first2, InputIt2 last2)
+{
+ while (first1 != last1 && first2 != last2)
+ {
+ if (*first1 < *first2)
+ {
+ ++first1;
+ continue;
+ }
+ if (*first2 < *first1)
+ {
+ ++first2;
+ continue;
+ }
+ return true;
+ }
+ return false;
+}
+
+void doListNames(
+ boost::asio::io_service& io, interface_map_type& interface_map,
+ sdbusplus::asio::connection* system_bus,
+ boost::container::flat_map<std::string, std::string>& name_owners,
+ sdbusplus::asio::object_server& objectServer)
+{
+ system_bus->async_method_call(
+ [&io, &interface_map, &name_owners, &objectServer,
+ system_bus](const boost::system::error_code ec,
+ std::vector<std::string> process_names) {
+ if (ec)
+ {
+ std::cerr << "Error getting names: " << ec << "\n";
+ std::exit(EXIT_FAILURE);
+ return;
+ }
+ std::cerr << "ListNames returned " << process_names.size()
+ << " entries\n";
+ // Try to make startup consistent
+ std::sort(process_names.begin(), process_names.end());
+ std::shared_ptr<std::chrono::time_point<std::chrono::steady_clock>>
+ global_start_time = std::make_shared<
+ std::chrono::time_point<std::chrono::steady_clock>>(
+ std::chrono::steady_clock::now());
+ for (const std::string& process_name : process_names)
+ {
+ if (need_to_introspect(process_name))
+ {
+ start_new_introspect(system_bus, io, interface_map,
+ process_name, global_start_time,
+ objectServer);
+ update_owners(system_bus, name_owners, process_name);
+ }
+ }
+ },
+ "org.freedesktop.DBus", "/org/freedesktop/DBus", "org.freedesktop.DBus",
+ "ListNames");
+}
+
+int main(int argc, char** argv)
+{
+ std::cerr << "started\n";
+ boost::asio::io_service io;
+ std::shared_ptr<sdbusplus::asio::connection> system_bus =
+ std::make_shared<sdbusplus::asio::connection>(io);
+
+ system_bus->request_name(OBJECT_MAPPER_DBUS_NAME);
+ sdbusplus::asio::object_server server(system_bus);
+
+ // Construct a signal set registered for process termination.
+ boost::asio::signal_set signals(io, SIGINT, SIGTERM);
+ signals.async_wait([&io](const boost::system::error_code& error,
+ int signal_number) { io.stop(); });
+
+ interface_map_type interface_map;
+ boost::container::flat_map<std::string, std::string> name_owners;
+
+ std::function<void(sdbusplus::message::message & message)>
+ nameChangeHandler = [&interface_map, &io, &name_owners, &server,
+ system_bus](sdbusplus::message::message& message) {
+ std::string name;
+ std::string old_owner;
+ std::string new_owner;
+
+ message.read(name, old_owner, new_owner);
+
+ if (!old_owner.empty())
+ {
+ if (boost::starts_with(old_owner, ":"))
+ {
+ auto it = name_owners.find(old_owner);
+ if (it != name_owners.end())
+ {
+ name_owners.erase(it);
+ }
+ }
+ // Connection removed
+ interface_map_type::iterator path_it = interface_map.begin();
+ while (path_it != interface_map.end())
+ {
+ path_it->second.erase(name);
+ if (path_it->second.empty())
+ {
+ // If the last connection to the object is gone,
+ // delete the top level object
+ path_it = interface_map.erase(path_it);
+ continue;
+ }
+ path_it++;
+ }
+ }
+
+ if (!new_owner.empty())
+ {
+ auto transaction = std::make_shared<
+ std::chrono::time_point<std::chrono::steady_clock>>(
+ std::chrono::steady_clock::now());
+ // New daemon added
+ if (need_to_introspect(name))
+ {
+ name_owners[new_owner] = name;
+ start_new_introspect(system_bus.get(), io, interface_map,
+ name, transaction, server);
+ }
+ }
+ };
+
+ sdbusplus::bus::match::match nameOwnerChanged(
+ static_cast<sdbusplus::bus::bus&>(*system_bus),
+ sdbusplus::bus::match::rules::nameOwnerChanged(), nameChangeHandler);
+
+ std::function<void(sdbusplus::message::message & message)>
+ interfacesAddedHandler = [&interface_map, &name_owners, &server](
+ sdbusplus::message::message& message) {
+ sdbusplus::message::object_path obj_path;
+ std::vector<std::pair<
+ std::string, std::vector<std::pair<
+ std::string, sdbusplus::message::variant<
+ std::vector<Association>>>>>>
+ interfaces_added;
+ message.read(obj_path, interfaces_added);
+ std::string well_known;
+ if (!get_well_known(name_owners, message.get_sender(), well_known))
+ {
+ return; // only introspect well-known
+ }
+ if (need_to_introspect(well_known))
+ {
+ auto& iface_list = interface_map[obj_path.str];
+
+ for (const std::pair<
+ std::string,
+ std::vector<std::pair<std::string,
+ sdbusplus::message::variant<
+ std::vector<Association>>>>>&
+ interface_pair : interfaces_added)
+ {
+ iface_list[well_known].emplace(interface_pair.first);
+
+ if (interface_pair.first == ASSOCIATIONS_INTERFACE)
+ {
+ const sdbusplus::message::variant<
+ std::vector<Association>>* variantAssociations =
+ nullptr;
+ for (const auto& interface : interface_pair.second)
+ {
+ if (interface.first == "associations")
+ {
+ variantAssociations = &(interface.second);
+ }
+ }
+ if (variantAssociations == nullptr)
+ {
+ std::cerr << "Illegal association found on "
+ << well_known << "\n";
+ continue;
+ }
+ std::vector<Association> associations =
+ sdbusplus::message::variant_ns::get<
+ std::vector<Association>>(*variantAssociations);
+ addAssociation(server, associations, obj_path.str);
+ }
+ }
+ }
+ };
+
+ sdbusplus::bus::match::match interfacesAdded(
+ static_cast<sdbusplus::bus::bus&>(*system_bus),
+ sdbusplus::bus::match::rules::interfacesAdded(),
+ interfacesAddedHandler);
+
+ std::function<void(sdbusplus::message::message & message)>
+ interfacesRemovedHandler = [&interface_map, &name_owners, &server](
+ sdbusplus::message::message& message) {
+ sdbusplus::message::object_path obj_path;
+ std::vector<std::string> interfaces_removed;
+ message.read(obj_path, interfaces_removed);
+ auto connection_map = interface_map.find(obj_path.str);
+ if (connection_map == interface_map.end())
+ {
+ return;
+ }
+
+ std::string sender;
+ if (!get_well_known(name_owners, message.get_sender(), sender))
+ {
+ return;
+ }
+ for (const std::string& interface : interfaces_removed)
+ {
+ auto interface_set = connection_map->second.find(sender);
+ if (interface_set == connection_map->second.end())
+ {
+ continue;
+ }
+
+ if (interface == ASSOCIATIONS_INTERFACE)
+ {
+ auto findAssociation =
+ associationInterfaces.find(interface);
+ if (findAssociation != associationInterfaces.end())
+ {
+ server.remove_interface(findAssociation->second);
+ findAssociation->second = nullptr;
+ }
+ }
+
+ interface_set->second.erase(interface);
+ // If this was the last interface on this connection,
+ // erase the connection
+ if (interface_set->second.empty())
+ {
+ connection_map->second.erase(interface_set);
+ }
+ }
+ // If this was the last connection on this object path,
+ // erase the object path
+ if (connection_map->second.empty())
+ {
+ interface_map.erase(connection_map);
+ }
+ };
+
+ sdbusplus::bus::match::match interfacesRemoved(
+ static_cast<sdbusplus::bus::bus&>(*system_bus),
+ sdbusplus::bus::match::rules::interfacesRemoved(),
+ interfacesRemovedHandler);
+
+ std::function<void(sdbusplus::message::message & message)>
+ associationChangedHandler =
+ [&server](sdbusplus::message::message& message) {
+ std::string objectName;
+ boost::container::flat_map<
+ std::string,
+ sdbusplus::message::variant<std::vector<Association>>>
+ values;
+ message.read(objectName, values);
+ auto findAssociations = values.find("associations");
+ if (findAssociations != values.end())
+ {
+ std::vector<Association> associations =
+ sdbusplus::message::variant_ns::get<
+ std::vector<Association>>(findAssociations->second);
+ addAssociation(server, associations, message.get_path());
+ }
+ };
+ sdbusplus::bus::match::match associationChanged(
+ static_cast<sdbusplus::bus::bus&>(*system_bus),
+ sdbusplus::bus::match::rules::interface(
+ "org.freedesktop.DBus.Properties") +
+ sdbusplus::bus::match::rules::member("PropertiesChanged") +
+ sdbusplus::bus::match::rules::argN(0, ASSOCIATIONS_INTERFACE),
+ associationChangedHandler);
+
+ std::shared_ptr<sdbusplus::asio::dbus_interface> iface =
+ server.add_interface("/xyz/openbmc_project/object_mapper",
+ "xyz.openbmc_project.ObjectMapper");
+
+ iface->register_method(
+ "GetAncestors", [&interface_map](const std::string& req_path,
+ std::vector<std::string>& interfaces) {
+ // Interfaces need to be sorted for intersect to function
+ std::sort(interfaces.begin(), interfaces.end());
+
+ std::vector<interface_map_type::value_type> ret;
+ for (auto& object_path : interface_map)
+ {
+ auto& this_path = object_path.first;
+ if (boost::starts_with(req_path, this_path))
+ {
+ if (interfaces.empty())
+ {
+ ret.emplace_back(object_path);
+ }
+ else
+ {
+ for (auto& interface_map : object_path.second)
+ {
+
+ if (intersect(interfaces.begin(), interfaces.end(),
+ interface_map.second.begin(),
+ interface_map.second.end()))
+ {
+ ret.emplace_back(object_path);
+ break;
+ }
+ }
+ }
+ }
+ }
+ if (ret.empty())
+ {
+ throw NotFoundException();
+ }
+
+ return ret;
+ });
+
+ iface->register_method(
+ "GetObject", [&interface_map](const std::string& path,
+ std::vector<std::string>& interfaces) {
+ // Interfaces need to be sorted for intersect to function
+ std::sort(interfaces.begin(), interfaces.end());
+ auto path_ref = interface_map.find(path);
+ if (path_ref == interface_map.end())
+ {
+ throw NotFoundException();
+ }
+ if (interfaces.empty())
+ {
+ return path_ref->second;
+ }
+ for (auto& interface_map : path_ref->second)
+ {
+ if (intersect(interfaces.begin(), interfaces.end(),
+ interface_map.second.begin(),
+ interface_map.second.end()))
+ {
+ return path_ref->second;
+ }
+ }
+ // Unable to find intersection, return default constructed
+ // object
+ throw NotFoundException();
+ });
+
+ iface->register_method(
+ "GetSubTree",
+ [&interface_map](const std::string& req_path, int32_t depth,
+ std::vector<std::string>& interfaces) {
+ if (depth <= 0)
+ {
+ depth = std::numeric_limits<int32_t>::max();
+ }
+ // Interfaces need to be sorted for intersect to function
+ std::sort(interfaces.begin(), interfaces.end());
+ std::vector<interface_map_type::value_type> ret;
+
+ for (auto& object_path : interface_map)
+ {
+ auto& this_path = object_path.first;
+ if (boost::starts_with(this_path, req_path))
+ {
+ // count the number of slashes past the search term
+ int32_t this_depth =
+ std::count(this_path.begin() + req_path.size(),
+ this_path.end(), '/');
+ if (this_depth <= depth)
+ {
+ bool add = interfaces.empty();
+ for (auto& interface_map : object_path.second)
+ {
+ if (intersect(interfaces.begin(), interfaces.end(),
+ interface_map.second.begin(),
+ interface_map.second.end()))
+ {
+ add = true;
+ break;
+ }
+ }
+ if (add)
+ {
+ // todo(ed) this is a copy
+ ret.emplace_back(object_path);
+ }
+ }
+ }
+ }
+ if (ret.empty())
+ {
+ throw NotFoundException();
+ }
+ return ret;
+ });
+
+ iface->register_method(
+ "GetSubTreePaths",
+ [&interface_map](const std::string& req_path, int32_t depth,
+ std::vector<std::string>& interfaces) {
+ if (depth <= 0)
+ {
+ depth = std::numeric_limits<int32_t>::max();
+ }
+ // Interfaces need to be sorted for intersect to function
+ std::sort(interfaces.begin(), interfaces.end());
+ std::vector<std::string> ret;
+ for (auto& object_path : interface_map)
+ {
+ auto& this_path = object_path.first;
+ if (boost::starts_with(this_path, req_path))
+ {
+ // count the number of slashes past the search term
+ int this_depth =
+ std::count(this_path.begin() + req_path.size(),
+ this_path.end(), '/');
+ if (this_depth <= depth)
+ {
+ bool add = interfaces.empty();
+ for (auto& interface_map : object_path.second)
+ {
+ if (intersect(interfaces.begin(), interfaces.end(),
+ interface_map.second.begin(),
+ interface_map.second.end()))
+ {
+ add = true;
+ break;
+ }
+ }
+ if (add)
+ {
+ // TODO(ed) this is a copy
+ ret.emplace_back(this_path);
+ }
+ }
+ }
+ }
+ if (ret.empty())
+ {
+ throw NotFoundException();
+ }
+ return ret;
+ });
+
+ iface->initialize();
+
+ io.post([&]() {
+ doListNames(io, interface_map, system_bus.get(), name_owners, server);
+ });
+
+ std::cerr << "starting event loop\n";
+ io.run();
+}
OpenPOWER on IntegriCloud