1 #pragma once
2 
3 #include "sdbusplus.hpp"
4 #include "types.hpp"
5 #include "zone.hpp"
6 
7 #include <phosphor-logging/log.hpp>
8 
9 namespace phosphor
10 {
11 namespace fan
12 {
13 namespace control
14 {
15 class Zone;
16 
17 using namespace phosphor::fan;
18 using namespace sdbusplus::bus::match;
19 using namespace phosphor::logging;
20 
21 /**
22  * @brief Create a zone handler function object
23  *
24  * @param[in] handler - The handler being created
25  *
26  * @return - The created zone handler function object
27  */
28 template <typename T>
make_zoneHandler(T && handler)29 auto make_zoneHandler(T&& handler)
30 {
31     return ZoneHandler(std::forward<T>(handler));
32 }
33 
34 /**
35  * @brief Create a trigger function object
36  *
37  * @param[in] trigger - The trigger being created
38  *
39  * @return - The created trigger function object
40  */
41 template <typename T>
make_trigger(T && trigger)42 auto make_trigger(T&& trigger)
43 {
44     return Trigger(std::forward<T>(trigger));
45 }
46 
47 /**
48  * @brief Create a handler function object
49  *
50  * @param[in] handler - The handler being created
51  *
52  * @return - The created handler function object
53  */
54 template <typename T, typename U>
make_handler(U && handler)55 auto make_handler(U&& handler)
56 {
57     return T(std::forward<U>(handler));
58 }
59 
60 /**
61  * @brief Create an action function object
62  *
63  * @param[in] action - The action being created
64  *
65  * @return - The created action function object
66  */
67 template <typename T>
make_action(T && action)68 auto make_action(T&& action)
69 {
70     return Action(std::forward<T>(action));
71 }
72 
73 /**
74  * @struct Properties
75  * @brief A set of match filter functors for Dbus property values. Each
76  * functor provides an associated process for retrieving the value
77  * for a given property and providing it to the given handler function.
78  *
79  * @tparam T - The type of the property value
80  * @tparam U - The type of the handler
81  */
82 template <typename T, typename U>
83 struct Properties
84 {
85     Properties() = delete;
86     ~Properties() = default;
87     Properties(const Properties&) = default;
88     Properties& operator=(const Properties&) = default;
89     Properties(Properties&&) = default;
90     Properties& operator=(Properties&&) = default;
Propertiesphosphor::fan::control::Properties91     explicit Properties(U&& handler) :
92         _path(""), _intf(""), _prop(""), _handler(std::forward<U>(handler))
93     {}
Propertiesphosphor::fan::control::Properties94     Properties(const char* path, const char* intf, const char* prop,
95                U&& handler) :
96         _path(path), _intf(intf), _prop(prop),
97         _handler(std::forward<U>(handler))
98     {}
99 
100     /** @brief Run signal handler function
101      *
102      * Extract the property from the PropertiesChanged
103      * message and run the handler function.
104      */
operator ()phosphor::fan::control::Properties105     void operator()(sdbusplus::bus_t&, sdbusplus::message_t& msg,
106                     Zone& zone) const
107     {
108         if (msg)
109         {
110             std::string intf;
111             msg.read(intf);
112             if (intf != _intf)
113             {
114                 // Interface name does not match on object
115                 return;
116             }
117 
118             std::map<std::string, PropertyVariantType> props;
119             msg.read(props);
120             auto it = props.find(_prop);
121             if (it == props.cend())
122             {
123                 // Property not included in dictionary of properties changed
124                 return;
125             }
126 
127             // Retrieve the property's value applying any visitors necessary
128             auto value =
129                 zone.getPropertyValueVisitor<T>(_intf, _prop, it->second);
130 
131             _handler(zone, _path, _intf, _prop, std::forward<T>(value));
132         }
133         else
134         {
135             try
136             {
137                 auto val = zone.getPropertyByName<T>(_path, _intf, _prop);
138                 _handler(zone, _path, _intf, _prop, std::forward<T>(val));
139             }
140             catch (const sdbusplus::exception_t&)
141             {
142                 // Property will not be used unless a property changed
143                 // signal message is received for this property.
144             }
145             catch (const util::DBusError&)
146             {
147                 // Property will not be used unless a property changed
148                 // signal message is received for this property.
149             }
150         }
151     }
152 
153     /** @brief Run init handler function
154      *
155      * Get the property from each member object of the group
156      * and run the handler function.
157      */
operator ()phosphor::fan::control::Properties158     void operator()(Zone& zone, const Group& group) const
159     {
160         std::for_each(
161             group.begin(), group.end(),
162             [&zone, handler = std::move(_handler)](const auto& member) {
163                 auto path = std::get<pathPos>(member);
164                 auto intf = std::get<intfPos>(member);
165                 auto prop = std::get<propPos>(member);
166                 try
167                 {
168                     auto val = zone.getPropertyByName<T>(path, intf, prop);
169                     handler(zone, path, intf, prop, std::forward<T>(val));
170                 }
171                 catch (const sdbusplus::exception_t&)
172                 {
173                     // Property value not sent to handler
174                 }
175                 catch (const util::DBusError&)
176                 {
177                     // Property value not sent to handler
178                 }
179             });
180     }
181 
182   private:
183     const char* _path;
184     const char* _intf;
185     const char* _prop;
186     U _handler;
187 };
188 
189 /**
190  * @brief Used to process a Dbus properties changed signal event
191  *
192  * @param[in] path - Object path
193  * @param[in] intf - Object interface
194  * @param[in] prop - Object property
195  * @param[in] handler - Handler function to perform
196  *
197  * @tparam T - The type of the property
198  * @tparam U - The type of the handler
199  */
200 template <typename T, typename U>
propertiesChanged(const char * path,const char * intf,const char * prop,U && handler)201 auto propertiesChanged(const char* path, const char* intf, const char* prop,
202                        U&& handler)
203 {
204     return Properties<T, U>(path, intf, prop, std::forward<U>(handler));
205 }
206 
207 /**
208  * @brief Used to get the properties of an event's group
209  *
210  * @param[in] handler - Handler function to perform
211  *
212  * @tparam T - The type of all the properties
213  * @tparam U - The type of the handler
214  */
215 template <typename T, typename U>
getProperties(U && handler)216 auto getProperties(U&& handler)
217 {
218     return Properties<T, U>(std::forward<U>(handler));
219 }
220 
221 /**
222  * @struct Interfaces Added
223  * @brief A match filter functor for Dbus interfaces added signals
224  *
225  * @tparam T - The type of the property value
226  * @tparam U - The type of the handler
227  */
228 template <typename T, typename U>
229 struct InterfacesAdded
230 {
231     InterfacesAdded() = delete;
232     ~InterfacesAdded() = default;
233     InterfacesAdded(const InterfacesAdded&) = default;
234     InterfacesAdded& operator=(const InterfacesAdded&) = default;
235     InterfacesAdded(InterfacesAdded&&) = default;
236     InterfacesAdded& operator=(InterfacesAdded&&) = default;
InterfacesAddedphosphor::fan::control::InterfacesAdded237     InterfacesAdded(const char* path, const char* intf, const char* prop,
238                     U&& handler) :
239         _path(path), _intf(intf), _prop(prop),
240         _handler(std::forward<U>(handler))
241     {}
242 
243     /** @brief Run signal handler function
244      *
245      * Extract the property from the InterfacesAdded
246      * message and run the handler function.
247      */
operator ()phosphor::fan::control::InterfacesAdded248     void operator()(sdbusplus::bus_t&, sdbusplus::message_t& msg,
249                     Zone& zone) const
250     {
251         if (msg)
252         {
253             sdbusplus::message::object_path op;
254 
255             msg.read(op);
256             if (static_cast<const std::string&>(op) != _path)
257             {
258                 // Object path does not match this handler's path
259                 return;
260             }
261 
262             std::map<std::string, std::map<std::string, PropertyVariantType>>
263                 intfProp;
264             msg.read(intfProp);
265             auto itIntf = intfProp.find(_intf);
266             if (itIntf == intfProp.cend())
267             {
268                 // Interface not found on this handler's path
269                 return;
270             }
271             auto itProp = itIntf->second.find(_prop);
272             if (itProp == itIntf->second.cend())
273             {
274                 // Property not found on this handler's path
275                 return;
276             }
277 
278             // Retrieve the property's value applying any visitors necessary
279             auto value =
280                 zone.getPropertyValueVisitor<T>(_intf, _prop, itProp->second);
281 
282             _handler(zone, _path, _intf, _prop, std::forward<T>(value));
283         }
284     }
285 
286   private:
287     const char* _path;
288     const char* _intf;
289     const char* _prop;
290     U _handler;
291 };
292 
293 /**
294  * @brief Used to process a Dbus interfaces added signal event
295  *
296  * @param[in] path - Object path
297  * @param[in] intf - Object interface
298  * @param[in] prop - Object property
299  * @param[in] handler - Handler function to perform
300  *
301  * @tparam T - The type of the property
302  * @tparam U - The type of the handler
303  */
304 template <typename T, typename U>
interfacesAdded(const char * path,const char * intf,const char * prop,U && handler)305 auto interfacesAdded(const char* path, const char* intf, const char* prop,
306                      U&& handler)
307 {
308     return InterfacesAdded<T, U>(path, intf, prop, std::forward<U>(handler));
309 }
310 
311 /**
312  * @struct Interfaces Removed
313  * @brief A match filter functor for Dbus interfaces removed signals
314  *
315  * @tparam U - The type of the handler
316  */
317 template <typename U>
318 struct InterfacesRemoved
319 {
320     InterfacesRemoved() = delete;
321     ~InterfacesRemoved() = default;
322     InterfacesRemoved(const InterfacesRemoved&) = default;
323     InterfacesRemoved& operator=(const InterfacesRemoved&) = default;
324     InterfacesRemoved(InterfacesRemoved&&) = default;
325     InterfacesRemoved& operator=(InterfacesRemoved&&) = default;
InterfacesRemovedphosphor::fan::control::InterfacesRemoved326     InterfacesRemoved(const char* path, const char* intf, U&& handler) :
327         _path(path), _intf(intf), _handler(std::forward<U>(handler))
328     {}
329 
330     /** @brief Run signal handler function
331      *
332      * Extract the interfaces from the InterfacesRemoved
333      * message and run the handler function.
334      */
operator ()phosphor::fan::control::InterfacesRemoved335     void operator()(sdbusplus::bus_t&, sdbusplus::message_t& msg,
336                     Zone& zone) const
337     {
338         if (msg)
339         {
340             std::vector<std::string> intfs;
341             sdbusplus::message::object_path op;
342 
343             msg.read(op);
344             if (static_cast<const std::string&>(op) != _path)
345             {
346                 // Object path does not match this handler's path
347                 return;
348             }
349 
350             msg.read(intfs);
351             auto itIntf = std::find(intfs.begin(), intfs.end(), _intf);
352             if (itIntf == intfs.cend())
353             {
354                 // Interface not found on this handler's path
355                 return;
356             }
357 
358             _handler(zone);
359         }
360     }
361 
362   private:
363     const char* _path;
364     const char* _intf;
365     U _handler;
366 };
367 
368 /**
369  * @brief Used to process a Dbus interfaces removed signal event
370  *
371  * @param[in] path - Object path
372  * @param[in] intf - Object interface
373  * @param[in] handler - Handler function to perform
374  *
375  * @tparam U - The type of the handler
376  */
377 template <typename U>
interfacesRemoved(const char * path,const char * intf,U && handler)378 auto interfacesRemoved(const char* path, const char* intf, U&& handler)
379 {
380     return InterfacesRemoved<U>(path, intf, std::forward<U>(handler));
381 }
382 
383 /**
384  * @struct Name Owner
385  * @brief A functor for Dbus name owner signals and methods
386  *
387  * @tparam U - The type of the handler
388  */
389 template <typename U>
390 struct NameOwner
391 {
392     NameOwner() = delete;
393     ~NameOwner() = default;
394     NameOwner(const NameOwner&) = default;
395     NameOwner& operator=(const NameOwner&) = default;
396     NameOwner(NameOwner&&) = default;
397     NameOwner& operator=(NameOwner&&) = default;
NameOwnerphosphor::fan::control::NameOwner398     explicit NameOwner(U&& handler) : _handler(std::forward<U>(handler)) {}
399 
400     /** @brief Run signal handler function
401      *
402      * Extract the name owner from the NameOwnerChanged
403      * message and run the handler function.
404      */
operator ()phosphor::fan::control::NameOwner405     void operator()(sdbusplus::bus_t&, sdbusplus::message_t& msg,
406                     Zone& zone) const
407     {
408         if (msg)
409         {
410             std::string name;
411             bool hasOwner = false;
412 
413             // Handle NameOwnerChanged signals
414             msg.read(name);
415 
416             std::string oldOwn;
417             msg.read(oldOwn);
418 
419             std::string newOwn;
420             msg.read(newOwn);
421             if (!newOwn.empty())
422             {
423                 hasOwner = true;
424             }
425             _handler(zone, name, hasOwner);
426         }
427     }
428 
operator ()phosphor::fan::control::NameOwner429     void operator()(Zone& zone, const Group& group) const
430     {
431         std::string name = "";
432         bool hasOwner = false;
433         std::for_each(
434             group.begin(), group.end(),
435             [&zone, &group, &name, &hasOwner,
436              handler = std::move(_handler)](const auto& member) {
437                 auto path = std::get<pathPos>(member);
438                 auto intf = std::get<intfPos>(member);
439                 try
440                 {
441                     auto servName = zone.getService(path, intf);
442                     if (name != servName)
443                     {
444                         name = servName;
445                         hasOwner = util::SDBusPlus::callMethodAndRead<bool>(
446                             zone.getBus(), "org.freedesktop.DBus",
447                             "/org/freedesktop/DBus", "org.freedesktop.DBus",
448                             "NameHasOwner", name);
449                         // Update service name owner state list of a group
450                         handler(zone, name, hasOwner);
451                     }
452                 }
453                 catch (const util::DBusMethodError& e)
454                 {
455                     // Failed to get service name owner state
456                     name = "";
457                     hasOwner = false;
458                 }
459             });
460     }
461 
462   private:
463     U _handler;
464 };
465 
466 /**
467  * @brief Used to process a Dbus name owner changed signal event
468  *
469  * @param[in] handler - Handler function to perform
470  *
471  * @tparam U - The type of the handler
472  *
473  * @return - The NameOwnerChanged signal struct
474  */
475 template <typename U>
nameOwnerChanged(U && handler)476 auto nameOwnerChanged(U&& handler)
477 {
478     return NameOwner<U>(std::forward<U>(handler));
479 }
480 
481 /**
482  * @brief Used to process the init of a name owner event
483  *
484  * @param[in] handler - Handler function to perform
485  *
486  * @tparam U - The type of the handler
487  *
488  * @return - The NameOwnerChanged signal struct
489  */
490 template <typename U>
nameHasOwner(U && handler)491 auto nameHasOwner(U&& handler)
492 {
493     return NameOwner<U>(std::forward<U>(handler));
494 }
495 
496 } // namespace control
497 } // namespace fan
498 } // namespace phosphor
499