blob: 06e8db9b9260b6820e7d30d0643434b44dae3af3 [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 {
110 auto val = util::SDBusPlus::getProperty<T>(bus,
111 _path,
112 _iface,
113 _property);
114 _handler(zone, std::forward<T>(val));
115 }
116 catch (const InternalFailure& ife)
117 {
118 // Property will not be used unless a property changed
119 // signal message is received for this property.
120 log<level::INFO>(
121 "Property not used, unless PropertyChanged signal received",
122 entry("PATH=%s", _path),
123 entry("INTERFACE=%s", _iface),
124 entry("PROPERTY=%s", _property));
125 }
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/**
256 * @struct Name Owner Changed
257 * @brief A match filter functor for Dbus name owner changed signals
258 *
259 * @tparam U - The type of the handler
260 */
261template <typename U>
262struct NameOwnerChanged
263{
264 NameOwnerChanged() = delete;
265 ~NameOwnerChanged() = default;
266 NameOwnerChanged(const NameOwnerChanged&) = default;
267 NameOwnerChanged& operator=(const NameOwnerChanged&) = default;
268 NameOwnerChanged(NameOwnerChanged&&) = default;
269 NameOwnerChanged& operator=(NameOwnerChanged&&) = default;
270 NameOwnerChanged(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 name owner from the NameOwnerChanged
280 * message (or read the name owner when the message is null)
281 * and run the handler function.
282 */
283 void operator()(sdbusplus::bus::bus& bus,
284 sdbusplus::message::message& msg,
285 Zone& zone) const
286 {
Matthew Barth5a302572017-10-03 11:27:06 -0500287 std::string name;
288 bool hasOwner = false;
Matthew Barth8fa02da2017-09-28 12:18:20 -0500289 if (msg)
290 {
Matthew Barth5a302572017-10-03 11:27:06 -0500291 // Handle NameOwnerChanged signals
292 msg.read(name);
293
294 std::string oldOwn;
295 msg.read(oldOwn);
296
297 std::string newOwn;
298 msg.read(newOwn);
299 if (!newOwn.empty())
300 {
301 hasOwner = true;
302 }
Matthew Barth8fa02da2017-09-28 12:18:20 -0500303 }
304 else
305 {
Matthew Barth5a302572017-10-03 11:27:06 -0500306 try
307 {
308 // Initialize NameOwnerChanged data store with service name
309 name = util::SDBusPlus::getService(bus,
310 _path,
311 _iface);
312 hasOwner = util::SDBusPlus::callMethodAndRead<bool>(
313 bus,
314 "org.freedesktop.DBus",
315 "/org/freedesktop/DBus",
316 "org.freedesktop.DBus",
317 "NameHasOwner",
318 name);
319 }
320 catch (const InternalFailure& ife)
321 {
322 // Failed to get service name owner state
323 hasOwner = false;
324 }
Matthew Barth8fa02da2017-09-28 12:18:20 -0500325 }
Matthew Barth5a302572017-10-03 11:27:06 -0500326
327 _handler(zone, name, hasOwner);
Matthew Barth8fa02da2017-09-28 12:18:20 -0500328 }
329
330private:
331 const char* _path;
332 const char* _iface;
333 U _handler;
334};
335
336/**
337 * @brief Used to process a Dbus name owner changed signal event
338 *
339 * @param[in] path - Object path
340 * @param[in] iface - Object interface
341 * @param[in] handler - Handler function to perform
342 *
343 * @tparam U - The type of the handler
344 *
345 * @return - The NameOwnerChanged signal struct
346 */
347template <typename U>
348auto ownerSignal(const char* path,
349 const char* iface,
350 U&& handler)
351{
352 return NameOwnerChanged<U>(path,
353 iface,
354 std::forward<U>(handler));
355}
356
Matthew Barth38a93a82017-05-11 14:12:27 -0500357} // namespace control
358} // namespace fan
359} // namespace phosphor