blob: 71607c5cbbd49b21219d705017d1c043da648178 [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;
18
19/**
20 * @brief Create a handler function object
21 *
22 * @param[in] handler - The handler being created
23 *
24 * @return - The created handler function object
25 */
26template <typename T>
27auto make_handler(T&& handler)
28{
29 return Handler(std::forward<T>(handler));
30}
31
32/**
Matthew Barth17d1fe22017-05-11 15:00:36 -050033 * @brief Create an action function object
34 *
35 * @param[in] action - The action being created
36 *
37 * @return - The created action function object
38 */
39template <typename T>
40auto make_action(T&& action)
41{
42 return Action(std::forward<T>(action));
43}
44
45/**
Matthew Barth38a93a82017-05-11 14:12:27 -050046 * @struct Property Changed
47 * @brief A match filter functor for Dbus property value changed signals
48 *
49 * @tparam T - The type of the property value
50 * @tparam U - The type of the handler
51 */
52template <typename T, typename U>
53struct PropertyChanged
54{
55 PropertyChanged() = delete;
56 ~PropertyChanged() = default;
57 PropertyChanged(const PropertyChanged&) = default;
58 PropertyChanged& operator=(const PropertyChanged&) = default;
59 PropertyChanged(PropertyChanged&&) = default;
60 PropertyChanged& operator=(PropertyChanged&&) = default;
Matthew Barth336f18a2017-09-26 09:15:56 -050061 PropertyChanged(const char* path,
62 const char* iface,
Matthew Barth38a93a82017-05-11 14:12:27 -050063 const char* property,
64 U&& handler) :
Matthew Barth336f18a2017-09-26 09:15:56 -050065 _path(path),
Matthew Barth38a93a82017-05-11 14:12:27 -050066 _iface(iface),
67 _property(property),
68 _handler(std::forward<U>(handler)) { }
69
70 /** @brief Run signal handler function
71 *
72 * Extract the property from the PropertiesChanged
Matthew Barth336f18a2017-09-26 09:15:56 -050073 * message (or read the property when the message is null)
74 * and run the handler function.
Matthew Barth38a93a82017-05-11 14:12:27 -050075 */
Matthew Barth336f18a2017-09-26 09:15:56 -050076 void operator()(sdbusplus::bus::bus& bus,
Matthew Barth38a93a82017-05-11 14:12:27 -050077 sdbusplus::message::message& msg,
78 Zone& zone) const
79 {
Matthew Barth336f18a2017-09-26 09:15:56 -050080 if (msg)
Matthew Barth38a93a82017-05-11 14:12:27 -050081 {
Matthew Barth336f18a2017-09-26 09:15:56 -050082 std::map<std::string, sdbusplus::message::variant<T>> properties;
Matthew Barthd5cfdbe2017-11-14 15:29:50 -060083 std::string iface;
Matthew Barth38a93a82017-05-11 14:12:27 -050084
Matthew Barth336f18a2017-09-26 09:15:56 -050085 msg.read(iface);
Matthew Barthd5cfdbe2017-11-14 15:29:50 -060086 if (iface != _iface)
Matthew Barth336f18a2017-09-26 09:15:56 -050087 {
88 return;
89 }
90
91 msg.read(properties);
92 auto it = properties.find(_property);
93 if (it == properties.cend())
94 {
95 log<level::ERR>("Unable to find property on interface",
96 entry("PROPERTY=%s", _property),
Matthew Barthe65f6172017-12-11 13:36:02 -060097 entry("INTERFACE=%s", _iface),
98 entry("PATH=%s", _path));
Matthew Barth336f18a2017-09-26 09:15:56 -050099 return;
100 }
101
William A. Kennington III4978e062018-11-27 11:47:12 -0800102 _handler(zone, std::forward<T>(
103 sdbusplus::message::variant_ns::get<T>(it->second)));
Matthew Barth336f18a2017-09-26 09:15:56 -0500104 }
105 else
Matthew Barth38a93a82017-05-11 14:12:27 -0500106 {
Matthew Barth336f18a2017-09-26 09:15:56 -0500107 try
108 {
Matthew Barth766f8542019-01-29 12:44:13 -0600109 auto val = zone.getPropertyByName<T>(_path, _iface, _property);
Matthew Barth336f18a2017-09-26 09:15:56 -0500110 _handler(zone, std::forward<T>(val));
111 }
Matthew Barth86be4762018-07-17 10:51:36 -0500112 catch (const sdbusplus::exception::SdBusError&)
113 {
114 // Property will not be used unless a property changed
115 // signal message is received for this property.
116 }
117 catch (const util::DBusError&)
Matthew Barth336f18a2017-09-26 09:15:56 -0500118 {
119 // Property will not be used unless a property changed
120 // signal message is received for this property.
Matthew Barth336f18a2017-09-26 09:15:56 -0500121 }
Matthew Barth38a93a82017-05-11 14:12:27 -0500122 }
Matthew Barth38a93a82017-05-11 14:12:27 -0500123 }
124
125private:
Matthew Barth336f18a2017-09-26 09:15:56 -0500126 const char* _path;
Matthew Barth38a93a82017-05-11 14:12:27 -0500127 const char* _iface;
128 const char* _property;
129 U _handler;
130};
131
132/**
133 * @brief Used to process a Dbus property changed signal event
134 *
Matthew Barth336f18a2017-09-26 09:15:56 -0500135 * @param[in] path - Object path
136 * @param[in] iface - Object interface
137 * @param[in] property - Object property
Matthew Barth38a93a82017-05-11 14:12:27 -0500138 * @param[in] handler - Handler function to perform
139 *
140 * @tparam T - The type of the property
141 * @tparam U - The type of the handler
142 */
143template <typename T, typename U>
Matthew Barth336f18a2017-09-26 09:15:56 -0500144auto propertySignal(const char* path,
145 const char* iface,
Matthew Barth38a93a82017-05-11 14:12:27 -0500146 const char* property,
147 U&& handler)
148{
Matthew Barth336f18a2017-09-26 09:15:56 -0500149 return PropertyChanged<T, U>(path,
150 iface,
151 property,
152 std::forward<U>(handler));
Matthew Barth38a93a82017-05-11 14:12:27 -0500153}
154
Matthew Bartheb639c52017-08-04 09:43:11 -0500155/**
156 * @struct Interface Added
157 * @brief A match filter functor for Dbus interface added signals
158 *
159 * @tparam T - The type of the property value
160 * @tparam U - The type of the handler
161 */
162template <typename T, typename U>
163struct InterfaceAdded
164{
165 InterfaceAdded() = delete;
166 ~InterfaceAdded() = default;
167 InterfaceAdded(const InterfaceAdded&) = default;
168 InterfaceAdded& operator=(const InterfaceAdded&) = default;
169 InterfaceAdded(InterfaceAdded&&) = default;
170 InterfaceAdded& operator=(InterfaceAdded&&) = default;
171 InterfaceAdded(const char* path,
172 const char* iface,
173 const char* property,
174 U&& handler) :
175 _path(path),
176 _iface(iface),
177 _property(property),
178 _handler(std::forward<U>(handler)) { }
179
180 /** @brief Run signal handler function
181 *
182 * Extract the property from the InterfacesAdded
183 * message and run the handler function.
184 */
185 void operator()(sdbusplus::bus::bus&,
186 sdbusplus::message::message& msg,
187 Zone& zone) const
188 {
Matthew Barth336f18a2017-09-26 09:15:56 -0500189 if (msg)
Matthew Bartheb639c52017-08-04 09:43:11 -0500190 {
Matthew Barth336f18a2017-09-26 09:15:56 -0500191 std::map<std::string,
192 std::map<std::string,
193 sdbusplus::message::variant<T>>> intfProp;
194 sdbusplus::message::object_path op;
Matthew Bartheb639c52017-08-04 09:43:11 -0500195
Matthew Barth336f18a2017-09-26 09:15:56 -0500196 msg.read(op);
Matthew Barthd5cfdbe2017-11-14 15:29:50 -0600197 if (static_cast<const std::string&>(op) != _path)
Matthew Barth336f18a2017-09-26 09:15:56 -0500198 {
199 // Object path does not match this handler's path
200 return;
201 }
Matthew Bartheb639c52017-08-04 09:43:11 -0500202
Matthew Barth336f18a2017-09-26 09:15:56 -0500203 msg.read(intfProp);
204 auto itIntf = intfProp.find(_iface);
205 if (itIntf == intfProp.cend())
206 {
207 // Interface not found on this handler's path
208 return;
209 }
210 auto itProp = itIntf->second.find(_property);
211 if (itProp == itIntf->second.cend())
212 {
213 // Property not found on this handler's path
214 return;
215 }
216
William A. Kennington III4978e062018-11-27 11:47:12 -0800217 _handler(zone, std::forward<T>(
218 sdbusplus::message::variant_ns::get<T>(itProp->second)));
Matthew Barth336f18a2017-09-26 09:15:56 -0500219 }
Matthew Bartheb639c52017-08-04 09:43:11 -0500220 }
221
222private:
223 const char* _path;
224 const char* _iface;
225 const char* _property;
226 U _handler;
227};
228
229/**
230 * @brief Used to process a Dbus interface added signal event
231 *
232 * @param[in] path - Object path
233 * @param[in] iface - Object interface
234 * @param[in] property - Object property
235 * @param[in] handler - Handler function to perform
236 *
237 * @tparam T - The type of the property
238 * @tparam U - The type of the handler
239 */
240template <typename T, typename U>
241auto objectSignal(const char* path,
242 const char* iface,
243 const char* property,
244 U&& handler)
245{
246 return InterfaceAdded<T, U>(path,
247 iface,
248 property,
249 std::forward<U>(handler));
250}
251
Matthew Barth8fa02da2017-09-28 12:18:20 -0500252/**
Matthew Barth1499a5c2018-03-20 15:52:33 -0500253 * @struct Interface Removed
254 * @brief A match filter functor for Dbus interface removed signals
255 *
256 * @tparam U - The type of the handler
257 */
258template <typename U>
259struct InterfaceRemoved
260{
261 InterfaceRemoved() = delete;
262 ~InterfaceRemoved() = default;
263 InterfaceRemoved(const InterfaceRemoved&) = default;
264 InterfaceRemoved& operator=(const InterfaceRemoved&) = default;
265 InterfaceRemoved(InterfaceRemoved&&) = default;
266 InterfaceRemoved& operator=(InterfaceRemoved&&) = default;
267 InterfaceRemoved(const char* path,
268 const char* iface,
269 U&& handler) :
270 _path(path),
271 _iface(iface),
272 _handler(std::forward<U>(handler)) { }
273
274 /** @brief Run signal handler function
275 *
276 * Extract the property from the InterfacesRemoved
277 * message and run the handler function.
278 */
279 void operator()(sdbusplus::bus::bus&,
280 sdbusplus::message::message& msg,
281 Zone& zone) const
282 {
283 if (msg)
284 {
285 std::vector<std::string> intfs;
286 sdbusplus::message::object_path op;
287
288 msg.read(op);
289 if (static_cast<const std::string&>(op) != _path)
290 {
291 // Object path does not match this handler's path
292 return;
293 }
294
295 msg.read(intfs);
296 auto itIntf = std::find(intfs.begin(), intfs.end(), _iface);
297 if (itIntf == intfs.cend())
298 {
299 // Interface not found on this handler's path
300 return;
301 }
302
303 _handler(zone);
304 }
305 }
306
307private:
308 const char* _path;
309 const char* _iface;
310 U _handler;
311};
312
313/**
314 * @brief Used to process a Dbus interface removed signal event
315 *
316 * @param[in] path - Object path
317 * @param[in] iface - Object interface
318 * @param[in] handler - Handler function to perform
319 *
320 * @tparam U - The type of the handler
321 */
322template <typename U>
323auto objectSignal(const char* path,
324 const char* iface,
325 U&& handler)
326{
327 return InterfaceRemoved<U>(path,
328 iface,
329 std::forward<U>(handler));
330}
331
332/**
Matthew Barth8fa02da2017-09-28 12:18:20 -0500333 * @struct Name Owner Changed
334 * @brief A match filter functor for Dbus name owner changed signals
335 *
336 * @tparam U - The type of the handler
337 */
338template <typename U>
339struct NameOwnerChanged
340{
341 NameOwnerChanged() = delete;
342 ~NameOwnerChanged() = default;
343 NameOwnerChanged(const NameOwnerChanged&) = default;
344 NameOwnerChanged& operator=(const NameOwnerChanged&) = default;
345 NameOwnerChanged(NameOwnerChanged&&) = default;
346 NameOwnerChanged& operator=(NameOwnerChanged&&) = default;
347 NameOwnerChanged(const char* path,
348 const char* iface,
349 U&& handler) :
350 _path(path),
351 _iface(iface),
352 _handler(std::forward<U>(handler)) { }
353
354 /** @brief Run signal handler function
355 *
356 * Extract the name owner from the NameOwnerChanged
357 * message (or read the name owner when the message is null)
358 * and run the handler function.
359 */
360 void operator()(sdbusplus::bus::bus& bus,
361 sdbusplus::message::message& msg,
362 Zone& zone) const
363 {
Matthew Barth5a302572017-10-03 11:27:06 -0500364 std::string name;
365 bool hasOwner = false;
Matthew Barth8fa02da2017-09-28 12:18:20 -0500366 if (msg)
367 {
Matthew Barth5a302572017-10-03 11:27:06 -0500368 // Handle NameOwnerChanged signals
369 msg.read(name);
370
371 std::string oldOwn;
372 msg.read(oldOwn);
373
374 std::string newOwn;
375 msg.read(newOwn);
376 if (!newOwn.empty())
377 {
378 hasOwner = true;
379 }
Matthew Barth8fa02da2017-09-28 12:18:20 -0500380 }
381 else
382 {
Matthew Barth5a302572017-10-03 11:27:06 -0500383 try
384 {
385 // Initialize NameOwnerChanged data store with service name
Matthew Barthc72b8912018-01-19 17:28:18 -0600386 name = zone.getService(_path, _iface);
Matthew Barth5a302572017-10-03 11:27:06 -0500387 hasOwner = util::SDBusPlus::callMethodAndRead<bool>(
388 bus,
389 "org.freedesktop.DBus",
390 "/org/freedesktop/DBus",
391 "org.freedesktop.DBus",
392 "NameHasOwner",
393 name);
394 }
Matt Spinlerba7b5fe2018-04-25 15:26:10 -0500395 catch (const util::DBusMethodError& e)
Matthew Barth5a302572017-10-03 11:27:06 -0500396 {
397 // Failed to get service name owner state
398 hasOwner = false;
399 }
Matthew Barth8fa02da2017-09-28 12:18:20 -0500400 }
Matthew Barth5a302572017-10-03 11:27:06 -0500401
402 _handler(zone, name, hasOwner);
Matthew Barth8fa02da2017-09-28 12:18:20 -0500403 }
404
405private:
406 const char* _path;
407 const char* _iface;
408 U _handler;
409};
410
411/**
412 * @brief Used to process a Dbus name owner changed signal event
413 *
414 * @param[in] path - Object path
415 * @param[in] iface - Object interface
416 * @param[in] handler - Handler function to perform
417 *
418 * @tparam U - The type of the handler
419 *
420 * @return - The NameOwnerChanged signal struct
421 */
422template <typename U>
423auto ownerSignal(const char* path,
424 const char* iface,
425 U&& handler)
426{
427 return NameOwnerChanged<U>(path,
428 iface,
429 std::forward<U>(handler));
430}
431
Matthew Barth38a93a82017-05-11 14:12:27 -0500432} // namespace control
433} // namespace fan
434} // namespace phosphor