1 #pragma once 2 3 #include "types.hpp" 4 #include "sdbusplus.hpp" 5 #include <phosphor-logging/log.hpp> 6 7 namespace phosphor 8 { 9 namespace fan 10 { 11 namespace control 12 { 13 class Zone; 14 15 using namespace phosphor::fan; 16 using namespace sdbusplus::bus::match; 17 using namespace phosphor::logging; 18 using InternalFailure = sdbusplus::xyz::openbmc_project::Common:: 19 Error::InternalFailure; 20 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 */ 28 template <typename T> 29 auto make_handler(T&& handler) 30 { 31 return Handler(std::forward<T>(handler)); 32 } 33 34 /** 35 * @brief Create an action function object 36 * 37 * @param[in] action - The action being created 38 * 39 * @return - The created action function object 40 */ 41 template <typename T> 42 auto make_action(T&& action) 43 { 44 return Action(std::forward<T>(action)); 45 } 46 47 /** 48 * @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 */ 54 template <typename T, typename U> 55 struct 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; 63 PropertyChanged(const char* path, 64 const char* iface, 65 const char* property, 66 U&& handler) : 67 _path(path), 68 _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 75 * message (or read the property when the message is null) 76 * and run the handler function. 77 */ 78 void operator()(sdbusplus::bus::bus& bus, 79 sdbusplus::message::message& msg, 80 Zone& zone) const 81 { 82 if (msg) 83 { 84 std::map<std::string, sdbusplus::message::variant<T>> properties; 85 std::string iface; 86 87 msg.read(iface); 88 if (iface != _iface) 89 { 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), 99 entry("INTERFACE=%s", _iface), 100 entry("PATH=%s", _path)); 101 return; 102 } 103 104 _handler(zone, std::forward<T>(it->second.template get<T>())); 105 } 106 else 107 { 108 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 } 126 } 127 } 128 129 private: 130 const char* _path; 131 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 * 139 * @param[in] path - Object path 140 * @param[in] iface - Object interface 141 * @param[in] property - Object property 142 * @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 */ 147 template <typename T, typename U> 148 auto propertySignal(const char* path, 149 const char* iface, 150 const char* property, 151 U&& handler) 152 { 153 return PropertyChanged<T, U>(path, 154 iface, 155 property, 156 std::forward<U>(handler)); 157 } 158 159 /** 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 */ 166 template <typename T, typename U> 167 struct 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 { 193 if (msg) 194 { 195 std::map<std::string, 196 std::map<std::string, 197 sdbusplus::message::variant<T>>> intfProp; 198 sdbusplus::message::object_path op; 199 200 msg.read(op); 201 if (static_cast<const std::string&>(op) != _path) 202 { 203 // Object path does not match this handler's path 204 return; 205 } 206 207 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 } 223 } 224 225 private: 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 */ 243 template <typename T, typename U> 244 auto 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 255 /** 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 */ 261 template <typename U> 262 struct 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 { 287 std::string name; 288 bool hasOwner = false; 289 if (msg) 290 { 291 // 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 } 303 } 304 else 305 { 306 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 } 325 } 326 327 _handler(zone, name, hasOwner); 328 } 329 330 private: 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 */ 347 template <typename U> 348 auto 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 357 } // namespace control 358 } // namespace fan 359 } // namespace phosphor 360