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