blob: 271d9b2088ed4513d210a19c10d9e531ddefe36d [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>
Andrew Geisslerae4c95c2020-05-16 13:58:53 -05009#include <string>
Patrick Venture3d6d3182018-08-31 09:33:09 -070010#include <vector>
11
Brad Bishop4b916f12017-05-23 18:06:38 -040012namespace phosphor
13{
14namespace dbus
15{
16namespace monitoring
17{
18
Brad Bishop4b916f12017-05-23 18:06:38 -040019using MappedPropertyIndex =
20 RefKeyMap<const std::string,
Brad Bishopd1eac882018-03-29 10:34:05 -040021 RefKeyMap<const std::string, RefVector<const std::string>>>;
Brad Bishop4b916f12017-05-23 18:06:38 -040022
23MappedPropertyIndex convert(const PropertyIndex& index);
24
25template <typename DBusInterfaceType>
26void PropertyWatch<DBusInterfaceType>::start()
27{
28 if (alreadyRan)
29 {
30 return;
31 }
Brad Bishop4b916f12017-05-23 18:06:38 -040032
33 // The index has a flat layout which is not optimal here. Nest
34 // properties in a map of interface names in a map of object paths.
35 auto mapped = convert(index);
36
37 for (const auto& m : mapped)
38 {
39 const auto& path = m.first.get();
40 const auto& interfaces = m.second;
41
42 // Watch for new interfaces on this path.
43 DBusInterfaceType::addMatch(
44 sdbusplus::bus::match::rules::interfacesAdded(path),
Brad Bishopd1eac882018-03-29 10:34:05 -040045 [this](auto& msg)
46 // *INDENT-OFF*
47 { this->interfacesAdded(msg); });
Brad Bishop4b916f12017-05-23 18:06:38 -040048 // *INDENT-ON*
49
50 // Do a query to populate the cache. Start with a mapper query.
51 // The specific services are queried below.
Brad Bishopcca7a7c2018-07-09 22:34:33 -040052 auto getObjectFromMapper = [](const auto& path) {
53 const std::vector<std::string> queryInterfaces; // all interfaces
54 try
55 {
56 return DBusInterfaceType::template callMethodAndRead<GetObject>(
57 MAPPER_BUSNAME, MAPPER_PATH, MAPPER_INTERFACE, "GetObject",
58 path, queryInterfaces);
59 }
Patrick Williams764adb52021-09-02 09:36:47 -050060 catch (const sdbusplus::exception::exception&)
Brad Bishopcca7a7c2018-07-09 22:34:33 -040061 {
62 // Paths in the configuration may not exist yet. Prime those
63 // later, when/if InterfacesAdded occurs.
64 return GetObject();
65 }
66 };
67 auto mapperResp = getObjectFromMapper(path);
Brad Bishop4b916f12017-05-23 18:06:38 -040068
69 for (const auto& i : interfaces)
70 {
71 const auto& interface = i.first.get();
72
73 // Watch for property changes on this interface.
74 DBusInterfaceType::addMatch(
Brad Bishopd1eac882018-03-29 10:34:05 -040075 sdbusplus::bus::match::rules::propertiesChanged(path,
76 interface),
77 [this](auto& msg)
Brad Bishop4b916f12017-05-23 18:06:38 -040078 // *INDENT-OFF*
79 {
80 std::string interface;
81 msg.read(interface);
82 auto path = msg.get_path();
83 this->propertiesChanged(msg, path, interface);
84 });
Brad Bishopd1eac882018-03-29 10:34:05 -040085 // *INDENT-ON*
Brad Bishop4b916f12017-05-23 18:06:38 -040086
87 // The mapper response is a busname:[interfaces] map. Look for
88 // each interface in the index and if found, query the service and
89 // populate the cache entries for the interface.
90 for (const auto& mr : mapperResp)
91 {
92 const auto& busName = mr.first;
93 const auto& mapperInterfaces = mr.second;
Brad Bishopd1eac882018-03-29 10:34:05 -040094 if (mapperInterfaces.end() ==
95 std::find(mapperInterfaces.begin(), mapperInterfaces.end(),
96 interface))
Brad Bishop4b916f12017-05-23 18:06:38 -040097 {
98 // This interface isn't being watched.
99 continue;
100 }
101
102 // Delegate type specific property updates to subclasses.
Brad Bishopcca7a7c2018-07-09 22:34:33 -0400103 try
104 {
105 updateProperties(busName, path, interface);
106 }
Patrick Williams764adb52021-09-02 09:36:47 -0500107 catch (const sdbusplus::exception::exception&)
Brad Bishopcca7a7c2018-07-09 22:34:33 -0400108 {
109 // If for some reason the path has gone away since
110 // the mapper lookup we'll simply try again if/when
111 // InterfacesAdded occurs the next time it shows up.
112 }
Brad Bishop4b916f12017-05-23 18:06:38 -0400113 }
114 }
115 }
Brad Bishopc1283ae2017-05-20 21:42:38 -0400116
117 alreadyRan = true;
Brad Bishop4b916f12017-05-23 18:06:38 -0400118}
119
Brad Bishopce4fbe12017-06-06 23:58:09 -0400120template <typename DBusInterfaceType>
Ratan Guptaa45e0862018-02-21 19:03:13 +0530121void PropertyWatch<DBusInterfaceType>::callback(Context ctx)
Brad Bishopce4fbe12017-06-06 23:58:09 -0400122{
Lei YU98d64622022-05-24 19:11:23 +0800123 // Ignore callback if ignoreStartCallback is true and it's the START
124 // callback
125 if (ctx == Context::START && ignoreStartCallback)
126 {
127 return;
128 }
Brad Bishopce4fbe12017-06-06 23:58:09 -0400129 // Invoke callback if present.
130 if (this->alreadyRan && this->cb)
131 {
Ratan Guptaa45e0862018-02-21 19:03:13 +0530132 (*this->cb)(ctx);
Brad Bishopce4fbe12017-06-06 23:58:09 -0400133 }
134}
135
Brad Bishop4b916f12017-05-23 18:06:38 -0400136template <typename T, typename DBusInterfaceType>
137void PropertyWatchOfType<T, DBusInterfaceType>::updateProperties(
Brad Bishopd1eac882018-03-29 10:34:05 -0400138 const std::string& busName, const std::string& path,
Brad Bishop4b916f12017-05-23 18:06:38 -0400139 const std::string& interface)
140{
141 auto properties =
142 DBusInterfaceType::template callMethodAndRead<PropertiesChanged<T>>(
Brad Bishopd1eac882018-03-29 10:34:05 -0400143 busName.c_str(), path.c_str(), "org.freedesktop.DBus.Properties",
144 "GetAll", interface);
Brad Bishop4b916f12017-05-23 18:06:38 -0400145 propertiesChanged(path, interface, properties);
146}
147
148template <typename T, typename DBusInterfaceType>
149void PropertyWatchOfType<T, DBusInterfaceType>::propertiesChanged(
Brad Bishopd1eac882018-03-29 10:34:05 -0400150 const std::string& path, const std::string& interface,
Brad Bishop4b916f12017-05-23 18:06:38 -0400151 const PropertiesChanged<T>& properties)
152{
153 // Update the cache for any watched properties.
154 for (const auto& p : properties)
155 {
156 auto key = std::make_tuple(path, interface, p.first);
157 auto item = this->index.find(key);
158 if (item == this->index.end())
159 {
160 // This property isn't being watched.
161 continue;
162 }
163
Matthew Barthae786ef2019-09-04 15:46:13 -0500164 // Run property value thru filter operations
165 auto isFiltered = false;
166 const auto& storage = std::get<storageIndex>(item->second);
Patrick Williams34ef1e52020-05-13 11:07:43 -0500167 auto value = std::get<T>(p.second);
Matthew Barthefe01582019-09-09 15:22:37 -0500168 if (filterOps)
Matthew Barthae786ef2019-09-04 15:46:13 -0500169 {
Matthew Barthefe01582019-09-09 15:22:37 -0500170 any_ns::any anyValue = value;
171 if ((*filterOps)(anyValue))
Matthew Barthae786ef2019-09-04 15:46:13 -0500172 {
173 // Property value filtered, clear it from storage so
174 // callback functions do not use it
175 isFiltered = true;
176 std::get<valueIndex>(storage.get()).clear();
Matthew Barthae786ef2019-09-04 15:46:13 -0500177 }
178 }
179 if (!isFiltered)
180 {
181 // Property value not filtered out, update
182 std::get<valueIndex>(storage.get()) = value;
183 // Invoke callback if present.
184 this->callback(Context::SIGNAL);
185 }
Brad Bishop4b916f12017-05-23 18:06:38 -0400186 }
187}
188
189template <typename T, typename DBusInterfaceType>
190void PropertyWatchOfType<T, DBusInterfaceType>::propertiesChanged(
Brad Bishopd1eac882018-03-29 10:34:05 -0400191 sdbusplus::message::message& msg, const std::string& path,
Brad Bishop4b916f12017-05-23 18:06:38 -0400192 const std::string& interface)
193{
194 PropertiesChanged<T> properties;
195 msg.read(properties);
196 propertiesChanged(path, interface, properties);
197}
198
199template <typename T, typename DBusInterfaceType>
200void PropertyWatchOfType<T, DBusInterfaceType>::interfacesAdded(
Brad Bishopd1eac882018-03-29 10:34:05 -0400201 const std::string& path, const InterfacesAdded<T>& interfaces)
Brad Bishop4b916f12017-05-23 18:06:38 -0400202{
203 for (const auto& i : interfaces)
204 {
205 propertiesChanged(path, i.first, i.second);
206 }
207}
208
209template <typename T, typename DBusInterfaceType>
210void PropertyWatchOfType<T, DBusInterfaceType>::interfacesAdded(
211 sdbusplus::message::message& msg)
212{
213 sdbusplus::message::object_path path;
214 InterfacesAdded<T> interfaces;
215 msg.read(path, interfaces);
216 interfacesAdded(path, interfaces);
217}
218
219} // namespace monitoring
220} // namespace dbus
221} // namespace phosphor