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 19 /** 20 * @brief Create a zone handler function object 21 * 22 * @param[in] handler - The handler being created 23 * 24 * @return - The created zone handler function object 25 */ 26 template <typename T> 27 auto make_zoneHandler(T&& handler) 28 { 29 return ZoneHandler(std::forward<T>(handler)); 30 } 31 32 /** 33 * @brief Create a handler function object 34 * 35 * @param[in] handler - The handler being created 36 * 37 * @return - The created handler function object 38 */ 39 template <typename T> 40 auto make_handler(T&& handler) 41 { 42 return Handler(std::forward<T>(handler)); 43 } 44 45 /** 46 * @brief Create an action function object 47 * 48 * @param[in] action - The action being created 49 * 50 * @return - The created action function object 51 */ 52 template <typename T> 53 auto make_action(T&& action) 54 { 55 return Action(std::forward<T>(action)); 56 } 57 58 /** 59 * @struct Property Changed 60 * @brief A match filter functor for Dbus property value changed signals 61 * 62 * @tparam T - The type of the property value 63 * @tparam U - The type of the handler 64 */ 65 template <typename T, typename U> 66 struct PropertyChanged 67 { 68 PropertyChanged() = delete; 69 ~PropertyChanged() = default; 70 PropertyChanged(const PropertyChanged&) = default; 71 PropertyChanged& operator=(const PropertyChanged&) = default; 72 PropertyChanged(PropertyChanged&&) = default; 73 PropertyChanged& operator=(PropertyChanged&&) = default; 74 PropertyChanged(const char* path, 75 const char* iface, 76 const char* property, 77 U&& handler) : 78 _path(path), 79 _iface(iface), 80 _property(property), 81 _handler(std::forward<U>(handler)) { } 82 83 /** @brief Run signal handler function 84 * 85 * Extract the property from the PropertiesChanged 86 * message (or read the property when the message is null) 87 * and run the handler function. 88 */ 89 void operator()(sdbusplus::bus::bus& bus, 90 sdbusplus::message::message& msg, 91 Zone& zone) const 92 { 93 if (msg) 94 { 95 std::map<std::string, sdbusplus::message::variant<T>> properties; 96 std::string iface; 97 98 msg.read(iface); 99 if (iface != _iface) 100 { 101 return; 102 } 103 104 msg.read(properties); 105 auto it = properties.find(_property); 106 if (it == properties.cend()) 107 { 108 log<level::ERR>("Unable to find property on interface", 109 entry("PROPERTY=%s", _property), 110 entry("INTERFACE=%s", _iface), 111 entry("PATH=%s", _path)); 112 return; 113 } 114 115 _handler(zone, std::forward<T>( 116 sdbusplus::message::variant_ns::get<T>(it->second))); 117 } 118 else 119 { 120 try 121 { 122 auto val = zone.getPropertyByName<T>(_path, _iface, _property); 123 _handler(zone, std::forward<T>(val)); 124 } 125 catch (const sdbusplus::exception::SdBusError&) 126 { 127 // Property will not be used unless a property changed 128 // signal message is received for this property. 129 } 130 catch (const util::DBusError&) 131 { 132 // Property will not be used unless a property changed 133 // signal message is received for this property. 134 } 135 } 136 } 137 138 private: 139 const char* _path; 140 const char* _iface; 141 const char* _property; 142 U _handler; 143 }; 144 145 /** 146 * @brief Used to process a Dbus property changed signal event 147 * 148 * @param[in] path - Object path 149 * @param[in] iface - Object interface 150 * @param[in] property - Object property 151 * @param[in] handler - Handler function to perform 152 * 153 * @tparam T - The type of the property 154 * @tparam U - The type of the handler 155 */ 156 template <typename T, typename U> 157 auto propertySignal(const char* path, 158 const char* iface, 159 const char* property, 160 U&& handler) 161 { 162 return PropertyChanged<T, U>(path, 163 iface, 164 property, 165 std::forward<U>(handler)); 166 } 167 168 /** 169 * @struct Interface Added 170 * @brief A match filter functor for Dbus interface added signals 171 * 172 * @tparam T - The type of the property value 173 * @tparam U - The type of the handler 174 */ 175 template <typename T, typename U> 176 struct InterfaceAdded 177 { 178 InterfaceAdded() = delete; 179 ~InterfaceAdded() = default; 180 InterfaceAdded(const InterfaceAdded&) = default; 181 InterfaceAdded& operator=(const InterfaceAdded&) = default; 182 InterfaceAdded(InterfaceAdded&&) = default; 183 InterfaceAdded& operator=(InterfaceAdded&&) = default; 184 InterfaceAdded(const char* path, 185 const char* iface, 186 const char* property, 187 U&& handler) : 188 _path(path), 189 _iface(iface), 190 _property(property), 191 _handler(std::forward<U>(handler)) { } 192 193 /** @brief Run signal handler function 194 * 195 * Extract the property from the InterfacesAdded 196 * message and run the handler function. 197 */ 198 void operator()(sdbusplus::bus::bus&, 199 sdbusplus::message::message& msg, 200 Zone& zone) const 201 { 202 if (msg) 203 { 204 std::map<std::string, 205 std::map<std::string, 206 sdbusplus::message::variant<T>>> intfProp; 207 sdbusplus::message::object_path op; 208 209 msg.read(op); 210 if (static_cast<const std::string&>(op) != _path) 211 { 212 // Object path does not match this handler's path 213 return; 214 } 215 216 msg.read(intfProp); 217 auto itIntf = intfProp.find(_iface); 218 if (itIntf == intfProp.cend()) 219 { 220 // Interface not found on this handler's path 221 return; 222 } 223 auto itProp = itIntf->second.find(_property); 224 if (itProp == itIntf->second.cend()) 225 { 226 // Property not found on this handler's path 227 return; 228 } 229 230 _handler(zone, std::forward<T>( 231 sdbusplus::message::variant_ns::get<T>(itProp->second))); 232 } 233 } 234 235 private: 236 const char* _path; 237 const char* _iface; 238 const char* _property; 239 U _handler; 240 }; 241 242 /** 243 * @brief Used to process a Dbus interface added signal event 244 * 245 * @param[in] path - Object path 246 * @param[in] iface - Object interface 247 * @param[in] property - Object property 248 * @param[in] handler - Handler function to perform 249 * 250 * @tparam T - The type of the property 251 * @tparam U - The type of the handler 252 */ 253 template <typename T, typename U> 254 auto objectSignal(const char* path, 255 const char* iface, 256 const char* property, 257 U&& handler) 258 { 259 return InterfaceAdded<T, U>(path, 260 iface, 261 property, 262 std::forward<U>(handler)); 263 } 264 265 /** 266 * @struct Interface Removed 267 * @brief A match filter functor for Dbus interface removed signals 268 * 269 * @tparam U - The type of the handler 270 */ 271 template <typename U> 272 struct InterfaceRemoved 273 { 274 InterfaceRemoved() = delete; 275 ~InterfaceRemoved() = default; 276 InterfaceRemoved(const InterfaceRemoved&) = default; 277 InterfaceRemoved& operator=(const InterfaceRemoved&) = default; 278 InterfaceRemoved(InterfaceRemoved&&) = default; 279 InterfaceRemoved& operator=(InterfaceRemoved&&) = default; 280 InterfaceRemoved(const char* path, 281 const char* iface, 282 U&& handler) : 283 _path(path), 284 _iface(iface), 285 _handler(std::forward<U>(handler)) { } 286 287 /** @brief Run signal handler function 288 * 289 * Extract the property from the InterfacesRemoved 290 * message and run the handler function. 291 */ 292 void operator()(sdbusplus::bus::bus&, 293 sdbusplus::message::message& msg, 294 Zone& zone) const 295 { 296 if (msg) 297 { 298 std::vector<std::string> intfs; 299 sdbusplus::message::object_path op; 300 301 msg.read(op); 302 if (static_cast<const std::string&>(op) != _path) 303 { 304 // Object path does not match this handler's path 305 return; 306 } 307 308 msg.read(intfs); 309 auto itIntf = std::find(intfs.begin(), intfs.end(), _iface); 310 if (itIntf == intfs.cend()) 311 { 312 // Interface not found on this handler's path 313 return; 314 } 315 316 _handler(zone); 317 } 318 } 319 320 private: 321 const char* _path; 322 const char* _iface; 323 U _handler; 324 }; 325 326 /** 327 * @brief Used to process a Dbus interface removed signal event 328 * 329 * @param[in] path - Object path 330 * @param[in] iface - Object interface 331 * @param[in] handler - Handler function to perform 332 * 333 * @tparam U - The type of the handler 334 */ 335 template <typename U> 336 auto objectSignal(const char* path, 337 const char* iface, 338 U&& handler) 339 { 340 return InterfaceRemoved<U>(path, 341 iface, 342 std::forward<U>(handler)); 343 } 344 345 /** 346 * @struct Name Owner Changed 347 * @brief A match filter functor for Dbus name owner changed signals 348 * 349 * @tparam U - The type of the handler 350 */ 351 template <typename U> 352 struct NameOwnerChanged 353 { 354 NameOwnerChanged() = delete; 355 ~NameOwnerChanged() = default; 356 NameOwnerChanged(const NameOwnerChanged&) = default; 357 NameOwnerChanged& operator=(const NameOwnerChanged&) = default; 358 NameOwnerChanged(NameOwnerChanged&&) = default; 359 NameOwnerChanged& operator=(NameOwnerChanged&&) = default; 360 NameOwnerChanged(const char* path, 361 const char* iface, 362 U&& handler) : 363 _path(path), 364 _iface(iface), 365 _handler(std::forward<U>(handler)) { } 366 367 /** @brief Run signal handler function 368 * 369 * Extract the name owner from the NameOwnerChanged 370 * message (or read the name owner when the message is null) 371 * and run the handler function. 372 */ 373 void operator()(sdbusplus::bus::bus& bus, 374 sdbusplus::message::message& msg, 375 Zone& zone) const 376 { 377 std::string name; 378 bool hasOwner = false; 379 if (msg) 380 { 381 // Handle NameOwnerChanged signals 382 msg.read(name); 383 384 std::string oldOwn; 385 msg.read(oldOwn); 386 387 std::string newOwn; 388 msg.read(newOwn); 389 if (!newOwn.empty()) 390 { 391 hasOwner = true; 392 } 393 } 394 else 395 { 396 try 397 { 398 // Initialize NameOwnerChanged data store with service name 399 name = zone.getService(_path, _iface); 400 hasOwner = util::SDBusPlus::callMethodAndRead<bool>( 401 bus, 402 "org.freedesktop.DBus", 403 "/org/freedesktop/DBus", 404 "org.freedesktop.DBus", 405 "NameHasOwner", 406 name); 407 } 408 catch (const util::DBusMethodError& e) 409 { 410 // Failed to get service name owner state 411 hasOwner = false; 412 } 413 } 414 415 _handler(zone, name, hasOwner); 416 } 417 418 private: 419 const char* _path; 420 const char* _iface; 421 U _handler; 422 }; 423 424 /** 425 * @brief Used to process a Dbus name owner changed signal event 426 * 427 * @param[in] path - Object path 428 * @param[in] iface - Object interface 429 * @param[in] handler - Handler function to perform 430 * 431 * @tparam U - The type of the handler 432 * 433 * @return - The NameOwnerChanged signal struct 434 */ 435 template <typename U> 436 auto ownerSignal(const char* path, 437 const char* iface, 438 U&& handler) 439 { 440 return NameOwnerChanged<U>(path, 441 iface, 442 std::forward<U>(handler)); 443 } 444 445 } // namespace control 446 } // namespace fan 447 } // namespace phosphor 448