1 /**
2  * Copyright © 2024 IBM Corporation
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *     http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #include "dbus_interfaces_finder.hpp"
18 
19 #include <algorithm>
20 #include <exception>
21 #include <map>
22 #include <utility>
23 
24 namespace phosphor::power::util
25 {
26 
DBusInterfacesFinder(sdbusplus::bus_t & bus,const std::string & service,const std::vector<std::string> & interfaces,Callback callback)27 DBusInterfacesFinder::DBusInterfacesFinder(
28     sdbusplus::bus_t& bus, const std::string& service,
29     const std::vector<std::string>& interfaces, Callback callback) :
30     bus{bus}, service{service}, interfaces{interfaces},
31     callback{std::move(callback)},
32     match{bus,
33           sdbusplus::bus::match::rules::interfacesAdded() +
34               sdbusplus::bus::match::rules::sender(service),
35           std::bind(&DBusInterfacesFinder::interfacesAddedCallback, this,
36                     std::placeholders::_1)}
37 {
38     findInterfaces();
39 }
40 
interfacesAddedCallback(sdbusplus::message_t & message)41 void DBusInterfacesFinder::interfacesAddedCallback(
42     sdbusplus::message_t& message)
43 {
44     // Exit if message is invalid
45     if (!message)
46     {
47         return;
48     }
49 
50     try
51     {
52         // Read the D-Bus message
53         sdbusplus::message::object_path path;
54         std::map<std::string, std::map<std::string, util::DbusVariant>>
55             interfaces;
56         message.read(path, interfaces);
57 
58         // Call callback for interfaces that we are looking for
59         for (const auto& [interface, properties] : interfaces)
60         {
61             if (std::ranges::contains(this->interfaces, interface))
62             {
63                 callback(path, interface, properties);
64             }
65         }
66     }
67     catch (const std::exception&)
68     {
69         // Error trying to read InterfacesAdded message.  One possible cause
70         // could be a property whose value is an unexpected data type.
71     }
72 }
73 
findInterfaces()74 void DBusInterfacesFinder::findInterfaces()
75 {
76     try
77     {
78         // Use ObjectMapper to find interface instances that already exist
79         auto objects = util::getSubTree(bus, "/", interfaces, 0);
80 
81         // Search for matching interfaces in returned objects
82         for (const auto& [path, services] : objects)
83         {
84             for (const auto& [service, interfaces] : services)
85             {
86                 if (service == this->service)
87                 {
88                     for (const auto& interface : interfaces)
89                     {
90                         if (std::ranges::contains(this->interfaces, interface))
91                         {
92                             auto properties = util::getAllProperties(
93                                 bus, path, interface, service);
94                             callback(path, interface, properties);
95                         }
96                     }
97                 }
98             }
99         }
100     }
101     catch (const std::exception&)
102     {
103         // Interface instances might not be available yet
104     }
105 }
106 
107 } // namespace phosphor::power::util
108