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             msg.read(intf);
113             if (intf != _intf)
114             {
115                 // Interface name does not match on object
116                 return;
117             }
118 
119             std::map<std::string, PropertyVariantType> props;
120             msg.read(props);
121             auto it = props.find(_prop);
122             if (it == props.cend())
123             {
124                 // Property not included in dictionary of properties changed
125                 return;
126             }
127 
128             // Retrieve the property's value applying any visitors necessary
129             auto value =
130                 zone.getPropertyValueVisitor<T>(_intf, _prop, it->second);
131 
132             _handler(zone, _path, _intf, _prop, std::forward<T>(value));
133         }
134         else
135         {
136             try
137             {
138                 auto val = zone.getPropertyByName<T>(_path, _intf, _prop);
139                 _handler(zone, _path, _intf, _prop, std::forward<T>(val));
140             }
141             catch (const sdbusplus::exception::SdBusError&)
142             {
143                 // Property will not be used unless a property changed
144                 // signal message is received for this property.
145             }
146             catch (const util::DBusError&)
147             {
148                 // Property will not be used unless a property changed
149                 // signal message is received for this property.
150             }
151         }
152     }
153 
154     /** @brief Run init handler function
155      *
156      * Get the property from each member object of the group
157      * and run the handler function.
158      */
159     void operator()(Zone& zone, const Group& group) const
160     {
161         std::for_each(
162             group.begin(),
163             group.end(),
164             [&zone, handler = std::move(_handler)](auto const& member)
165             {
166                 auto path = std::get<pathPos>(member);
167                 auto intf = std::get<intfPos>(member);
168                 auto prop = std::get<propPos>(member);
169                 try
170                 {
171                     auto val = zone.getPropertyByName<T>(path, intf, prop);
172                     handler(zone, path, intf, prop, std::forward<T>(val));
173                 }
174                 catch (const sdbusplus::exception::SdBusError&)
175                 {
176                     // Property value not sent to handler
177                 }
178                 catch (const util::DBusError&)
179                 {
180                     // Property value not sent to handler
181                 }
182             }
183         );
184     }
185 
186 private:
187     const char* _path;
188     const char* _intf;
189     const char* _prop;
190     U _handler;
191 };
192 
193 /**
194  * @brief Used to process a Dbus properties changed signal event
195  *
196  * @param[in] path - Object path
197  * @param[in] intf - Object interface
198  * @param[in] prop - Object property
199  * @param[in] handler - Handler function to perform
200  *
201  * @tparam T - The type of the property
202  * @tparam U - The type of the handler
203  */
204 template <typename T, typename U>
205 auto propertiesChanged(const char* path,
206                        const char* intf,
207                        const char* prop,
208                        U&& handler)
209 {
210     return Properties<T, U>(path,
211                             intf,
212                             prop,
213                             std::forward<U>(handler));
214 }
215 
216 /**
217  * @brief Used to get the properties of an event's group
218  *
219  * @param[in] handler - Handler function to perform
220  *
221  * @tparam T - The type of all the properties
222  * @tparam U - The type of the handler
223  */
224 template <typename T, typename U>
225 auto getProperties(U&& handler)
226 {
227     return Properties<T, U>(std::forward<U>(handler));
228 }
229 
230 /**
231  * @struct Interfaces Added
232  * @brief A match filter functor for Dbus interfaces added signals
233  *
234  * @tparam T - The type of the property value
235  * @tparam U - The type of the handler
236  */
237 template <typename T, typename U>
238 struct InterfacesAdded
239 {
240     InterfacesAdded() = delete;
241     ~InterfacesAdded() = default;
242     InterfacesAdded(const InterfacesAdded&) = default;
243     InterfacesAdded& operator=(const InterfacesAdded&) = default;
244     InterfacesAdded(InterfacesAdded&&) = default;
245     InterfacesAdded& operator=(InterfacesAdded&&) = default;
246     InterfacesAdded(const char* path,
247                     const char* intf,
248                     const char* prop,
249                     U&& handler) :
250         _path(path),
251         _intf(intf),
252         _prop(prop),
253         _handler(std::forward<U>(handler)) { }
254 
255     /** @brief Run signal handler function
256      *
257      * Extract the property from the InterfacesAdded
258      * message and run the handler function.
259      */
260     void operator()(sdbusplus::bus::bus&,
261                     sdbusplus::message::message& msg,
262                     Zone& zone) const
263     {
264         if (msg)
265         {
266             sdbusplus::message::object_path op;
267 
268             msg.read(op);
269             if (static_cast<const std::string&>(op) != _path)
270             {
271                 // Object path does not match this handler's path
272                 return;
273             }
274 
275             std::map<std::string, std::map<std::string,
276                     PropertyVariantType>> intfProp;
277             msg.read(intfProp);
278             auto itIntf = intfProp.find(_intf);
279             if (itIntf == intfProp.cend())
280             {
281                 // Interface not found on this handler's path
282                 return;
283             }
284             auto itProp = itIntf->second.find(_prop);
285             if (itProp == itIntf->second.cend())
286             {
287                 // Property not found on this handler's path
288                 return;
289             }
290 
291             // Retrieve the property's value applying any visitors necessary
292             auto value =
293                 zone.getPropertyValueVisitor<T>(_intf, _prop, itProp->second);
294 
295             _handler(zone, _path, _intf, _prop, std::forward<T>(value));
296         }
297     }
298 
299 private:
300     const char* _path;
301     const char* _intf;
302     const char* _prop;
303     U _handler;
304 };
305 
306 /**
307  * @brief Used to process a Dbus interfaces added signal event
308  *
309  * @param[in] path - Object path
310  * @param[in] intf - Object interface
311  * @param[in] prop - Object property
312  * @param[in] handler - Handler function to perform
313  *
314  * @tparam T - The type of the property
315  * @tparam U - The type of the handler
316  */
317 template <typename T, typename U>
318 auto interfacesAdded(const char* path,
319                      const char* intf,
320                      const char* prop,
321                      U&& handler)
322 {
323     return InterfacesAdded<T, U>(path,
324                                  intf,
325                                  prop,
326                                  std::forward<U>(handler));
327 }
328 
329 /**
330  * @struct Interfaces Removed
331  * @brief A match filter functor for Dbus interfaces removed signals
332  *
333  * @tparam U - The type of the handler
334  */
335 template <typename U>
336 struct InterfacesRemoved
337 {
338     InterfacesRemoved() = delete;
339     ~InterfacesRemoved() = default;
340     InterfacesRemoved(const InterfacesRemoved&) = default;
341     InterfacesRemoved& operator=(const InterfacesRemoved&) = default;
342     InterfacesRemoved(InterfacesRemoved&&) = default;
343     InterfacesRemoved& operator=(InterfacesRemoved&&) = default;
344     InterfacesRemoved(const char* path,
345                       const char* intf,
346                       U&& handler) :
347         _path(path),
348         _intf(intf),
349         _handler(std::forward<U>(handler)) { }
350 
351     /** @brief Run signal handler function
352      *
353      * Extract the interfaces from the InterfacesRemoved
354      * message and run the handler function.
355      */
356     void operator()(sdbusplus::bus::bus&,
357                     sdbusplus::message::message& msg,
358                     Zone& zone) const
359     {
360         if (msg)
361         {
362             std::vector<std::string> intfs;
363             sdbusplus::message::object_path op;
364 
365             msg.read(op);
366             if (static_cast<const std::string&>(op) != _path)
367             {
368                 // Object path does not match this handler's path
369                 return;
370             }
371 
372             msg.read(intfs);
373             auto itIntf = std::find(intfs.begin(), intfs.end(), _intf);
374             if (itIntf == intfs.cend())
375             {
376                 // Interface not found on this handler's path
377                 return;
378             }
379 
380             _handler(zone);
381         }
382     }
383 
384 private:
385     const char* _path;
386     const char* _intf;
387     U _handler;
388 };
389 
390 /**
391  * @brief Used to process a Dbus interfaces removed signal event
392  *
393  * @param[in] path - Object path
394  * @param[in] intf - Object interface
395  * @param[in] handler - Handler function to perform
396  *
397  * @tparam U - The type of the handler
398  */
399 template <typename U>
400 auto interfacesRemoved(const char* path,
401                        const char* intf,
402                        U&& handler)
403 {
404     return InterfacesRemoved<U>(path,
405                                 intf,
406                                 std::forward<U>(handler));
407 }
408 
409 /**
410  * @struct Name Owner
411  * @brief A functor for Dbus name owner signals and methods
412  *
413  * @tparam U - The type of the handler
414  */
415 template <typename U>
416 struct NameOwner
417 {
418     NameOwner() = delete;
419     ~NameOwner() = default;
420     NameOwner(const NameOwner&) = default;
421     NameOwner& operator=(const NameOwner&) = default;
422     NameOwner(NameOwner&&) = default;
423     NameOwner& operator=(NameOwner&&) = default;
424     explicit NameOwner(U&& handler) :
425         _handler(std::forward<U>(handler)) { }
426 
427     /** @brief Run signal handler function
428      *
429      * Extract the name owner from the NameOwnerChanged
430      * message and run the handler function.
431      */
432     void operator()(sdbusplus::bus::bus& bus,
433                     sdbusplus::message::message& msg,
434                     Zone& zone) const
435     {
436         std::string name;
437         bool hasOwner = false;
438         if (msg)
439         {
440             // Handle NameOwnerChanged signals
441             msg.read(name);
442 
443             std::string oldOwn;
444             msg.read(oldOwn);
445 
446             std::string newOwn;
447             msg.read(newOwn);
448             if (!newOwn.empty())
449             {
450                 hasOwner = true;
451             }
452             _handler(zone, name, hasOwner);
453         }
454     }
455 
456     void operator()(Zone& zone,
457                     const Group& group) const
458     {
459         std::string name = "";
460         bool hasOwner = false;
461         std::for_each(
462             group.begin(),
463             group.end(),
464             [&zone, &group, &name, &hasOwner, handler = std::move(_handler)](
465                 auto const& member)
466             {
467                 auto path = std::get<pathPos>(member);
468                 auto intf = std::get<intfPos>(member);
469                 try
470                 {
471                     auto servName = zone.getService(path, intf);
472                     if (name != servName)
473                     {
474                         name = servName;
475                         hasOwner = util::SDBusPlus::callMethodAndRead<bool>(
476                                 zone.getBus(),
477                                 "org.freedesktop.DBus",
478                                 "/org/freedesktop/DBus",
479                                 "org.freedesktop.DBus",
480                                 "NameHasOwner",
481                                 name);
482                         // Update service name owner state list of a group
483                         handler(zone, name, hasOwner);
484                     }
485                 }
486                 catch (const util::DBusMethodError& e)
487                 {
488                     // Failed to get service name owner state
489                     name = "";
490                     hasOwner = false;
491                 }
492             }
493         );
494     }
495 
496 private:
497     U _handler;
498 };
499 
500 /**
501  * @brief Used to process a Dbus name owner changed signal event
502  *
503  * @param[in] handler - Handler function to perform
504  *
505  * @tparam U - The type of the handler
506  *
507  * @return - The NameOwnerChanged signal struct
508  */
509 template <typename U>
510 auto nameOwnerChanged(U&& handler)
511 {
512     return NameOwner<U>(std::forward<U>(handler));
513 }
514 
515 /**
516  * @brief Used to process the init of a name owner event
517  *
518  * @param[in] handler - Handler function to perform
519  *
520  * @tparam U - The type of the handler
521  *
522  * @return - The NameOwnerChanged signal struct
523  */
524 template <typename U>
525 auto nameHasOwner(U&& handler)
526 {
527     return NameOwner<U>(std::forward<U>(handler));
528 }
529 
530 } // namespace control
531 } // namespace fan
532 } // namespace phosphor
533