blob: faf0d3e7370f2863f25a57a674f3291cf399b8ea [file] [log] [blame]
Matthew Barth38a93a82017-05-11 14:12:27 -05001#pragma once
2
3#include "types.hpp"
Matthew Barth336f18a2017-09-26 09:15:56 -05004#include "sdbusplus.hpp"
Matthew Barth38a93a82017-05-11 14:12:27 -05005#include <phosphor-logging/log.hpp>
6
7namespace phosphor
8{
9namespace fan
10{
11namespace control
12{
13class Zone;
14
Matthew Barth336f18a2017-09-26 09:15:56 -050015using namespace phosphor::fan;
Matthew Barth5a302572017-10-03 11:27:06 -050016using namespace sdbusplus::bus::match;
Matthew Barth38a93a82017-05-11 14:12:27 -050017using namespace phosphor::logging;
Matthew Barth336f18a2017-09-26 09:15:56 -050018using InternalFailure = sdbusplus::xyz::openbmc_project::Common::
19 Error::InternalFailure;
Matthew Barth38a93a82017-05-11 14:12:27 -050020
21/**
22 * @brief Create a handler function object
23 *
24 * @param[in] handler - The handler being created
25 *
26 * @return - The created handler function object
27 */
28template <typename T>
29auto make_handler(T&& handler)
30{
31 return Handler(std::forward<T>(handler));
32}
33
34/**
Matthew Barth17d1fe22017-05-11 15:00:36 -050035 * @brief Create an action function object
36 *
37 * @param[in] action - The action being created
38 *
39 * @return - The created action function object
40 */
41template <typename T>
42auto make_action(T&& action)
43{
44 return Action(std::forward<T>(action));
45}
46
47/**
Matthew Barth38a93a82017-05-11 14:12:27 -050048 * @struct Property Changed
49 * @brief A match filter functor for Dbus property value changed signals
50 *
51 * @tparam T - The type of the property value
52 * @tparam U - The type of the handler
53 */
54template <typename T, typename U>
55struct PropertyChanged
56{
57 PropertyChanged() = delete;
58 ~PropertyChanged() = default;
59 PropertyChanged(const PropertyChanged&) = default;
60 PropertyChanged& operator=(const PropertyChanged&) = default;
61 PropertyChanged(PropertyChanged&&) = default;
62 PropertyChanged& operator=(PropertyChanged&&) = default;
Matthew Barth336f18a2017-09-26 09:15:56 -050063 PropertyChanged(const char* path,
64 const char* iface,
Matthew Barth38a93a82017-05-11 14:12:27 -050065 const char* property,
66 U&& handler) :
Matthew Barth336f18a2017-09-26 09:15:56 -050067 _path(path),
Matthew Barth38a93a82017-05-11 14:12:27 -050068 _iface(iface),
69 _property(property),
70 _handler(std::forward<U>(handler)) { }
71
72 /** @brief Run signal handler function
73 *
74 * Extract the property from the PropertiesChanged
Matthew Barth336f18a2017-09-26 09:15:56 -050075 * message (or read the property when the message is null)
76 * and run the handler function.
Matthew Barth38a93a82017-05-11 14:12:27 -050077 */
Matthew Barth336f18a2017-09-26 09:15:56 -050078 void operator()(sdbusplus::bus::bus& bus,
Matthew Barth38a93a82017-05-11 14:12:27 -050079 sdbusplus::message::message& msg,
80 Zone& zone) const
81 {
Matthew Barth336f18a2017-09-26 09:15:56 -050082 if (msg)
Matthew Barth38a93a82017-05-11 14:12:27 -050083 {
Matthew Barth336f18a2017-09-26 09:15:56 -050084 std::map<std::string, sdbusplus::message::variant<T>> properties;
85 const char* iface = nullptr;
Matthew Barth38a93a82017-05-11 14:12:27 -050086
Matthew Barth336f18a2017-09-26 09:15:56 -050087 msg.read(iface);
88 if (!iface || strcmp(iface, _iface))
89 {
90 return;
91 }
92
93 msg.read(properties);
94 auto it = properties.find(_property);
95 if (it == properties.cend())
96 {
97 log<level::ERR>("Unable to find property on interface",
98 entry("PROPERTY=%s", _property),
99 entry("INTERFACE=%s", _iface));
100 return;
101 }
102
103 _handler(zone, std::forward<T>(it->second.template get<T>()));
104 }
105 else
Matthew Barth38a93a82017-05-11 14:12:27 -0500106 {
Matthew Barth336f18a2017-09-26 09:15:56 -0500107 try
108 {
109 auto val = util::SDBusPlus::getProperty<T>(bus,
110 _path,
111 _iface,
112 _property);
113 _handler(zone, std::forward<T>(val));
114 }
115 catch (const InternalFailure& ife)
116 {
117 // Property will not be used unless a property changed
118 // signal message is received for this property.
119 log<level::INFO>(
120 "Property not used, unless PropertyChanged signal received",
121 entry("PATH=%s", _path),
122 entry("INTERFACE=%s", _iface),
123 entry("PROPERTY=%s", _property));
124 }
Matthew Barth38a93a82017-05-11 14:12:27 -0500125 }
Matthew Barth38a93a82017-05-11 14:12:27 -0500126 }
127
128private:
Matthew Barth336f18a2017-09-26 09:15:56 -0500129 const char* _path;
Matthew Barth38a93a82017-05-11 14:12:27 -0500130 const char* _iface;
131 const char* _property;
132 U _handler;
133};
134
135/**
136 * @brief Used to process a Dbus property changed signal event
137 *
Matthew Barth336f18a2017-09-26 09:15:56 -0500138 * @param[in] path - Object path
139 * @param[in] iface - Object interface
140 * @param[in] property - Object property
Matthew Barth38a93a82017-05-11 14:12:27 -0500141 * @param[in] handler - Handler function to perform
142 *
143 * @tparam T - The type of the property
144 * @tparam U - The type of the handler
145 */
146template <typename T, typename U>
Matthew Barth336f18a2017-09-26 09:15:56 -0500147auto propertySignal(const char* path,
148 const char* iface,
Matthew Barth38a93a82017-05-11 14:12:27 -0500149 const char* property,
150 U&& handler)
151{
Matthew Barth336f18a2017-09-26 09:15:56 -0500152 return PropertyChanged<T, U>(path,
153 iface,
154 property,
155 std::forward<U>(handler));
Matthew Barth38a93a82017-05-11 14:12:27 -0500156}
157
Matthew Bartheb639c52017-08-04 09:43:11 -0500158/**
159 * @struct Interface Added
160 * @brief A match filter functor for Dbus interface added signals
161 *
162 * @tparam T - The type of the property value
163 * @tparam U - The type of the handler
164 */
165template <typename T, typename U>
166struct InterfaceAdded
167{
168 InterfaceAdded() = delete;
169 ~InterfaceAdded() = default;
170 InterfaceAdded(const InterfaceAdded&) = default;
171 InterfaceAdded& operator=(const InterfaceAdded&) = default;
172 InterfaceAdded(InterfaceAdded&&) = default;
173 InterfaceAdded& operator=(InterfaceAdded&&) = default;
174 InterfaceAdded(const char* path,
175 const char* iface,
176 const char* property,
177 U&& handler) :
178 _path(path),
179 _iface(iface),
180 _property(property),
181 _handler(std::forward<U>(handler)) { }
182
183 /** @brief Run signal handler function
184 *
185 * Extract the property from the InterfacesAdded
186 * message and run the handler function.
187 */
188 void operator()(sdbusplus::bus::bus&,
189 sdbusplus::message::message& msg,
190 Zone& zone) const
191 {
Matthew Barth336f18a2017-09-26 09:15:56 -0500192 if (msg)
Matthew Bartheb639c52017-08-04 09:43:11 -0500193 {
Matthew Barth336f18a2017-09-26 09:15:56 -0500194 std::map<std::string,
195 std::map<std::string,
196 sdbusplus::message::variant<T>>> intfProp;
197 sdbusplus::message::object_path op;
Matthew Bartheb639c52017-08-04 09:43:11 -0500198
Matthew Barth336f18a2017-09-26 09:15:56 -0500199 msg.read(op);
200 auto objPath = static_cast<const std::string&>(op).c_str();
201 if (!objPath || strcmp(objPath, _path))
202 {
203 // Object path does not match this handler's path
204 return;
205 }
Matthew Bartheb639c52017-08-04 09:43:11 -0500206
Matthew Barth336f18a2017-09-26 09:15:56 -0500207 msg.read(intfProp);
208 auto itIntf = intfProp.find(_iface);
209 if (itIntf == intfProp.cend())
210 {
211 // Interface not found on this handler's path
212 return;
213 }
214 auto itProp = itIntf->second.find(_property);
215 if (itProp == itIntf->second.cend())
216 {
217 // Property not found on this handler's path
218 return;
219 }
220
221 _handler(zone, std::forward<T>(itProp->second.template get<T>()));
222 }
Matthew Bartheb639c52017-08-04 09:43:11 -0500223 }
224
225private:
226 const char* _path;
227 const char* _iface;
228 const char* _property;
229 U _handler;
230};
231
232/**
233 * @brief Used to process a Dbus interface added signal event
234 *
235 * @param[in] path - Object path
236 * @param[in] iface - Object interface
237 * @param[in] property - Object property
238 * @param[in] handler - Handler function to perform
239 *
240 * @tparam T - The type of the property
241 * @tparam U - The type of the handler
242 */
243template <typename T, typename U>
244auto objectSignal(const char* path,
245 const char* iface,
246 const char* property,
247 U&& handler)
248{
249 return InterfaceAdded<T, U>(path,
250 iface,
251 property,
252 std::forward<U>(handler));
253}
254
Matthew Barth8fa02da2017-09-28 12:18:20 -0500255/**
256 * @struct Name Owner Changed
257 * @brief A match filter functor for Dbus name owner changed signals
258 *
259 * @tparam U - The type of the handler
260 */
261template <typename U>
262struct NameOwnerChanged
263{
264 NameOwnerChanged() = delete;
265 ~NameOwnerChanged() = default;
266 NameOwnerChanged(const NameOwnerChanged&) = default;
267 NameOwnerChanged& operator=(const NameOwnerChanged&) = default;
268 NameOwnerChanged(NameOwnerChanged&&) = default;
269 NameOwnerChanged& operator=(NameOwnerChanged&&) = default;
270 NameOwnerChanged(const char* path,
271 const char* iface,
272 U&& handler) :
273 _path(path),
274 _iface(iface),
275 _handler(std::forward<U>(handler)) { }
276
277 /** @brief Run signal handler function
278 *
279 * Extract the name owner from the NameOwnerChanged
280 * message (or read the name owner when the message is null)
281 * and run the handler function.
282 */
283 void operator()(sdbusplus::bus::bus& bus,
284 sdbusplus::message::message& msg,
285 Zone& zone) const
286 {
Matthew Barth5a302572017-10-03 11:27:06 -0500287 std::string name;
288 bool hasOwner = false;
Matthew Barth8fa02da2017-09-28 12:18:20 -0500289 if (msg)
290 {
Matthew Barth5a302572017-10-03 11:27:06 -0500291 // Handle NameOwnerChanged signals
292 msg.read(name);
293
294 std::string oldOwn;
295 msg.read(oldOwn);
296
297 std::string newOwn;
298 msg.read(newOwn);
299 if (!newOwn.empty())
300 {
301 hasOwner = true;
302 }
Matthew Barth8fa02da2017-09-28 12:18:20 -0500303 }
304 else
305 {
Matthew Barth5a302572017-10-03 11:27:06 -0500306 try
307 {
308 // Initialize NameOwnerChanged data store with service name
309 name = util::SDBusPlus::getService(bus,
310 _path,
311 _iface);
312 hasOwner = util::SDBusPlus::callMethodAndRead<bool>(
313 bus,
314 "org.freedesktop.DBus",
315 "/org/freedesktop/DBus",
316 "org.freedesktop.DBus",
317 "NameHasOwner",
318 name);
319 }
320 catch (const InternalFailure& ife)
321 {
322 // Failed to get service name owner state
323 hasOwner = false;
324 }
Matthew Barth8fa02da2017-09-28 12:18:20 -0500325 }
Matthew Barth5a302572017-10-03 11:27:06 -0500326
327 _handler(zone, name, hasOwner);
Matthew Barth8fa02da2017-09-28 12:18:20 -0500328 }
329
330private:
331 const char* _path;
332 const char* _iface;
333 U _handler;
334};
335
336/**
337 * @brief Used to process a Dbus name owner changed signal event
338 *
339 * @param[in] path - Object path
340 * @param[in] iface - Object interface
341 * @param[in] handler - Handler function to perform
342 *
343 * @tparam U - The type of the handler
344 *
345 * @return - The NameOwnerChanged signal struct
346 */
347template <typename U>
348auto ownerSignal(const char* path,
349 const char* iface,
350 U&& handler)
351{
352 return NameOwnerChanged<U>(path,
353 iface,
354 std::forward<U>(handler));
355}
356
Matthew Barth38a93a82017-05-11 14:12:27 -0500357} // namespace control
358} // namespace fan
359} // namespace phosphor