blob: 6500a1543ec1c9950b69e22a8bb76b846772eb8b [file] [log] [blame]
Brad Bishop4b916f12017-05-23 18:06:38 -04001#pragma once
2
3#include <sdbusplus/message.hpp>
4#include <sdbusplus/bus/match.hpp>
5#include <vector>
Brad Bishopfccdc392017-05-22 21:11:09 -04006#include "callback.hpp"
Brad Bishop4b916f12017-05-23 18:06:38 -04007#include "data_types.hpp"
8#include "propertywatch.hpp"
9
10namespace phosphor
11{
12namespace dbus
13{
14namespace monitoring
15{
16
Brad Bishop4b916f12017-05-23 18:06:38 -040017using MappedPropertyIndex =
18 RefKeyMap<const std::string,
Brad Bishopd1eac882018-03-29 10:34:05 -040019 RefKeyMap<const std::string, RefVector<const std::string>>>;
Brad Bishop4b916f12017-05-23 18:06:38 -040020
21MappedPropertyIndex convert(const PropertyIndex& index);
22
23template <typename DBusInterfaceType>
24void PropertyWatch<DBusInterfaceType>::start()
25{
26 if (alreadyRan)
27 {
28 return;
29 }
Brad Bishop4b916f12017-05-23 18:06:38 -040030
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),
Brad Bishopd1eac882018-03-29 10:34:05 -040043 [this](auto& msg)
44 // *INDENT-OFF*
45 { this->interfacesAdded(msg); });
Brad Bishop4b916f12017-05-23 18:06:38 -040046 // *INDENT-ON*
47
48 // Do a query to populate the cache. Start with a mapper query.
49 // The specific services are queried below.
Brad Bishopcca7a7c2018-07-09 22:34:33 -040050 auto getObjectFromMapper = [](const auto& path) {
51 const std::vector<std::string> queryInterfaces; // all interfaces
52 try
53 {
54 return DBusInterfaceType::template callMethodAndRead<GetObject>(
55 MAPPER_BUSNAME, MAPPER_PATH, MAPPER_INTERFACE, "GetObject",
56 path, queryInterfaces);
57 }
58 catch (const sdbusplus::exception::SdBusError&)
59 {
60 // Paths in the configuration may not exist yet. Prime those
61 // later, when/if InterfacesAdded occurs.
62 return GetObject();
63 }
64 };
65 auto mapperResp = getObjectFromMapper(path);
Brad Bishop4b916f12017-05-23 18:06:38 -040066
67 for (const auto& i : interfaces)
68 {
69 const auto& interface = i.first.get();
70
71 // Watch for property changes on this interface.
72 DBusInterfaceType::addMatch(
Brad Bishopd1eac882018-03-29 10:34:05 -040073 sdbusplus::bus::match::rules::propertiesChanged(path,
74 interface),
75 [this](auto& msg)
Brad Bishop4b916f12017-05-23 18:06:38 -040076 // *INDENT-OFF*
77 {
78 std::string interface;
79 msg.read(interface);
80 auto path = msg.get_path();
81 this->propertiesChanged(msg, path, interface);
82 });
Brad Bishopd1eac882018-03-29 10:34:05 -040083 // *INDENT-ON*
Brad Bishop4b916f12017-05-23 18:06:38 -040084
85 // The mapper response is a busname:[interfaces] map. Look for
86 // each interface in the index and if found, query the service and
87 // populate the cache entries for the interface.
88 for (const auto& mr : mapperResp)
89 {
90 const auto& busName = mr.first;
91 const auto& mapperInterfaces = mr.second;
Brad Bishopd1eac882018-03-29 10:34:05 -040092 if (mapperInterfaces.end() ==
93 std::find(mapperInterfaces.begin(), mapperInterfaces.end(),
94 interface))
Brad Bishop4b916f12017-05-23 18:06:38 -040095 {
96 // This interface isn't being watched.
97 continue;
98 }
99
100 // Delegate type specific property updates to subclasses.
Brad Bishopcca7a7c2018-07-09 22:34:33 -0400101 try
102 {
103 updateProperties(busName, path, interface);
104 }
105 catch (const sdbusplus::exception::SdBusError&)
106 {
107 // If for some reason the path has gone away since
108 // the mapper lookup we'll simply try again if/when
109 // InterfacesAdded occurs the next time it shows up.
110 }
Brad Bishop4b916f12017-05-23 18:06:38 -0400111 }
112 }
113 }
Brad Bishopc1283ae2017-05-20 21:42:38 -0400114
115 alreadyRan = true;
Brad Bishop4b916f12017-05-23 18:06:38 -0400116}
117
Brad Bishopce4fbe12017-06-06 23:58:09 -0400118template <typename DBusInterfaceType>
Ratan Guptaa45e0862018-02-21 19:03:13 +0530119void PropertyWatch<DBusInterfaceType>::callback(Context ctx)
Brad Bishopce4fbe12017-06-06 23:58:09 -0400120{
121 // Invoke callback if present.
122 if (this->alreadyRan && this->cb)
123 {
Ratan Guptaa45e0862018-02-21 19:03:13 +0530124 (*this->cb)(ctx);
Brad Bishopce4fbe12017-06-06 23:58:09 -0400125 }
126}
127
Brad Bishop4b916f12017-05-23 18:06:38 -0400128template <typename T, typename DBusInterfaceType>
129void PropertyWatchOfType<T, DBusInterfaceType>::updateProperties(
Brad Bishopd1eac882018-03-29 10:34:05 -0400130 const std::string& busName, const std::string& path,
Brad Bishop4b916f12017-05-23 18:06:38 -0400131 const std::string& interface)
132{
133 auto properties =
134 DBusInterfaceType::template callMethodAndRead<PropertiesChanged<T>>(
Brad Bishopd1eac882018-03-29 10:34:05 -0400135 busName.c_str(), path.c_str(), "org.freedesktop.DBus.Properties",
136 "GetAll", interface);
Brad Bishop4b916f12017-05-23 18:06:38 -0400137 propertiesChanged(path, interface, properties);
138}
139
140template <typename T, typename DBusInterfaceType>
141void PropertyWatchOfType<T, DBusInterfaceType>::propertiesChanged(
Brad Bishopd1eac882018-03-29 10:34:05 -0400142 const std::string& path, const std::string& interface,
Brad Bishop4b916f12017-05-23 18:06:38 -0400143 const PropertiesChanged<T>& properties)
144{
145 // Update the cache for any watched properties.
146 for (const auto& p : properties)
147 {
148 auto key = std::make_tuple(path, interface, p.first);
149 auto item = this->index.find(key);
150 if (item == this->index.end())
151 {
152 // This property isn't being watched.
153 continue;
154 }
155
Matt Spinler1abcb062018-02-26 09:14:31 -0600156 std::get<valueIndex>(std::get<storageIndex>(item->second).get()) =
Brad Bishopd1eac882018-03-29 10:34:05 -0400157 p.second.template get<T>();
Brad Bishopfccdc392017-05-22 21:11:09 -0400158
159 // Invoke callback if present.
Ratan Guptaa45e0862018-02-21 19:03:13 +0530160 this->callback(Context::SIGNAL);
Brad Bishop4b916f12017-05-23 18:06:38 -0400161 }
162}
163
164template <typename T, typename DBusInterfaceType>
165void PropertyWatchOfType<T, DBusInterfaceType>::propertiesChanged(
Brad Bishopd1eac882018-03-29 10:34:05 -0400166 sdbusplus::message::message& msg, const std::string& path,
Brad Bishop4b916f12017-05-23 18:06:38 -0400167 const std::string& interface)
168{
169 PropertiesChanged<T> properties;
170 msg.read(properties);
171 propertiesChanged(path, interface, properties);
172}
173
174template <typename T, typename DBusInterfaceType>
175void PropertyWatchOfType<T, DBusInterfaceType>::interfacesAdded(
Brad Bishopd1eac882018-03-29 10:34:05 -0400176 const std::string& path, const InterfacesAdded<T>& interfaces)
Brad Bishop4b916f12017-05-23 18:06:38 -0400177{
178 for (const auto& i : interfaces)
179 {
180 propertiesChanged(path, i.first, i.second);
181 }
182}
183
184template <typename T, typename DBusInterfaceType>
185void PropertyWatchOfType<T, DBusInterfaceType>::interfacesAdded(
186 sdbusplus::message::message& msg)
187{
188 sdbusplus::message::object_path path;
189 InterfacesAdded<T> interfaces;
190 msg.read(path, interfaces);
191 interfacesAdded(path, interfaces);
192}
193
194} // namespace monitoring
195} // namespace dbus
196} // namespace phosphor