1 #pragma once 2 3 #include <sdbusplus/message.hpp> 4 #include <sdbusplus/bus/match.hpp> 5 #include <vector> 6 #include "callback.hpp" 7 #include "data_types.hpp" 8 #include "propertywatch.hpp" 9 10 namespace phosphor 11 { 12 namespace dbus 13 { 14 namespace monitoring 15 { 16 17 using MappedPropertyIndex = 18 RefKeyMap<const std::string, 19 RefKeyMap<const std::string, RefVector<const std::string>>>; 20 21 MappedPropertyIndex convert(const PropertyIndex& index); 22 23 template <typename DBusInterfaceType> 24 void PropertyWatch<DBusInterfaceType>::start() 25 { 26 if (alreadyRan) 27 { 28 return; 29 } 30 31 // The index has a flat layout which is not optimal here. Nest 32 // properties in a map of interface names in a map of object paths. 33 auto mapped = convert(index); 34 35 for (const auto& m : mapped) 36 { 37 const auto& path = m.first.get(); 38 const auto& interfaces = m.second; 39 40 // Watch for new interfaces on this path. 41 DBusInterfaceType::addMatch( 42 sdbusplus::bus::match::rules::interfacesAdded(path), 43 [this](auto& msg) 44 // *INDENT-OFF* 45 { this->interfacesAdded(msg); }); 46 // *INDENT-ON* 47 48 // Do a query to populate the cache. Start with a mapper query. 49 // The specific services are queried below. 50 const std::vector<std::string> queryInterfaces; // all interfaces 51 auto mapperResp = 52 DBusInterfaceType::template callMethodAndRead<GetObject>( 53 MAPPER_BUSNAME, MAPPER_PATH, MAPPER_INTERFACE, "GetObject", 54 path, queryInterfaces); 55 56 for (const auto& i : interfaces) 57 { 58 const auto& interface = i.first.get(); 59 60 // Watch for property changes on this interface. 61 DBusInterfaceType::addMatch( 62 sdbusplus::bus::match::rules::propertiesChanged(path, 63 interface), 64 [this](auto& msg) 65 // *INDENT-OFF* 66 { 67 std::string interface; 68 msg.read(interface); 69 auto path = msg.get_path(); 70 this->propertiesChanged(msg, path, interface); 71 }); 72 // *INDENT-ON* 73 74 // The mapper response is a busname:[interfaces] map. Look for 75 // each interface in the index and if found, query the service and 76 // populate the cache entries for the interface. 77 for (const auto& mr : mapperResp) 78 { 79 const auto& busName = mr.first; 80 const auto& mapperInterfaces = mr.second; 81 if (mapperInterfaces.end() == 82 std::find(mapperInterfaces.begin(), mapperInterfaces.end(), 83 interface)) 84 { 85 // This interface isn't being watched. 86 continue; 87 } 88 89 // Delegate type specific property updates to subclasses. 90 updateProperties(busName, path, interface); 91 } 92 } 93 } 94 95 alreadyRan = true; 96 } 97 98 template <typename DBusInterfaceType> 99 void PropertyWatch<DBusInterfaceType>::callback(Context ctx) 100 { 101 // Invoke callback if present. 102 if (this->alreadyRan && this->cb) 103 { 104 (*this->cb)(ctx); 105 } 106 } 107 108 template <typename T, typename DBusInterfaceType> 109 void PropertyWatchOfType<T, DBusInterfaceType>::updateProperties( 110 const std::string& busName, const std::string& path, 111 const std::string& interface) 112 { 113 auto properties = 114 DBusInterfaceType::template callMethodAndRead<PropertiesChanged<T>>( 115 busName.c_str(), path.c_str(), "org.freedesktop.DBus.Properties", 116 "GetAll", interface); 117 propertiesChanged(path, interface, properties); 118 } 119 120 template <typename T, typename DBusInterfaceType> 121 void PropertyWatchOfType<T, DBusInterfaceType>::propertiesChanged( 122 const std::string& path, const std::string& interface, 123 const PropertiesChanged<T>& properties) 124 { 125 // Update the cache for any watched properties. 126 for (const auto& p : properties) 127 { 128 auto key = std::make_tuple(path, interface, p.first); 129 auto item = this->index.find(key); 130 if (item == this->index.end()) 131 { 132 // This property isn't being watched. 133 continue; 134 } 135 136 std::get<valueIndex>(std::get<storageIndex>(item->second).get()) = 137 p.second.template get<T>(); 138 139 // Invoke callback if present. 140 this->callback(Context::SIGNAL); 141 } 142 } 143 144 template <typename T, typename DBusInterfaceType> 145 void PropertyWatchOfType<T, DBusInterfaceType>::propertiesChanged( 146 sdbusplus::message::message& msg, const std::string& path, 147 const std::string& interface) 148 { 149 PropertiesChanged<T> properties; 150 msg.read(properties); 151 propertiesChanged(path, interface, properties); 152 } 153 154 template <typename T, typename DBusInterfaceType> 155 void PropertyWatchOfType<T, DBusInterfaceType>::interfacesAdded( 156 const std::string& path, const InterfacesAdded<T>& interfaces) 157 { 158 for (const auto& i : interfaces) 159 { 160 propertiesChanged(path, i.first, i.second); 161 } 162 } 163 164 template <typename T, typename DBusInterfaceType> 165 void PropertyWatchOfType<T, DBusInterfaceType>::interfacesAdded( 166 sdbusplus::message::message& msg) 167 { 168 sdbusplus::message::object_path path; 169 InterfacesAdded<T> interfaces; 170 msg.read(path, interfaces); 171 interfacesAdded(path, interfaces); 172 } 173 174 } // namespace monitoring 175 } // namespace dbus 176 } // namespace phosphor 177