summary refs log tree commit diff
path: root/src/nm-dbus-object.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/nm-dbus-object.c')
-rw-r--r--src/nm-dbus-object.c362
1 files changed, 200 insertions, 162 deletions
diff --git a/src/nm-dbus-object.c b/src/nm-dbus-object.c
index a1332686..f49610ab 100644
--- a/src/nm-dbus-object.c
+++ b/src/nm-dbus-object.c
@@ -1,4 +1,4 @@
-// SPDX-License-Identifier: GPL-2.0+
+/* SPDX-License-Identifier: GPL-2.0+ */
 /*
  * Copyright (C) 2018 Red Hat, Inc.
  */
@@ -8,64 +8,66 @@
 #include "nm-dbus-object.h"
 
 #include "nm-dbus-manager.h"
+#include "NetworkManagerUtils.h"
 
 /*****************************************************************************/
 
 enum {
-	EXPORTED_CHANGED,
+    EXPORTED_CHANGED,
 
-	LAST_SIGNAL,
+    LAST_SIGNAL,
 };
 
-static guint signals[LAST_SIGNAL] = { 0 };
+static guint signals[LAST_SIGNAL] = {0};
 
-G_DEFINE_ABSTRACT_TYPE (NMDBusObject, nm_dbus_object, G_TYPE_OBJECT);
+G_DEFINE_ABSTRACT_TYPE(NMDBusObject, nm_dbus_object, G_TYPE_OBJECT);
 
 /*****************************************************************************/
 
-#define _NMLOG_DOMAIN      LOGD_CORE
-#define _NMLOG(level, ...) __NMLOG_DEFAULT_WITH_ADDR (level, _NMLOG_DOMAIN, "dbus-object", __VA_ARGS__)
+#define _NMLOG_DOMAIN LOGD_CORE
+#define _NMLOG(level, ...) \
+    __NMLOG_DEFAULT_WITH_ADDR(level, _NMLOG_DOMAIN, "dbus-object", __VA_ARGS__)
 
-#define _NMLOG2_DOMAIN      LOGD_DBUS_PROPS
-#define _NMLOG2(level, ...) __NMLOG_DEFAULT_WITH_ADDR (level, _NMLOG2_DOMAIN, "properties-changed", __VA_ARGS__)
+#define _NMLOG2_DOMAIN LOGD_DBUS_PROPS
+#define _NMLOG2(level, ...) \
+    __NMLOG_DEFAULT_WITH_ADDR(level, _NMLOG2_DOMAIN, "properties-changed", __VA_ARGS__)
 
 /*****************************************************************************/
 
 static void
-_emit_exported_changed (NMDBusObject *self)
+_emit_exported_changed(NMDBusObject *self)
 {
-	g_signal_emit (self, signals[EXPORTED_CHANGED], 0);
+    g_signal_emit(self, signals[EXPORTED_CHANGED], 0);
 }
 
 static char *
-_create_export_path (NMDBusObjectClass *klass)
+_create_export_path(NMDBusObjectClass *klass)
 {
-	nm_assert (NM_IS_DBUS_OBJECT_CLASS (klass));
-	nm_assert (klass->export_path.path);
+    nm_assert(NM_IS_DBUS_OBJECT_CLASS(klass));
+    nm_assert(klass->export_path.path);
 
 #if NM_MORE_ASSERTS
-	{
-		const char *p;
-
-		p = strchr (klass->export_path.path, '%');
-		if (klass->export_path.int_counter) {
-			nm_assert (p);
-			nm_assert (p[1] == 'l');
-			nm_assert (p[2] == 'l');
-			nm_assert (p[3] == 'u');
-			nm_assert (p[4] == '\0');
-		} else
-			nm_assert (!p);
-	}
+    {
+        const char *p;
+
+        p = strchr(klass->export_path.path, '%');
+        if (klass->export_path.int_counter) {
+            nm_assert(p);
+            nm_assert(p[1] == 'l');
+            nm_assert(p[2] == 'l');
+            nm_assert(p[3] == 'u');
+            nm_assert(p[4] == '\0');
+        } else
+            nm_assert(!p);
+    }
 #endif
 
-	if (klass->export_path.int_counter) {
-		NM_PRAGMA_WARNING_DISABLE("-Wformat-nonliteral")
-		return g_strdup_printf (klass->export_path.path,
-		                        ++(*klass->export_path.int_counter));
-		NM_PRAGMA_WARNING_REENABLE
-	}
-	return g_strdup (klass->export_path.path);
+    if (klass->export_path.int_counter) {
+        NM_PRAGMA_WARNING_DISABLE("-Wformat-nonliteral")
+        return g_strdup_printf(klass->export_path.path, ++(*klass->export_path.int_counter));
+        NM_PRAGMA_WARNING_REENABLE
+    }
+    return g_strdup(klass->export_path.path);
 }
 
 /**
@@ -83,26 +85,27 @@ _create_export_path (NMDBusObjectClass *klass)
  * Returns: the path @self was exported under
  */
 const char *
