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>
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>
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>
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>
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;
91     explicit Properties(U&& handler) :
92         _path(""), _intf(""), _prop(""), _handler(std::forward<U>(handler))
93     {}
94     Properties(const char* path, const char* intf, const char* prop,
95                U&& handler) :
96         _path(path),
97         _intf(intf), _prop(prop), _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      */
105     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      */
158     void operator()(Zone& zone, const Group& group) const
159     {
160         std::for_each(
161             group.begin(), group.end(),
162             [&zone, handler = std::move(_handler)](auto const& 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>
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>
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;
237     InterfacesAdded(const char* path, const char* intf, const char* prop,
238                     U&& handler) :
239         _path(path),
240         _intf(intf), _prop(prop), _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      */
248     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>
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;
326     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      */
335     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>
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;
398     explicit NameOwner(U&& handler) : _handler(std::forward<U>(handler))
399     {}
400 
401     /** @brief Run signal handler function
402      *
403      * Extract the name owner from the NameOwnerChanged
404      * message and run the handler function.
405      */
406     void operator()(sdbusplus::bus_t&, sdbusplus::message_t& msg,
407                     Zone& zone) const
408     {
409         if (msg)
410         {
411             std::string name;
412             bool hasOwner = false;
413 
414             // Handle NameOwnerChanged signals
415             msg.read(name);
416 
417             std::string oldOwn;
418             msg.read(oldOwn);
419 
420             std::string newOwn;
421             msg.read(newOwn);
422             if (!newOwn.empty())
423             {
424                 hasOwner = true;
425             }
426             _handler(zone, name, hasOwner);
427         }
428     }
429 
430     void operator()(Zone& zone, const Group& group) const
431     {
432         std::string name = "";
433         bool hasOwner = false;
434         std::for_each(
435             group.begin(), group.end(),
436             [&zone, &group, &name, &hasOwner,
437              handler = std::move(_handler)](auto const& member) {
438                 auto path = std::get<pathPos>(member);
439                 auto intf = std::get<intfPos>(member);
440                 try
441                 {
442                     auto servName = zone.getService(path, intf);
443                     if (name != servName)
444                     {
445                         name = servName;
446                         hasOwner = util::SDBusPlus::callMethodAndRead<bool>(
447                             zone.getBus(), "org.freedesktop.DBus",
448                             "/org/freedesktop/DBus", "org.freedesktop.DBus",
449                             "NameHasOwner", name);
450                         // Update service name owner state list of a group
451                         handler(zone, name, hasOwner);
452                     }
453                 }
454                 catch (const util::DBusMethodError& e)
455                 {
456                     // Failed to get service name owner state
457                     name = "";
458                     hasOwner = false;
459                 }
460             });
461     }
462 
463   private:
464     U _handler;
465 };
466 
467 /**
468  * @brief Used to process a Dbus name owner changed signal event
469  *
470  * @param[in] handler - Handler function to perform
471  *
472  * @tparam U - The type of the handler
473  *
474  * @return - The NameOwnerChanged signal struct
475  */
476 template <typename U>
477 auto nameOwnerChanged(U&& handler)
478 {
479     return NameOwner<U>(std::forward<U>(handler));
480 }
481 
482 /**
483  * @brief Used to process the init of a name owner event
484  *
485  * @param[in] handler - Handler function to perform
486  *
487  * @tparam U - The type of the handler
488  *
489  * @return - The NameOwnerChanged signal struct
490  */
491 template <typename U>
492 auto nameHasOwner(U&& handler)
493 {
494     return NameOwner<U>(std::forward<U>(handler));
495 }
496 
497 } // namespace control
498 } // namespace fan
499 } // namespace phosphor
500