diff options
author | Dan Winship <danw@redhat.com> | 2015-03-27 08:02:25 -0400 |
---|---|---|
committer | Dan Winship <danw@redhat.com> | 2015-04-03 16:58:40 -0400 |
commit | 4e61f4bf357cda85303af50e96930648d87144e0 (patch) | |
tree | 2c92016daf5861be8668a931e408126ea1a97c27 | |
parent | 353570224facca779d60f821db2d0e77f075c0d6 (diff) | |
download | NetworkManager-4e61f4bf357cda85303af50e96930648d87144e0.tar.gz |
libnm-core: add _nm_dbus_signal_connect()
Add _nm_dbus_signal_connect(), for connecting to D-Bus signals on a
GDBusProxy, with typechecking and pre-parsing of the parameters
variant.
-rw-r--r-- | libnm-core/Makefile.libnm-core | 1 | ||||
-rw-r--r-- | libnm-core/nm-core-internal.h | 12 | ||||
-rw-r--r-- | libnm-core/nm-dbus-utils.c | 176 |
3 files changed, 189 insertions, 0 deletions
diff --git a/libnm-core/Makefile.libnm-core b/libnm-core/Makefile.libnm-core index 09a80c714b..bbd504503a 100644 --- a/libnm-core/Makefile.libnm-core +++ b/libnm-core/Makefile.libnm-core @@ -58,6 +58,7 @@ libnm_core_sources = \ $(core_build)/nm-core-enum-types.c \ $(core)/crypto.c \ $(core)/nm-connection.c \ + $(core)/nm-dbus-utils.c \ $(core)/nm-errors.c \ $(core)/nm-keyfile-reader.c \ $(core)/nm-keyfile-utils.c \ diff --git a/libnm-core/nm-core-internal.h b/libnm-core/nm-core-internal.h index 8f21e8fe36..002f183f01 100644 --- a/libnm-core/nm-core-internal.h +++ b/libnm-core/nm-core-internal.h @@ -33,6 +33,8 @@ * and some test programs. **/ +#include <gio/gio.h> + #include "nm-connection.h" #include "nm-core-enum-types.h" #include "nm-dbus-interface.h" @@ -139,4 +141,14 @@ GByteArray *nm_utils_rsa_key_encrypt (const guint8 *data, gint64 _nm_utils_ascii_str_to_int64 (const char *str, guint base, gint64 min, gint64 max, gint64 fallback); +gulong _nm_dbus_signal_connect_data (GDBusProxy *proxy, + const char *signal_name, + const GVariantType *signature, + GCallback c_handler, + gpointer data, + GClosureNotify destroy_data, + GConnectFlags connect_flags); +#define _nm_dbus_signal_connect(proxy, name, signature, handler, data) \ + _nm_dbus_signal_connect_data (proxy, name, signature, handler, data, NULL, (GConnectFlags) 0) + #endif diff --git a/libnm-core/nm-dbus-utils.c b/libnm-core/nm-dbus-utils.c new file mode 100644 index 0000000000..aa1fdd9387 --- /dev/null +++ b/libnm-core/nm-dbus-utils.c @@ -0,0 +1,176 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */ +/* + * 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. + * + * Copyright 2015 Red Hat, Inc. + */ + +#include "config.h" + +#include <string.h> +#include <gio/gio.h> + +#include "nm-core-internal.h" + +typedef struct { + char *signal_name; + const GVariantType *signature; +} NMDBusSignalData; + +static void +dbus_signal_data_free (gpointer data, GClosure *closure) +{ + NMDBusSignalData *sd = data; + + g_free (sd->signal_name); + g_slice_free (NMDBusSignalData, sd); +} + +static void +dbus_signal_meta_marshal (GClosure *closure, + GValue *return_value, + guint n_param_values, + const GValue *param_values, + gpointer invocation_hint, + gpointer marshal_data) +{ + NMDBusSignalData *sd = marshal_data; + const char *signal_name; + GVariant *parameters, *param; + GValue *closure_params; + gsize n_params, i; + + g_return_if_fail (n_param_values == 4); + + signal_name = g_value_get_string (¶m_values[2]); + parameters = g_value_get_variant (¶m_values[3]); + + if (strcmp (signal_name, sd->signal_name) != 0) + return; + + if (sd->signature) { + if (!g_variant_is_of_type (parameters, sd->signature)) { + g_warning ("%p: got signal '%s' but parameters were of type '%s', not '%s'", + g_value_get_object (¶m_values[0]), + signal_name, g_variant_get_type_string (parameters), + g_variant_type_peek_string (sd->signature)); + return; + } + + n_params = g_variant_n_children (parameters) + 1; + } else + n_params = 1; + + closure_params = g_new0 (GValue, n_params); + g_value_init (&closure_params[0], G_TYPE_OBJECT); + g_value_copy (¶m_values[0], &closure_params[0]); + + for (i = 1; i < n_params; i++) { + param = g_variant_get_child_value (parameters, i - 1); + if ( g_variant_is_of_type (param, G_VARIANT_TYPE ("ay")) + || g_variant_is_of_type (param, G_VARIANT_TYPE ("aay"))) { + /* g_dbus_gvariant_to_gvalue() thinks 'ay' means "non-UTF-8 NUL-terminated string" */ + g_value_init (&closure_params[i], G_TYPE_VARIANT); + g_value_set_variant (&closure_params[i], param); + } else + g_dbus_gvariant_to_gvalue (param, &closure_params[i]); + g_variant_unref (param); + } + + g_cclosure_marshal_generic (closure, + NULL, + n_params, + closure_params, + invocation_hint, + NULL); + + for (i = 0; i < n_params; i++) + g_value_unset (&closure_params[i]); + g_free (closure_params); +} + +/** + * _nm_dbus_signal_connect_data: + * @proxy: a #GDBusProxy + * @signal_name: the D-Bus signal to connect to + * @signature: (allow-none): the signal's type signature (must be a tuple) + * @c_handler: the signal handler function + * @data: (allow-none): data to pass to @c_handler + * @destroy_data: (allow-none): closure destroy notify for @data + * @connect_flags: connection flags + * + * Connects to the D-Bus signal @signal_name on @proxy. @c_handler must be a + * void function whose first argument is a #GDBusProxy, followed by arguments + * for each element of @signature, ending with a #gpointer argument for @data. + * + * The argument types in @c_handler correspond to the types output by + * g_dbus_gvariant_to_gvalue(), except for 'ay' and 'aay'. In particular: + * - both 16-bit and 32-bit integers are passed as #gint/#guint + * - 'as' values are passed as #GStrv (char **) + * - all other array, tuple, and dict types are passed as #GVariant + * + * If @signature is %NULL, then the signal's parameters will be ignored, and + * @c_handler should take only the #GDBusProxy and #gpointer arguments. + * + * Returns: the signal handler ID, which can be used with + * g_signal_handler_remove(). Beware that because of the way the signal is + * connected, you will not be able to remove it with + * g_signal_handlers_disconnect_by_func(), although + * g_signal_handlers_disconnect_by_data() will work correctly. + */ +gulong +_nm_dbus_signal_connect_data (GDBusProxy *proxy, + const char *signal_name, + const GVariantType *signature, + GCallback c_handler, + gpointer data, + GClosureNotify destroy_data, + GConnectFlags connect_flags) +{ + NMDBusSignalData *sd; + GClosure *closure; + gboolean swapped = !!(connect_flags & G_CONNECT_SWAPPED); + gboolean after = !!(connect_flags & G_CONNECT_AFTER); + + g_return_val_if_fail (G_IS_DBUS_PROXY (proxy), 0); + g_return_val_if_fail (signal_name != NULL, 0); + g_return_val_if_fail (signature == NULL || g_variant_type_is_tuple (signature), 0); + g_return_val_if_fail (c_handler != NULL, 0); + + sd = g_slice_new (NMDBusSignalData); + sd->signal_name = g_strdup (signal_name); + sd->signature = signature; + + closure = (swapped ? g_cclosure_new_swap : g_cclosure_new) (c_handler, data, destroy_data); + g_closure_set_marshal (closure, g_cclosure_marshal_generic); + g_closure_set_meta_marshal (closure, sd, dbus_signal_meta_marshal); + g_closure_add_finalize_notifier (closure, sd, dbus_signal_data_free); + + return g_signal_connect_closure (proxy, "g-signal", closure, after); +} + +/** + * _nm_dbus_signal_connect: + * @proxy: a #GDBusProxy + * @signal_name: the D-Bus signal to connect to + * @signature: the signal's type signature (must be a tuple) + * @c_handler: the signal handler function + * @data: (allow-none): data to pass to @c_handler + * + * Simplified version of _nm_dbus_signal_connect_data() with fewer arguments. + * + * Returns: the signal handler ID, as with _nm_signal_connect_data(). + */ |