1 #pragma once 2 3 #include "callback.hpp" 4 #include "data_types.hpp" 5 #include "propertywatch.hpp" 6 7 #include <sdbusplus/bus/match.hpp> 8 #include <sdbusplus/message.hpp> 9 #include <string> 10 #include <vector> 11 12 namespace phosphor 13 { 14 namespace dbus 15 { 16 namespace monitoring 17 { 18 19 using MappedPropertyIndex = 20 RefKeyMap<const std::string, 21 RefKeyMap<const std::string, RefVector<const std::string>>>; 22 23 MappedPropertyIndex convert(const PropertyIndex& index); 24 25 template <typename DBusInterfaceType> 26 void PropertyWatch<DBusInterfaceType>::start() 27 { 28 if (alreadyRan) 29 { 30 return; 31 } 32 33 // The index has a flat layout which is not optimal here. Nest 34 // properties in a map of interface names in a map of object paths. 35 auto mapped = convert(index); 36 37 for (const auto& m : mapped) 38 { 39 const auto& path = m.first.get(); 40 const auto& interfaces = m.second; 41 42 // Watch for new interfaces on this path. 43 DBusInterfaceType::addMatch( 44 sdbusplus::bus::match::rules::interfacesAdded(path), 45 [this](auto& msg) 46 // *INDENT-OFF* 47 { this->interfacesAdded(msg); }); 48 // *INDENT-ON* 49 50 // Do a query to populate the cache. Start with a mapper query. 51 // The specific services are queried below. 52 auto getObjectFromMapper = [](const auto& path) { 53 const std::vector<std::string> queryInterfaces; // all interfaces 54 try 55 { 56 return DBusInterfaceType::template callMethodAndRead<GetObject>( 57 MAPPER_BUSNAME, MAPPER_PATH, MAPPER_INTERFACE, "GetObject", 58 path, queryInterfaces); 59 } 60 catch (const sdbusplus::exception::SdBusError&) 61 { 62 // Paths in the configuration may not exist yet. Prime those 63 // later, when/if InterfacesAdded occurs. 64 return GetObject(); 65 } 66 }; 67 auto mapperResp = getObjectFromMapper(path); 68 69 for (const auto& i : interfaces) 70 { 71 const auto& interface = i.first.get(); 72 73 // Watch for property changes on this interface. 74 DBusInterfaceType::addMatch( 75 sdbusplus::bus::match::rules::propertiesChanged(path, 76 interface), 77 [this](auto& msg) 78 // *INDENT-OFF* 79 { 80 std::string interface; 81 msg.read(interface); 82 auto path = msg.get_path(); 83 this->propertiesChanged(msg, path, interface); 84 }); 85 // *INDENT-ON* 86 87 // The mapper response is a busname:[interfaces] map. Look for 88 // each interface in the index and if found, query the service and 89 // populate the cache entries for the interface. 90 for (const auto& mr : mapperResp) 91 { 92 const auto& busName = mr.first; 93 const auto& mapperInterfaces = mr.second; 94 if (mapperInterfaces.end() == 95 std::find(mapperInterfaces.begin(), mapperInterfaces.end(), 96 interface)) 97 { 98 // This interface isn't being watched. 99 continue; 100 } 101 102 // Delegate type specific property updates to subclasses. 103 try 104 { 105 updateProperties(busName, path, interface); 106 } 107 catch (const sdbusplus::exception::SdBusError&) 108 { 109 // If for some reason the path has gone away since 110 // the mapper lookup we'll simply try again if/when 111 // InterfacesAdded occurs the next time it shows up. 112 } 113 } 114 } 115 } 116 117 alreadyRan = true; 118 } 119 120 template <typename DBusInterfaceType> 121 void PropertyWatch<DBusInterfaceType>::callback(Context ctx) 122 { 123 // Invoke callback if present. 124 if (this->alreadyRan && this->cb) 125 { 126 (*this->cb)(ctx); 127 } 128 } 129 130 template <typename T, typename DBusInterfaceType> 131 void PropertyWatchOfType<T, DBusInterfaceType>::updateProperties( 132 const std::string& busName, const std::string& path, 133 const std::string& interface) 134 { 135 auto properties = 136 DBusInterfaceType::template callMethodAndRead<PropertiesChanged<T>>( 137 busName.c_str(), path.c_str(), "org.freedesktop.DBus.Properties", 138 "GetAll", interface); 139 propertiesChanged(path, interface, properties); 140 } 141 142 template <typename T, typename DBusInterfaceType> 143 void PropertyWatchOfType<T, DBusInterfaceType>::propertiesChanged( 144 const std::string& path, const std::string& interface, 145 const PropertiesChanged<T>& properties) 146 { 147 // Update the cache for any watched properties. 148 for (const auto& p : properties) 149 { 150 auto key = std::make_tuple(path, interface, p.first); 151 auto item = this->index.find(key); 152 if (item == this->index.end()) 153 { 154 // This property isn't being watched. 155 continue; 156 } 157 158 // Run property value thru filter operations 159 auto isFiltered = false; 160 const auto& storage = std::get<storageIndex>(item->second); 161 auto value = std::get<T>(p.second); 162 if (filterOps) 163 { 164 any_ns::any anyValue = value; 165 if ((*filterOps)(anyValue)) 166 { 167 // Property value filtered, clear it from storage so 168 // callback functions do not use it 169 isFiltered = true; 170 std::get<valueIndex>(storage.get()).clear(); 171 } 172 } 173 if (!isFiltered) 174 { 175 // Property value not filtered out, update 176 std::get<valueIndex>(storage.get()) = value; 177 // Invoke callback if present. 178 this->callback(Context::SIGNAL); 179 } 180 } 181 } 182 183 template <typename T, typename DBusInterfaceType> 184 void PropertyWatchOfType<T, DBusInterfaceType>::propertiesChanged( 185 sdbusplus::message::message& msg, const std::string& path, 186 const std::string& interface) 187 { 188 PropertiesChanged<T> properties; 189 msg.read(properties); 190 propertiesChanged(path, interface, properties); 191 } 192 193 template <typename T, typename DBusInterfaceType> 194 void PropertyWatchOfType<T, DBusInterfaceType>::interfacesAdded( 195 const std::string& path, const InterfacesAdded<T>& interfaces) 196 { 197 for (const auto& i : interfaces) 198 { 199 propertiesChanged(path, i.first, i.second); 200 } 201 } 202 203 template <typename T, typename DBusInterfaceType> 204 void PropertyWatchOfType<T, DBusInterfaceType>::interfacesAdded( 205 sdbusplus::message::message& msg) 206 { 207 sdbusplus::message::object_path path; 208 InterfacesAdded<T> interfaces; 209 msg.read(path, interfaces); 210 interfacesAdded(path, interfaces); 211 } 212 213 } // namespace monitoring 214 } // namespace dbus 215 } // namespace phosphor 216