1 #pragma once
2 
3 #include "sdbusplus.hpp"
4 #include "types.hpp"
5 
6 #include <phosphor-logging/log.hpp>
7 
8 namespace phosphor
9 {
10 namespace fan
11 {
12 namespace control
13 {
14 class Zone;
15 
16 using namespace phosphor::fan;
17 using namespace sdbusplus::bus::match;
18 using namespace phosphor::logging;
19 
20 /**
21  * @brief Create a zone handler function object
22  *
23  * @param[in] handler - The handler being created
24  *
25  * @return - The created zone handler function object
26  */
27 template <typename T>
28 auto make_zoneHandler(T&& handler)
29 {
30     return ZoneHandler(std::forward<T>(handler));
31 }
32 
33 /**
34  * @brief Create a trigger function object
35  *
36  * @param[in] trigger - The trigger being created
37  *
38  * @return - The created trigger function object
39  */
40 template <typename T>
41 auto make_trigger(T&& trigger)
42 {
43     return Trigger(std::forward<T>(trigger));
44 }
45 
46 /**
47  * @brief Create a handler function object
48  *
49  * @param[in] handler - The handler being created
50  *
51  * @return - The created handler function object
52  */
53 template <typename T, typename U>
54 auto make_handler(U&& handler)
55 {
56     return T(std::forward<U>(handler));
57 }
58 
59 /**
60  * @brief Create an action function object
61  *
62  * @param[in] action - The action being created
63  *
64  * @return - The created action function object
65  */
66 template <typename T>
67 auto make_action(T&& action)
68 {
69     return Action(std::forward<T>(action));
70 }
71 
72 /**
73  * @struct Properties
74  * @brief A set of match filter functors for Dbus property values. Each
75  * functor provides an associated process for retrieving the value
76  * for a given property and providing it to the given handler function.
77  *
78  * @tparam T - The type of the property value
79  * @tparam U - The type of the handler
80  */
81 template <typename T, typename U>
82 struct Properties
83 {
84     Properties() = delete;
85     ~Properties() = default;
86     Properties(const Properties&) = default;
87     Properties& operator=(const Properties&) = default;
88     Properties(Properties&&) = default;
89     Properties& operator=(Properties&&) = default;
90     explicit Properties(U&& handler) :
91         _path(""), _intf(""), _prop(""), _handler(std::forward<U>(handler))
92     {}
93     Properties(const char* path, const char* intf, const char* prop,
94                U&& handler) :
95         _path(path),
96         _intf(intf), _prop(prop), _handler(std::forward<U>(handler))
97     {}
98 
99     /** @brief Run signal handler function
100      *
101      * Extract the property from the PropertiesChanged
102      * message and run the handler function.
103      */
104     void operator()(sdbusplus::bus::bus& bus, sdbusplus::message::message& msg,
105                     Zone& zone) const
106     {
107         if (msg)
108         {
109             std::string intf;
110             msg.read(intf);
111             if (intf != _intf)
112             {
113                 // Interface name does not match on object
114                 return;
115             }
116 
117             std::map<std::string, PropertyVariantType> props;
118             msg.read(props);
119             auto it = props.find(_prop);
120             if (it == props.cend())
121             {
122                 // Property not included in dictionary of properties changed
123                 return;
124             }
125 
126             // Retrieve the property's value applying any visitors necessary
127             auto value =
128                 zone.getPropertyValueVisitor<T>(_intf, _prop, it->second);
129 
130             _handler(zone, _path, _intf, _prop, std::forward<T>(value));
131         }
132         else
133         {
134             try
135             {
136                 auto val = zone.getPropertyByName<T>(_path, _intf, _prop);
137                 _handler(zone, _path, _intf, _prop, std::forward<T>(val));
138             }
139             catch (const sdbusplus::exception::SdBusError&)
140             {
141                 // Property will not be used unless a property changed
142                 // signal message is received for this property.
143             }
144             catch (const util::DBusError&)
145             {
146                 // Property will not be used unless a property changed
147                 // signal message is received for this property.
148             }
149         }
150     }
151 
152     /** @brief Run init handler function
153      *
154      * Get the property from each member object of the group
155      * and run the handler function.
156      */
157     void operator()(Zone& zone, const Group& group) const
158     {
159         std::for_each(
160             group.begin(), group.end(),
161             [&zone, handler = std::move(_handler)](auto const& member) {
162                 auto path = std::get<pathPos>(member);
163                 auto intf = std::get<intfPos>(member);
164                 auto prop = std::get<propPos>(member);
165                 try
166                 {
167                     auto val = zone.getPropertyByName<T>(path, intf, prop);
168                     handler(zone, path, intf, prop, std::forward<T>(val));
169                 }
170                 catch (const sdbusplus::exception::SdBusError&)
171                 {
172                     // Property value not sent to handler
173                 }
174                 catch (const util::DBusError&)
175                 {
176                     // Property value not sent to handler
177                 }
178             });
179     }
180 
181   private:
182     const char* _path;
183     const char* _intf;
184     const char* _prop;
185     U _handler;
186 };
187 
188 /**
189  * @brief Used to process a Dbus properties changed signal event
190  *
191  * @param[in] path - Object path
192  * @param[in] intf - Object interface
193  * @param[in] prop - Object property
194  * @param[in] handler - Handler function to perform
195  *
196  * @tparam T - The type of the property
197  * @tparam U - The type of the handler
198  */
199 template <typename T, typename U>
200 auto propertiesChanged(const char* path, const char* intf, const char* prop,
201                        U&& handler)
202 {
203     return Properties<T, U>(path, intf, prop, std::forward<U>(handler));
204 }
205 
206 /**
207  * @brief Used to get the properties of an event's group
208  *
209  * @param[in] handler - Handler function to perform
210  *
211  * @tparam T - The type of all the properties
212  * @tparam U - The type of the handler
213  */
214 template <typename T, typename U>
215 auto getProperties(U&& handler)
216 {
217     return Properties<T, U>(std::forward<U>(handler));
218 }
219 
220 /**
221  * @struct Interfaces Added
222  * @brief A match filter functor for Dbus interfaces added signals
223  *
224  * @tparam T - The type of the property value
225  * @tparam U - The type of the handler
226  */
227 template <typename T, typename U>
228 struct InterfacesAdded
229 {
230     InterfacesAdded() = delete;
231     ~InterfacesAdded() = default;
232     InterfacesAdded(const InterfacesAdded&) = default;
233     InterfacesAdded& operator=(const InterfacesAdded&) = default;
234     InterfacesAdded(InterfacesAdded&&) = default;
235     InterfacesAdded& operator=(InterfacesAdded&&) = default;
236     InterfacesAdded(const char* path, const char* intf, const char* prop,
237                     U&& handler) :
238         _path(path),
239         _intf(intf), _prop(prop), _handler(std::forward<U>(handler))
240     {}
241 
242     /** @brief Run signal handler function
243      *
244      * Extract the property from the InterfacesAdded
245      * message and run the handler function.
246      */
247     void operator()(sdbusplus::bus::bus&, sdbusplus::message::message& msg,
248                     Zone& zone) const
249     {
250         if (msg)
251         {
252             sdbusplus::message::object_path op;
253 
254             msg.read(op);
255             if (static_cast<const std::string&>(op) != _path)
256             {
257                 // Object path does not match this handler's path
258                 return;
259             }
260 
261             std::map<std::string, std::map<std::string, PropertyVariantType>>
262                 intfProp;
263             msg.read(intfProp);
264             auto itIntf = intfProp.find(_intf);
265             if (itIntf == intfProp.cend())
266             {
267                 // Interface not found on this handler's path
268                 return;
269             }
270             auto itProp = itIntf->second.find(_prop);
271             if (itProp == itIntf->second.cend())
272             {
273                 // Property not found on this handler's path
274                 return;
275             }
276 
277             // Retrieve the property's value applying any visitors necessary
278             auto value =
279                 zone.getPropertyValueVisitor<T>(_intf, _prop, itProp->second);
280 
281             _handler(zone, _path, _intf, _prop, std::forward<T>(value));
282         }
283     }
284 
285   private:
286     const char* _path;
287     const char* _intf;
288     const char* _prop;
289     U _handler;
290 };
291 
292 /**
293  * @brief Used to process a Dbus interfaces added signal event
294  *
295  * @param[in] path - Object path
296  * @param[in] intf - Object interface
297  * @param[in] prop - Object property
298  * @param[in] handler - Handler function to perform
299  *
300  * @tparam T - The type of the property
301  * @tparam U - The type of the handler
302  */
303 template <typename T, typename U>
304 auto interfacesAdded(const char* path, const char* intf, const char* prop,
305                      U&& handler)
306 {
307     return InterfacesAdded<T, U>(path, intf, prop, std::forward<U>(handler));
308 }
309 
310 /**
311  * @struct Interfaces Removed
312  * @brief A match filter functor for Dbus interfaces removed signals
313  *
314  * @tparam U - The type of the handler
315  */
316 template <typename U>
317 struct InterfacesRemoved
318 {
319     InterfacesRemoved() = delete;
320     ~InterfacesRemoved() = default;
321     InterfacesRemoved(const InterfacesRemoved&) = default;
322     InterfacesRemoved& operator=(const InterfacesRemoved&) = default;
323     InterfacesRemoved(InterfacesRemoved&&) = default;
324     InterfacesRemoved& operator=(InterfacesRemoved&&) = default;
325     InterfacesRemoved(const char* path, const char* intf, U&& handler) :
326         _path(path), _intf(intf), _handler(std::forward<U>(handler))
327     {}
328 
329     /** @brief Run signal handler function
330      *
331      * Extract the interfaces from the InterfacesRemoved
332      * message and run the handler function.
333      */
334     void operator()(sdbusplus::bus::bus&, sdbusplus::message::message& msg,
335                     Zone& zone) const
336     {
337         if (msg)
338         {
339             std::vector<std::string> intfs;
340             sdbusplus::message::object_path op;
341 
342             msg.read(op);
343             if (static_cast<const std::string&>(op) != _path)
344             {
345                 // Object path does not match this handler's path
346                 return;
347             }
348 
349             msg.read(intfs);
350             auto itIntf = std::find(intfs.begin(), intfs.end(), _intf);
351             if (itIntf == intfs.cend())
352             {
353                 // Interface not found on this handler's path
354                 return;
355             }
356 
357             _handler(zone);
358         }
359     }
360 
361   private:
362     const char* _path;
363     const char* _intf;
364     U _handler;
365 };
366 
367 /**
368  * @brief Used to process a Dbus interfaces removed signal event
369  *
370  * @param[in] path - Object path
371  * @param[in] intf - Object interface
372  * @param[in] handler - Handler function to perform
373  *
374  * @tparam U - The type of the handler
375  */
376 template <typename U>
377 auto interfacesRemoved(const char* path, const char* intf, U&& handler)
378 {
379     return InterfacesRemoved<U>(path, intf, std::forward<U>(handler));
380 }
381 
382 /**
383  * @struct Name Owner
384  * @brief A functor for Dbus name owner signals and methods
385  *
386  * @tparam U - The type of the handler
387  */
388 template <typename U>
389 struct NameOwner
390 {
391     NameOwner() = delete;
392     ~NameOwner() = default;
393     NameOwner(const NameOwner&) = default;
394     NameOwner& operator=(const NameOwner&) = default;
395     NameOwner(NameOwner&&) = default;
396     NameOwner& operator=(NameOwner&&) = default;
397     explicit NameOwner(U&& handler) : _handler(std::forward<U>(handler))
398     {}
399 
400     /** @brief Run signal handler function
401      *
402      * Extract the name owner from the NameOwnerChanged
403      * message and run the handler function.
404      */
405     void operator()(sdbusplus::bus::bus& bus, sdbusplus::message::message& 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 
429     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)](auto const& 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>
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>
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