summary refs log tree commit diff
path: root/shared/nm-glib-aux/nm-dbus-aux.c
diff options
context:
space:
mode:
Diffstat (limited to 'shared/nm-glib-aux/nm-dbus-aux.c')
-rw-r--r--shared/nm-glib-aux/nm-dbus-aux.c333
1 files changed, 315 insertions, 18 deletions
diff --git a/shared/nm-glib-aux/nm-dbus-aux.c b/shared/nm-glib-aux/nm-dbus-aux.c
index 083c4fee..75b282bc 100644
--- a/shared/nm-glib-aux/nm-dbus-aux.c
+++ b/shared/nm-glib-aux/nm-dbus-aux.c
@@ -1,21 +1,6 @@
-/* NetworkManager -- Network link manager
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the
- * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
- * Boston, MA 02110-1301 USA.
- *
- * (C) Copyright 2019 Red Hat, Inc.
+// SPDX-License-Identifier: LGPL-2.1+
+/*
+ * Copyright (C) 2019 Red Hat, Inc.
  */
 
 #include "nm-default.h"
@@ -67,3 +52,315 @@ nm_dbus_connection_call_get_name_owner (GDBusConnection *dbus_connection,
 	                        _nm_dbus_connection_call_get_name_owner_cb,
 	                        nm_utils_user_data_pack (user_data, callback));
 }
