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>(it->second.template get<T>())); 103 } 104 else 105 { 106 try 107 { 108 auto service = zone.getService(_path, _iface); 109 auto val = util::SDBusPlus::getProperty<T>(bus, 110 service, 111 _path, 112 _iface, 113 _property); 114 _handler(zone, std::forward<T>(val)); 115 } 116 catch (const sdbusplus::exception::SdBusError&) 117 { 118 // Property will not be used unless a property changed 119 // signal message is received for this property. 120 } 121 catch (const util::DBusError&) 122 { 123 // Property will not be used unless a property changed 124 // signal message is received for this 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 Interface Removed 257 * @brief A match filter functor for Dbus interface removed signals 258 * 259 * @tparam U - The type of the handler 260 */ 261 template <typename U> 262 struct InterfaceRemoved 263 { 264 InterfaceRemoved() = delete; 265 ~InterfaceRemoved() = default; 266 InterfaceRemoved(const InterfaceRemoved&) = default; 267 InterfaceRemoved& operator=(const InterfaceRemoved&) = default; 268 InterfaceRemoved(InterfaceRemoved&&) = default; 269 InterfaceRemoved& operator=(InterfaceRemoved&&) = default; 270 InterfaceRemoved(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 property from the InterfacesRemoved 280 * message and run the handler function. 281 */ 282 void operator()(sdbusplus::bus::bus&, 283 sdbusplus::message::message& msg, 284 Zone& zone) const 285 { 286 if (msg) 287 { 288 std::vector<std::string> intfs; 289 sdbusplus::message::object_path op; 290 291 msg.read(op); 292 if (static_cast<const std::string&>(op) != _path) 293 { 294 // Object path does not match this handler's path 295 return; 296 } 297 298 msg.read(intfs); 299 auto itIntf = std::find(intfs.begin(), intfs.end(), _iface); 300 if (itIntf == intfs.cend()) 301 { 302 // Interface not found on this handler's path 303 return; 304 } 305 306 _handler(zone); 307 } 308 } 309 310 private: 311 const char* _path; 312 const char* _iface; 313 U _handler; 314 }; 315 316 /** 317 * @brief Used to process a Dbus interface removed signal event 318 * 319 * @param[in] path - Object path 320 * @param[in] iface - Object interface 321 * @param[in] handler - Handler function to perform 322 * 323 * @tparam U - The type of the handler 324 */ 325 template <typename U> 326 auto objectSignal(const char* path, 327 const char* iface, 328 U&& handler) 329 { 330 return InterfaceRemoved<U>(path, 331 iface, 332 std::forward<U>(handler)); 333 } 334 335 /** 336 * @struct Name Owner Changed 337 * @brief A match filter functor for Dbus name owner changed signals 338 * 339 * @tparam U - The type of the handler 340 */ 341 template <typename U> 342 struct NameOwnerChanged 343 { 344 NameOwnerChanged() = delete; 345 ~NameOwnerChanged() = default; 346 NameOwnerChanged(const NameOwnerChanged&) = default; 347 NameOwnerChanged& operator=(const NameOwnerChanged&) = default; 348 NameOwnerChanged(NameOwnerChanged&&) = default; 349 NameOwnerChanged& operator=(NameOwnerChanged&&) = default; 350 NameOwnerChanged(const char* path, 351 const char* iface, 352 U&& handler) : 353 _path(path), 354 _iface(iface), 355 _handler(std::forward<U>(handler)) { } 356 357 /** @brief Run signal handler function 358 * 359 * Extract the name owner from the NameOwnerChanged 360 * message (or read the name owner when the message is null) 361 * and run the handler function. 362 */ 363 void operator()(sdbusplus::bus::bus& bus, 364 sdbusplus::message::message& msg, 365 Zone& zone) const 366 { 367 std::string name; 368 bool hasOwner = false; 369 if (msg) 370 { 371 // Handle NameOwnerChanged signals 372 msg.read(name); 373 374 std::string oldOwn; 375 msg.read(oldOwn); 376 377 std::string newOwn; 378 msg.read(newOwn); 379 if (!newOwn.empty()) 380 { 381 hasOwner = true; 382 } 383 } 384 else 385 { 386 try 387 { 388 // Initialize NameOwnerChanged data store with service name 389 name = zone.getService(_path, _iface); 390 hasOwner = util::SDBusPlus::callMethodAndRead<bool>( 391 bus, 392 "org.freedesktop.DBus", 393 "/org/freedesktop/DBus", 394 "org.freedesktop.DBus", 395 "NameHasOwner", 396 name); 397 } 398 catch (const util::DBusMethodError& e) 399 { 400 // Failed to get service name owner state 401 hasOwner = false; 402 } 403 } 404 405 _handler(zone, name, hasOwner); 406 } 407 408 private: 409 const char* _path; 410 const char* _iface; 411 U _handler; 412 }; 413 414 /** 415 * @brief Used to process a Dbus name owner changed signal event 416 * 417 * @param[in] path - Object path 418 * @param[in] iface - Object interface 419 * @param[in] handler - Handler function to perform 420 * 421 * @tparam U - The type of the handler 422 * 423 * @return - The NameOwnerChanged signal struct 424 */ 425 template <typename U> 426 auto ownerSignal(const char* path, 427 const char* iface, 428 U&& handler) 429 { 430 return NameOwnerChanged<U>(path, 431 iface, 432 std::forward<U>(handler)); 433 } 434 435 } // namespace control 436 } // namespace fan 437 } // namespace phosphor 438