-nm_dbus_object_export (NMDBusObject *self)
+nm_dbus_object_export(gpointer /* (NMDBusObject *) */ self)
 {
-	static guint64 id_counter = 0;
+    NMDBusObject * self1      = self;
+    static guint64 id_counter = 0;
 
-	g_return_val_if_fail (NM_IS_DBUS_OBJECT (self), NULL);
+    g_return_val_if_fail(NM_IS_DBUS_OBJECT(self1), NULL);
 
-	g_return_val_if_fail (!self->internal.path, self->internal.path);
+    g_return_val_if_fail(!self1->internal.path, self1->internal.path);
 
-	nm_assert (!self->internal.is_unexporting);
+    nm_assert(!self1->internal.is_unexporting);
 
-	self->internal.path = _create_export_path (NM_DBUS_OBJECT_GET_CLASS (self));
+    self1->internal.path = _create_export_path(NM_DBUS_OBJECT_GET_CLASS(self1));
 
-	self->internal.export_version_id = ++id_counter;
+    self1->internal.export_version_id = ++id_counter;
 
-	_LOGT ("export: \"%s\"", self->internal.path);
+    _LOGT("export: \"%s\"", self1->internal.path);
 
-	_nm_dbus_manager_obj_export (self);
+    _nm_dbus_manager_obj_export(self1);
 
-	_emit_exported_changed (self);
-	return self->internal.path;
+    _emit_exported_changed(self1);
+    return self1->internal.path;
 }
 
 /**
@@ -113,182 +116,217 @@ nm_dbus_object_export (NMDBusObject *self)
  * auto-exported on future connections).
  */
 void
