about summary refs log tree commit diff
path: root/libnm/nm-client.c
diff options
context:
space:
mode:
authorMichael Biebl <biebl@debian.org>2020-01-31 12:10:14 +0100
committerMichael Biebl <biebl@debian.org>2020-01-31 12:10:14 +0100
commitf3c6d0765dff885e168b94f28e06ecc640315a74 (patch)
tree30d67309f4d9b48ad269dfad6e80e5c15373ea75 /libnm/nm-client.c
parent90c93214efba0966274224a93a77d235d4f8c034 (diff)
New upstream version 1.22.6 upstream/1.22.6
Diffstat (limited to 'libnm/nm-client.c')
-rw-r--r--libnm/nm-client.c117
1 files changed, 102 insertions, 15 deletions
diff --git a/libnm/nm-client.c b/libnm/nm-client.c
index eabbe022..4fa1c1f3 100644
--- a/libnm/nm-client.c
+++ b/libnm/nm-client.c
@@ -2988,9 +2988,12 @@ _dbus_handle_interface_removed (NMClient *self,
 }
 
 static void
-_dbus_managed_objects_changed_cb (const char *object_path,
-                                  GVariant *added_interfaces_and_properties,
-                                  const char *const*removed_interfaces,
+_dbus_managed_objects_changed_cb (GDBusConnection *connection,
+                                  const char *sender_name,
+                                  const char *arg_object_path,
+                                  const char *interface_name,
+                                  const char *signal_name,
+                                  GVariant *parameters,
                                   gpointer user_data)
 {
 	NMClient *self = user_data;
@@ -2998,19 +3001,50 @@ _dbus_managed_objects_changed_cb (const char *object_path,
 	const char *log_context;
 	gboolean changed;
 
+	nm_assert (nm_streq0 (interface_name, DBUS_INTERFACE_OBJECT_MANAGER));
+
 	if (priv->get_managed_objects_cancellable) {
 		/* we still wait for the initial GetManagedObjects(). Ignore the event. */
 		return;
 	}
 
-	if (!added_interfaces_and_properties) {
-		log_context = "interfaces-removed";
-		changed = _dbus_handle_interface_removed (self, log_context, object_path, NULL, removed_interfaces);
-	} else {
+	if (nm_streq (signal_name, "InterfacesAdded")) {
+		gs_unref_variant GVariant *interfaces_and_properties = NULL;
+		const char *object_path;
+
+		if (!g_variant_is_of_type (parameters, G_VARIANT_TYPE ("(oa{sa{sv}})")))
+			return;
+
+		g_variant_get (parameters,
+		               "(&o@a{sa{sv}})",
+		               &object_path,
+		               &interfaces_and_properties);
+
 		log_context = "interfaces-added";
-		changed = _dbus_handle_interface_added (self, log_context, object_path, added_interfaces_and_properties);
+		changed = _dbus_handle_interface_added (self, log_context, object_path, interfaces_and_properties);
+		goto out;
+	}
+
+	if (nm_streq (signal_name, "InterfacesRemoved")) {
+		gs_free const char **interfaces = NULL;
+		const char *object_path;
+
+		if (!g_variant_is_of_type (parameters, G_VARIANT_TYPE ("(oas)")))
+			return;
+
+		g_variant_get (parameters,
+		               "(&o^a&s)",
+		               &object_path,
+		               &interfaces);
+
+		log_context = "interfaces-removed";
+		changed = _dbus_handle_interface_removed (self, log_context, object_path, NULL, interfaces);
+		goto out;
 	}
 
+	return;
+
+out:
 	if (changed)
 		_dbus_handle_changes (self, log_context, TRUE);
 }
@@ -5143,7 +5177,7 @@ nm_client_add_and_activate_connection2_finish (NMClient *client,
 {
 	return NM_ACTIVE_CONNECTION (_request_wait_finish (client,
 	                                                   result,
-	                                                   nm_client_add_connection2,
+	                                                   nm_client_add_and_activate_connection2,
 	                                                   out_result,
 	                                                   error));
 }
@@ -6512,12 +6546,13 @@ _init_fetch_all (NMClient *self)
 
 	priv->get_managed_objects_cancellable = g_cancellable_new ();
 
-	priv->dbsid_nm_object_manager = nm_dbus_connection_signal_subscribe_object_manager (priv->dbus_connection,
-	                                                                                    priv->name_owner,
-	                                                                                    "/org/freedesktop",
-	                                                                                    _dbus_managed_objects_changed_cb,
-	                                                                                    self,
-	                                                                                    NULL);
+	priv->dbsid_nm_object_manager = nm_dbus_connection_signal_subscribe_object_manager_plain (priv->dbus_connection,
+	                                                                                          priv->name_owner,
+	                                                                                          "/org/freedesktop",
+	                                                                                          NULL,
+	                                                                                          _dbus_managed_objects_changed_cb,
+	                                                                                          self,
+	                                                                                          NULL);
 
 	priv->dbsid_dbus_properties_properties_changed = nm_dbus_connection_signal_subscribe_properties_changed (priv->dbus_connection,
 	                                                                                                         priv->name_owner,
@@ -7398,6 +7433,18 @@ constructed (GObject *object)
 	NML_NMCLIENT_LOG_D (self, "new NMClient instance");
 }
 
+static inline gboolean
+_dispose_cleanup_context_busy_watcher_cb (gpointer user_data)
+{
+	nm_auto_unref_gmaincontext GMainContext *context = NULL;
+	gs_unref_object GObject *context_busy_watcher = NULL;
+
+	nm_utils_user_data_unpack (user_data, &context, &context_busy_watcher);
+
+	nm_assert (G_IS_OBJECT (context_busy_watcher));
+	return G_SOURCE_REMOVE;
+}
+
 static void
 dispose (GObject *object)
 {
@@ -7446,6 +7493,46 @@ dispose (GObject *object)
 
 	nm_clear_pointer (&priv->udev, udev_unref);
 
+	if (   priv->context_busy_watcher
+	    && priv->dbus_context) {
+		GSource *cleanup_source;
+
+		/* Technically, we cancelled all pending actions (and these actions
+		 * (GTask) keep the context_busy_watcher object alive). Also, we passed
+		 * no destroy notify to g_dbus_connection_signal_subscribe().
+		 * That means, there should be no other unaccounted GSource'es left.
+		 *
+		 * However, we really need to be sure that the context_busy_watcher's
+		 * lifetime matches the time that the context is busy. That is especially
+		 * important with synchronous initialization, where the context-busy-watcher
+		 * keeps the inner GMainContext integrated in the caller's.
+		 * We must not g_source_destroy() that integration too early.
+		 *
+		 * So to be really sure all this is given, always schedule one last
+		 * cleanup idle action with low priority. This should be the last
+		 * thing related to this instance that keeps the context busy.
+		 *
+		 * Note that we could also *not* take a reference on priv->dbus_context
+		 * and unref priv->context_busy_watcher via the GDestroyNotify. That would
+		 * allow for the context to be wrapped up early, and when the last user
+		 * gives up the reference to the context, the destroy notify could complete
+		 * without even invoke the idle handler. However, that destroy notify may
+		 * not be called in the right thread. So, we want to be sure that we unref
+		 * the context-busy-watcher in the right context. Hence, we always take an
+		 * additional reference and always cleanup in the idle handler. This means:
+		 * the user *MUST* always keep iterating the context after NMClient got destroyed.
+		 * But that is not a severe limitation, because the user anyway must be prepared
+		 * to do that. That is because in many cases it is necessary anyway (and the user
+		 * wouldn't know a priory when not). This way, it is just always necessary. */
+		cleanup_source = nm_g_idle_source_new (G_PRIORITY_LOW + 10,
+		                                       _dispose_cleanup_context_busy_watcher_cb,
+		                                       nm_utils_user_data_pack (g_main_context_ref (priv->dbus_context),
+		                                                                g_steal_pointer (&priv->context_busy_watcher)),
+		                                       NULL);
+		g_source_attach (cleanup_source, priv->dbus_context);
+		g_source_unref (cleanup_source);
+	}
+
 	nm_clear_pointer (&priv->dbus_context, g_main_context_unref);
 	nm_clear_pointer (&priv->main_context, g_main_context_unref);