blob: e86bae7e89d72264641774905f9717cbf53c415c [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 }
Matthew Barth86be4762018-07-17 10:51:36 -0500116 catch (const sdbusplus::exception::SdBusError&)
117 {
118 // Property will not be used unless a property changed
119 // signal message is received for this property.
120 }
121 catch (const util::DBusError&)
Matthew Barth336f18a2017-09-26 09:15:56 -0500122 {
123 // Property will not be used unless a property changed
124 // signal message is received for this property.
Matthew Barth336f18a2017-09-26 09:15:56 -0500125 }
Matthew Barth38a93a82017-05-11 14:12:27 -0500126 }
Matthew Barth38a93a82017-05-11 14:12:27 -0500127 }
128
129private:
Matthew Barth336f18a2017-09-26 09:15:56 -0500130 const char* _path;
Matthew Barth38a93a82017-05-11 14:12:27 -0500131 const char* _iface;
132 const char* _property;
133 U _handler;
134};
135
136/**
137 * @brief Used to process a Dbus property changed signal event
138 *
Matthew Barth336f18a2017-09-26 09:15:56 -0500139 * @param[in] path - Object path
140 * @param[in] iface - Object interface
141 * @param[in] property - Object property
Matthew Barth38a93a82017-05-11 14:12:27 -0500142 * @param[in] handler - Handler function to perform
143 *
144 * @tparam T - The type of the property
145 * @tparam U - The type of the handler
146 */
147template <typename T, typename U>
Matthew Barth336f18a2017-09-26 09:15:56 -0500148auto propertySignal(const char* path,
149 const char* iface,
Matthew Barth38a93a82017-05-11 14:12:27 -0500150 const char* property,
151 U&& handler)
152{
Matthew Barth336f18a2017-09-26 09:15:56 -0500153 return PropertyChanged<T, U>(path,
154 iface,
155 property,
156 std::forward<U>(handler));
Matthew Barth38a93a82017-05-11 14:12:27 -0500157}
158
Matthew Bartheb639c52017-08-04 09:43:11 -0500159/**
160 * @struct Interface Added
161 * @brief A match filter functor for Dbus interface added signals
162 *
163 * @tparam T - The type of the property value
164 * @tparam U - The type of the handler
165 */
166template <typename T, typename U>
167struct InterfaceAdded
168{
169 InterfaceAdded() = delete;
170 ~InterfaceAdded() = default;
171 InterfaceAdded(const InterfaceAdded&) = default;
172 InterfaceAdded& operator=(const InterfaceAdded&) = default;
173 InterfaceAdded(InterfaceAdded&&) = default;
174 InterfaceAdded& operator=(InterfaceAdded&&) = default;
175 InterfaceAdded(const char* path,
176 const char* iface,
177 const char* property,
178 U&& handler) :
179 _path(path),
180 _iface(iface),
181 _property(property),
182 _handler(std::forward<U>(handler)) { }
183
184 /** @brief Run signal handler function
185 *
186 * Extract the property from the InterfacesAdded
187 * message and run the handler function.
188 */
189 void operator()(sdbusplus::bus::bus&,
190 sdbusplus::message::message& msg,
191 Zone& zone) const
192 {
Matthew Barth336f18a2017-09-26 09:15:56 -0500193 if (msg)
Matthew Bartheb639c52017-08-04 09:43:11 -0500194 {
Matthew Barth336f18a2017-09-26 09:15:56 -0500195 std::map<std::string,
196 std::map<std::string,
197 sdbusplus::message::variant<T>>> intfProp;
198 sdbusplus::message::object_path op;
Matthew Bartheb639c52017-08-04 09:43:11 -0500199
Matthew Barth336f18a2017-09-26 09:15:56 -0500200 msg.read(op);
Matthew Barthd5cfdbe2017-11-14 15:29:50 -0600201 if (static_cast<const std::string&>(op) != _path)
Matthew Barth336f18a2017-09-26 09:15:56 -0500202 {
203 // Object path does not match this handler's path
204 return;
205 }
Matthew Bartheb639c52017-08-04 09:43:11 -0500206
Matthew Barth336f18a2017-09-26 09:15:56 -0500207 msg.read(intfProp);
208 auto itIntf = intfProp.find(_iface);
209 if (itIntf == intfProp.cend())
210 {
211 // Interface not found on this handler's path
212 return;
213 }
214 auto itProp = itIntf->second.find(_property);
215 if (itProp == itIntf->second.cend())
216 {
217 // Property not found on this handler's path
218 return;
219 }
220
221 _handler(zone, std::forward<T>(itProp->second.template get<T>()));
222 }
Matthew Bartheb639c52017-08-04 09:43:11 -0500223 }
224
225private:
226 const char* _path;
227 const char* _iface;
228 const char* _property;
229 U _handler;
230};
231
232/**
233 * @brief Used to process a Dbus interface added signal event
234 *
235 * @param[in] path - Object path
236 * @param[in] iface - Object interface
237 * @param[in] property - Object property
238 * @param[in] handler - Handler function to perform
239 *
240 * @tparam T - The type of the property
241 * @tparam U - The type of the handler
242 */
243template <typename T, typename U>
244auto objectSignal(const char* path,
245 const char* iface,
246 const char* property,
247 U&& handler)
248{
249 return InterfaceAdded<T, U>(path,
250 iface,
251 property,
252 std::forward<U>(handler));
253}
254
Matthew Barth8fa02da2017-09-28 12:18:20 -0500255/**
Matthew Barth1499a5c2018-03-20 15:52:33 -0500256 * @struct Interface Removed
257 * @brief A match filter functor for Dbus interface removed signals
258 *
259 * @tparam U - The type of the handler
260 */
261template <typename U>
262struct InterfaceRemoved
263{
264 InterfaceRemoved() = delete;
265 ~InterfaceRemoved() = default;
266 InterfaceRemoved(const InterfaceRemoved&) = default;
267 InterfaceRemoved& operator=(const InterfaceRemoved&) = default;
268 InterfaceRemoved(InterfaceRemoved&&) = default;
269 InterfaceRemoved& operator=(InterfaceRemoved&&) = default;
270 InterfaceRemoved(const char* path,
271 const char* iface,
272 U&& handler) :
273 _path(path),
274 _iface(iface),
275 _handler(std::forward<U>(handler)) { }
276
277 /** @brief Run signal handler function
278 *
279 * Extract the property from the InterfacesRemoved
280 * message and run the handler function.
281 */
282 void operator()(sdbusplus::bus::bus&,
283 sdbusplus::message::message& msg,
284 Zone& zone) const
285 {
286 if (msg)
287 {
288 std::vector<std::string> intfs;
289 sdbusplus::message::object_path op;
290
291 msg.read(op);
292 if (static_cast<const std::string&>(op) != _path)
293 {
294 // Object path does not match this handler's path
295 return;
296 }
297
298 msg.read(intfs);
299 auto itIntf = std::find(intfs.begin(), intfs.end(), _iface);
300 if (itIntf == intfs.cend())
301 {
302 // Interface not found on this handler's path
303 return;
304 }
305
306 _handler(zone);
307 }
308 }
309
310private:
311 const char* _path;
312 const char* _iface;
313 U _handler;
314};
315
316/**
317 * @brief Used to process a Dbus interface removed signal event
318 *
319 * @param[in] path - Object path
320 * @param[in] iface - Object interface
321 * @param[in] handler - Handler function to perform
322 *
323 * @tparam U - The type of the handler
324 */
325template <typename U>
326auto objectSignal(const char* path,
327 const char* iface,
328 U&& handler)
329{
330 return InterfaceRemoved<U>(path,
331 iface,
332 std::forward<U>(handler));
333}
334
335/**
Matthew Barth8fa02da2017-09-28 12:18:20 -0500336 * @struct Name Owner Changed
337 * @brief A match filter functor for Dbus name owner changed signals
338 *
339 * @tparam U - The type of the handler
340 */
341template <typename U>
342struct NameOwnerChanged
343{
344 NameOwnerChanged() = delete;
345 ~NameOwnerChanged() = default;
346 NameOwnerChanged(const NameOwnerChanged&) = default;
347 NameOwnerChanged& operator=(const NameOwnerChanged&) = default;
348 NameOwnerChanged(NameOwnerChanged&&) = default;
349 NameOwnerChanged& operator=(NameOwnerChanged&&) = default;
350 NameOwnerChanged(const char* path,
351 const char* iface,
352 U&& handler) :
353 _path(path),
354 _iface(iface),
355 _handler(std::forward<U>(handler)) { }
356
357 /** @brief Run signal handler function
358 *
359 * Extract the name owner from the NameOwnerChanged
360 * message (or read the name owner when the message is null)
361 * and run the handler function.
362 */
363 void operator()(sdbusplus::bus::bus& bus,
364 sdbusplus::message::message& msg,
365 Zone& zone) const
366 {
Matthew Barth5a302572017-10-03 11:27:06 -0500367 std::string name;
368 bool hasOwner = false;
Matthew Barth8fa02da2017-09-28 12:18:20 -0500369 if (msg)
370 {
Matthew Barth5a302572017-10-03 11:27:06 -0500371 // Handle NameOwnerChanged signals
372 msg.read(name);
373
374 std::string oldOwn;
375 msg.read(oldOwn);
376
377 std::string newOwn;
378 msg.read(newOwn);
379 if (!newOwn.empty())
380 {
381 hasOwner = true;
382 }
Matthew Barth8fa02da2017-09-28 12:18:20 -0500383 }
384 else
385 {
Matthew Barth5a302572017-10-03 11:27:06 -0500386 try
387 {
388 // Initialize NameOwnerChanged data store with service name
Matthew Barthc72b8912018-01-19 17:28:18 -0600389 name = zone.getService(_path, _iface);
Matthew Barth5a302572017-10-03 11:27:06 -0500390 hasOwner = util::SDBusPlus::callMethodAndRead<bool>(
391 bus,
392 "org.freedesktop.DBus",
393 "/org/freedesktop/DBus",
394 "org.freedesktop.DBus",
395 "NameHasOwner",
396 name);
397 }
Matt Spinlerba7b5fe2018-04-25 15:26:10 -0500398 catch (const util::DBusMethodError& e)
Matthew Barth5a302572017-10-03 11:27:06 -0500399 {
400 // Failed to get service name owner state
401 hasOwner = false;
402 }
Matthew Barth8fa02da2017-09-28 12:18:20 -0500403 }
Matthew Barth5a302572017-10-03 11:27:06 -0500404
405 _handler(zone, name, hasOwner);
Matthew Barth8fa02da2017-09-28 12:18:20 -0500406 }
407
408private:
409 const char* _path;
410 const char* _iface;
411 U _handler;
412};
413
414/**
415 * @brief Used to process a Dbus name owner changed signal event
416 *
417 * @param[in] path - Object path
418 * @param[in] iface - Object interface
419 * @param[in] handler - Handler function to perform
420 *
421 * @tparam U - The type of the handler
422 *
423 * @return - The NameOwnerChanged signal struct
424 */
425template <typename U>
426auto ownerSignal(const char* path,
427 const char* iface,
428 U&& handler)
429{
430 return NameOwnerChanged<U>(path,
431 iface,
432 std::forward<U>(handler));
433}
434
Matthew Barth38a93a82017-05-11 14:12:27 -0500435} // namespace control
436} // namespace fan
437} // namespace phosphor