blob: ae0ed294f129a60f7df3dc1760a708d03e80d266 [file] [log] [blame]
Brad Bishop4b916f12017-05-23 18:06:38 -04001#pragma once
2
Brad Bishopfccdc392017-05-22 21:11:09 -04003#include "callback.hpp"
Brad Bishop4b916f12017-05-23 18:06:38 -04004#include "data_types.hpp"
5#include "propertywatch.hpp"
6
Patrick Venture3d6d3182018-08-31 09:33:09 -07007#include <sdbusplus/bus/match.hpp>
8#include <sdbusplus/message.hpp>
George Liu3fe976c2022-06-21 09:37:04 +08009
Andrew Geisslerae4c95c2020-05-16 13:58:53 -050010#include <string>
Patrick Venture3d6d3182018-08-31 09:33:09 -070011#include <vector>
12
Brad Bishop4b916f12017-05-23 18:06:38 -040013namespace phosphor
14{
15namespace dbus
16{
17namespace monitoring
18{
19
Brad Bishop4b916f12017-05-23 18:06:38 -040020using MappedPropertyIndex =
21 RefKeyMap<const std::string,
Brad Bishopd1eac882018-03-29 10:34:05 -040022 RefKeyMap<const std::string, RefVector<const std::string>>>;
Brad Bishop4b916f12017-05-23 18:06:38 -040023
24MappedPropertyIndex convert(const PropertyIndex& index);
25
26template <typename DBusInterfaceType>
27void PropertyWatch<DBusInterfaceType>::start()
28{
29 if (alreadyRan)
30 {
31 return;
32 }
Brad Bishop4b916f12017-05-23 18:06:38 -040033
34 // The index has a flat layout which is not optimal here. Nest
35 // properties in a map of interface names in a map of object paths.
36 auto mapped = convert(index);
37
38 for (const auto& m : mapped)
39 {
40 const auto& path = m.first.get();
41 const auto& interfaces = m.second;
42
43 // Watch for new interfaces on this path.
44 DBusInterfaceType::addMatch(
45 sdbusplus::bus::match::rules::interfacesAdded(path),
Brad Bishopd1eac882018-03-29 10:34:05 -040046 [this](auto& msg)
47 // *INDENT-OFF*
48 { this->interfacesAdded(msg); });
Brad Bishop4b916f12017-05-23 18:06:38 -040049 // *INDENT-ON*
50
51 // Do a query to populate the cache. Start with a mapper query.
52 // The specific services are queried below.
Brad Bishopcca7a7c2018-07-09 22:34:33 -040053 auto getObjectFromMapper = [](const auto& path) {
54 const std::vector<std::string> queryInterfaces; // all interfaces
55 try
56 {
57 return DBusInterfaceType::template callMethodAndRead<GetObject>(
58 MAPPER_BUSNAME, MAPPER_PATH, MAPPER_INTERFACE, "GetObject",
59 path, queryInterfaces);
60 }
Patrick Williams764adb52021-09-02 09:36:47 -050061 catch (const sdbusplus::exception::exception&)
Brad Bishopcca7a7c2018-07-09 22:34:33 -040062 {
63 // Paths in the configuration may not exist yet. Prime those
64 // later, when/if InterfacesAdded occurs.
65 return GetObject();
66 }
67 };
68 auto mapperResp = getObjectFromMapper(path);
Brad Bishop4b916f12017-05-23 18:06:38 -040069
70 for (const auto& i : interfaces)
71 {
72 const auto& interface = i.first.get();
73
74 // Watch for property changes on this interface.
75 DBusInterfaceType::addMatch(
Brad Bishopd1eac882018-03-29 10:34:05 -040076 sdbusplus::bus::match::rules::propertiesChanged(path,
77 interface),
78 [this](auto& msg)
Brad Bishop4b916f12017-05-23 18:06:38 -040079 // *INDENT-OFF*
80 {
81 std::string interface;
82 msg.read(interface);
83 auto path = msg.get_path();
84 this->propertiesChanged(msg, path, interface);
85 });
Brad Bishopd1eac882018-03-29 10:34:05 -040086 // *INDENT-ON*
Brad Bishop4b916f12017-05-23 18:06:38 -040087
88 // The mapper response is a busname:[interfaces] map. Look for
89 // each interface in the index and if found, query the service and
90 // populate the cache entries for the interface.
91 for (const auto& mr : mapperResp)
92 {
93 const auto& busName = mr.first;
94 const auto& mapperInterfaces = mr.second;
Brad Bishopd1eac882018-03-29 10:34:05 -040095 if (mapperInterfaces.end() ==
96 std::find(mapperInterfaces.begin(), mapperInterfaces.end(),
97 interface))
Brad Bishop4b916f12017-05-23 18:06:38 -040098 {
99 // This interface isn't being watched.
100 continue;
101 }
102
103 // Delegate type specific property updates to subclasses.
Brad Bishopcca7a7c2018-07-09 22:34:33 -0400104 try
105 {
106 updateProperties(busName, path, interface);
107 }
Patrick Williams764adb52021-09-02 09:36:47 -0500108 catch (const sdbusplus::exception::exception&)
Brad Bishopcca7a7c2018-07-09 22:34:33 -0400109 {
110 // If for some reason the path has gone away since
111 // the mapper lookup we'll simply try again if/when
112 // InterfacesAdded occurs the next time it shows up.
113 }
Brad Bishop4b916f12017-05-23 18:06:38 -0400114 }
115 }
116 }
Brad Bishopc1283ae2017-05-20 21:42:38 -0400117
118 alreadyRan = true;
Brad Bishop4b916f12017-05-23 18:06:38 -0400119}
120
Brad Bishopce4fbe12017-06-06 23:58:09 -0400121template <typename DBusInterfaceType>
Ratan Guptaa45e0862018-02-21 19:03:13 +0530122void PropertyWatch<DBusInterfaceType>::callback(Context ctx)
Brad Bishopce4fbe12017-06-06 23:58:09 -0400123{
Lei YU98d64622022-05-24 19:11:23 +0800124 // Ignore callback if ignoreStartCallback is true and it's the START
125 // callback
126 if (ctx == Context::START && ignoreStartCallback)
127 {
128 return;
129 }
Brad Bishopce4fbe12017-06-06 23:58:09 -0400130 // Invoke callback if present.
131 if (this->alreadyRan && this->cb)
132 {
Ratan Guptaa45e0862018-02-21 19:03:13 +0530133 (*this->cb)(ctx);
Brad Bishopce4fbe12017-06-06 23:58:09 -0400134 }
135}
136
Brad Bishop4b916f12017-05-23 18:06:38 -0400137template <typename T, typename DBusInterfaceType>
138void PropertyWatchOfType<T, DBusInterfaceType>::updateProperties(
Brad Bishopd1eac882018-03-29 10:34:05 -0400139 const std::string& busName, const std::string& path,
Brad Bishop4b916f12017-05-23 18:06:38 -0400140 const std::string& interface)
141{
142 auto properties =
143 DBusInterfaceType::template callMethodAndRead<PropertiesChanged<T>>(
Brad Bishopd1eac882018-03-29 10:34:05 -0400144 busName.c_str(), path.c_str(), "org.freedesktop.DBus.Properties",
145 "GetAll", interface);
Brad Bishop4b916f12017-05-23 18:06:38 -0400146 propertiesChanged(path, interface, properties);
147}
148
149template <typename T, typename DBusInterfaceType>
150void PropertyWatchOfType<T, DBusInterfaceType>::propertiesChanged(
Brad Bishopd1eac882018-03-29 10:34:05 -0400151 const std::string& path, const std::string& interface,
Brad Bishop4b916f12017-05-23 18:06:38 -0400152 const PropertiesChanged<T>& properties)
153{
154 // Update the cache for any watched properties.
155 for (const auto& p : properties)
156 {
157 auto key = std::make_tuple(path, interface, p.first);
158 auto item = this->index.find(key);
159 if (item == this->index.end())
160 {
161 // This property isn't being watched.
162 continue;
163 }
164
Matthew Barthae786ef2019-09-04 15:46:13 -0500165 // Run property value thru filter operations
166 auto isFiltered = false;
167 const auto& storage = std::get<storageIndex>(item->second);
Patrick Williams34ef1e52020-05-13 11:07:43 -0500168 auto value = std::get<T>(p.second);
Matthew Barthefe01582019-09-09 15:22:37 -0500169 if (filterOps)
Matthew Barthae786ef2019-09-04 15:46:13 -0500170 {
Patrick Williams26dc0bc2022-06-16 17:06:18 -0500171 std::any anyValue = value;
Matthew Barthefe01582019-09-09 15:22:37 -0500172 if ((*filterOps)(anyValue))
Matthew Barthae786ef2019-09-04 15:46:13 -0500173 {
174 // Property value filtered, clear it from storage so
175 // callback functions do not use it
176 isFiltered = true;
Patrick Williams26dc0bc2022-06-16 17:06:18 -0500177 std::get<valueIndex>(storage.get()).reset();
Matthew Barthae786ef2019-09-04 15:46:13 -0500178 }
179 }
180 if (!isFiltered)
181 {
182 // Property value not filtered out, update
183 std::get<valueIndex>(storage.get()) = value;
184 // Invoke callback if present.
185 this->callback(Context::SIGNAL);
186 }
Brad Bishop4b916f12017-05-23 18:06:38 -0400187 }
188}
189
190template <typename T, typename DBusInterfaceType>
191void PropertyWatchOfType<T, DBusInterfaceType>::propertiesChanged(
Brad Bishopd1eac882018-03-29 10:34:05 -0400192 sdbusplus::message::message& msg, const std::string& path,
Brad Bishop4b916f12017-05-23 18:06:38 -0400193 const std::string& interface)
194{
195 PropertiesChanged<T> properties;
196 msg.read(properties);
197 propertiesChanged(path, interface, properties);
198}
199
200template <typename T, typename DBusInterfaceType>
201void PropertyWatchOfType<T, DBusInterfaceType>::interfacesAdded(
Brad Bishopd1eac882018-03-29 10:34:05 -0400202 const std::string& path, const InterfacesAdded<T>& interfaces)
Brad Bishop4b916f12017-05-23 18:06:38 -0400203{
204 for (const auto& i : interfaces)
205 {
206 propertiesChanged(path, i.first, i.second);
207 }
208}
209
210template <typename T, typename DBusInterfaceType>
211void PropertyWatchOfType<T, DBusInterfaceType>::interfacesAdded(
212 sdbusplus::message::message& msg)
213{
214 sdbusplus::message::object_path path;
215 InterfacesAdded<T> interfaces;
216 msg.read(path, interfaces);
217 interfacesAdded(path, interfaces);
218}
219
220} // namespace monitoring
221} // namespace dbus
222} // namespace phosphor