[gupnp/gupnp-1.0] connman: fix a race on the DBus interface to connman



commit a8c8de24316bf237cc796761cf7b0ca49ad32d70
Author: Sven Neumann <neumann teufel de>
Date:   Wed Oct 7 17:26:10 2015 +0200

    connman: fix a race on the DBus interface to connman
    
    If a service property changes between the time that the
    DBus proxy for the service is created and the connection
    to the "PropertyChanged" signal has been made, then this
    property change is lost.
    
    Fix this by doing an extra "GetProperties" call after
    the signal connection has been made.
    
    https://bugzilla.gnome.org/show_bug.cgi?id=770318

 libgupnp/gupnp-connman-manager.c |  112 +++++++++++++++++++++++++++++++-------
 1 files changed, 91 insertions(+), 21 deletions(-)
---
diff --git a/libgupnp/gupnp-connman-manager.c b/libgupnp/gupnp-connman-manager.c
index cb0d3ac..fc682ba 100644
--- a/libgupnp/gupnp-connman-manager.c
+++ b/libgupnp/gupnp-connman-manager.c
@@ -201,28 +201,20 @@ service_context_update (CMService *cm_service, CMServiceState new_state)
 }
 
 static void
-on_service_property_signal (GDBusConnection *connection,
-                            const gchar     *sender_name,
-                            const gchar     *object_path,
-                            const gchar     *interface_name,
-                            const gchar     *signal_name,
-                            GVariant        *parameters,
-                            gpointer        user_data)
+on_service_property_changed (CMService   *cm_service,
+                             const gchar *name,
+                             GVariant    *value)
 {
-        CMService      *cm_service;
-        GVariant       *value;
-        gchar          *name;
-        const gchar    *state_str;
         CMServiceState new_state;
-
-        cm_service = (CMService *) user_data;
-        g_variant_get (parameters, "(&sv)", &name, &value);
+        const gchar *state_str;
 
         if (g_strcmp0 (name, "Name") == 0) {
                 g_free (cm_service->name);
                 g_variant_get (value, "s", &cm_service->name);
 
-                if (cm_service->context != NULL)
+                if (cm_service->context != NULL &&
+                    g_strcmp0 (cm_service->name,
+                               gssdp_client_get_network (GSSDP_CLIENT (cm_service->context))) != 0)
                         g_object_set (G_OBJECT (cm_service->context),
                                                "network",
                                                cm_service->name,
@@ -232,7 +224,9 @@ on_service_property_signal (GDBusConnection *connection,
                 g_free (cm_service->iface);
                 g_variant_lookup (value, "Interface", "s", &cm_service->iface);
 
-                if (cm_service->context != NULL) {
+                if (cm_service->context != NULL &&
+                    g_strcmp0 (cm_service->iface,
+                               gssdp_client_get_interface (GSSDP_CLIENT (cm_service->context))) != 0) {
                         service_context_delete (cm_service);
                         service_context_create (cm_service);
                 }
@@ -248,6 +242,25 @@ on_service_property_signal (GDBusConnection *connection,
 
                 service_context_update (cm_service, new_state);
         }
+}
+
+static void
+on_service_property_signal (GDBusConnection *connection,
+                            const gchar     *sender_name,
+                            const gchar     *object_path,
+                            const gchar     *interface_name,
+                            const gchar     *signal_name,
+                            GVariant        *parameters,
+                            gpointer        user_data)
+{
+        CMService *cm_service;
+        GVariant  *value;
+        gchar     *name;
+
+        cm_service = (CMService *) user_data;
+        g_variant_get (parameters, "(&sv)", &name, &value);
+
+        on_service_property_changed (cm_service, name, value);
 
         g_variant_unref (value);
 }
@@ -283,13 +296,10 @@ cm_service_free (CMService *cm_service)
 
                 g_object_unref (cm_service->proxy);
         }
-        else if (cm_service->cancellable != NULL)  {
-                g_cancellable_cancel (cm_service->cancellable);
-        }
 
-        if (cm_service->cancellable != NULL)  {
+        if (cm_service->cancellable != NULL) {
+                g_cancellable_cancel (cm_service->cancellable);
                 g_object_unref (cm_service->cancellable);
-                cm_service->cancellable = NULL;
         }
 
         service_context_remove_creation_timeout (cm_service);
@@ -308,6 +318,57 @@ cm_service_free (CMService *cm_service)
 }
 
 static void
+get_properties_cb (GObject      *source_object,
+                   GAsyncResult *res,
+                   gpointer     user_data)
+{
+        CMService    *cm_service;
+        GVariant     *ret;
+        GVariant     *dict;
+        GVariant     *value;
+        GVariantIter  iter;
+        gchar        *key;
+        GError       *error = NULL;
+
+        ret = g_dbus_proxy_call_finish (G_DBUS_PROXY (source_object),
+                                        res,
+                                        &error);
+
+        if (error != NULL) {
+                if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
+                        g_warning ("Error fetching properties: %s", error->message);
+                g_error_free (error);
+
+                return;
+        }
+
+        if (ret == NULL) {
+                g_warning ("Failed fetching properties but no error");
+
+                return;
+        }
+
+        if (g_variant_is_container (ret) != TRUE)
+        {
+                g_warning ("Unexpected result type: %s", g_variant_get_type_string (ret));
+               g_variant_unref (ret);
+
+                return;
+        }
+
+        cm_service = user_data;
+
+        dict = g_variant_get_child_value (ret, 0);
+        g_variant_iter_init (&iter, dict);
+
+        while (g_variant_iter_loop (&iter, "{sv}", &key, &value))
+                on_service_property_changed (cm_service, key, value);
+
+        g_variant_unref (dict);
+        g_variant_unref (ret);
+}
+
+static void
 cm_service_use (GUPnPConnmanManager *manager,
                 CMService           *cm_service)
 {
@@ -327,6 +388,15 @@ cm_service_use (GUPnPConnmanManager *manager,
                                 cm_service,
                                 NULL);
 
+        g_dbus_proxy_call (cm_service->proxy,
+                           "GetProperties",
+                           NULL,
+                           G_DBUS_CALL_FLAGS_NONE,
+                           -1,
+                           cm_service->cancellable,
+                           get_properties_cb,
+                           cm_service);
+
         if (cm_service->current == CM_SERVICE_STATE_ACTIVE)
                 if (service_context_create (cm_service) == FALSE)
                         cm_service->current = CM_SERVICE_STATE_INACTIVE;


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]