+
+/*****************************************************************************/
+
+static void
+_nm_dbus_connection_call_get_all_cb (GObject *source,
+                                     GAsyncResult *res,
+                                     gpointer user_data)
+{
+	gs_unref_variant GVariant *ret = NULL;
+	gs_free_error GError *error = NULL;
+	gpointer orig_user_data;
+	NMDBusConnectionCallDefaultCb callback;
+
+	nm_utils_user_data_unpack (user_data, &orig_user_data, &callback);
+
+	ret = g_dbus_connection_call_finish (G_DBUS_CONNECTION (source), res, &error);
+
+	nm_assert ((!!ret) != (!!error));
+
+	callback (ret, error, orig_user_data);
+}
+
+void
+nm_dbus_connection_call_get_all (GDBusConnection *dbus_connection,
+                                 const char *bus_name,
+                                 const char *object_path,
+                                 const char *interface_name,
+                                 int timeout_msec,
+                                 GCancellable *cancellable,
+                                 NMDBusConnectionCallDefaultCb callback,
+                                 gpointer user_data)
+{
+	nm_assert (callback);
+
+	g_dbus_connection_call (dbus_connection,
+	                        bus_name,
+	                        object_path,
+	                        DBUS_INTERFACE_PROPERTIES,
+	                        "GetAll",
+	                        g_variant_new ("(s)", interface_name),
+	                        G_VARIANT_TYPE ("(a{sv})"),
+	                        G_DBUS_CALL_FLAGS_NONE,
+	                        timeout_msec,
+	                        cancellable,
+	                        _nm_dbus_connection_call_get_all_cb,
+	                        nm_utils_user_data_pack (user_data, callback));
+}
+
+/*****************************************************************************/
+
+typedef struct {
+	NMDBusConnectionSignalObjectMangerCb callback;
+	gpointer user_data;
+	GDestroyNotify user_data_free_func;
+} SubscribeObjectManagerData;
+
+static void
+_subscribe_object_manager_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)
+{
+	const SubscribeObjectManagerData *d = user_data;
+
+	nm_assert (nm_streq0 (interface_name, DBUS_INTERFACE_OBJECT_MANAGER));
+
+	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);
+
+		d->callback (object_path, interfaces_and_properties, NULL, d->user_data);
+		return;
+	}
+
+	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);
+
+		d->callback (object_path, NULL, interfaces, d->user_data);
+		return;
+	}
+}
+
+static void
+_subscribe_object_manager_data_free (gpointer ptr)
+{
+	SubscribeObjectManagerData *d = ptr;
+
+	if (d->user_data_free_func)
+		d->user_data_free_func (d->user_data);
+	nm_g_slice_free (d);
+}
+
+guint
+nm_dbus_connection_signal_subscribe_object_manager (GDBusConnection *dbus_connection,
+                                                    const char *service_name,
+                                                    const char *object_path,
+                                                    NMDBusConnectionSignalObjectMangerCb callback,
+                                                    gpointer user_data,
+                                                    GDestroyNotify user_data_free_func)
+{
+	SubscribeObjectManagerData *d;
+
+	g_return_val_if_fail (callback, 0);
+
+	d = g_slice_new (SubscribeObjectManagerData);
+	*d = (SubscribeObjectManagerData) {
+		.callback            = callback,
+		.user_data           = user_data,
+		.user_data_free_func = user_data_free_func,
+	};
+
+	return nm_dbus_connection_signal_subscribe_object_manager_plain (dbus_connection,
+	                                                                 service_name,
+	                                                                 object_path,
+	                                                                 NULL,
+	                                                                 _subscribe_object_manager_cb,
+	                                                                 d,
+	                                                                 _subscribe_object_manager_data_free);
+}
+
+/*****************************************************************************/
+
+static void
+_nm_dbus_connection_call_get_managed_objects_cb (GObject *source,
+                                                 GAsyncResult *res,
+                                                 gpointer user_data)
+{
+	gs_unref_variant GVariant *ret = NULL;
+	gs_unref_variant GVariant *arg = NULL;
+	gs_free_error GError *error = NULL;
+	gpointer orig_user_data;
+	NMDBusConnectionCallDefaultCb callback;
+
+	nm_utils_user_data_unpack (user_data, &orig_user_data, &callback);
+
+	ret = g_dbus_connection_call_finish (G_DBUS_CONNECTION (source), res, &error);
+
+	nm_assert ((!!ret) != (!!error));
+
+	if (ret) {
+		nm_assert (g_variant_is_of_type (ret, G_VARIANT_TYPE ("(a{oa{sa{sv}}})")));
+		arg = g_variant_get_child_value (ret, 0);
+	}
+
+	callback (arg, error, orig_user_data);
+}
+
+void
+nm_dbus_connection_call_get_managed_objects (GDBusConnection *dbus_connection,
+                                             const char *bus_name,
+                                             const char *object_path,
+                                             GDBusCallFlags flags,
+                                             int timeout_msec,
+                                             GCancellable *cancellable,
+                                             NMDBusConnectionCallDefaultCb callback,
+                                             gpointer user_data)
+{
+	nm_assert (callback);
+
+	g_dbus_connection_call (dbus_connection,
+	                        bus_name,
+	                        object_path,
+	                        DBUS_INTERFACE_OBJECT_MANAGER,
+	                        "GetManagedObjects",
+	                        NULL,
+	                        G_VARIANT_TYPE ("(a{oa{sa{sv}}})"),
+	                        flags,
+	                        timeout_msec,
+	                        cancellable,
+	                        _nm_dbus_connection_call_get_managed_objects_cb,
+	                        nm_utils_user_data_pack (user_data, callback));
+}
+
+/*****************************************************************************/
+
+static void
+_call_finish_cb (GObject *source,
+                 GAsyncResult *result,
+                 gpointer user_data,
+                 gboolean return_void,
+                 gboolean strip_dbus_error)
+{
+	gs_unref_object GTask *task = user_data;
+	gs_unref_variant GVariant *ret = NULL;
+	GError *error = NULL;
+
+	nm_assert (G_IS_DBUS_CONNECTION (source));
+	nm_assert (G_IS_TASK (user_data));
+
+	ret = g_dbus_connection_call_finish (G_DBUS_CONNECTION (source), result, &error);
+	if (!ret) {
+		if (strip_dbus_error)
+			g_dbus_error_strip_remote_error (error);
+		g_task_return_error (task, error);
+		return;
+	}
+
+	if (!return_void) {
+		nm_assert (!g_variant_is_of_type (ret, G_VARIANT_TYPE ("()")));
+		g_task_return_pointer (task, g_steal_pointer (&ret), (GDestroyNotify) g_variant_unref);
+	} else {
+		nm_assert (g_variant_is_of_type (ret, G_VARIANT_TYPE ("()")));
+		g_task_return_boolean (task, TRUE);
+	}
+}
+
+/**
+ * nm_dbus_connection_call_finish_void_cb:
+ *
+ * A default callback to pass as callback to g_dbus_connection_call().
+ *
+ * - user_data must be a GTask, whose reference will be consumed by the
+ *   callback.
+ * - the return GVariant must be a empty tuple "()".
+ * - the GTask is returned either with error or TRUE boolean.
+ */
+void
+nm_dbus_connection_call_finish_void_cb (GObject *source,
+                                        GAsyncResult *result,
+                                        gpointer user_data)
+{
+	_call_finish_cb (source, result, user_data, TRUE, FALSE);
+}
+
+/**
+ * nm_dbus_connection_call_finish_void_strip_dbus_error_cb:
+ *
+ * Like nm_dbus_connection_call_finish_void_cb(). The difference
+ * is that on error this will first call g_dbus_error_strip_remote_error() on the error.
+ */
+void
+nm_dbus_connection_call_finish_void_strip_dbus_error_cb (GObject *source,
+                                                         GAsyncResult *result,
+                                                         gpointer user_data)
+{
+	_call_finish_cb (source, result, user_data, TRUE, TRUE);
+}
+
+/**
+ * nm_dbus_connection_call_finish_variant_cb:
+ *
+ * A default callback to pass as callback to g_dbus_connection_call().
+ *
+ * - user_data must be a GTask, whose reference will be consumed by the
+ *   callback.
+ * - the return GVariant must not be an empty tuple "()".
+ * - the GTask is returned either with error or with a pointer containing the GVariant.
+ */
+void
+nm_dbus_connection_call_finish_variant_cb (GObject *source,
+                                           GAsyncResult *result,
+                                           gpointer user_data)
+{
+	_call_finish_cb (source, result, user_data, FALSE, FALSE);
+}
+
+/**
+ * nm_dbus_connection_call_finish_variant_strip_dbus_error_cb:
+ *
+ * Like nm_dbus_connection_call_finish_variant_strip_dbus_error_cb(). The difference
+ * is that on error this will first call g_dbus_error_strip_remote_error() on the error.
+ */
+void
+nm_dbus_connection_call_finish_variant_strip_dbus_error_cb (GObject *source,
+                                                            GAsyncResult *result,
+                                                            gpointer user_data)
+{
+	_call_finish_cb (source, result, user_data, FALSE, TRUE);
+}
+
+/*****************************************************************************/
+
+gboolean
+_nm_dbus_error_is (GError *error, ...)
+{
+	gs_free char *dbus_error = NULL;
+	const char *name;
+	va_list ap;
+
+	dbus_error = g_dbus_error_get_remote_error (error);
+	if (!dbus_error)
+		return FALSE;
+
+	va_start (ap, error);
+	while ((name = va_arg (ap, const char *))) {
+		if (nm_streq (dbus_error, name))
+			return TRUE;
+	}
+	va_end (ap);
+
+	return FALSE;
+}