| #pragma once |
| |
| #ifndef BOOST_COROUTINES_NO_DEPRECATION_WARNING |
| // users should define this if they directly include boost/asio/spawn.hpp, |
| // but by defining it here, warnings won't cause problems with a compile |
| #define BOOST_COROUTINES_NO_DEPRECATION_WARNING |
| #endif |
| |
| #include <boost/asio/spawn.hpp> |
| #include <sdbusplus/asio/connection.hpp> |
| #include <sdbusplus/exception.hpp> |
| #include <sdbusplus/message/read.hpp> |
| #include <sdbusplus/message/types.hpp> |
| #include <sdbusplus/server.hpp> |
| #include <sdbusplus/utility/tuple_to_array.hpp> |
| #include <sdbusplus/utility/type_traits.hpp> |
| |
| #include <any> |
| #include <list> |
| #include <optional> |
| #include <set> |
| #include <unordered_map> |
| |
| namespace sdbusplus |
| { |
| namespace asio |
| { |
| |
| class callback |
| { |
| public: |
| virtual ~callback() = default; |
| virtual int call(message_t& m) = 0; |
| }; |
| |
| enum class SetPropertyReturnValue |
| { |
| fail = 0, |
| valueUpdated, |
| sameValueUpdated, |
| }; |
| |
| class callback_set |
| { |
| public: |
| virtual ~callback_set() = default; |
| virtual SetPropertyReturnValue call(message_t& m) = 0; |
| virtual SetPropertyReturnValue set(const std::any& value) = 0; |
| }; |
| |
| template <typename T> |
| inline const bool FirstArgIsYield_v = |
| std::is_same_v<utility::get_first_arg_t<utility::decay_tuple_t< |
| boost::callable_traits::args_t<T>>>, |
| boost::asio::yield_context>; |
| |
| template <typename T> |
| inline const bool FirstArgIsMessage_v = |
| std::is_same_v<utility::get_first_arg_t<utility::decay_tuple_t< |
| boost::callable_traits::args_t<T>>>, |
| message_t>; |
| |
| template <typename T> |
| inline const bool SecondArgIsMessage_v = std::is_same_v< |
| utility::get_first_arg_t<utility::strip_first_arg_t< |
| utility::decay_tuple_t<boost::callable_traits::args_t<T>>>>, |
| message_t>; |
| |
| template <typename T> |
| static constexpr bool callbackWantsMessage = FirstArgIsMessage_v<T> || |
| SecondArgIsMessage_v<T>; |
| |
| namespace details |
| { |
| // small helper class to count the number of non-dbus arguments |
| // to a registered dbus function (like message_t or yield_context) |
| // so the registered signature can omit them |
| template <typename FirstArg, typename... Rest> |
| struct NonDbusArgsCount; |
| |
| template <> |
| struct NonDbusArgsCount<std::tuple<>> |
| { |
| constexpr static std::size_t size() |
| { |
| return 0; |
| } |
| }; |
| template <typename FirstArg, typename... OtherArgs> |
| struct NonDbusArgsCount<std::tuple<FirstArg, OtherArgs...>> |
| { |
| constexpr static std::size_t size() |
| { |
| if constexpr (std::is_same_v<FirstArg, message_t> || |
| std::is_same_v<FirstArg, boost::asio::yield_context>) |
| { |
| return 1 + NonDbusArgsCount<std::tuple<OtherArgs...>>::size(); |
| } |
| else |
| { |
| return NonDbusArgsCount<std::tuple<OtherArgs...>>::size(); |
| } |
| } |
| }; |
| } // namespace details |
| |
| template <typename InputArgs, typename Callback> |
| void callFunction(message_t& m, InputArgs& inputArgs, Callback&& callback) |
| { |
| using ResultType = boost::callable_traits::return_type_t<Callback>; |
| if constexpr (std::is_void_v<ResultType>) |
| { |
| std::apply(callback, inputArgs); |
| } |
| else |
| { |
| auto r = std::apply(callback, inputArgs); |
| m.append(r); |
| } |
| } |
| |
| template <typename CallbackType> |
| class callback_method_instance : public callback |
| { |
| public: |
| callback_method_instance(CallbackType&& func) : func_(std::move(func)) {} |
| int call(message_t& m) override |
| { |
| return expandCall(m); |
| } |
| |
| private: |
| using CallbackSignature = boost::callable_traits::args_t<CallbackType>; |
| using InputTupleType = utility::decay_tuple_t<CallbackSignature>; |
| CallbackType func_; |
| |
| // optional message-first-argument callback |
| int expandCall(message_t& m) |
| { |
| using DbusTupleType = utility::strip_first_n_args_t< |
| details::NonDbusArgsCount<InputTupleType>::size(), InputTupleType>; |
| |
| DbusTupleType dbusArgs; |
| if (!utility::read_into_tuple(dbusArgs, m)) |
| { |
| return -EINVAL; |
| } |
| auto ret = m.new_method_return(); |
| std::optional<InputTupleType> inputArgs; |
| if constexpr (callbackWantsMessage<CallbackType>) |
| { |
| inputArgs.emplace( |
| std::tuple_cat(std::forward_as_tuple(std::move(m)), dbusArgs)); |
| } |
| else |
| { |
| inputArgs.emplace(dbusArgs); |
| } |
| callFunction(ret, *inputArgs, func_); |
| ret.method_return(); |
| return 1; |
| } |
| }; |
| |
| template <typename CallbackType> |
| class coroutine_method_instance : public callback |
| { |
| public: |
| using self_t = coroutine_method_instance<CallbackType>; |
| |
| coroutine_method_instance(boost::asio::io_context& io, |
| CallbackType&& func) : |
| io_(io), |
| func_(std::move(func)) |
| {} |
| |
| int call(message_t& m) override |
| { |
| // make a copy of m to move into the coroutine |
| message_t b{m}; |
| // spawn off a new coroutine to handle the method call |
| boost::asio::spawn(io_, std::bind_front(&self_t::after_spawn, this, b)); |
| return 1; |
| } |
| |
| private: |
| void after_spawn(message_t b, boost::asio::yield_context yield) |
| { |
| std::optional<message_t> err{}; |
| |
| try |
| { |
| expandCall(yield, b); |
| } |
| catch (const sdbusplus::exception::SdBusError& e) |
| { |
| // Catch D-Bus error explicitly called by method handler |
| err = b.new_method_errno(e.get_errno(), e.get_error()); |
| } |
| catch (const sdbusplus::exception_t& e) |
| { |
| err = b.new_method_error(e); |
| } |
| catch (...) |
| { |
| err = b.new_method_errno(-EIO); |
| } |
| |
| if (err) |
| { |
| err->method_return(); |
| } |
| } |
| |
| using CallbackSignature = boost::callable_traits::args_t<CallbackType>; |
| using InputTupleType = utility::decay_tuple_t<CallbackSignature>; |
| boost::asio::io_context& io_; |
| CallbackType func_; |
| |
| // co-routine body for call |
| void expandCall(boost::asio::yield_context yield, message_t& m) |
| { |
| using DbusTupleType = utility::strip_first_n_args_t< |
| details::NonDbusArgsCount<InputTupleType>::size(), InputTupleType>; |
| DbusTupleType dbusArgs; |
| try |
| { |
| utility::read_into_tuple(dbusArgs, m); |
| } |
| catch (const exception::SdBusError& e) |
| { |
| auto ret = m.new_method_errno(e.get_errno(), e.get_error()); |
| ret.method_return(); |
| return; |
| } |
| |
| auto ret = m.new_method_return(); |
| std::optional<InputTupleType> inputArgs; |
| if constexpr (callbackWantsMessage<CallbackType>) |
| { |
| inputArgs.emplace( |
| std::tuple_cat(std::forward_as_tuple(std::move(yield)), |
| std::forward_as_tuple(std::move(m)), dbusArgs)); |
| } |
| else |
| { |
| inputArgs.emplace(std::tuple_cat( |
| std::forward_as_tuple(std::move(yield)), dbusArgs)); |
| } |
| callFunction(ret, *inputArgs, func_); |
| ret.method_return(); |
| } |
| }; |
| |
| template <typename PropertyType, typename CallbackType> |
| class callback_get_instance : public callback |
| { |
| public: |
| callback_get_instance(const std::shared_ptr<PropertyType>& value, |
| CallbackType&& func) : |
| value_(value), |
| func_(std::move(func)) |
| {} |
| int call(message_t& m) override |
| { |
| *value_ = func_(*value_); |
| m.append(*value_); |
| return 1; |
| } |
| |
| private: |
| std::shared_ptr<PropertyType> value_; |
| CallbackType func_; |
| }; |
| |
| template <typename PropertyType, typename CallbackType> |
| class callback_set_instance : public callback_set |
| { |
| public: |
| callback_set_instance(const std::shared_ptr<PropertyType>& value, |
| CallbackType&& func) : |
| value_(value), |
| func_(std::move(func)) |
| {} |
| SetPropertyReturnValue call(message_t& m) override |
| { |
| PropertyType input; |
| m.read(input); |
| return set_(input); |
| } |
| SetPropertyReturnValue set(const std::any& value) override |
| { |
| return set_(std::any_cast<PropertyType>(value)); |
| } |
| |
| private: |
| SetPropertyReturnValue set_(const PropertyType& newValue) |
| { |
| PropertyType oldValue = *value_; |
| if (func_(newValue, *value_)) |
| { |
| if (oldValue == *value_) |
| { |
| return SetPropertyReturnValue::sameValueUpdated; |
| } |
| return SetPropertyReturnValue::valueUpdated; |
| } |
| return SetPropertyReturnValue::fail; |
| } |
| |
| private: |
| std::shared_ptr<PropertyType> value_; |
| CallbackType func_; |
| }; |
| |
| enum class PropertyPermission |
| { |
| readOnly, |
| readWrite |
| }; |
| class dbus_interface |
| { |
| public: |
| dbus_interface(std::shared_ptr<sdbusplus::asio::connection> conn, |
| const std::string& path, const std::string& name) : |
| conn_(conn), |
| path_(path), name_(name) |
| |
| { |
| vtable_.emplace_back(vtable::start()); |
| } |
| ~dbus_interface() |
| { |
| conn_->emit_interfaces_removed(path_.c_str(), |
| std::vector<std::string>{name_}); |
| } |
| |
| template <typename PropertyType, typename CallbackTypeGet> |
| bool register_property_r(const std::string& name, |
| const PropertyType& property, |
| decltype(vtable_t::flags) flags, |
| CallbackTypeGet&& getFunction) |
| { |
| // can only register once |
| if (is_initialized()) |
| { |
| return false; |
| } |
| if (sd_bus_member_name_is_valid(name.c_str()) != 1) |
| { |
| return false; |
| } |
| static const auto type = |
| utility::tuple_to_array(message::types::type_id<PropertyType>()); |
| |
| auto nameItr = propertyNames_.emplace(propertyNames_.end(), name); |
| auto propertyPtr = std::make_shared<PropertyType>(property); |
| |
| callbacksGet_[name] = std::make_unique< |
| callback_get_instance<PropertyType, CallbackTypeGet>>( |
| propertyPtr, std::move(getFunction)); |
| callbacksSet_[name] = std::make_unique<callback_set_instance< |
| PropertyType, |
| std::function<int(const PropertyType&, PropertyType&)>>>( |
| propertyPtr, [](const PropertyType& req, PropertyType& old) { |
| old = req; |
| return 1; |
| }); |
| |
| vtable_.emplace_back(vtable::property(nameItr->c_str(), type.data(), |
| get_handler, flags)); |
| |
| return true; |
| } |
| |
| template <typename PropertyType, typename CallbackTypeGet> |
| bool register_property_r(const std::string& name, |
| decltype(vtable_t::flags) flags, |
| CallbackTypeGet&& getFunction) |
| { |
| return register_property_r(name, PropertyType{}, flags, |
| std::forward<CallbackTypeGet>(getFunction)); |
| } |
| |
| template <typename PropertyType, typename CallbackTypeSet, |
| typename CallbackTypeGet> |
| bool register_property_rw(const std::string& name, |
| const PropertyType& property, |
| decltype(vtable_t::flags) flags, |
| CallbackTypeSet&& setFunction, |
| CallbackTypeGet&& getFunction) |
| { |
| // can only register once |
| if (is_initialized()) |
| { |
| return false; |
| } |
| if (sd_bus_member_name_is_valid(name.c_str()) != 1) |
| { |
| return false; |
| } |
| static const auto type = |
| utility::tuple_to_array(message::types::type_id<PropertyType>()); |
| |
| auto nameItr = propertyNames_.emplace(propertyNames_.end(), name); |
| auto propertyPtr = std::make_shared<PropertyType>(property); |
| |
| callbacksGet_[name] = std::make_unique< |
| callback_get_instance<PropertyType, CallbackTypeGet>>( |
| propertyPtr, std::move(getFunction)); |
| callbacksSet_[name] = std::make_unique< |
| callback_set_instance<PropertyType, CallbackTypeSet>>( |
| propertyPtr, std::move(setFunction)); |
| |
| vtable_.emplace_back(vtable::property(nameItr->c_str(), type.data(), |
| get_handler, set_handler, flags)); |
| |
| return true; |
| } |
| |
| template <typename PropertyType, typename CallbackTypeSet, |
| typename CallbackTypeGet> |
| bool register_property_rw(const std::string& name, |
| decltype(vtable_t::flags) flags, |
| CallbackTypeSet&& setFunction, |
| CallbackTypeGet&& getFunction) |
| { |
| return register_property_rw(name, PropertyType{}, flags, |
| std::forward<CallbackTypeSet>(setFunction), |
| std::forward<CallbackTypeGet>(getFunction)); |
| } |
| |
| // default getter and setter |
| template <typename PropertyType> |
| bool register_property( |
| const std::string& name, const PropertyType& property, |
| PropertyPermission access = PropertyPermission::readOnly) |
| { |
| if (access == PropertyPermission::readOnly) |
| { |
| return register_property_r( |
| name, property, vtable::property_::emits_change, |
| [](const PropertyType& value) { return value; }); |
| } |
| else |
| { |
| return register_property_rw( |
| name, property, vtable::property_::emits_change, |
| [](const PropertyType& req, PropertyType& old) { |
| old = req; |
| return true; |
| }, |
| [](const PropertyType& value) { return value; }); |
| } |
| } |
| |
| // custom setter, sets take an input property and respond with an int status |
| template <typename PropertyType, typename CallbackTypeSet> |
| bool register_property(const std::string& name, |
| const PropertyType& property, |
| CallbackTypeSet&& setFunction) |
| { |
| return register_property_rw( |
| name, property, vtable::property_::emits_change, |
| std::forward<CallbackTypeSet>(setFunction), |
| [](const PropertyType& value) { return value; }); |
| } |
| |
| // custom getter and setter, gets take an input of void and respond with a |
| // property. property is only passed for type deduction |
| template <typename PropertyType, typename CallbackTypeSet, |
| typename CallbackTypeGet> |
| bool register_property(const std::string& name, |
| const PropertyType& property, |
| CallbackTypeSet&& setFunction, |
| CallbackTypeGet&& getFunction) |
| { |
| return register_property_rw(name, property, |
| vtable::property_::emits_change, |
| std::forward<CallbackTypeSet>(setFunction), |
| std::forward<CallbackTypeGet>(getFunction)); |
| } |
| |
| template <typename PropertyType, bool changesOnly = false> |
| bool set_property(const std::string& name, const PropertyType& value) |
| { |
| if (!is_initialized()) |
| { |
| return false; |
| } |
| auto func = callbacksSet_.find(name); |
| if (func != callbacksSet_.end()) |
| { |
| SetPropertyReturnValue status = func->second->set(value); |
| if ((status == SetPropertyReturnValue::valueUpdated) || |
| (status == SetPropertyReturnValue::sameValueUpdated)) |
| { |
| if (status != SetPropertyReturnValue::sameValueUpdated) |
| { |
| signal_property(name); |
| return true; |
| } |
| if constexpr (!changesOnly) |
| { |
| return true; |
| } |
| } |
| } |
| return false; |
| } |
| |
| template <typename... SignalSignature> |
| bool register_signal(const std::string& name) |
| { |
| if (is_initialized()) |
| { |
| return false; |
| } |
| if (sd_bus_member_name_is_valid(name.c_str()) != 1) |
| { |
| return false; |
| } |
| |
| static constexpr auto signature = utility::tuple_to_array( |
| message::types::type_id<SignalSignature...>()); |
| |
| const std::string& itr = methodOrSignalNames_.emplace_back(name); |
| vtable_.emplace_back(vtable::signal(itr.c_str(), signature.data())); |
| return true; |
| } |
| |
| template <typename CallbackType> |
| bool register_method(const std::string& name, CallbackType&& handler) |
| { |
| using ActualSignature = boost::callable_traits::args_t<CallbackType>; |
| using CallbackSignature = utility::strip_first_n_args_t< |
| details::NonDbusArgsCount<ActualSignature>::size(), |
| ActualSignature>; |
| using InputTupleType = utility::decay_tuple_t<CallbackSignature>; |
| using ResultType = boost::callable_traits::return_type_t<CallbackType>; |
| |
| if (is_initialized()) |
| { |
| return false; |
| } |
| static const auto argType = utility::strip_ends( |
| utility::tuple_to_array(message::types::type_id<InputTupleType>())); |
| static const auto resultType = |
| utility::tuple_to_array(message::types::type_id<ResultType>()); |
| |
| const std::string& nameItr = methodOrSignalNames_.emplace_back(name); |
| |
| if constexpr (FirstArgIsYield_v<CallbackType>) |
| { |
| callbacksMethod_[name] = |
| std::make_unique<coroutine_method_instance<CallbackType>>( |
| conn_->get_io_context(), std::move(handler)); |
| } |
| else |
| { |
| callbacksMethod_[name] = |
| std::make_unique<callback_method_instance<CallbackType>>( |
| std::move(handler)); |
| } |
| |
| vtable_.emplace_back(vtable::method(nameItr.c_str(), argType.data(), |
| resultType.data(), method_handler)); |
| return true; |
| } |
| |
| static int get_handler(sd_bus* /*bus*/, const char* /*path*/, |
| const char* /*interface*/, const char* property, |
| sd_bus_message* reply, void* userdata, |
| sd_bus_error* error) |
| { |
| dbus_interface* data = static_cast<dbus_interface*>(userdata); |
| auto func = data->callbacksGet_.find(property); |
| auto mesg = message_t(reply); |
| if (func != data->callbacksGet_.end()) |
| { |
| #ifdef __EXCEPTIONS |
| try |
| { |
| #endif |
| return func->second->call(mesg); |
| #ifdef __EXCEPTIONS |
| } |
| |
| catch (const sdbusplus::exception_t& e) |
| { |
| return sd_bus_error_set(error, e.name(), e.description()); |
| } |
| catch (...) |
| { |
| // hit default error below |
| } |
| #endif |
| } |
| return sd_bus_error_set_const(error, SD_BUS_ERROR_INVALID_ARGS, |
| nullptr); |
| } |
| |
| static int set_handler(sd_bus* /*bus*/, const char* /*path*/, |
| const char* /*interface*/, const char* property, |
| sd_bus_message* value, void* userdata, |
| sd_bus_error* error) |
| { |
| dbus_interface* data = static_cast<dbus_interface*>(userdata); |
| auto func = data->callbacksSet_.find(property); |
| auto mesg = message_t(value); |
| if (func != data->callbacksSet_.end()) |
| { |
| #ifdef __EXCEPTIONS |
| try |
| { |
| #endif |
| SetPropertyReturnValue status = func->second->call(mesg); |
| if ((status == SetPropertyReturnValue::valueUpdated) || |
| (status == SetPropertyReturnValue::sameValueUpdated)) |
| { |
| if (status != SetPropertyReturnValue::sameValueUpdated) |
| { |
| data->signal_property(property); |
| } |
| // There shouldn't be any other callbacks that want to |
| // handle the message so just return a positive integer. |
| return 1; |
| } |
| #ifdef __EXCEPTIONS |
| } |
| |
| catch (const sdbusplus::exception_t& e) |
| { |
| return sd_bus_error_set(error, e.name(), e.description()); |
| } |
| catch (...) |
| { |
| // hit default error below |
| } |
| #endif |
| } |
| return sd_bus_error_set_const(error, SD_BUS_ERROR_INVALID_ARGS, |
| nullptr); |
| } |
| |
| static int method_handler(sd_bus_message* m, void* userdata, |
| sd_bus_error* error) |
| { |
| dbus_interface* data = static_cast<dbus_interface*>(userdata); |
| auto mesg = message_t(m); |
| auto func = data->callbacksMethod_.find(mesg.get_member()); |
| if (func != data->callbacksMethod_.end()) |
| { |
| #ifdef __EXCEPTIONS |
| try |
| { |
| #endif |
| int status = func->second->call(mesg); |
| if (status == 1) |
| { |
| return status; |
| } |
| #ifdef __EXCEPTIONS |
| } |
| |
| catch (const sdbusplus::exception_t& e) |
| { |
| return sd_bus_error_set(error, e.name(), e.description()); |
| } |
| catch (...) |
| { |
| // hit default error below |
| } |
| #endif |
| } |
| return sd_bus_error_set_const(error, SD_BUS_ERROR_INVALID_ARGS, |
| nullptr); |
| } |
| |
| /** @brief Create a new signal message. |
| * |
| * @param[in] member - The signal name to create. |
| */ |
| auto new_signal(const char* member) |
| { |
| if (is_initialized()) |
| { |
| return message_t(nullptr); |
| } |
| return interface_->new_signal(member); |
| } |
| |
| bool initialize(const bool skipPropertyChangedSignal = false) |
| { |
| // can only register once |
| if (is_initialized()) |
| { |
| return false; |
| } |
| vtable_.emplace_back(vtable::end()); |
| |
| interface_.emplace(static_cast<sdbusplus::bus_t&>(*conn_), |
| path_.c_str(), name_.c_str(), |
| static_cast<const sd_bus_vtable*>(&vtable_[0]), |
| this); |
| conn_->emit_interfaces_added(path_.c_str(), |
| std::vector<std::string>{name_}); |
| if (!skipPropertyChangedSignal) |
| { |
| for (const std::string& name : propertyNames_) |
| { |
| signal_property(name); |
| } |
| } |
| return true; |
| } |
| |
| bool is_initialized() |
| { |
| return interface_.has_value(); |
| } |
| |
| bool signal_property(const std::string& name) |
| { |
| if (!is_initialized()) |
| { |
| return false; |
| } |
| interface_->property_changed(name.c_str()); |
| return true; |
| } |
| |
| std::string get_object_path(void) |
| { |
| return path_; |
| } |
| |
| std::string get_interface_name(void) |
| { |
| return name_; |
| } |
| |
| private: |
| std::shared_ptr<sdbusplus::asio::connection> conn_; |
| std::string path_; |
| std::string name_; |
| std::list<std::string> propertyNames_; |
| std::list<std::string> methodOrSignalNames_; |
| std::unordered_map<std::string, std::unique_ptr<callback>> callbacksGet_; |
| std::unordered_map<std::string, std::unique_ptr<callback_set>> |
| callbacksSet_; |
| std::unordered_map<std::string, std::unique_ptr<callback>> callbacksMethod_; |
| std::vector<sd_bus_vtable> vtable_; |
| std::optional<sdbusplus::server::interface_t> interface_; |
| }; |
| |
| class object_server |
| { |
| public: |
| object_server(const std::shared_ptr<sdbusplus::asio::connection>& conn, |
| const bool skipManager = false) : |
| conn_(conn) |
| { |
| if (!skipManager) |
| { |
| add_manager("/"); |
| } |
| } |
| |
| std::shared_ptr<dbus_interface> add_interface(const std::string& path, |
| const std::string& name) |
| { |
| auto dbusIface = std::make_shared<dbus_interface>(conn_, path, name); |
| interfaces_.emplace_back(dbusIface); |
| return dbusIface; |
| } |
| |
| std::unique_ptr<dbus_interface> |
| add_unique_interface(const std::string& path, const std::string& name) |
| { |
| return std::make_unique<dbus_interface>(conn_, path, name); |
| } |
| |
| /** |
| @brief creates initialized dbus_interface |
| @param path a string path to interface |
| @param name a string name of the interface |
| @param initializer a functor (void (dbus_interface&)) to be called before |
| call to dbus_interface::initialize |
| @return an unique_ptr to initialized dbus_interface |
| */ |
| template <class Initializer> |
| std::unique_ptr<dbus_interface> |
| add_unique_interface(const std::string& path, const std::string& name, |
| Initializer&& initializer) |
| { |
| auto dbusIface = std::make_unique<dbus_interface>(conn_, path, name); |
| initializer(*dbusIface); |
| dbusIface->initialize(); |
| return dbusIface; |
| } |
| |
| void add_manager(const std::string& path) |
| { |
| managers_.emplace_back(static_cast<sdbusplus::bus_t&>(*conn_), |
| path.c_str()); |
| } |
| |
| bool remove_interface(const std::shared_ptr<dbus_interface>& iface) |
| { |
| auto findIface = std::find(interfaces_.begin(), interfaces_.end(), |
| iface); |
| if (findIface != interfaces_.end()) |
| { |
| interfaces_.erase(findIface); |
| return true; |
| } |
| return false; |
| } |
| |
| private: |
| std::shared_ptr<sdbusplus::asio::connection> conn_; |
| std::vector<std::shared_ptr<dbus_interface>> interfaces_; |
| std::vector<server::manager_t> managers_; |
| }; |
| |
| } // namespace asio |
| } // namespace sdbusplus |