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 SerialOps::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 SerialOps::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 SerialOps::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 SerialOps::deserialize(path, iface); 131 } 132 133 /** @struct MakeInterface 134 * @brief Adapt an sdbusplus interface proxy. 135 * 136 * Template instances are builder functions that create 137 * adapted sdbusplus interface proxy interface objects. 138 * 139 * @tparam T - The type of the interface being adapted. 140 */ 141 142 template <typename T> 143 struct MakeInterface 144 { 145 static std::any make(sdbusplus::bus::bus& bus, const char* path, 146 const Interface& props) 147 { 148 return propMake<T>(bus, path, props); 149 } 150 151 static void assign(const Interface& props, std::any& holder) 152 { 153 propAssign<T>(props, holder); 154 } 155 156 static void serialize(const std::string& path, const std::string& iface, 157 const std::any& holder) 158 { 159 propSerialize<T>(path, iface, holder); 160 } 161 162 static void deserialize(const std::string& path, const std::string& iface, 163 std::any& holder) 164 { 165 propDeSerialize<T>(path, iface, holder); 166 } 167 }; 168 169 /** @class Manager 170 * @brief OpenBMC inventory manager implementation. 171 * 172 * A concrete implementation for the xyz.openbmc_project.Inventory.Manager 173 * DBus API. 174 */ 175 class Manager final : public ServerObject<ManagerIface> 176 { 177 public: 178 Manager() = delete; 179 Manager(const Manager&) = delete; 180 Manager& operator=(const Manager&) = delete; 181 Manager(Manager&&) = default; 182 Manager& operator=(Manager&&) = default; 183 ~Manager() = default; 184 185 /** @brief Construct an inventory manager. 186 * 187 * @param[in] bus - An sdbusplus bus connection. 188 * @param[in] busname - The DBus busname to own. 189 * @param[in] root - The DBus path on which to implement 190 * an inventory manager. 191 * @param[in] iface - The DBus inventory interface to implement. 192 */ 193 Manager(sdbusplus::bus::bus&&, const char*, const char*, const char*); 194 195 using EventInfo = 196 std::tuple<std::vector<EventBasePtr>, std::vector<Action>>; 197 198 /** @brief Start processing DBus messages. */ 199 void run() noexcept; 200 201 /** @brief Provided for testing only. */ 202 void shutdown() noexcept; 203 204 /** @brief sd_bus Notify method implementation callback. */ 205 void 206 notify(std::map<sdbusplus::message::object_path, Object> objs) override; 207 208 /** @brief Event processing entry point. */ 209 void handleEvent(sdbusplus::message::message&, const Event& event, 210 const EventInfo& info); 211 212 /** @brief Drop one or more objects from DBus. */ 213 void destroyObjects(const std::vector<const char*>& paths); 214 215 /** @brief Add objects to DBus. */ 216 void createObjects( 217 const std::map<sdbusplus::message::object_path, Object>& objs); 218 219 /** @brief Add or update objects on DBus. */ 220 void updateObjects( 221 const std::map<sdbusplus::message::object_path, Object>& objs, 222 bool restoreFromCache = false); 223 224 /** @brief Restore persistent inventory items */ 225 void restore(); 226 227 /** @brief Invoke an sdbusplus server binding method. 228 * 229 * Invoke the requested method with a reference to the requested 230 * sdbusplus server binding interface as a parameter. 231 * 232 * @tparam T - The sdbusplus server binding interface type. 233 * @tparam U - The type of the sdbusplus server binding member. 234 * @tparam Args - Argument types of the binding member. 235 * 236 * @param[in] path - The DBus path on which the method should 237 * be invoked. 238 * @param[in] interface - The DBus interface hosting the method. 239 * @param[in] member - Pointer to sdbusplus server binding member. 240 * @param[in] args - Arguments to forward to the binding member. 241 * 242 * @returns - The return/value type of the binding method being 243 * called. 244 */ 245 template <typename T, typename U, typename... Args> 246 decltype(auto) invokeMethod(const char* path, const char* interface, 247 U&& member, Args&&... args) 248 { 249 auto& iface = getInterface<T>(path, interface); 250 return (iface.*member)(std::forward<Args>(args)...); 251 } 252 253 using SigArgs = std::vector<std::unique_ptr< 254 std::tuple<Manager*, const DbusSignal*, const EventInfo*>>>; 255 using SigArg = SigArgs::value_type::element_type; 256 257 private: 258 using InterfaceComposite = std::map<std::string, std::any>; 259 using ObjectReferences = std::map<std::string, InterfaceComposite>; 260 using Events = std::vector<EventInfo>; 261 262 // The int instantiations are safe since the signature of these 263 // functions don't change from one instantiation to the next. 264 using MakerType = std::add_pointer_t<decltype(MakeInterface<int>::make)>; 265 using AssignerType = 266 std::add_pointer_t<decltype(MakeInterface<int>::assign)>; 267 using SerializerType = 268 std::add_pointer_t<decltype(MakeInterface<int>::serialize)>; 269 using DeserializerType = 270 std::add_pointer_t<decltype(MakeInterface<int>::deserialize)>; 271 using Makers = 272 std::map<std::string, std::tuple<MakerType, AssignerType, 273 SerializerType, DeserializerType>>; 274 275 /** @brief Provides weak references to interface holders. 276 * 277 * Common code for all types for the templated getInterface 278 * methods. 279 * 280 * @param[in] path - The DBus path for which the interface 281 * holder instance should be provided. 282 * @param[in] interface - The DBus interface for which the 283 * holder instance should be provided. 284 * 285 * @returns A weak reference to the holder instance. 286 */ 287 const std::any& getInterfaceHolder(const char*, const char*) const; 288 std::any& getInterfaceHolder(const char*, const char*); 289 290 /** @brief Provides weak references to interface holders. 291 * 292 * @tparam T - The sdbusplus server binding interface type. 293 * 294 * @param[in] path - The DBus path for which the interface 295 * should be provided. 296 * @param[in] interface - The DBus interface to obtain. 297 * 298 * @returns A weak reference to the interface holder. 299 */ 300 template <typename T> 301 auto& getInterface(const char* path, const char* interface) 302 { 303 auto& holder = getInterfaceHolder(path, interface); 304 return *std::any_cast<std::shared_ptr<T>&>(holder); 305 } 306 template <typename T> 307 auto& getInterface(const char* path, const char* interface) const 308 { 309 auto& holder = getInterfaceHolder(path, interface); 310 return *std::any_cast<T>(holder); 311 } 312 313 /** @brief Add or update interfaces on DBus. */ 314 void updateInterfaces(const sdbusplus::message::object_path& path, 315 const Object& interfaces, 316 ObjectReferences::iterator pos, 317 bool emitSignals = true, 318 bool restoreFromCache = false); 319 320 /** @brief Provided for testing only. */ 321 volatile bool _shutdown; 322 323 /** @brief Path prefix applied to any relative paths. */ 324 const char* _root; 325 326 /** @brief A container of sdbusplus server interface references. */ 327 ObjectReferences _refs; 328 329 /** @brief A container contexts for signal callbacks. */ 330 SigArgs _sigargs; 331 332 /** @brief A container of sdbusplus signal matches. */ 333 std::vector<sdbusplus::bus::match_t> _matches; 334 335 /** @brief Persistent sdbusplus DBus bus connection. */ 336 sdbusplus::bus::bus _bus; 337 338 /** @brief sdbusplus org.freedesktop.DBus.ObjectManager reference. */ 339 sdbusplus::server::manager::manager _manager; 340 341 /** @brief A container of pimgen generated events and responses. */ 342 static const Events _events; 343 344 /** @brief A container of pimgen generated factory methods. */ 345 static const Makers _makers; 346 }; 347 348 } // namespace manager 349 } // namespace inventory 350 } // namespace phosphor 351 352 // vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4 353