[gupnp/gupnp-1.0] connman: fix a race on the DBus interface to connman
- From: Jens Georg <jensgeorg src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gupnp/gupnp-1.0] connman: fix a race on the DBus interface to connman
- Date: Sat, 15 Oct 2016 10:13:41 +0000 (UTC)
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]