blob: 17ae3afe779767cb0e824c679e8fe495f3eb6632 [file] [log] [blame]
Matthew Barth38a93a82017-05-11 14:12:27 -05001#pragma once
2
3#include "types.hpp"
Matthew Barth336f18a2017-09-26 09:15:56 -05004#include "sdbusplus.hpp"
Matthew Barth38a93a82017-05-11 14:12:27 -05005#include <phosphor-logging/log.hpp>
6
7namespace phosphor
8{
9namespace fan
10{
11namespace control
12{
13class Zone;
14
Matthew Barth336f18a2017-09-26 09:15:56 -050015using namespace phosphor::fan;
Matthew Barth5a302572017-10-03 11:27:06 -050016using namespace sdbusplus::bus::match;
Matthew Barth38a93a82017-05-11 14:12:27 -050017using namespace phosphor::logging;
18
19/**
20 * @brief Create a handler function object
21 *
22 * @param[in] handler - The handler being created
23 *
24 * @return - The created handler function object
25 */
26template <typename T>
27auto make_handler(T&& handler)
28{
29 return Handler(std::forward<T>(handler));
30}
31
32/**
Matthew Barth17d1fe22017-05-11 15:00:36 -050033 * @brief Create an action function object
34 *
35 * @param[in] action - The action being created
36 *
37 * @return - The created action function object
38 */
39template <typename T>
40auto make_action(T&& action)
41{
42 return Action(std::forward<T>(action));
43}
44
45/**
Matthew Barth38a93a82017-05-11 14:12:27 -050046 * @struct Property Changed
47 * @brief A match filter functor for Dbus property value changed signals
48 *
49 * @tparam T - The type of the property value
50 * @tparam U - The type of the handler
51 */
52template <typename T, typename U>
53struct PropertyChanged
54{
55 PropertyChanged() = delete;
56 ~PropertyChanged() = default;
57 PropertyChanged(const PropertyChanged&) = default;
58 PropertyChanged& operator=(const PropertyChanged&) = default;
59 PropertyChanged(PropertyChanged&&) = default;
60 PropertyChanged& operator=(PropertyChanged&&) = default;
Matthew Barth336f18a2017-09-26 09:15:56 -050061 PropertyChanged(const char* path,
62 const char* iface,
Matthew Barth38a93a82017-05-11 14:12:27 -050063 const char* property,
64 U&& handler) :
Matthew Barth336f18a2017-09-26 09:15:56 -050065 _path(path),
Matthew Barth38a93a82017-05-11 14:12:27 -050066 _iface(iface),
67 _property(property),
68 _handler(std::forward<U>(handler)) { }
69
70 /** @brief Run signal handler function
71 *
72 * Extract the property from the PropertiesChanged
Matthew Barth336f18a2017-09-26 09:15:56 -050073 * message (or read the property when the message is null)
74 * and run the handler function.
Matthew Barth38a93a82017-05-11 14:12:27 -050075 */
Matthew Barth336f18a2017-09-26 09:15:56 -050076 void operator()(sdbusplus::bus::bus& bus,
Matthew Barth38a93a82017-05-11 14:12:27 -050077 sdbusplus::message::message& msg,
78 Zone& zone) const
79 {
Matthew Barth336f18a2017-09-26 09:15:56 -050080 if (msg)
Matthew Barth38a93a82017-05-11 14:12:27 -050081 {
Matthew Barth336f18a2017-09-26 09:15:56 -050082 std::map<std::string, sdbusplus::message::variant<T>> properties;
Matthew Barthd5cfdbe2017-11-14 15:29:50 -060083 std::string iface;
Matthew Barth38a93a82017-05-11 14:12:27 -050084
Matthew Barth336f18a2017-09-26 09:15:56 -050085 msg.read(iface);
Matthew Barthd5cfdbe2017-11-14 15:29:50 -060086 if (iface != _iface)
Matthew Barth336f18a2017-09-26 09:15:56 -050087 {
88 return;
89 }
90
91 msg.read(properties);
92 auto it = properties.find(_property);
93 if (it == properties.cend())
94 {
95 log<level::ERR>("Unable to find property on interface",
96 entry("PROPERTY=%s", _property),
Matthew Barthe65f6172017-12-11 13:36:02 -060097 entry("INTERFACE=%s", _iface),
98 entry("PATH=%s", _path));
Matthew Barth336f18a2017-09-26 09:15:56 -050099 return;
100 }
101
102 _handler(zone, std::forward<T>(it->second.template get<T>()));
103 }
104 else
Matthew Barth38a93a82017-05-11 14:12:27 -0500105 {
Matthew Barth336f18a2017-09-26 09:15:56 -0500106 try
107 {
Matthew Barthc72b8912018-01-19 17:28:18 -0600108 auto service = zone.getService(_path, _iface);
Matthew Barth336f18a2017-09-26 09:15:56 -0500109 auto val = util::SDBusPlus::getProperty<T>(bus,
Matthew Barthc72b8912018-01-19 17:28:18 -0600110 service,
Matthew Barth336f18a2017-09-26 09:15:56 -0500111 _path,
112 _iface,
113 _property);
114 _handler(zone, std::forward<T>(val));
115 }
Matt Spinlerba7b5fe2018-04-25 15:26:10 -0500116 catch (const util::DBusError& e)
Matthew Barth336f18a2017-09-26 09:15:56 -0500117 {
118 // Property will not be used unless a property changed
119 // signal message is received for this property.
Matthew Barth336f18a2017-09-26 09:15:56 -0500120 }
Matthew Barth38a93a82017-05-11 14:12:27 -0500121 }
Matthew Barth38a93a82017-05-11 14:12:27 -0500122 }
123
124private:
Matthew Barth336f18a2017-09-26 09:15:56 -0500125 const char* _path;
Matthew Barth38a93a82017-05-11 14:12:27 -0500126 const char* _iface;
127 const char* _property;
128 U _handler;
129};
130
131/**
132 * @brief Used to process a Dbus property changed signal event
133 *
Matthew Barth336f18a2017-09-26 09:15:56 -0500134 * @param[in] path - Object path
135 * @param[in] iface - Object interface
136 * @param[in] property - Object property
Matthew Barth38a93a82017-05-11 14:12:27 -0500137 * @param[in] handler - Handler function to perform
138 *
139 * @tparam T - The type of the property
140 * @tparam U - The type of the handler
141 */
142template <typename T, typename U>
Matthew Barth336f18a2017-09-26 09:15:56 -0500143auto propertySignal(const char* path,
144 const char* iface,
Matthew Barth38a93a82017-05-11 14:12:27 -0500145 const char* property,
146 U&& handler)
147{
Matthew Barth336f18a2017-09-26 09:15:56 -0500148 return PropertyChanged<T, U>(path,
149 iface,
150 property,
151 std::forward<U>(handler));
Matthew Barth38a93a82017-05-11 14:12:27 -0500152}
153
Matthew Bartheb639c52017-08-04 09:43:11 -0500154/**
155 * @struct Interface Added
156 * @brief A match filter functor for Dbus interface added signals
157 *
158 * @tparam T - The type of the property value
159 * @tparam U - The type of the handler
160 */
161template <typename T, typename U>
162struct InterfaceAdded
163{
164 InterfaceAdded() = delete;
165 ~InterfaceAdded() = default;
166 InterfaceAdded(const InterfaceAdded&) = default;
167 InterfaceAdded& operator=(const InterfaceAdded&) = default;
168 InterfaceAdded(InterfaceAdded&&) = default;
169 InterfaceAdded& operator=(InterfaceAdded&&) = default;
170 InterfaceAdded(const char* path,
171 const char* iface,
172 const char* property,
173 U&& handler) :
174 _path(path),
175 _iface(iface),
176 _property(property),
177 _handler(std::forward<U>(handler)) { }
178
179 /** @brief Run signal handler function
180 *
181 * Extract the property from the InterfacesAdded
182 * message and run the handler function.
183 */
184 void operator()(sdbusplus::bus::bus&,
185 sdbusplus::message::message& msg,
186 Zone& zone) const
187 {
Matthew Barth336f18a2017-09-26 09:15:56 -0500188 if (msg)
Matthew Bartheb639c52017-08-04 09:43:11 -0500189 {
Matthew Barth336f18a2017-09-26 09:15:56 -0500190 std::map<std::string,
191 std::map<std::string,
192 sdbusplus::message::variant<T>>> intfProp;
193 sdbusplus::message::object_path op;
Matthew Bartheb639c52017-08-04 09:43:11 -0500194
Matthew Barth336f18a2017-09-26 09:15:56 -0500195 msg.read(op);
Matthew Barthd5cfdbe2017-11-14 15:29:50 -0600196 if (static_cast<const std::string&>(op) != _path)
Matthew Barth336f18a2017-09-26 09:15:56 -0500197 {
198 // Object path does not match this handler's path
199 return;
200 }
Matthew Bartheb639c52017-08-04 09:43:11 -0500201
Matthew Barth336f18a2017-09-26 09:15:56 -0500202 msg.read(intfProp);
203 auto itIntf = intfProp.find(_iface);
204 if (itIntf == intfProp.cend())
205 {
206 // Interface not found on this handler's path
207 return;
208 }
209 auto itProp = itIntf->second.find(_property);
210 if (itProp == itIntf->second.cend())
211 {
212 // Property not found on this handler's path
213 return;
214 }
215
216 _handler(zone, std::forward<T>(itProp->second.template get<T>()));
217 }
Matthew Bartheb639c52017-08-04 09:43:11 -0500218 }
219
220private:
221 const char* _path;
222 const char* _iface;
223 const char* _property;
224 U _handler;
225};
226
227/**
228 * @brief Used to process a Dbus interface added signal event
229 *
230 * @param[in] path - Object path
231 * @param[in] iface - Object interface
232 * @param[in] property - Object property
233 * @param[in] handler - Handler function to perform
234 *
235 * @tparam T - The type of the property
236 * @tparam U - The type of the handler
237 */
238template <typename T, typename U>
239auto objectSignal(const char* path,
240 const char* iface,
241 const char* property,
242 U&& handler)
243{
244 return InterfaceAdded<T, U>(path,
245 iface,
246 property,
247 std::forward<U>(handler));
248}
249
Matthew Barth8fa02da2017-09-28 12:18:20 -0500250/**
Matthew Barth1499a5c2018-03-20 15:52:33 -0500251 * @struct Interface Removed
252 * @brief A match filter functor for Dbus interface removed signals
253 *
254 * @tparam U - The type of the handler
255 */
256template <typename U>
257struct InterfaceRemoved
258{
259 InterfaceRemoved() = delete;
260 ~InterfaceRemoved() = default;
261 InterfaceRemoved(const InterfaceRemoved&) = default;
262 InterfaceRemoved& operator=(const InterfaceRemoved&) = default;
263 InterfaceRemoved(InterfaceRemoved&&) = default;
264 InterfaceRemoved& operator=(InterfaceRemoved&&) = default;
265 InterfaceRemoved(const char* path,
266 const char* iface,
267 U&& handler) :
268 _path(path),
269 _iface(iface),
270 _handler(std::forward<U>(handler)) { }
271
272 /** @brief Run signal handler function
273 *
274 * Extract the property from the InterfacesRemoved
275 * message and run the handler function.
276 */
277 void operator()(sdbusplus::bus::bus&,
278 sdbusplus::message::message& msg,
279 Zone& zone) const
280 {
281 if (msg)
282 {
283 std::vector<std::string> intfs;
284 sdbusplus::message::object_path op;
285
286 msg.read(op);
287 if (static_cast<const std::string&>(op) != _path)
288 {
289 // Object path does not match this handler's path
290 return;
291 }
292
293 msg.read(intfs);
294 auto itIntf = std::find(intfs.begin(), intfs.end(), _iface);
295 if (itIntf == intfs.cend())
296 {
297 // Interface not found on this handler's path
298 return;
299 }
300
301 _handler(zone);
302 }
303 }
304
305private:
306 const char* _path;
307 const char* _iface;
308 U _handler;
309};
310
311/**
312 * @brief Used to process a Dbus interface removed signal event
313 *
314 * @param[in] path - Object path
315 * @param[in] iface - Object interface
316 * @param[in] handler - Handler function to perform
317 *
318 * @tparam U - The type of the handler
319 */
320template <typename U>
321auto objectSignal(const char* path,
322 const char* iface,
323 U&& handler)
324{
325 return InterfaceRemoved<U>(path,
326 iface,
327 std::forward<U>(handler));
328}
329
330/**
Matthew Barth8fa02da2017-09-28 12:18:20 -0500331 * @struct Name Owner Changed
332 * @brief A match filter functor for Dbus name owner changed signals
333 *
334 * @tparam U - The type of the handler
335 */
336template <typename U>
337struct NameOwnerChanged
338{
339 NameOwnerChanged() = delete;
340 ~NameOwnerChanged() = default;
341 NameOwnerChanged(const NameOwnerChanged&) = default;
342 NameOwnerChanged& operator=(const NameOwnerChanged&) = default;
343 NameOwnerChanged(NameOwnerChanged&&) = default;
344 NameOwnerChanged& operator=(NameOwnerChanged&&) = default;
345 NameOwnerChanged(const char* path,
346 const char* iface,
347 U&& handler) :
348 _path(path),
349 _iface(iface),
350 _handler(std::forward<U>(handler)) { }
351
352 /** @brief Run signal handler function
353 *
354 * Extract the name owner from the NameOwnerChanged
355 * message (or read the name owner when the message is null)
356 * and run the handler function.
357 */
358 void operator()(sdbusplus::bus::bus& bus,
359 sdbusplus::message::message& msg,
360 Zone& zone) const
361 {
Matthew Barth5a302572017-10-03 11:27:06 -0500362 std::string name;
363 bool hasOwner = false;
Matthew Barth8fa02da2017-09-28 12:18:20 -0500364 if (msg)
365 {
Matthew Barth5a302572017-10-03 11:27:06 -0500366 // Handle NameOwnerChanged signals
367 msg.read(name);
368
369 std::string oldOwn;
370 msg.read(oldOwn);
371
372 std::string newOwn;
373 msg.read(newOwn);
374 if (!newOwn.empty())
375 {
376 hasOwner = true;
377 }
Matthew Barth8fa02da2017-09-28 12:18:20 -0500378 }
379 else
380 {
Matthew Barth5a302572017-10-03 11:27:06 -0500381 try
382 {
383 // Initialize NameOwnerChanged data store with service name
Matthew Barthc72b8912018-01-19 17:28:18 -0600384 name = zone.getService(_path, _iface);
Matthew Barth5a302572017-10-03 11:27:06 -0500385 hasOwner = util::SDBusPlus::callMethodAndRead<bool>(
386 bus,
387 "org.freedesktop.DBus",
388 "/org/freedesktop/DBus",
389 "org.freedesktop.DBus",
390 "NameHasOwner",
391 name);
392 }
Matt Spinlerba7b5fe2018-04-25 15:26:10 -0500393 catch (const util::DBusMethodError& e)
Matthew Barth5a302572017-10-03 11:27:06 -0500394 {
395 // Failed to get service name owner state
396 hasOwner = false;
397 }
Matthew Barth8fa02da2017-09-28 12:18:20 -0500398 }
Matthew Barth5a302572017-10-03 11:27:06 -0500399
400 _handler(zone, name, hasOwner);
Matthew Barth8fa02da2017-09-28 12:18:20 -0500401 }
402
403private:
404 const char* _path;
405 const char* _iface;
406 U _handler;
407};
408
409/**
410 * @brief Used to process a Dbus name owner changed signal event
411 *
412 * @param[in] path - Object path
413 * @param[in] iface - Object interface
414 * @param[in] handler - Handler function to perform
415 *
416 * @tparam U - The type of the handler
417 *
418 * @return - The NameOwnerChanged signal struct
419 */
420template <typename U>
421auto ownerSignal(const char* path,
422 const char* iface,
423 U&& handler)
424{
425 return NameOwnerChanged<U>(path,
426 iface,
427 std::forward<U>(handler));
428}
429
Matthew Barth38a93a82017-05-11 14:12:27 -0500430} // namespace control
431} // namespace fan
432} // namespace phosphor