From 76786f7f381cc02fefec41a40b4c10a293f7c73d Mon Sep 17 00:00:00 2001 From: Ossama Othman Date: Tue, 3 Dec 2013 12:51:05 -0800 Subject: Support technology PropertyChanged signal reporting again. Change-Id: I6a68046a324b603388a20a084950bfc1f4baa73e Signed-off-by: Ossama Othman --- configure.ac | 2 +- plugins/connman/Makefile.am | 4 +- plugins/connman/connman_manager.cpp | 124 ++++++++++++++++++++++++++++--- plugins/connman/connman_manager.hpp | 33 +++++++- plugins/connman/subscription_manager.cpp | 117 +++++++++++++++++++++++++++++ plugins/connman/subscription_manager.hpp | 110 +++++++++++++++++++++++++++ 6 files changed, 376 insertions(+), 14 deletions(-) create mode 100644 plugins/connman/subscription_manager.cpp create mode 100644 plugins/connman/subscription_manager.hpp diff --git a/configure.ac b/configure.ac index 59a97b6..aa0d1e3 100644 --- a/configure.ac +++ b/configure.ac @@ -24,7 +24,7 @@ Boston, MA 02110-1301 USA ]) AC_INIT([settingsd], [0.2], [ossama.othman@intel.com]) -AM_INIT_AUTOMAKE([1.11.1 foreign -Wall -Werror silent-rules]) +AM_INIT_AUTOMAKE([1.11.1 foreign -Wall -Werror -Wno-portability silent-rules]) LT_INIT([disable-static dlopen]) AC_CONFIG_SRCDIR([src/daemon.cpp]) diff --git a/plugins/connman/Makefile.am b/plugins/connman/Makefile.am index f6683fc..d452e63 100644 --- a/plugins/connman/Makefile.am +++ b/plugins/connman/Makefile.am @@ -42,6 +42,7 @@ connman_la_SOURCES = \ technology.cpp \ clock.cpp \ registration.cpp \ + subscription_manager.cpp $(BUILT_SOURCES) connman_la_CXXFLAGS = \ $(IVI_SETTINGS_PLUGIN_CXXFLAGS) \ @@ -68,7 +69,8 @@ noinst_HEADERS = \ connman_technology.hpp \ service.hpp \ technology.hpp \ - clock.hpp + clock.hpp \ + subscription_manager.hpp dbus_codegen_verbose = $(dbus_codegen_verbose_$(V)) dbus_codegen_verbose_ = $(dbus_codegen_verbose_$(AM_DEFAULT_VERBOSITY)) diff --git a/plugins/connman/connman_manager.cpp b/plugins/connman/connman_manager.cpp index 9285144..79a70eb 100644 --- a/plugins/connman/connman_manager.cpp +++ b/plugins/connman/connman_manager.cpp @@ -25,14 +25,12 @@ */ #include "connman_manager.hpp" -#include "dbus_connection.hpp" #include #include #include #include - #include // ---------------------------------------------------------------------- @@ -40,6 +38,66 @@ namespace { std::string const manager_name("connman::manager"); + + void + on_technology_added(GDBusConnection * connection, + char const * sender_name, + char const * object_path, + char const * interface_name, + char const * signal_name, + GVariant * parameters, + gpointer user_data) + { + // The technology's object path is found in the first argument. + ivi::settings::unique_ptr const tech_path( + g_variant_get_child_value(parameters, 0)); + + // Subscribe to the technology's PropertyChanged signal. + typedef ivi::settings::connman_manager::signal_data signal_data; + signal_data * const data = static_cast(user_data); + + data->subscriptions.subscribe("net.connman.Technology", + "PropertyChanged", + g_variant_get_string(tech_path.get(), + nullptr)); + + ivi::settings::on_dbus_signal(connection, + sender_name, + object_path, + interface_name, + signal_name, + parameters, + &data->callback); + } + + void + on_technology_removed(GDBusConnection * connection, + char const * sender_name, + char const * object_path, + char const * interface_name, + char const * signal_name, + GVariant * parameters, + gpointer user_data) + { + // The technology's object path is found in the first argument. + ivi::settings::unique_ptr const tech_path( + g_variant_get_child_value(parameters, 0)); + + // Unubscribe from the technology's PropertyChanged signal. + typedef ivi::settings::connman_manager::signal_data signal_data; + signal_data * const data = static_cast(user_data); + + data->subscriptions.unsubscribe( + g_variant_get_string(tech_path.get(), nullptr)); + + ivi::settings::on_dbus_signal(connection, + sender_name, + object_path, + interface_name, + signal_name, + parameters, + &data->callback); + } } // ---------------------------------------------------------------------- @@ -51,13 +109,19 @@ ivi::settings::connman_manager::connman_manager( "/", // Object path connection, e) - , event_callback_(e) + , data_(connection, e) , technology_added_id_(subscribe_to_signal(connection, - "TechnologyAdded")) + "TechnologyAdded", + on_technology_added, + &data_)) , technology_removed_id_(subscribe_to_signal(connection, - "TechnologyRemoved")) + "TechnologyRemoved", + on_technology_removed, + &data_)) , services_changed_id_(subscribe_to_signal(connection, - "ServicesChanged")) + "ServicesChanged", + on_dbus_signal, + &data_.callback)) { // The ServicesChanged signal parameters are: // @@ -67,6 +131,46 @@ ivi::settings::connman_manager::connman_manager( // dictionary of object-specific properties. The first parameter is // list of changed services. The second is a list of removed // services. + + /** + * @todo Refactor duplicate code found here an in get_properties() + * method. + */ + // Subscribe to PropertyChanged signal for all technologies. + constexpr gint const timeout = 5000; // milliseconds + GError * error = nullptr; + + unique_ptr const dictionary( + g_dbus_proxy_call_sync(connman_.proxy(), + "GetTechnologies", + nullptr, // No parameters + G_DBUS_CALL_FLAGS_NONE, + timeout, + nullptr, // Not cancellable + &error)); + unique_ptr safe_error(error); + + if (dictionary != nullptr) { + GVariantIter * i = nullptr; + g_variant_get(dictionary.get(), "(a(oa{sv}))", &i); + unique_ptr const safe_i(i); + + for (unique_ptr child(g_variant_iter_next_value(i)); + child != nullptr; + child.reset(g_variant_iter_next_value(i))) { + + // The object path is the first tuple element. + unique_ptr const tmp( + g_variant_get_child_value(child.get(), 0)); + + char const * const tech_path = + g_variant_get_string(tmp.get(), nullptr); + + data_.subscriptions.subscribe("net.connman.Technology", + "PropertyChanged", + tech_path); + } + } } ivi::settings::connman_manager::~connman_manager() @@ -229,7 +333,9 @@ ivi::settings::connman_manager::call_method( guint ivi::settings::connman_manager::subscribe_to_signal( GDBusConnection * connection, - char const* name) + char const* name, + ivi_signal_callback callback, + void * user_data) { return g_dbus_connection_signal_subscribe(connection, @@ -239,8 +345,8 @@ ivi::settings::connman_manager::subscribe_to_signal( connman_.object_path(), nullptr, G_DBUS_SIGNAL_FLAGS_NONE, - on_dbus_signal, - &event_callback_, + callback, + user_data, nullptr); } diff --git a/plugins/connman/connman_manager.hpp b/plugins/connman/connman_manager.hpp index 23ef262..e96542d 100644 --- a/plugins/connman/connman_manager.hpp +++ b/plugins/connman/connman_manager.hpp @@ -28,6 +28,7 @@ #define IVI_SETTINGS_CONNMAN_MANAGER_HPP #include "connman.hpp" +#include "subscription_manager.hpp" #include #include @@ -97,6 +98,22 @@ namespace ivi */ void get_services(response_callback & response) const; + struct signal_data + { + signal_data(GDBusConnection * connection, + event_callback const & e) + : callback(e) + , subscriptions(connection, callback) + { + } + + /// Callback through which events will be sent to clients. + event_callback callback; + + /// Signal subscription manager. + subscription_manager subscriptions; + }; + private: /** @@ -120,17 +137,27 @@ namespace ivi void call_method(char const * name, response_callback & response) const; + typedef void (*ivi_signal_callback)(GDBusConnection * connection, + char const * sender_name, + char const * object_path, + char const * interface_name, + char const * signal_name, + GVariant * parameters, + gpointer user_data); + /// Subscribe to Connman Manager signal @a name. guint subscribe_to_signal(GDBusConnection * connection, - char const * name); + char const * name, + ivi_signal_callback callback, + void * user_data); private: /// The proxy used to access the connman Manager D-Bus API. connman connman_; - /// Callback through which events will be sent to clients. - event_callback event_callback_; + /// Data passed to signal handlers. + signal_data data_; /// TechnologyAdded signal subscription ID. guint const technology_added_id_; diff --git a/plugins/connman/subscription_manager.cpp b/plugins/connman/subscription_manager.cpp new file mode 100644 index 0000000..8f6751f --- /dev/null +++ b/plugins/connman/subscription_manager.cpp @@ -0,0 +1,117 @@ +/** + * @file subscription_manager.cpp + * + * @brief Signal subscription manager. + * + * @author Ossama Othman @ + * + * @copyright @par + * Copyright 2013 Intel Corporation All Rights Reserved. + * @par + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License. + * @par + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * @par + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA + */ + +#include "subscription_manager.hpp" + +#include + + +ivi::settings::subscription_manager::subscription_manager( + GDBusConnection * connection, + event_callback & e) + : connection_(connection) + , event_callback_(e) + , mutex_() + , subscriptions_() +{ +} + +ivi::settings::subscription_manager::~subscription_manager() +{ + // No need to grab the lock here since no other threads should be + // accessing this object by the time this destructor is called. + + for (auto const & i : subscriptions_) { + // The signal ID is the second pair member. + g_dbus_connection_signal_unsubscribe(connection_, + i.second); + } +} + +bool +ivi::settings::subscription_manager::subscribe( + char const * interface_name, + char const * signal_name, + char const * object_path) +{ + std::pair result; + + { + std::lock_guard guard(mutex_); + result = subscriptions_.insert(std::make_pair(object_path, 0)); + } + + if (result.second) { + // Insertion succeeded, meaning no previous subscription for the + // given object path exists. + guint const id = + g_dbus_connection_signal_subscribe(connection_, + nullptr, + interface_name, + signal_name, + object_path, + nullptr, + G_DBUS_SIGNAL_FLAGS_NONE, + on_dbus_signal, + &event_callback_, + nullptr); + + auto & pos = result.first; // The iterator. + + pos->second = id; // Dereference the iterator to get + // access to the second pair member, + // i.e. the signal subscription ID. + } + + return result.second; +} + +bool +ivi::settings::subscription_manager::unsubscribe( + char const * object_path) +{ + bool result = false; + + std::lock_guard guard(mutex_); + map_type::iterator pos = subscriptions_.find(object_path); + + if (pos != subscriptions_.end()) { + // The signal ID is the second pair member. + g_dbus_connection_signal_unsubscribe(connection_, + pos->second); + + result = true; + } + + return result; +} + + +// Local Variables: +// mode:c++ +// c-basic-offset:2 +// indent-tabs-mode: nil +// End: diff --git a/plugins/connman/subscription_manager.hpp b/plugins/connman/subscription_manager.hpp new file mode 100644 index 0000000..b3d3687 --- /dev/null +++ b/plugins/connman/subscription_manager.hpp @@ -0,0 +1,110 @@ +/** + * @file subscription_manager.hpp + * + * @brief Connman signal subscription manager header. + * + * @author Ossama Othman @ + * + * @copyright @par + * Copyright 2013 Intel Corporation All Rights Reserved. + * @par + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License. + * @par + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * @par + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA + */ + +#ifndef IVI_SETTINGS_CONNMAN_SUBSCRIPTION_MANAGER_HPP +#define IVI_SETTINGS_CONNMAN_SUBSCRIPTION_MANAGER_HPP + +#include + +#include +#include +#include + + +namespace ivi +{ + namespace settings + { + class event_callback; + + /** + * @class subscription_manager + * + * @brief Connman signal subscription manager. + * + * This class manages all Connman signal subscriptions. + */ + class subscription_manager + { + public: + + /// Constructor. + subscription_manager(GDBusConnection * connection, + event_callback & e); + + /// Destructor. + ~subscription_manager(); + + /** + * Subscribe to signal @a signal_name exposed by + * @a interface_name at @a object_path. + */ + bool subscribe(char const * interface_name, + char const * signal_name, + char const * object_path); + + /** + * Unsubscribe from signal corresponding to given @a + * object_path. This @a object_path corresponds to path passed + * to Connman signals like @c TechnologyRemoved. + * + * @note An assumption is made that the object path will be + * unique accross interfaces. If that's not reasonable + * we'll have to take into account the interface name as + * well. + */ + bool unsubscribe(char const * object_path); + + private: + + typedef std::map map_type; + + /// Underlying D-Bus connection. + GDBusConnection * const connection_; + + /// Callback through which events will be sent to clients. + event_callback & event_callback_; + + /// Mutex used to synchronize access to the underlying map. + std::mutex mutex_; + + /// Map of D-Bus object path to signal subscription ID. + map_type subscriptions_; + + }; + + } +} + + +#endif /* IVI_SETTINGS_CONNMAN_SUBSCRIPTION_MANAGER_HPP */ + + +// Local Variables: +// mode:c++ +// c-basic-offset:2 +// indent-tabs-mode: nil +// End: -- cgit v1.2.3