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