-nm_dbus_object_unexport (NMDBusObject *self)
+nm_dbus_object_unexport(gpointer /* (NMDBusObject *) */ self)
 {
-	g_return_if_fail (NM_IS_DBUS_OBJECT (self));
+    NMDBusObject *self1 = self;
 
-	g_return_if_fail (self->internal.path);
+    g_return_if_fail(NM_IS_DBUS_OBJECT(self1));
 
-	_LOGT ("unexport: \"%s\"", self->internal.path);
+    g_return_if_fail(self1->internal.path);
 
-	/* note that we emit the signal *before* actually unexporting the object.
-	 * The reason is, that listeners want to use this signal to know that
-	 * the object goes away, and clear their D-Bus path to this object.
-	 *
-	 * But this must happen before we actually unregister the object, so
-	 * that we first emit a D-Bus signal that other objects no longer
-	 * reference this object, before finally unregistering the object itself.
-	 *
-	 * The inconvenient part is, that at this point nm_dbus_object_get_path()
-	 * still returns the path. So, the callee needs to handle that. Possibly
-	 * by using "nm_dbus_object_get_path_still_exported()". */
-	self->internal.is_unexporting = TRUE;
+    _LOGT("unexport: \"%s\"", self1->internal.path);
 
-	_emit_exported_changed (self);
+    /* note that we emit the signal *before* actually unexporting the object.
+     * The reason is, that listeners want to use this signal to know that
+     * the object goes away, and clear their D-Bus path to this object.
+     *
+     * But this must happen before we actually unregister the object, so
+     * that we first emit a D-Bus signal that other objects no longer
+     * reference this object, before finally unregistering the object itself.
+     *
+     * The inconvenient part is, that at this point nm_dbus_object_get_path()
+     * still returns the path. So, the callee needs to handle that. Possibly
+     * by using "nm_dbus_object_get_path_still_exported()". */
+    self1->internal.is_unexporting = TRUE;
 
-	_nm_dbus_manager_obj_unexport (self);
+    _emit_exported_changed(self1);
 
-	nm_clear_g_free (&self->internal.path);
-	self->internal.export_version_id = 0;
+    _nm_dbus_manager_obj_unexport(self1);
 
-	self->internal.is_unexporting = FALSE;
+    nm_clear_g_free(&self1->internal.path);
+    self1->internal.export_version_id = 0;
+
+    self1->internal.is_unexporting = FALSE;
+}
+
+static gboolean
+_unexport_on_idle_cb(gpointer user_data)
+{
+    gs_unref_object NMDBusObject *self = user_data;
+
+    nm_dbus_object_unexport(self);
+    return G_SOURCE_REMOVE;
+}
+
+void
+nm_dbus_object_unexport_on_idle(gpointer /* (NMDBusObject *) */ self_take)
+{
+    NMDBusObject *self = g_steal_pointer(&self_take);
+
+    if (!self)
+        return;
+
+    g_return_if_fail(NM_IS_DBUS_OBJECT(self));
+
+    g_return_if_fail(self->internal.path);
+
+    /* There is no mechanism to cancel or abort the unexport. It will always
+     * gonna happen.
+     *
+     * However, we register it to block shutdown, so that we ensure that it will happen. */
+
+    nm_shutdown_wait_obj_register_object(self, "unexport-dbus-obj-on-idle");
+
+    /* pass on ownership. */
+    g_idle_add(_unexport_on_idle_cb, g_steal_pointer(&self));
 }
 
 /*****************************************************************************/
 
 void
-_nm_dbus_object_clear_and_unexport (NMDBusObject **location)
+_nm_dbus_object_clear_and_unexport(NMDBusObject **location)
 {
-	NMDBusObject *self;
+    NMDBusObject *self;
 
-	g_return_if_fail (location);
-	if (!*location)
-		return;
+    g_return_if_fail(location);
+    if (!*location)
+        return;
 
-	self = g_steal_pointer (location);
+    self = g_steal_pointer(location);
 
-	g_return_if_fail (NM_IS_DBUS_OBJECT (self));
+    g_return_if_fail(NM_IS_DBUS_OBJECT(self));
 
-	if (self->internal.path)
-		nm_dbus_object_unexport (self);
+    if (self->internal.path)
+        nm_dbus_object_unexport(self);
 
-	g_object_unref (self);
+    g_object_unref(self);
 }
 
 /*****************************************************************************/
 
 void
-nm_dbus_object_emit_signal_variant (NMDBusObject *self,
-                                    const NMDBusInterfaceInfoExtended *interface_info,
-                                    const GDBusSignalInfo *signal_info,
-                                    GVariant *args)
+nm_dbus_object_emit_signal_variant(NMDBusObject *                     self,
+                                   const NMDBusInterfaceInfoExtended *interface_info,
+                                   const GDBusSignalInfo *            signal_info,
+                                   GVariant *                         args)
 {
-	if (!self->internal.path) {
-		nm_g_variant_unref_floating (args);
-		return;
-	}
-	_nm_dbus_manager_obj_emit_signal (self, interface_info, signal_info, args);
+    if (!self->internal.path) {
+        nm_g_variant_unref_floating(args);
+        return;
+    }
+    _nm_dbus_manager_obj_emit_signal(self, interface_info, signal_info, args);
 }
 
 void
