about summary refs log tree commit diff
path: root/libnm/nm-client.c
diff options
context:
space:
mode:
authorSebastien Bacher <seb128@ubuntu.com>2020-02-26 16:32:44 +0100
committerSebastien Bacher <seb128@ubuntu.com>2020-02-26 16:32:44 +0100
commit447eb1ee6c50e2cac4009e66add3c1d449822589 (patch)
tree7bc7db8f5d7e12137e758ea03ebe5c1eb8b07a23 /libnm/nm-client.c
parent0b818c504ebbb9454b501c532be8603bf383e37a (diff)
parent3cbb3d6ecfef1076fc757632ee8327935250afee (diff)
Merge remote-tracking branch 'salsa/debian/master' into ubuntu/master
Diffstat (limited to 'libnm/nm-client.c')
-rw-r--r--libnm/nm-client.c131
1 files changed, 113 insertions, 18 deletions
diff --git a/libnm/nm-client.c b/libnm/nm-client.c
index eabbe022..0c4daab2 100644
--- a/libnm/nm-client.c
+++ b/libnm/nm-client.c
@@ -1256,7 +1256,7 @@ nml_dbus_object_obj_changed_link (NMClient *self,
 	nm_assert (changed_type != NML_DBUS_OBJ_CHANGED_TYPE_NONE);
 
 	if (!NM_FLAGS_ALL ((NMLDBusObjChangedType ) dbobj->obj_changed_type, changed_type))
-		NML_NMCLIENT_LOG_T (self, "[%s] changed-type 0x%02x linked", dbobj->dbus_path->str, (guint) changed_type);
+		NML_NMCLIENT_LOG_T (self, "[%s]: changed-type 0x%02x linked", dbobj->dbus_path->str, (guint) changed_type);
 
 	if (dbobj->obj_changed_type == NML_DBUS_OBJ_CHANGED_TYPE_NONE) {
 		NMClientPrivate *priv;
@@ -1302,7 +1302,7 @@ nml_dbus_object_obj_changed_consume (NMClient *self,
 	if (dbobj->obj_changed_type == NML_DBUS_OBJ_CHANGED_TYPE_NONE) {
 		c_list_unlink (&dbobj->obj_changed_lst);
 		nm_assert (changed_type_res != NML_DBUS_OBJ_CHANGED_TYPE_NONE);
-		NML_NMCLIENT_LOG_T (self, "[%s] changed-type 0x%02x consumed", dbobj->dbus_path->str, (guint) changed_type_res);
+		NML_NMCLIENT_LOG_T (self, "[%s]: changed-type 0x%02x consumed", dbobj->dbus_path->str, (guint) changed_type_res);
 		return changed_type_res;
 	}
 
@@ -1310,7 +1310,7 @@ nml_dbus_object_obj_changed_consume (NMClient *self,
 
 	nm_assert (!c_list_contains (&priv->obj_changed_lst_head, &dbobj->obj_changed_lst));
 	nm_c_list_move_tail (&priv->obj_changed_lst_head, &dbobj->obj_changed_lst);
-	NML_NMCLIENT_LOG_T (self, "[%s] changed-type 0x%02x consumed  (still has 0x%02x)", dbobj->dbus_path->str, (guint) changed_type_res, (guint) dbobj->obj_changed_type);
+	NML_NMCLIENT_LOG_T (self, "[%s]: changed-type 0x%02x consumed  (still has 0x%02x)", dbobj->dbus_path->str, (guint) changed_type_res, (guint) dbobj->obj_changed_type);
 	return changed_type_res;
 }
 
@@ -1567,6 +1567,14 @@ nml_dbus_property_o_is_ready (const NMLDBusPropertyO *pr_o)
 	       || !pr_o->owner_dbobj;
 }
 
+gboolean
+nml_dbus_property_o_is_ready_fully (const NMLDBusPropertyO *pr_o)
+{
+	return    !pr_o->owner_dbobj
+	       || !pr_o->obj_watcher
+	       || pr_o->nmobj;
+}
+
 static void
 nml_dbus_property_o_notify_changed (NMLDBusPropertyO *pr_o,
                                     NMClient *self)
@@ -2988,9 +2996,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 +3009,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 +5185,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 +6554,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 +7441,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 +7501,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);