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 handler function object 21 * 22 * @param[in] handler - The handler being created 23 * 24 * @return - The created handler function object 25 */ 26 template <typename T> 27 auto make_handler(T&& handler) 28 { 29 return Handler(std::forward<T>(handler)); 30 } 31 32 /** 33 * @brief Create an action function object 34 * 35 * @param[in] action - The action being created 36 * 37 * @return - The created action function object 38 */ 39 template <typename T> 40 auto make_action(T&& action) 41 { 42 return Action(std::forward<T>(action)); 43 } 44 45 /** 46 * @struct Property Changed 47 * @brief A match filter functor for Dbus property value changed signals 48 * 49 * @tparam T - The type of the property value 50 * @tparam U - The type of the handler 51 */ 52 template <typename T, typename U> 53 struct PropertyChanged 54 { 55 PropertyChanged() = delete; 56 ~PropertyChanged() = default; 57 PropertyChanged(const PropertyChanged&) = default; 58 PropertyChanged& operator=(const PropertyChanged&) = default; 59 PropertyChanged(PropertyChanged&&) = default; 60 PropertyChanged& operator=(PropertyChanged&&) = default; 61 PropertyChanged(const char* path, 62 const char* iface, 63 const char* property, 64 U&& handler) : 65 _path(path), 66 _iface(iface), 67 _property(property), 68 _handler(std::forward<U>(handler)) { } 69 70 /** @brief Run signal handler function 71 * 72 * Extract the property from the PropertiesChanged 73 * message (or read the property when the message is null) 74 * and run the handler function. 75 */ 76 void operator()(sdbusplus::bus::bus& bus, 77 sdbusplus::message::message& msg, 78 Zone& zone) const 79 { 80 if (msg) 81 { 82 std::map<std::string, sdbusplus::message::variant<T>> properties; 83 std::string iface; 84 85 msg.read(iface); 86 if (iface != _iface) 87 { 88 return; 89 } 90 91 msg.read(properties); 92 auto it = properties.find(_property); 93 if (it == properties.cend()) 94 { 95 log<level::ERR>("Unable to find property on interface", 96 entry("PROPERTY=%s", _property), 97 entry("INTERFACE=%s", _iface), 98 entry("PATH=%s", _path)); 99 return; 100 } 101 102 _handler(zone, std::forward<T>( 103 sdbusplus::message::variant_ns::get<T>(it->second))); 104 } 105 else 106 { 107 try 108 { 109 auto service = zone.getService(_path, _iface); 110 auto val = util::SDBusPlus::getProperty<T>(bus, 111 service, 112 _path, 113 _iface, 114 _property); 115 _handler(zone, std::forward<T>(val)); 116 } 117 catch (const sdbusplus::exception::SdBusError&) 118 { 119 // Property will not be used unless a property changed 120 // signal message is received for this property. 121 } 122 catch (const util::DBusError&) 123 { 124 // Property will not be used unless a property changed 125 // signal message is received for this property. 126 } 127 } 128 } 129 130 private: 131 const char* _path; 132 const char* _iface; 133 const char* _property; 134 U _handler; 135 }; 136 137 /** 138 * @brief Used to process a Dbus property changed signal event 139 * 140 * @param[in] path - Object path 141 * @param[in] iface - Object interface 142 * @param[in] property - Object property 143 * @param[in] handler - Handler function to perform 144 * 145 * @tparam T - The type of the property 146 * @tparam U - The type of the handler 147 */ 148 template <typename T, typename U> 149 auto propertySignal(const char* path, 150 const char* iface, 151 const char* property, 152 U&& handler) 153 { 154 return PropertyChanged<T, U>(path, 155 iface, 156 property, 157 std::forward<U>(handler)); 158 } 159 160 /** 161 * @struct Interface Added 162 * @brief A match filter functor for Dbus interface added signals 163 * 164 * @tparam T - The type of the property value 165 * @tparam U - The type of the handler 166 */ 167 template <typename T, typename U> 168 struct InterfaceAdded 169 { 170 InterfaceAdded() = delete; 171 ~InterfaceAdded() = default; 172 InterfaceAdded(const InterfaceAdded&) = default; 173 InterfaceAdded& operator=(const InterfaceAdded&) = default; 174 InterfaceAdded(InterfaceAdded&&) = default; 175 InterfaceAdded& operator=(InterfaceAdded&&) = default; 176 InterfaceAdded(const char* path, 177 const char* iface, 178 const char* property, 179 U&& handler) : 180 _path(path), 181 _iface(iface), 182 _property(property), 183 _handler(std::forward<U>(handler)) { } 184 185 /** @brief Run signal handler function 186 * 187 * Extract the property from the InterfacesAdded 188 * message and run the handler function. 189 */ 190 void operator()(sdbusplus::bus::bus&, 191 sdbusplus::message::message& msg, 192 Zone& zone) const 193 { 194 if (msg) 195 { 196 std::map<std::string, 197 std::map<std::string, 198 sdbusplus::message::variant<T>>> intfProp; 199 sdbusplus::message::object_path op; 200 201 msg.read(op); 202 if (static_cast<const std::string&>(op) != _path) 203 { 204 // Object path does not match this handler's path 205 return; 206 } 207 208 msg.read(intfProp); 209 auto itIntf = intfProp.find(_iface); 210 if (itIntf == intfProp.cend()) 211 { 212 // Interface not found on this handler's path 213 return; 214 } 215 auto itProp = itIntf->second.find(_property); 216 if (itProp == itIntf->second.cend()) 217 { 218 // Property not found on this handler's path 219 return; 220 } 221 222 _handler(zone, std::forward<T>( 223 sdbusplus::message::variant_ns::get<T>(itProp->second))); 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 util::DBusMethodError& e) 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