blob: b96f650d2a717b7637ac736006eacb2de8ed98e6 [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
William A. Kennington III4978e062018-11-27 11:47:12 -0800102 _handler(zone, std::forward<T>(
103 sdbusplus::message::variant_ns::get<T>(it->second)));
Matthew Barth336f18a2017-09-26 09:15:56 -0500104 }
105 else
Matthew Barth38a93a82017-05-11 14:12:27 -0500106 {
Matthew Barth336f18a2017-09-26 09:15:56 -0500107 try
108 {
Matthew Barthc72b8912018-01-19 17:28:18 -0600109 auto service = zone.getService(_path, _iface);
Matthew Barth336f18a2017-09-26 09:15:56 -0500110 auto val = util::SDBusPlus::getProperty<T>(bus,
Matthew Barthc72b8912018-01-19 17:28:18 -0600111 service,
Matthew Barth336f18a2017-09-26 09:15:56 -0500112 _path,
113 _iface,
114 _property);
115 _handler(zone, std::forward<T>(val));
116 }
Matthew Barth86be4762018-07-17 10:51:36 -0500117 catch (const sdbusplus::exception::SdBusError&)
118 {
119 // Property will not be used unless a property changed
120 // signal message is received for this property.
121 }
122 catch (const util::DBusError&)
Matthew Barth336f18a2017-09-26 09:15:56 -0500123 {
124 // Property will not be used unless a property changed
125 // signal message is received for this property.
Matthew Barth336f18a2017-09-26 09:15:56 -0500126 }
Matthew Barth38a93a82017-05-11 14:12:27 -0500127 }
Matthew Barth38a93a82017-05-11 14:12:27 -0500128 }
129
130private:
Matthew Barth336f18a2017-09-26 09:15:56 -0500131 const char* _path;
Matthew Barth38a93a82017-05-11 14:12:27 -0500132 const char* _iface;
133 const char* _property;
134 U _handler;
135};
136
137/**
138 * @brief Used to process a Dbus property changed signal event
139 *
Matthew Barth336f18a2017-09-26 09:15:56 -0500140 * @param[in] path - Object path
141 * @param[in] iface - Object interface
142 * @param[in] property - Object property
Matthew Barth38a93a82017-05-11 14:12:27 -0500143 * @param[in] handler - Handler function to perform
144 *
145 * @tparam T - The type of the property
146 * @tparam U - The type of the handler
147 */
148template <typename T, typename U>
Matthew Barth336f18a2017-09-26 09:15:56 -0500149auto propertySignal(const char* path,
150 const char* iface,
Matthew Barth38a93a82017-05-11 14:12:27 -0500151 const char* property,
152 U&& handler)
153{
Matthew Barth336f18a2017-09-26 09:15:56 -0500154 return PropertyChanged<T, U>(path,
155 iface,
156 property,
157 std::forward<U>(handler));
Matthew Barth38a93a82017-05-11 14:12:27 -0500158}
159
Matthew Bartheb639c52017-08-04 09:43:11 -0500160/**
161 * @struct Interface Added
162 * @brief A match filter functor for Dbus interface added signals
163 *
164 * @tparam T - The type of the property value
165 * @tparam U - The type of the handler
166 */
167template <typename T, typename U>
168struct InterfaceAdded
169{
170 InterfaceAdded() = delete;
171 ~InterfaceAdded() = default;
172 InterfaceAdded(const InterfaceAdded&) = default;
173 InterfaceAdded& operator=(const InterfaceAdded&) = default;
174 InterfaceAdded(InterfaceAdded&&) = default;
175 InterfaceAdded& operator=(InterfaceAdded&&) = default;
176 InterfaceAdded(const char* path,
177 const char* iface,
178 const char* property,
179 U&& handler) :
180 _path(path),
181 _iface(iface),
182 _property(property),
183 _handler(std::forward<U>(handler)) { }
184
185 /** @brief Run signal handler function
186 *
187 * Extract the property from the InterfacesAdded
188 * message and run the handler function.
189 */
190 void operator()(sdbusplus::bus::bus&,
191 sdbusplus::message::message& msg,
192 Zone& zone) const
193 {
Matthew Barth336f18a2017-09-26 09:15:56 -0500194 if (msg)
Matthew Bartheb639c52017-08-04 09:43:11 -0500195 {
Matthew Barth336f18a2017-09-26 09:15:56 -0500196 std::map<std::string,
197 std::map<std::string,
198 sdbusplus::message::variant<T>>> intfProp;
199 sdbusplus::message::object_path op;
Matthew Bartheb639c52017-08-04 09:43:11 -0500200
Matthew Barth336f18a2017-09-26 09:15:56 -0500201 msg.read(op);
Matthew Barthd5cfdbe2017-11-14 15:29:50 -0600202 if (static_cast<const std::string&>(op) != _path)
Matthew Barth336f18a2017-09-26 09:15:56 -0500203 {
204 // Object path does not match this handler's path
205 return;
206 }
Matthew Bartheb639c52017-08-04 09:43:11 -0500207
Matthew Barth336f18a2017-09-26 09:15:56 -0500208 msg.read(intfProp);
209 auto itIntf = intfProp.find(_iface);
210 if (itIntf == intfProp.cend())
211 {
212 // Interface not found on this handler's path
213 return;
214 }
215 auto itProp = itIntf->second.find(_property);
216 if (itProp == itIntf->second.cend())
217 {
218 // Property not found on this handler's path
219 return;
220 }
221
William A. Kennington III4978e062018-11-27 11:47:12 -0800222 _handler(zone, std::forward<T>(
223 sdbusplus::message::variant_ns::get<T>(itProp->second)));
Matthew Barth336f18a2017-09-26 09:15:56 -0500224 }
Matthew Bartheb639c52017-08-04 09:43:11 -0500225 }
226
227private:
228 const char* _path;
229 const char* _iface;
230 const char* _property;
231 U _handler;
232};
233
234/**
235 * @brief Used to process a Dbus interface added signal event
236 *
237 * @param[in] path - Object path
238 * @param[in] iface - Object interface
239 * @param[in] property - Object property
240 * @param[in] handler - Handler function to perform
241 *
242 * @tparam T - The type of the property
243 * @tparam U - The type of the handler
244 */
245template <typename T, typename U>
246auto objectSignal(const char* path,
247 const char* iface,
248 const char* property,
249 U&& handler)
250{
251 return InterfaceAdded<T, U>(path,
252 iface,
253 property,
254 std::forward<U>(handler));
255}
256
Matthew Barth8fa02da2017-09-28 12:18:20 -0500257/**
Matthew Barth1499a5c2018-03-20 15:52:33 -0500258 * @struct Interface Removed
259 * @brief A match filter functor for Dbus interface removed signals
260 *
261 * @tparam U - The type of the handler
262 */
263template <typename U>
264struct InterfaceRemoved
265{
266 InterfaceRemoved() = delete;
267 ~InterfaceRemoved() = default;
268 InterfaceRemoved(const InterfaceRemoved&) = default;
269 InterfaceRemoved& operator=(const InterfaceRemoved&) = default;
270 InterfaceRemoved(InterfaceRemoved&&) = default;
271 InterfaceRemoved& operator=(InterfaceRemoved&&) = default;
272 InterfaceRemoved(const char* path,
273 const char* iface,
274 U&& handler) :
275 _path(path),
276 _iface(iface),
277 _handler(std::forward<U>(handler)) { }
278
279 /** @brief Run signal handler function
280 *
281 * Extract the property from the InterfacesRemoved
282 * message and run the handler function.
283 */
284 void operator()(sdbusplus::bus::bus&,
285 sdbusplus::message::message& msg,
286 Zone& zone) const
287 {
288 if (msg)
289 {
290 std::vector<std::string> intfs;
291 sdbusplus::message::object_path op;
292
293 msg.read(op);
294 if (static_cast<const std::string&>(op) != _path)
295 {
296 // Object path does not match this handler's path
297 return;
298 }
299
300 msg.read(intfs);
301 auto itIntf = std::find(intfs.begin(), intfs.end(), _iface);
302 if (itIntf == intfs.cend())
303 {
304 // Interface not found on this handler's path
305 return;
306 }
307
308 _handler(zone);
309 }
310 }
311
312private:
313 const char* _path;
314 const char* _iface;
315 U _handler;
316};
317
318/**
319 * @brief Used to process a Dbus interface removed signal event
320 *
321 * @param[in] path - Object path
322 * @param[in] iface - Object interface
323 * @param[in] handler - Handler function to perform
324 *
325 * @tparam U - The type of the handler
326 */
327template <typename U>
328auto objectSignal(const char* path,
329 const char* iface,
330 U&& handler)
331{
332 return InterfaceRemoved<U>(path,
333 iface,
334 std::forward<U>(handler));
335}
336
337/**
Matthew Barth8fa02da2017-09-28 12:18:20 -0500338 * @struct Name Owner Changed
339 * @brief A match filter functor for Dbus name owner changed signals
340 *
341 * @tparam U - The type of the handler
342 */
343template <typename U>
344struct NameOwnerChanged
345{
346 NameOwnerChanged() = delete;
347 ~NameOwnerChanged() = default;
348 NameOwnerChanged(const NameOwnerChanged&) = default;
349 NameOwnerChanged& operator=(const NameOwnerChanged&) = default;
350 NameOwnerChanged(NameOwnerChanged&&) = default;
351 NameOwnerChanged& operator=(NameOwnerChanged&&) = default;
352 NameOwnerChanged(const char* path,
353 const char* iface,
354 U&& handler) :
355 _path(path),
356 _iface(iface),
357 _handler(std::forward<U>(handler)) { }
358
359 /** @brief Run signal handler function
360 *
361 * Extract the name owner from the NameOwnerChanged
362 * message (or read the name owner when the message is null)
363 * and run the handler function.
364 */
365 void operator()(sdbusplus::bus::bus& bus,
366 sdbusplus::message::message& msg,
367 Zone& zone) const
368 {
Matthew Barth5a302572017-10-03 11:27:06 -0500369 std::string name;
370 bool hasOwner = false;
Matthew Barth8fa02da2017-09-28 12:18:20 -0500371 if (msg)
372 {
Matthew Barth5a302572017-10-03 11:27:06 -0500373 // Handle NameOwnerChanged signals
374 msg.read(name);
375
376 std::string oldOwn;
377 msg.read(oldOwn);
378
379 std::string newOwn;
380 msg.read(newOwn);
381 if (!newOwn.empty())
382 {
383 hasOwner = true;
384 }
Matthew Barth8fa02da2017-09-28 12:18:20 -0500385 }
386 else
387 {
Matthew Barth5a302572017-10-03 11:27:06 -0500388 try
389 {
390 // Initialize NameOwnerChanged data store with service name
Matthew Barthc72b8912018-01-19 17:28:18 -0600391 name = zone.getService(_path, _iface);
Matthew Barth5a302572017-10-03 11:27:06 -0500392 hasOwner = util::SDBusPlus::callMethodAndRead<bool>(
393 bus,
394 "org.freedesktop.DBus",
395 "/org/freedesktop/DBus",
396 "org.freedesktop.DBus",
397 "NameHasOwner",
398 name);
399 }
Matt Spinlerba7b5fe2018-04-25 15:26:10 -0500400 catch (const util::DBusMethodError& e)
Matthew Barth5a302572017-10-03 11:27:06 -0500401 {
402 // Failed to get service name owner state
403 hasOwner = false;
404 }
Matthew Barth8fa02da2017-09-28 12:18:20 -0500405 }
Matthew Barth5a302572017-10-03 11:27:06 -0500406
407 _handler(zone, name, hasOwner);
Matthew Barth8fa02da2017-09-28 12:18:20 -0500408 }
409
410private:
411 const char* _path;
412 const char* _iface;
413 U _handler;
414};
415
416/**
417 * @brief Used to process a Dbus name owner changed signal event
418 *
419 * @param[in] path - Object path
420 * @param[in] iface - Object interface
421 * @param[in] handler - Handler function to perform
422 *
423 * @tparam U - The type of the handler
424 *
425 * @return - The NameOwnerChanged signal struct
426 */
427template <typename U>
428auto ownerSignal(const char* path,
429 const char* iface,
430 U&& handler)
431{
432 return NameOwnerChanged<U>(path,
433 iface,
434 std::forward<U>(handler));
435}
436
Matthew Barth38a93a82017-05-11 14:12:27 -0500437} // namespace control
438} // namespace fan
439} // namespace phosphor