blob: c63921007a8b98b1d3bae5563ff23ecb933185b9 [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>
9#include <vector>
10
Brad Bishop4b916f12017-05-23 18:06:38 -040011namespace phosphor
12{
13namespace dbus
14{
15namespace monitoring
16{
17
Brad Bishop4b916f12017-05-23 18:06:38 -040018using MappedPropertyIndex =
19 RefKeyMap<const std::string,
Brad Bishopd1eac882018-03-29 10:34:05 -040020 RefKeyMap<const std::string, RefVector<const std::string>>>;
Brad Bishop4b916f12017-05-23 18:06:38 -040021
22MappedPropertyIndex convert(const PropertyIndex& index);
23
24template <typename DBusInterfaceType>
25void PropertyWatch<DBusInterfaceType>::start()
26{
27 if (alreadyRan)
28 {
29 return;
30 }
Brad Bishop4b916f12017-05-23 18:06:38 -040031
32 // The index has a flat layout which is not optimal here. Nest
33 // properties in a map of interface names in a map of object paths.
34 auto mapped = convert(index);
35
36 for (const auto& m : mapped)
37 {
38 const auto& path = m.first.get();
39 const auto& interfaces = m.second;
40
41 // Watch for new interfaces on this path.
42 DBusInterfaceType::addMatch(
43 sdbusplus::bus::match::rules::interfacesAdded(path),
Brad Bishopd1eac882018-03-29 10:34:05 -040044 [this](auto& msg)
45 // *INDENT-OFF*
46 { this->interfacesAdded(msg); });
Brad Bishop4b916f12017-05-23 18:06:38 -040047 // *INDENT-ON*
48
49 // Do a query to populate the cache. Start with a mapper query.
50 // The specific services are queried below.
Brad Bishopcca7a7c2018-07-09 22:34:33 -040051 auto getObjectFromMapper = [](const auto& path) {
52 const std::vector<std::string> queryInterfaces; // all interfaces
53 try
54 {
55 return DBusInterfaceType::template callMethodAndRead<GetObject>(
56 MAPPER_BUSNAME, MAPPER_PATH, MAPPER_INTERFACE, "GetObject",
57 path, queryInterfaces);
58 }
59 catch (const sdbusplus::exception::SdBusError&)
60 {
61 // Paths in the configuration may not exist yet. Prime those
62 // later, when/if InterfacesAdded occurs.
63 return GetObject();
64 }
65 };
66 auto mapperResp = getObjectFromMapper(path);
Brad Bishop4b916f12017-05-23 18:06:38 -040067
68 for (const auto& i : interfaces)
69 {
70 const auto& interface = i.first.get();
71
72 // Watch for property changes on this interface.
73 DBusInterfaceType::addMatch(
Brad Bishopd1eac882018-03-29 10:34:05 -040074 sdbusplus::bus::match::rules::propertiesChanged(path,
75 interface),
76 [this](auto& msg)
Brad Bishop4b916f12017-05-23 18:06:38 -040077 // *INDENT-OFF*
78 {
79 std::string interface;
80 msg.read(interface);
81 auto path = msg.get_path();
82 this->propertiesChanged(msg, path, interface);
83 });
Brad Bishopd1eac882018-03-29 10:34:05 -040084 // *INDENT-ON*
Brad Bishop4b916f12017-05-23 18:06:38 -040085
86 // The mapper response is a busname:[interfaces] map. Look for
87 // each interface in the index and if found, query the service and
88 // populate the cache entries for the interface.
89 for (const auto& mr : mapperResp)
90 {
91 const auto& busName = mr.first;
92 const auto& mapperInterfaces = mr.second;
Brad Bishopd1eac882018-03-29 10:34:05 -040093 if (mapperInterfaces.end() ==
94 std::find(mapperInterfaces.begin(), mapperInterfaces.end(),
95 interface))
Brad Bishop4b916f12017-05-23 18:06:38 -040096 {
97 // This interface isn't being watched.
98 continue;
99 }
100
101 // Delegate type specific property updates to subclasses.
Brad Bishopcca7a7c2018-07-09 22:34:33 -0400102 try
103 {
104 updateProperties(busName, path, interface);
105 }
106 catch (const sdbusplus::exception::SdBusError&)
107 {
108 // If for some reason the path has gone away since
109 // the mapper lookup we'll simply try again if/when
110 // InterfacesAdded occurs the next time it shows up.
111 }
Brad Bishop4b916f12017-05-23 18:06:38 -0400112 }
113 }
114 }
Brad Bishopc1283ae2017-05-20 21:42:38 -0400115
116 alreadyRan = true;
Brad Bishop4b916f12017-05-23 18:06:38 -0400117}
118
Brad Bishopce4fbe12017-06-06 23:58:09 -0400119template <typename DBusInterfaceType>
Ratan Guptaa45e0862018-02-21 19:03:13 +0530120void PropertyWatch<DBusInterfaceType>::callback(Context ctx)
Brad Bishopce4fbe12017-06-06 23:58:09 -0400121{
122 // Invoke callback if present.
123 if (this->alreadyRan && this->cb)
124 {
Ratan Guptaa45e0862018-02-21 19:03:13 +0530125 (*this->cb)(ctx);
Brad Bishopce4fbe12017-06-06 23:58:09 -0400126 }
127}
128
Brad Bishop4b916f12017-05-23 18:06:38 -0400129template <typename T, typename DBusInterfaceType>
130void PropertyWatchOfType<T, DBusInterfaceType>::updateProperties(
Brad Bishopd1eac882018-03-29 10:34:05 -0400131 const std::string& busName, const std::string& path,
Brad Bishop4b916f12017-05-23 18:06:38 -0400132 const std::string& interface)
133{
134 auto properties =
135 DBusInterfaceType::template callMethodAndRead<PropertiesChanged<T>>(
Brad Bishopd1eac882018-03-29 10:34:05 -0400136 busName.c_str(), path.c_str(), "org.freedesktop.DBus.Properties",
137 "GetAll", interface);
Brad Bishop4b916f12017-05-23 18:06:38 -0400138 propertiesChanged(path, interface, properties);
139}
140
141template <typename T, typename DBusInterfaceType>
142void PropertyWatchOfType<T, DBusInterfaceType>::propertiesChanged(
Brad Bishopd1eac882018-03-29 10:34:05 -0400143 const std::string& path, const std::string& interface,
Brad Bishop4b916f12017-05-23 18:06:38 -0400144 const PropertiesChanged<T>& properties)
145{
146 // Update the cache for any watched properties.
147 for (const auto& p : properties)
148 {
149 auto key = std::make_tuple(path, interface, p.first);
150 auto item = this->index.find(key);
151 if (item == this->index.end())
152 {
153 // This property isn't being watched.
154 continue;
155 }
156
Matthew Barthae786ef2019-09-04 15:46:13 -0500157 // Run property value thru filter operations
158 auto isFiltered = false;
159 const auto& storage = std::get<storageIndex>(item->second);
160 auto value = sdbusplus::message::variant_ns::get<T>(p.second);
161 for (auto& filterOp : filterOps)
162 {
163 if (!filterOp(value))
164 {
165 // Property value filtered, clear it from storage so
166 // callback functions do not use it
167 isFiltered = true;
168 std::get<valueIndex>(storage.get()).clear();
169 break;
170 }
171 }
172 if (!isFiltered)
173 {
174 // Property value not filtered out, update
175 std::get<valueIndex>(storage.get()) = value;
176 // Invoke callback if present.
177 this->callback(Context::SIGNAL);
178 }
Brad Bishop4b916f12017-05-23 18:06:38 -0400179 }
180}
181
182template <typename T, typename DBusInterfaceType>
183void PropertyWatchOfType<T, DBusInterfaceType>::propertiesChanged(
Brad Bishopd1eac882018-03-29 10:34:05 -0400184 sdbusplus::message::message& msg, const std::string& path,
Brad Bishop4b916f12017-05-23 18:06:38 -0400185 const std::string& interface)
186{
187 PropertiesChanged<T> properties;
188 msg.read(properties);
189 propertiesChanged(path, interface, properties);
190}
191
192template <typename T, typename DBusInterfaceType>
193void PropertyWatchOfType<T, DBusInterfaceType>::interfacesAdded(
Brad Bishopd1eac882018-03-29 10:34:05 -0400194 const std::string& path, const InterfacesAdded<T>& interfaces)
Brad Bishop4b916f12017-05-23 18:06:38 -0400195{
196 for (const auto& i : interfaces)
197 {
198 propertiesChanged(path, i.first, i.second);
199 }
200}
201
202template <typename T, typename DBusInterfaceType>
203void PropertyWatchOfType<T, DBusInterfaceType>::interfacesAdded(
204 sdbusplus::message::message& msg)
205{
206 sdbusplus::message::object_path path;
207 InterfacesAdded<T> interfaces;
208 msg.read(path, interfaces);
209 interfacesAdded(path, interfaces);
210}
211
212} // namespace monitoring
213} // namespace dbus
214} // namespace phosphor