-nm_dbus_object_emit_signal (NMDBusObject *self,
-                            const NMDBusInterfaceInfoExtended *interface_info,
-                            const GDBusSignalInfo *signal_info,
-                            const char *format,
-                            ...)
+nm_dbus_object_emit_signal(NMDBusObject *                     self,
+                           const NMDBusInterfaceInfoExtended *interface_info,
+                           const GDBusSignalInfo *            signal_info,
+                           const char *                       format,
+                           ...)
 {
-	va_list ap;
+    va_list ap;
 
-	nm_assert (NM_IS_DBUS_OBJECT (self));
-	nm_assert (format);
+    nm_assert(NM_IS_DBUS_OBJECT(self));
+    nm_assert(format);
 
-	if (!self->internal.path)
-		return;
+    if (!self->internal.path)
+        return;
 
-	va_start (ap, format);
-	_nm_dbus_manager_obj_emit_signal (self,
-	                                 interface_info,
-	                                 signal_info,
-	                                 g_variant_new_va (format, NULL, &ap));
-	va_end (ap);
+    va_start(ap, format);
+    _nm_dbus_manager_obj_emit_signal(self,
+                                     interface_info,
+                                     signal_info,
+                                     g_variant_new_va(format, NULL, &ap));
+    va_end(ap);
 }
 
 /*****************************************************************************/
 
 static void
-dispatch_properties_changed (GObject *object,
-                             guint n_pspecs,
-                             GParamSpec **pspecs)
+dispatch_properties_changed(GObject *object, guint n_pspecs, GParamSpec **pspecs)
 {
-	NMDBusObject *self = NM_DBUS_OBJECT (object);
+    NMDBusObject *self = NM_DBUS_OBJECT(object);
 
-	if (self->internal.path)
-		_nm_dbus_manager_obj_notify (self, n_pspecs, (const GParamSpec *const*) pspecs);
+    if (self->internal.path)
+        _nm_dbus_manager_obj_notify(self, n_pspecs, (const GParamSpec *const *) pspecs);
 
-	G_OBJECT_CLASS (nm_dbus_object_parent_class)->dispatch_properties_changed (object, n_pspecs, pspecs);
+    G_OBJECT_CLASS(nm_dbus_object_parent_class)
+        ->dispatch_properties_changed(object, n_pspecs, pspecs);
 }
 
 /*****************************************************************************/
 
 static void
-nm_dbus_object_init (NMDBusObject *self)
+nm_dbus_object_init(NMDBusObject *self)
 {
-	c_list_init (&self->internal.objects_lst);
-	c_list_init (&self->internal.registration_lst_head);
-	self->internal.bus_manager = nm_g_object_ref (nm_dbus_manager_get ());
+    c_list_init(&self->internal.objects_lst);
+    c_list_init(&self->internal.registration_lst_head);
+    self->internal.bus_manager = nm_g_object_ref(nm_dbus_manager_get());
 }
 
 static void
