blob: 0a2b95518ba02416ee4d5ffb0598eb2b6d712369 [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;
Matthew Barth336f18a2017-09-26 09:15:56 -050018using InternalFailure = sdbusplus::xyz::openbmc_project::Common::
19 Error::InternalFailure;
Matthew Barth38a93a82017-05-11 14:12:27 -050020
21/**
22 * @brief Create a handler function object
23 *
24 * @param[in] handler - The handler being created
25 *
26 * @return - The created handler function object
27 */
28template <typename T>
29auto make_handler(T&& handler)
30{
31 return Handler(std::forward<T>(handler));
32}
33
34/**
Matthew Barth17d1fe22017-05-11 15:00:36 -050035 * @brief Create an action function object
36 *
37 * @param[in] action - The action being created
38 *
39 * @return - The created action function object
40 */
41template <typename T>
42auto make_action(T&& action)
43{
44 return Action(std::forward<T>(action));
45}
46
47/**
Matthew Barth38a93a82017-05-11 14:12:27 -050048 * @struct Property Changed
49 * @brief A match filter functor for Dbus property value changed signals
50 *
51 * @tparam T - The type of the property value
52 * @tparam U - The type of the handler
53 */
54template <typename T, typename U>
55struct PropertyChanged
56{
57 PropertyChanged() = delete;
58 ~PropertyChanged() = default;
59 PropertyChanged(const PropertyChanged&) = default;
60 PropertyChanged& operator=(const PropertyChanged&) = default;
61 PropertyChanged(PropertyChanged&&) = default;
62 PropertyChanged& operator=(PropertyChanged&&) = default;
Matthew Barth336f18a2017-09-26 09:15:56 -050063 PropertyChanged(const char* path,
64 const char* iface,
Matthew Barth38a93a82017-05-11 14:12:27 -050065 const char* property,
66 U&& handler) :
Matthew Barth336f18a2017-09-26 09:15:56 -050067 _path(path),
Matthew Barth38a93a82017-05-11 14:12:27 -050068 _iface(iface),
69 _property(property),
70 _handler(std::forward<U>(handler)) { }
71
72 /** @brief Run signal handler function
73 *
74 * Extract the property from the PropertiesChanged
Matthew Barth336f18a2017-09-26 09:15:56 -050075 * message (or read the property when the message is null)
76 * and run the handler function.
Matthew Barth38a93a82017-05-11 14:12:27 -050077 */
Matthew Barth336f18a2017-09-26 09:15:56 -050078 void operator()(sdbusplus::bus::bus& bus,
Matthew Barth38a93a82017-05-11 14:12:27 -050079 sdbusplus::message::message& msg,
80 Zone& zone) const
81 {
Matthew Barth336f18a2017-09-26 09:15:56 -050082 if (msg)
Matthew Barth38a93a82017-05-11 14:12:27 -050083 {
Matthew Barth336f18a2017-09-26 09:15:56 -050084 std::map<std::string, sdbusplus::message::variant<T>> properties;
Matthew Barthd5cfdbe2017-11-14 15:29:50 -060085 std::string iface;
Matthew Barth38a93a82017-05-11 14:12:27 -050086
Matthew Barth336f18a2017-09-26 09:15:56 -050087 msg.read(iface);
Matthew Barthd5cfdbe2017-11-14 15:29:50 -060088 if (iface != _iface)
Matthew Barth336f18a2017-09-26 09:15:56 -050089 {
90 return;
91 }
92
93 msg.read(properties);
94 auto it = properties.find(_property);
95 if (it == properties.cend())
96 {
97 log<level::ERR>("Unable to find property on interface",
98 entry("PROPERTY=%s", _property),
Matthew Barthe65f6172017-12-11 13:36:02 -060099 entry("INTERFACE=%s", _iface),
100 entry("PATH=%s", _path));
Matthew Barth336f18a2017-09-26 09:15:56 -0500101 return;
102 }
103
104 _handler(zone, std::forward<T>(it->second.template get<T>()));
105 }
106 else
Matthew Barth38a93a82017-05-11 14:12:27 -0500107 {
Matthew Barth336f18a2017-09-26 09:15:56 -0500108 try
109 {
Matthew Barthc72b8912018-01-19 17:28:18 -0600110 auto service = zone.getService(_path, _iface);
Matthew Barth336f18a2017-09-26 09:15:56 -0500111 auto val = util::SDBusPlus::getProperty<T>(bus,
Matthew Barthc72b8912018-01-19 17:28:18 -0600112 service,
Matthew Barth336f18a2017-09-26 09:15:56 -0500113 _path,
114 _iface,
115 _property);
116 _handler(zone, std::forward<T>(val));
117 }
118 catch (const InternalFailure& ife)
119 {
120 // Property will not be used unless a property changed
121 // signal message is received for this property.
122 log<level::INFO>(
123 "Property not used, unless PropertyChanged signal received",
124 entry("PATH=%s", _path),
125 entry("INTERFACE=%s", _iface),
126 entry("PROPERTY=%s", _property));
127 }
Matthew Barth38a93a82017-05-11 14:12:27 -0500128 }
Matthew Barth38a93a82017-05-11 14:12:27 -0500129 }
130
131private:
Matthew Barth336f18a2017-09-26 09:15:56 -0500132 const char* _path;
Matthew Barth38a93a82017-05-11 14:12:27 -0500133 const char* _iface;
134 const char* _property;
135 U _handler;
136};
137
138/**
139 * @brief Used to process a Dbus property changed signal event
140 *
Matthew Barth336f18a2017-09-26 09:15:56 -0500141 * @param[in] path - Object path
142 * @param[in] iface - Object interface
143 * @param[in] property - Object property
Matthew Barth38a93a82017-05-11 14:12:27 -0500144 * @param[in] handler - Handler function to perform
145 *
146 * @tparam T - The type of the property
147 * @tparam U - The type of the handler
148 */
149template <typename T, typename U>
Matthew Barth336f18a2017-09-26 09:15:56 -0500150auto propertySignal(const char* path,
151 const char* iface,
Matthew Barth38a93a82017-05-11 14:12:27 -0500152 const char* property,
153 U&& handler)
154{
Matthew Barth336f18a2017-09-26 09:15:56 -0500155 return PropertyChanged<T, U>(path,
156 iface,
157 property,
158 std::forward<U>(handler));
Matthew Barth38a93a82017-05-11 14:12:27 -0500159}
160
Matthew Bartheb639c52017-08-04 09:43:11 -0500161/**
162 * @struct Interface Added
163 * @brief A match filter functor for Dbus interface added signals
164 *
165 * @tparam T - The type of the property value
166 * @tparam U - The type of the handler
167 */
168template <typename T, typename U>
169struct InterfaceAdded
170{
171 InterfaceAdded() = delete;
172 ~InterfaceAdded() = default;
173 InterfaceAdded(const InterfaceAdded&) = default;
174 InterfaceAdded& operator=(const InterfaceAdded&) = default;
175 InterfaceAdded(InterfaceAdded&&) = default;
176 InterfaceAdded& operator=(InterfaceAdded&&) = default;
177 InterfaceAdded(const char* path,
178 const char* iface,
179 const char* property,
180 U&& handler) :
181 _path(path),
182 _iface(iface),
183 _property(property),
184 _handler(std::forward<U>(handler)) { }
185
186 /** @brief Run signal handler function
187 *
188 * Extract the property from the InterfacesAdded
189 * message and run the handler function.
190 */
191 void operator()(sdbusplus::bus::bus&,
192 sdbusplus::message::message& msg,
193 Zone& zone) const
194 {
Matthew Barth336f18a2017-09-26 09:15:56 -0500195 if (msg)
Matthew Bartheb639c52017-08-04 09:43:11 -0500196 {
Matthew Barth336f18a2017-09-26 09:15:56 -0500197 std::map<std::string,
198 std::map<std::string,
199 sdbusplus::message::variant<T>>> intfProp;
200 sdbusplus::message::object_path op;
Matthew Bartheb639c52017-08-04 09:43:11 -0500201
Matthew Barth336f18a2017-09-26 09:15:56 -0500202 msg.read(op);
Matthew Barthd5cfdbe2017-11-14 15:29:50 -0600203 if (static_cast<const std::string&>(op) != _path)
Matthew Barth336f18a2017-09-26 09:15:56 -0500204 {
205 // Object path does not match this handler's path
206 return;
207 }
Matthew Bartheb639c52017-08-04 09:43:11 -0500208
Matthew Barth336f18a2017-09-26 09:15:56 -0500209 msg.read(intfProp);
210 auto itIntf = intfProp.find(_iface);
211 if (itIntf == intfProp.cend())
212 {
213 // Interface not found on this handler's path
214 return;
215 }
216 auto itProp = itIntf->second.find(_property);
217 if (itProp == itIntf->second.cend())
218 {
219 // Property not found on this handler's path
220 return;
221 }
222
223 _handler(zone, std::forward<T>(itProp->second.template get<T>()));
224 }
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 }
400 catch (const InternalFailure& ife)
401 {
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