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