Support technology PropertyChanged signal reporting again. 36/13336/1
authorOssama Othman <ossama.othman@intel.com>
Tue, 3 Dec 2013 20:51:05 +0000 (12:51 -0800)
committerOssama Othman <ossama.othman@intel.com>
Tue, 3 Dec 2013 20:51:32 +0000 (12:51 -0800)
Change-Id: I6a68046a324b603388a20a084950bfc1f4baa73e
Signed-off-by: Ossama Othman <ossama.othman@intel.com>
configure.ac
plugins/connman/Makefile.am
plugins/connman/connman_manager.cpp
plugins/connman/connman_manager.hpp
plugins/connman/subscription_manager.cpp [new file with mode: 0644]
plugins/connman/subscription_manager.hpp [new file with mode: 0644]

index 59a97b6..aa0d1e3 100644 (file)
@@ -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])
index f6683fc..d452e63 100644 (file)
@@ -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))
index 9285144..79a70eb 100644 (file)
  */
 
 #include "connman_manager.hpp"
-#include "dbus_connection.hpp"
 
 #include <settingsd/response_callback.hpp>
 #include <settingsd/dbus_signal_callback.hpp>
 #include <settingsd/glib_traits.hpp>
 #include <settingsd/unique_ptr.hpp>
 
-
 #include <cstring>
 
 // ----------------------------------------------------------------------
 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<GVariant> 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<signal_data *>(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<GVariant> 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<signal_data *>(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<GVariant> 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<GError> safe_error(error);
+
+  if (dictionary != nullptr) {
+    GVariantIter * i = nullptr;
+    g_variant_get(dictionary.get(), "(a(oa{sv}))", &i);
+    unique_ptr<GVariantIter> const safe_i(i);
+
+    for (unique_ptr<GVariant> 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<GVariant> 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);
 }
 
index 23ef262..e96542d 100644 (file)
@@ -28,6 +28,7 @@
 #define IVI_SETTINGS_CONNMAN_MANAGER_HPP
 
 #include "connman.hpp"
+#include "subscription_manager.hpp"
 
 #include <settingsd/plugin.hpp>
 #include <settingsd/event_callback.hpp>
@@ -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 (file)
index 0000000..8f6751f
--- /dev/null
@@ -0,0 +1,117 @@
+/**
+ * @file subscription_manager.cpp
+ *
+ * @brief Signal subscription manager.
+ *
+ * @author Ossama Othman @<ossama.othman@@intel.com@>
+ *
+ * @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 <settingsd/dbus_signal_callback.hpp>
+
+
+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<map_type::iterator, bool> result;
+
+  {
+    std::lock_guard<std::mutex> 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<std::mutex> 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 (file)
index 0000000..b3d3687
--- /dev/null
@@ -0,0 +1,110 @@
+/**
+ * @file subscription_manager.hpp
+ *
+ * @brief Connman signal subscription manager header.
+ *
+ * @author Ossama Othman @<ossama.othman@@intel.com@>
+ *
+ * @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 <gio/gio.h>
+
+#include <mutex>
+#include <map>
+#include <string>
+
+
+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<std::string, guint> 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: