1 #pragma once 2 3 #include "sdbusplus.hpp" 4 #include "types.hpp" 5 #include "zone.hpp" 6 7 #include <phosphor-logging/log.hpp> 8 9 namespace phosphor 10 { 11 namespace fan 12 { 13 namespace control 14 { 15 class Zone; 16 17 using namespace phosphor::fan; 18 using namespace sdbusplus::bus::match; 19 using namespace phosphor::logging; 20 21 /** 22 * @brief Create a zone handler function object 23 * 24 * @param[in] handler - The handler being created 25 * 26 * @return - The created zone handler function object 27 */ 28 template <typename T> 29 auto make_zoneHandler(T&& handler) 30 { 31 return ZoneHandler(std::forward<T>(handler)); 32 } 33 34 /** 35 * @brief Create a trigger function object 36 * 37 * @param[in] trigger - The trigger being created 38 * 39 * @return - The created trigger function object 40 */ 41 template <typename T> 42 auto make_trigger(T&& trigger) 43 { 44 return Trigger(std::forward<T>(trigger)); 45 } 46 47 /** 48 * @brief Create a handler function object 49 * 50 * @param[in] handler - The handler being created 51 * 52 * @return - The created handler function object 53 */ 54 template <typename T, typename U> 55 auto make_handler(U&& handler) 56 { 57 return T(std::forward<U>(handler)); 58 } 59 60 /** 61 * @brief Create an action function object 62 * 63 * @param[in] action - The action being created 64 * 65 * @return - The created action function object 66 */ 67 template <typename T> 68 auto make_action(T&& action) 69 { 70 return Action(std::forward<T>(action)); 71 } 72 73 /** 74 * @struct Properties 75 * @brief A set of match filter functors for Dbus property values. Each 76 * functor provides an associated process for retrieving the value 77 * for a given property and providing it to the given handler function. 78 * 79 * @tparam T - The type of the property value 80 * @tparam U - The type of the handler 81 */ 82 template <typename T, typename U> 83 struct Properties 84 { 85 Properties() = delete; 86 ~Properties() = default; 87 Properties(const Properties&) = default; 88 Properties& operator=(const Properties&) = default; 89 Properties(Properties&&) = default; 90 Properties& operator=(Properties&&) = default; 91 explicit Properties(U&& handler) : 92 _path(""), _intf(""), _prop(""), _handler(std::forward<U>(handler)) 93 {} 94 Properties(const char* path, const char* intf, const char* prop, 95 U&& handler) : 96 _path(path), 97 _intf(intf), _prop(prop), _handler(std::forward<U>(handler)) 98 {} 99 100 /** @brief Run signal handler function 101 * 102 * Extract the property from the PropertiesChanged 103 * message and run the handler function. 104 */ 105 void operator()(sdbusplus::bus::bus& bus, sdbusplus::message::message& msg, 106 Zone& zone) const 107 { 108 if (msg) 109 { 110 std::string intf; 111 msg.read(intf); 112 if (intf != _intf) 113 { 114 // Interface name does not match on object 115 return; 116 } 117 118 std::map<std::string, PropertyVariantType> props; 119 msg.read(props); 120 auto it = props.find(_prop); 121 if (it == props.cend()) 122 { 123 // Property not included in dictionary of properties changed 124 return; 125 } 126 127 // Retrieve the property's value applying any visitors necessary 128 auto value = 129 zone.getPropertyValueVisitor<T>(_intf, _prop, it->second); 130 131 _handler(zone, _path, _intf, _prop, std::forward<T>(value)); 132 } 133 else 134 { 135 try 136 { 137 auto val = zone.getPropertyByName<T>(_path, _intf, _prop); 138 _handler(zone, _path, _intf, _prop, std::forward<T>(val)); 139 } 140 catch (const sdbusplus::exception::exception&) 141 { 142 // Property will not be used unless a property changed 143 // signal message is received for this property. 144 } 145 catch (const util::DBusError&) 146 { 147 // Property will not be used unless a property changed 148 // signal message is received for this property. 149 } 150 } 151 } 152 153 /** @brief Run init handler function 154 * 155 * Get the property from each member object of the group 156 * and run the handler function. 157 */ 158 void operator()(Zone& zone, const Group& group) const 159 { 160 std::for_each( 161 group.begin(), group.end(), 162 [&zone, handler = std::move(_handler)](auto const& member) { 163 auto path = std::get<pathPos>(member); 164 auto intf = std::get<intfPos>(member); 165 auto prop = std::get<propPos>(member); 166 try 167 { 168 auto val = zone.getPropertyByName<T>(path, intf, prop); 169 handler(zone, path, intf, prop, std::forward<T>(val)); 170 } 171 catch (const sdbusplus::exception::exception&) 172 { 173 // Property value not sent to handler 174 } 175 catch (const util::DBusError&) 176 { 177 // Property value not sent to handler 178 } 179 }); 180 } 181 182 private: 183 const char* _path; 184 const char* _intf; 185 const char* _prop; 186 U _handler; 187 }; 188 189 /** 190 * @brief Used to process a Dbus properties changed signal event 191 * 192 * @param[in] path - Object path 193 * @param[in] intf - Object interface 194 * @param[in] prop - Object property 195 * @param[in] handler - Handler function to perform 196 * 197 * @tparam T - The type of the property 198 * @tparam U - The type of the handler 199 */ 200 template <typename T, typename U> 201 auto propertiesChanged(const char* path, const char* intf, const char* prop, 202 U&& handler) 203 { 204 return Properties<T, U>(path, intf, prop, std::forward<U>(handler)); 205 } 206 207 /** 208 * @brief Used to get the properties of an event's group 209 * 210 * @param[in] handler - Handler function to perform 211 * 212 * @tparam T - The type of all the properties 213 * @tparam U - The type of the handler 214 */ 215 template <typename T, typename U> 216 auto getProperties(U&& handler) 217 { 218 return Properties<T, U>(std::forward<U>(handler)); 219 } 220 221 /** 222 * @struct Interfaces Added 223 * @brief A match filter functor for Dbus interfaces added signals 224 * 225 * @tparam T - The type of the property value 226 * @tparam U - The type of the handler 227 */ 228 template <typename T, typename U> 229 struct InterfacesAdded 230 { 231 InterfacesAdded() = delete; 232 ~InterfacesAdded() = default; 233 InterfacesAdded(const InterfacesAdded&) = default; 234 InterfacesAdded& operator=(const InterfacesAdded&) = default; 235 InterfacesAdded(InterfacesAdded&&) = default; 236 InterfacesAdded& operator=(InterfacesAdded&&) = default; 237 InterfacesAdded(const char* path, const char* intf, const char* prop, 238 U&& handler) : 239 _path(path), 240 _intf(intf), _prop(prop), _handler(std::forward<U>(handler)) 241 {} 242 243 /** @brief Run signal handler function 244 * 245 * Extract the property from the InterfacesAdded 246 * message and run the handler function. 247 */ 248 void operator()(sdbusplus::bus::bus&, sdbusplus::message::message& msg, 249 Zone& zone) const 250 { 251 if (msg) 252 { 253 sdbusplus::message::object_path op; 254 255 msg.read(op); 256 if (static_cast<const std::string&>(op) != _path) 257 { 258 // Object path does not match this handler's path 259 return; 260 } 261 262 std::map<std::string, std::map<std::string, PropertyVariantType>> 263 intfProp; 264 msg.read(intfProp); 265 auto itIntf = intfProp.find(_intf); 266 if (itIntf == intfProp.cend()) 267 { 268 // Interface not found on this handler's path 269 return; 270 } 271 auto itProp = itIntf->second.find(_prop); 272 if (itProp == itIntf->second.cend()) 273 { 274 // Property not found on this handler's path 275 return; 276 } 277 278 // Retrieve the property's value applying any visitors necessary 279 auto value = 280 zone.getPropertyValueVisitor<T>(_intf, _prop, itProp->second); 281 282 _handler(zone, _path, _intf, _prop, std::forward<T>(value)); 283 } 284 } 285 286 private: 287 const char* _path; 288 const char* _intf; 289 const char* _prop; 290 U _handler; 291 }; 292 293 /** 294 * @brief Used to process a Dbus interfaces added signal event 295 * 296 * @param[in] path - Object path 297 * @param[in] intf - Object interface 298 * @param[in] prop - Object property 299 * @param[in] handler - Handler function to perform 300 * 301 * @tparam T - The type of the property 302 * @tparam U - The type of the handler 303 */ 304 template <typename T, typename U> 305 auto interfacesAdded(const char* path, const char* intf, const char* prop, 306 U&& handler) 307 { 308 return InterfacesAdded<T, U>(path, intf, prop, std::forward<U>(handler)); 309 } 310 311 /** 312 * @struct Interfaces Removed 313 * @brief A match filter functor for Dbus interfaces removed signals 314 * 315 * @tparam U - The type of the handler 316 */ 317 template <typename U> 318 struct InterfacesRemoved 319 { 320 InterfacesRemoved() = delete; 321 ~InterfacesRemoved() = default; 322 InterfacesRemoved(const InterfacesRemoved&) = default; 323 InterfacesRemoved& operator=(const InterfacesRemoved&) = default; 324 InterfacesRemoved(InterfacesRemoved&&) = default; 325 InterfacesRemoved& operator=(InterfacesRemoved&&) = default; 326 InterfacesRemoved(const char* path, const char* intf, U&& handler) : 327 _path(path), _intf(intf), _handler(std::forward<U>(handler)) 328 {} 329 330 /** @brief Run signal handler function 331 * 332 * Extract the interfaces from the InterfacesRemoved 333 * message and run the handler function. 334 */ 335 void operator()(sdbusplus::bus::bus&, sdbusplus::message::message& msg, 336 Zone& zone) const 337 { 338 if (msg) 339 { 340 std::vector<std::string> intfs; 341 sdbusplus::message::object_path op; 342 343 msg.read(op); 344 if (static_cast<const std::string&>(op) != _path) 345 { 346 // Object path does not match this handler's path 347 return; 348 } 349 350 msg.read(intfs); 351 auto itIntf = std::find(intfs.begin(), intfs.end(), _intf); 352 if (itIntf == intfs.cend()) 353 { 354 // Interface not found on this handler's path 355 return; 356 } 357 358 _handler(zone); 359 } 360 } 361 362 private: 363 const char* _path; 364 const char* _intf; 365 U _handler; 366 }; 367 368 /** 369 * @brief Used to process a Dbus interfaces removed signal event 370 * 371 * @param[in] path - Object path 372 * @param[in] intf - Object interface 373 * @param[in] handler - Handler function to perform 374 * 375 * @tparam U - The type of the handler 376 */ 377 template <typename U> 378 auto interfacesRemoved(const char* path, const char* intf, U&& handler) 379 { 380 return InterfacesRemoved<U>(path, intf, std::forward<U>(handler)); 381 } 382 383 /** 384 * @struct Name Owner 385 * @brief A functor for Dbus name owner signals and methods 386 * 387 * @tparam U - The type of the handler 388 */ 389 template <typename U> 390 struct NameOwner 391 { 392 NameOwner() = delete; 393 ~NameOwner() = default; 394 NameOwner(const NameOwner&) = default; 395 NameOwner& operator=(const NameOwner&) = default; 396 NameOwner(NameOwner&&) = default; 397 NameOwner& operator=(NameOwner&&) = default; 398 explicit NameOwner(U&& handler) : _handler(std::forward<U>(handler)) 399 {} 400 401 /** @brief Run signal handler function 402 * 403 * Extract the name owner from the NameOwnerChanged 404 * message and run the handler function. 405 */ 406 void operator()(sdbusplus::bus::bus& bus, sdbusplus::message::message& msg, 407 Zone& zone) const 408 { 409 if (msg) 410 { 411 std::string name; 412 bool hasOwner = false; 413 414 // Handle NameOwnerChanged signals 415 msg.read(name); 416 417 std::string oldOwn; 418 msg.read(oldOwn); 419 420 std::string newOwn; 421 msg.read(newOwn); 422 if (!newOwn.empty()) 423 { 424 hasOwner = true; 425 } 426 _handler(zone, name, hasOwner); 427 } 428 } 429 430 void operator()(Zone& zone, const Group& group) const 431 { 432 std::string name = ""; 433 bool hasOwner = false; 434 std::for_each( 435 group.begin(), group.end(), 436 [&zone, &group, &name, &hasOwner, 437 handler = std::move(_handler)](auto const& member) { 438 auto path = std::get<pathPos>(member); 439 auto intf = std::get<intfPos>(member); 440 try 441 { 442 auto servName = zone.getService(path, intf); 443 if (name != servName) 444 { 445 name = servName; 446 hasOwner = util::SDBusPlus::callMethodAndRead<bool>( 447 zone.getBus(), "org.freedesktop.DBus", 448 "/org/freedesktop/DBus", "org.freedesktop.DBus", 449 "NameHasOwner", name); 450 // Update service name owner state list of a group 451 handler(zone, name, hasOwner); 452 } 453 } 454 catch (const util::DBusMethodError& e) 455 { 456 // Failed to get service name owner state 457 name = ""; 458 hasOwner = false; 459 } 460 }); 461 } 462 463 private: 464 U _handler; 465 }; 466 467 /** 468 * @brief Used to process a Dbus name owner changed signal event 469 * 470 * @param[in] handler - Handler function to perform 471 * 472 * @tparam U - The type of the handler 473 * 474 * @return - The NameOwnerChanged signal struct 475 */ 476 template <typename U> 477 auto nameOwnerChanged(U&& handler) 478 { 479 return NameOwner<U>(std::forward<U>(handler)); 480 } 481 482 /** 483 * @brief Used to process the init of a name owner event 484 * 485 * @param[in] handler - Handler function to perform 486 * 487 * @tparam U - The type of the handler 488 * 489 * @return - The NameOwnerChanged signal struct 490 */ 491 template <typename U> 492 auto nameHasOwner(U&& handler) 493 { 494 return NameOwner<U>(std::forward<U>(handler)); 495 } 496 497 } // namespace control 498 } // namespace fan 499 } // namespace phosphor 500