-constructed (GObject *object)
+constructed(GObject *object)
 {
-	NMDBusObjectClass *klass;
-
-	G_OBJECT_CLASS (nm_dbus_object_parent_class)->constructed (object);
-
-	klass = NM_DBUS_OBJECT_GET_CLASS (object);
-
-	if (klass->export_on_construction)
-		nm_dbus_object_export ((NMDBusObject *) object);
-
-	/* NMDBusObject types should be very careful when overwriting notify().
-	 * It is possible to do, but this is a reminder that it's probably not
-	 * a good idea.
-	 *
-	 * It's not a good idea, because NMDBusObject uses dispatch_properties_changed()
-	 * to emit signals about a bunch of property changes. So, we want to make
-	 * use of g_object_freeze_notify() / g_object_thaw_notify() to combine multiple
-	 * property changes in one signal on D-Bus. Note that notify() is not invoked
-	 * while the signal is frozen, that means, whatever you do inside notify()
-	 * will not make it into the same batch of PropertiesChanged signal. That is
-	 * confusing, and probably not what you want.
-	 *
-	 * Simple solution: don't overwrite notify(). */
-	nm_assert (!G_OBJECT_CLASS (klass)->notify);
+    NMDBusObjectClass *klass;
+
+    G_OBJECT_CLASS(nm_dbus_object_parent_class)->constructed(object);
+
+    klass = NM_DBUS_OBJECT_GET_CLASS(object);
+
+    if (klass->export_on_construction)
+        nm_dbus_object_export((NMDBusObject *) object);
+
+    /* NMDBusObject types should be very careful when overwriting notify().
+     * It is possible to do, but this is a reminder that it's probably not
+     * a good idea.
+     *
+     * It's not a good idea, because NMDBusObject uses dispatch_properties_changed()
+     * to emit signals about a bunch of property changes. So, we want to make
+     * use of g_object_freeze_notify() / g_object_thaw_notify() to combine multiple
+     * property changes in one signal on D-Bus. Note that notify() is not invoked
+     * while the signal is frozen, that means, whatever you do inside notify()
+     * will not make it into the same batch of PropertiesChanged signal. That is
+     * confusing, and probably not what you want.
+     *
+     * Simple solution: don't overwrite notify(). */
+    nm_assert(!G_OBJECT_CLASS(klass)->notify);
 }
 
 static void
-dispose (GObject *object)
+dispose(GObject *object)
 {
-	NMDBusObject *self = NM_DBUS_OBJECT (object);
+    NMDBusObject *self = NM_DBUS_OBJECT(object);
 
-	/* Objects should have already been unexported by their owner, unless
-	 * we are quitting, where many objects stick around until exit.
-	 */
-	if (self->internal.path) {
-		if (!nm_dbus_manager_is_stopping (nm_dbus_object_get_manager (self)))
-			g_warn_if_reached ();
-		nm_dbus_object_unexport (self);
-	}
+    /* Objects should have already been unexported by their owner, unless
+     * we are quitting, where many objects stick around until exit.
+     */
+    if (self->internal.path) {
+        if (!nm_dbus_manager_is_stopping(nm_dbus_object_get_manager(self)))
+            g_warn_if_reached();
+        nm_dbus_object_unexport(self);
+    }
 
-	G_OBJECT_CLASS (nm_dbus_object_parent_class)->dispose (object);
+    G_OBJECT_CLASS(nm_dbus_object_parent_class)->dispose(object);
 
-	g_clear_object (&self->internal.bus_manager);
+    g_clear_object(&self->internal.bus_manager);
 }
 
 static void
-nm_dbus_object_class_init (NMDBusObjectClass *klass)
+nm_dbus_object_class_init(NMDBusObjectClass *klass)
 {
-	GObjectClass *object_class = G_OBJECT_CLASS (klass);
-
-	object_class->constructed = constructed;
-	object_class->dispose = dispose;
-	object_class->dispatch_properties_changed = dispatch_properties_changed;
-
-	signals[EXPORTED_CHANGED] =
-	    g_signal_new (NM_DBUS_OBJECT_EXPORTED_CHANGED,
-	                  G_OBJECT_CLASS_TYPE (object_class),
-	                  G_SIGNAL_RUN_FIRST,
-	                  0, NULL, NULL,
-	                  g_cclosure_marshal_VOID__VOID,
-	                  G_TYPE_NONE, 0);
+    GObjectClass *object_class = G_OBJECT_CLASS(klass);
+
+    object_class->constructed                 = constructed;
+    object_class->dispose                     = dispose;
+    object_class->dispatch_properties_changed = dispatch_properties_changed;
+
+    signals[EXPORTED_CHANGED] = g_signal_new(NM_DBUS_OBJECT_EXPORTED_CHANGED,
+                                             G_OBJECT_CLASS_TYPE(object_class),
+                                             G_SIGNAL_RUN_FIRST,
+                                             0,
+                                             NULL,
+                                             NULL,
+                                             g_cclosure_marshal_VOID__VOID,
+                                             G_TYPE_NONE,
+                                             0);
 }