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 service = zone.getService(_path, _iface); 111 auto val = util::SDBusPlus::getProperty<T>(bus, 112 service, 113 _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 } 128 } 129 } 130 131 private: 132 const char* _path; 133 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 * 141 * @param[in] path - Object path 142 * @param[in] iface - Object interface 143 * @param[in] property - Object property 144 * @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 */ 149 template <typename T, typename U> 150 auto propertySignal(const char* path, 151 const char* iface, 152 const char* property, 153 U&& handler) 154 { 155 return PropertyChanged<T, U>(path, 156 iface, 157 property, 158 std::forward<U>(handler)); 159 } 160 161 /** 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 */ 168 template <typename T, typename U> 169 struct 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 { 195 if (msg) 196 { 197 std::map<std::string, 198 std::map<std::string, 199 sdbusplus::message::variant<T>>> intfProp; 200 sdbusplus::message::object_path op; 201 202 msg.read(op); 203 if (static_cast<const std::string&>(op) != _path) 204 { 205 // Object path does not match this handler's path 206 return; 207 } 208 209 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 } 225 } 226 227 private: 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 */ 245 template <typename T, typename U> 246 auto 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 257 /** 258 * @struct Interface Removed 259 * @brief A match filter functor for Dbus interface removed signals 260 * 261 * @tparam U - The type of the handler 262 */ 263 template <typename U> 264 struct 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 312 private: 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 */ 327 template <typename U> 328 auto 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 /** 338 * @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 */ 343 template <typename U> 344 struct 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 { 369 std::string name; 370 bool hasOwner = false; 371 if (msg) 372 { 373 // 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 } 385 } 386 else 387 { 388 try 389 { 390 // Initialize NameOwnerChanged data store with service name 391 name = zone.getService(_path, _iface); 392 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 } 405 } 406 407 _handler(zone, name, hasOwner); 408 } 409 410 private: 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 */ 427 template <typename U> 428 auto 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 437 } // namespace control 438 } // namespace fan 439 } // namespace phosphor 440