1 #pragma once 2 3 #include "events.hpp" 4 #include "functor.hpp" 5 #include "serialize.hpp" 6 #include "types.hpp" 7 8 #include <any> 9 #include <map> 10 #include <memory> 11 #include <sdbusplus/server.hpp> 12 #include <string> 13 #include <vector> 14 #include <xyz/openbmc_project/Inventory/Manager/server.hpp> 15 16 namespace phosphor 17 { 18 namespace inventory 19 { 20 namespace manager 21 { 22 23 template <typename T> 24 using ServerObject = T; 25 26 using ManagerIface = 27 sdbusplus::xyz::openbmc_project::Inventory::server::Manager; 28 29 /** @struct PropertiesVariant 30 * @brief Wrapper for sdbusplus PropertiesVariant. 31 * 32 * A wrapper is useful since MakeInterface is instantiated with 'int' 33 * to deduce the return type of its methods, which does not depend 34 * on T. 35 * 36 * @tparam T - The sdbusplus server binding type. 37 */ 38 template <typename T, typename Enable = void> 39 struct PropertiesVariant 40 { 41 }; 42 43 template <typename T> 44 struct PropertiesVariant< 45 T, typename std::enable_if<std::is_object<T>::value>::type> 46 { 47 using Type = typename T::PropertiesVariant; 48 }; 49 50 template <typename T> 51 using PropertiesVariantType = typename PropertiesVariant<T>::Type; 52 53 template <typename T, typename U = int> 54 struct HasProperties : std::false_type 55 { 56 }; 57 58 template <typename T> 59 struct HasProperties< 60 T, decltype((void)std::declval<typename T::PropertiesVariant>(), 0)> 61 : std::true_type 62 { 63 }; 64 65 template <typename T, std::enable_if_t<HasProperties<T>::value, bool> = true> 66 std::any propMake(sdbusplus::bus::bus& bus, const char* path, 67 const Interface& props) 68 { 69 using InterfaceVariant = std::map<std::string, PropertiesVariantType<T>>; 70 71 InterfaceVariant v; 72 for (const auto& p : props) 73 { 74 v.emplace(p.first, convertVariant<PropertiesVariantType<T>>(p.second)); 75 } 76 77 return std::any(std::make_shared<T>(bus, path, v)); 78 } 79 80 template <typename T, std::enable_if_t<!HasProperties<T>::value, bool> = false> 81 std::any propMake(sdbusplus::bus::bus& bus, const char* path, 82 const Interface& props) 83 { 84 return std::any(std::make_shared<T>(bus, path)); 85 } 86 87 template <typename T, std::enable_if_t<HasProperties<T>::value, bool> = true> 88 void propAssign(const Interface& props, std::any& holder) 89 { 90 auto& iface = *std::any_cast<std::shared_ptr<T>&>(holder); 91 for (const auto& p : props) 92 { 93 iface.setPropertyByName( 94 p.first, convertVariant<PropertiesVariantType<T>>(p.second)); 95 } 96 } 97 98 template <typename T, std::enable_if_t<!HasProperties<T>::value, bool> = false> 99 void propAssign(const Interface& props, std::any& holder) 100 { 101 } 102 103 template <typename T, std::enable_if_t<HasProperties<T>::value, bool> = true> 104 void propSerialize(const std::string& path, const std::string& iface, 105 const std::any& holder) 106 { 107 const auto& object = *std::any_cast<const std::shared_ptr<T>&>(holder); 108 cereal::serialize(path, iface, object); 109 } 110 111 template <typename T, std::enable_if_t<!HasProperties<T>::value, bool> = false> 112 void propSerialize(const std::string& path, const std::string& iface, 113 const std::any& holder) 114 { 115 cereal::serialize(path, iface); 116 } 117 118 template <typename T, std::enable_if_t<HasProperties<T>::value, bool> = true> 119 void propDeSerialize(const std::string& path, const std::string& iface, 120 std::any& holder) 121 { 122 auto& object = *std::any_cast<std::shared_ptr<T>&>(holder); 123 cereal::deserialize(path, iface, object); 124 } 125 126 template <typename T, std::enable_if_t<!HasProperties<T>::value, bool> = false> 127 void propDeSerialize(const std::string& path, const std::string& iface, 128 std::any& holder) 129 { 130 } 131 132 /** @struct MakeInterface 133 * @brief Adapt an sdbusplus interface proxy. 134 * 135 * Template instances are builder functions that create 136 * adapted sdbusplus interface proxy interface objects. 137 * 138 * @tparam T - The type of the interface being adapted. 139 */ 140 141 template <typename T> 142 struct MakeInterface 143 { 144 static std::any make(sdbusplus::bus::bus& bus, const char* path, 145 const Interface& props) 146 { 147 return propMake<T>(bus, path, props); 148 } 149 150 static void assign(const Interface& props, std::any& holder) 151 { 152 propAssign<T>(props, holder); 153 } 154 155 static void serialize(const std::string& path, const std::string& iface, 156 const std::any& holder) 157 { 158 propSerialize<T>(path, iface, holder); 159 } 160 161 static void deserialize(const std::string& path, const std::string& iface, 162 std::any& holder) 163 { 164 propDeSerialize<T>(path, iface, holder); 165 } 166 }; 167 168 /** @class Manager 169 * @brief OpenBMC inventory manager implementation. 170 * 171 * A concrete implementation for the xyz.openbmc_project.Inventory.Manager 172 * DBus API. 173 */ 174 class Manager final : public ServerObject<ManagerIface> 175 { 176 public: 177 Manager() = delete; 178 Manager(const Manager&) = delete; 179 Manager& operator=(const Manager&) = delete; 180 Manager(Manager&&) = default; 181 Manager& operator=(Manager&&) = default; 182 ~Manager() = default; 183 184 /** @brief Construct an inventory manager. 185 * 186 * @param[in] bus - An sdbusplus bus connection. 187 * @param[in] busname - The DBus busname to own. 188 * @param[in] root - The DBus path on which to implement 189 * an inventory manager. 190 * @param[in] iface - The DBus inventory interface to implement. 191 */ 192 Manager(sdbusplus::bus::bus&&, const char*, const char*, const char*); 193 194 using EventInfo = 195 std::tuple<std::vector<EventBasePtr>, std::vector<Action>>; 196 197 /** @brief Start processing DBus messages. */ 198 void run() noexcept; 199 200 /** @brief Provided for testing only. */ 201 void shutdown() noexcept; 202 203 /** @brief sd_bus Notify method implementation callback. */ 204 void 205 notify(std::map<sdbusplus::message::object_path, Object> objs) override; 206 207 /** @brief Event processing entry point. */ 208 void handleEvent(sdbusplus::message::message&, const Event& event, 209 const EventInfo& info); 210 211 /** @brief Drop one or more objects from DBus. */ 212 void destroyObjects(const std::vector<const char*>& paths); 213 214 /** @brief Add objects to DBus. */ 215 void createObjects( 216 const std::map<sdbusplus::message::object_path, Object>& objs); 217 218 /** @brief Add or update objects on DBus. */ 219 void updateObjects( 220 const std::map<sdbusplus::message::object_path, Object>& objs, 221 bool restoreFromCache = false); 222 223 /** @brief Restore persistent inventory items */ 224 void restore(); 225 226 /** @brief Invoke an sdbusplus server binding method. 227 * 228 * Invoke the requested method with a reference to the requested 229 * sdbusplus server binding interface as a parameter. 230 * 231 * @tparam T - The sdbusplus server binding interface type. 232 * @tparam U - The type of the sdbusplus server binding member. 233 * @tparam Args - Argument types of the binding member. 234 * 235 * @param[in] path - The DBus path on which the method should 236 * be invoked. 237 * @param[in] interface - The DBus interface hosting the method. 238 * @param[in] member - Pointer to sdbusplus server binding member. 239 * @param[in] args - Arguments to forward to the binding member. 240 * 241 * @returns - The return/value type of the binding method being 242 * called. 243 */ 244 template <typename T, typename U, typename... Args> 245 decltype(auto) invokeMethod(const char* path, const char* interface, 246 U&& member, Args&&... args) 247 { 248 auto& iface = getInterface<T>(path, interface); 249 return (iface.*member)(std::forward<Args>(args)...); 250 } 251 252 using SigArgs = std::vector<std::unique_ptr< 253 std::tuple<Manager*, const DbusSignal*, const EventInfo*>>>; 254 using SigArg = SigArgs::value_type::element_type; 255 256 private: 257 using InterfaceComposite = std::map<std::string, std::any>; 258 using ObjectReferences = std::map<std::string, InterfaceComposite>; 259 using Events = std::vector<EventInfo>; 260 261 // The int instantiations are safe since the signature of these 262 // functions don't change from one instantiation to the next. 263 using MakerType = std::add_pointer_t<decltype(MakeInterface<int>::make)>; 264 using AssignerType = 265 std::add_pointer_t<decltype(MakeInterface<int>::assign)>; 266 using SerializerType = 267 std::add_pointer_t<decltype(MakeInterface<int>::serialize)>; 268 using DeserializerType = 269 std::add_pointer_t<decltype(MakeInterface<int>::deserialize)>; 270 using Makers = 271 std::map<std::string, std::tuple<MakerType, AssignerType, 272 SerializerType, DeserializerType>>; 273 274 /** @brief Provides weak references to interface holders. 275 * 276 * Common code for all types for the templated getInterface 277 * methods. 278 * 279 * @param[in] path - The DBus path for which the interface 280 * holder instance should be provided. 281 * @param[in] interface - The DBus interface for which the 282 * holder instance should be provided. 283 * 284 * @returns A weak reference to the holder instance. 285 */ 286 const std::any& getInterfaceHolder(const char*, const char*) const; 287 std::any& getInterfaceHolder(const char*, const char*); 288 289 /** @brief Provides weak references to interface holders. 290 * 291 * @tparam T - The sdbusplus server binding interface type. 292 * 293 * @param[in] path - The DBus path for which the interface 294 * should be provided. 295 * @param[in] interface - The DBus interface to obtain. 296 * 297 * @returns A weak reference to the interface holder. 298 */ 299 template <typename T> 300 auto& getInterface(const char* path, const char* interface) 301 { 302 auto& holder = getInterfaceHolder(path, interface); 303 return *std::any_cast<std::shared_ptr<T>&>(holder); 304 } 305 template <typename T> 306 auto& getInterface(const char* path, const char* interface) const 307 { 308 auto& holder = getInterfaceHolder(path, interface); 309 return *std::any_cast<T>(holder); 310 } 311 312 /** @brief Add or update interfaces on DBus. */ 313 void updateInterfaces(const sdbusplus::message::object_path& path, 314 const Object& interfaces, 315 ObjectReferences::iterator pos, 316 bool emitSignals = true, 317 bool restoreFromCache = false); 318 319 /** @brief Provided for testing only. */ 320 volatile bool _shutdown; 321 322 /** @brief Path prefix applied to any relative paths. */ 323 const char* _root; 324 325 /** @brief A container of sdbusplus server interface references. */ 326 ObjectReferences _refs; 327 328 /** @brief A container contexts for signal callbacks. */ 329 SigArgs _sigargs; 330 331 /** @brief A container of sdbusplus signal matches. */ 332 std::vector<sdbusplus::bus::match_t> _matches; 333 334 /** @brief Persistent sdbusplus DBus bus connection. */ 335 sdbusplus::bus::bus _bus; 336 337 /** @brief sdbusplus org.freedesktop.DBus.ObjectManager reference. */ 338 sdbusplus::server::manager::manager _manager; 339 340 /** @brief A container of pimgen generated events and responses. */ 341 static const Events _events; 342 343 /** @brief A container of pimgen generated factory methods. */ 344 static const Makers _makers; 345 }; 346 347 } // namespace manager 348 } // namespace inventory 349 } // namespace phosphor 350 351 // vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4 352