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