1 #pragma once
2 
3 #include <sdbusplus/message.hpp>
4 #include <sdbusplus/bus/match.hpp>
5 #include <vector>
6 #include "callback.hpp"
7 #include "data_types.hpp"
8 #include "propertywatch.hpp"
9 
10 namespace phosphor
11 {
12 namespace dbus
13 {
14 namespace monitoring
15 {
16 
17 using MappedPropertyIndex =
18     RefKeyMap<const std::string,
19               RefKeyMap<const std::string, RefVector<const std::string>>>;
20 
21 MappedPropertyIndex convert(const PropertyIndex& index);
22 
23 template <typename DBusInterfaceType>
24 void PropertyWatch<DBusInterfaceType>::start()
25 {
26     if (alreadyRan)
27     {
28         return;
29     }
30 
31     // The index has a flat layout which is not optimal here.  Nest
32     // properties in a map of interface names in a map of object paths.
33     auto mapped = convert(index);
34 
35     for (const auto& m : mapped)
36     {
37         const auto& path = m.first.get();
38         const auto& interfaces = m.second;
39 
40         // Watch for new interfaces on this path.
41         DBusInterfaceType::addMatch(
42             sdbusplus::bus::match::rules::interfacesAdded(path),
43             [this](auto& msg)
44             // *INDENT-OFF*
45             { this->interfacesAdded(msg); });
46         // *INDENT-ON*
47 
48         // Do a query to populate the cache.  Start with a mapper query.
49         // The specific services are queried below.
50         const std::vector<std::string> queryInterfaces; // all interfaces
51         auto mapperResp =
52             DBusInterfaceType::template callMethodAndRead<GetObject>(
53                 MAPPER_BUSNAME, MAPPER_PATH, MAPPER_INTERFACE, "GetObject",
54                 path, queryInterfaces);
55 
56         for (const auto& i : interfaces)
57         {
58             const auto& interface = i.first.get();
59 
60             // Watch for property changes on this interface.
61             DBusInterfaceType::addMatch(
62                 sdbusplus::bus::match::rules::propertiesChanged(path,
63                                                                 interface),
64                 [this](auto& msg)
65                 // *INDENT-OFF*
66                 {
67                     std::string interface;
68                     msg.read(interface);
69                     auto path = msg.get_path();
70                     this->propertiesChanged(msg, path, interface);
71                 });
72             // *INDENT-ON*
73 
74             // The mapper response is a busname:[interfaces] map.  Look for
75             // each interface in the index and if found, query the service and
76             // populate the cache entries for the interface.
77             for (const auto& mr : mapperResp)
78             {
79                 const auto& busName = mr.first;
80                 const auto& mapperInterfaces = mr.second;
81                 if (mapperInterfaces.end() ==
82                     std::find(mapperInterfaces.begin(), mapperInterfaces.end(),
83                               interface))
84                 {
85                     // This interface isn't being watched.
86                     continue;
87                 }
88 
89                 // Delegate type specific property updates to subclasses.
90                 updateProperties(busName, path, interface);
91             }
92         }
93     }
94 
95     alreadyRan = true;
96 }
97 
98 template <typename DBusInterfaceType>
99 void PropertyWatch<DBusInterfaceType>::callback(Context ctx)
100 {
101     // Invoke callback if present.
102     if (this->alreadyRan && this->cb)
103     {
104         (*this->cb)(ctx);
105     }
106 }
107 
108 template <typename T, typename DBusInterfaceType>
109 void PropertyWatchOfType<T, DBusInterfaceType>::updateProperties(
110     const std::string& busName, const std::string& path,
111     const std::string& interface)
112 {
113     auto properties =
114         DBusInterfaceType::template callMethodAndRead<PropertiesChanged<T>>(
115             busName.c_str(), path.c_str(), "org.freedesktop.DBus.Properties",
116             "GetAll", interface);
117     propertiesChanged(path, interface, properties);
118 }
119 
120 template <typename T, typename DBusInterfaceType>
121 void PropertyWatchOfType<T, DBusInterfaceType>::propertiesChanged(
122     const std::string& path, const std::string& interface,
123     const PropertiesChanged<T>& properties)
124 {
125     // Update the cache for any watched properties.
126     for (const auto& p : properties)
127     {
128         auto key = std::make_tuple(path, interface, p.first);
129         auto item = this->index.find(key);
130         if (item == this->index.end())
131         {
132             // This property isn't being watched.
133             continue;
134         }
135 
136         std::get<valueIndex>(std::get<storageIndex>(item->second).get()) =
137             p.second.template get<T>();
138 
139         // Invoke callback if present.
140         this->callback(Context::SIGNAL);
141     }
142 }
143 
144 template <typename T, typename DBusInterfaceType>
145 void PropertyWatchOfType<T, DBusInterfaceType>::propertiesChanged(
146     sdbusplus::message::message& msg, const std::string& path,
147     const std::string& interface)
148 {
149     PropertiesChanged<T> properties;
150     msg.read(properties);
151     propertiesChanged(path, interface, properties);
152 }
153 
154 template <typename T, typename DBusInterfaceType>
155 void PropertyWatchOfType<T, DBusInterfaceType>::interfacesAdded(
156     const std::string& path, const InterfacesAdded<T>& interfaces)
157 {
158     for (const auto& i : interfaces)
159     {
160         propertiesChanged(path, i.first, i.second);
161     }
162 }
163 
164 template <typename T, typename DBusInterfaceType>
165 void PropertyWatchOfType<T, DBusInterfaceType>::interfacesAdded(
166     sdbusplus::message::message& msg)
167 {
168     sdbusplus::message::object_path path;
169     InterfacesAdded<T> interfaces;
170     msg.read(path, interfaces);
171     interfacesAdded(path, interfaces);
172 }
173 
174 } // namespace monitoring
175 } // namespace dbus
176 } // namespace phosphor
177