diff options
-rw-r--r-- | Makefile.am | 1 | ||||
-rw-r--r-- | po/POTFILES.in | 2 | ||||
-rw-r--r-- | src/core/devices/wwan/nm-modem-ofono.c | 61 | ||||
-rw-r--r-- | src/core/nm-dispatcher.c | 3 | ||||
-rw-r--r-- | src/core/nm-sleep-monitor.c | 31 | ||||
-rw-r--r-- | src/core/supplicant/nm-supplicant-interface.c | 2 | ||||
-rw-r--r-- | src/core/supplicant/nm-supplicant-manager.c | 4 | ||||
-rw-r--r-- | src/libnm-core-impl/meson.build | 1 | ||||
-rw-r--r-- | src/libnm-core-impl/nm-dbus-utils.c | 259 | ||||
-rw-r--r-- | src/libnm-core-intern/nm-core-internal.h | 25 | ||||
-rw-r--r-- | src/libnm-glib-aux/nm-dbus-aux.c | 205 | ||||
-rw-r--r-- | src/libnm-glib-aux/nm-dbus-aux.h | 36 |
12 files changed, 290 insertions, 340 deletions
diff --git a/Makefile.am b/Makefile.am index d75aefae86..7142073cad 100644 --- a/Makefile.am +++ b/Makefile.am @@ -1370,7 +1370,6 @@ src_libnm_core_impl_lib_c_settings_real = \ src_libnm_core_impl_lib_c_real = \ $(src_libnm_core_impl_lib_c_settings_real) \ src/libnm-core-impl/nm-connection.c \ - src/libnm-core-impl/nm-dbus-utils.c \ src/libnm-core-impl/nm-errors.c \ src/libnm-core-impl/nm-keyfile-utils.c \ src/libnm-core-impl/nm-keyfile.c \ diff --git a/po/POTFILES.in b/po/POTFILES.in index 82895456b0..a1a5730075 100644 --- a/po/POTFILES.in +++ b/po/POTFILES.in @@ -72,7 +72,6 @@ src/libnm-client-impl/nm-vpn-service-plugin.c src/libnm-core-aux-extern/nm-libnm-core-aux.c src/libnm-core-aux-intern/nm-libnm-core-utils.c src/libnm-core-impl/nm-connection.c -src/libnm-core-impl/nm-dbus-utils.c src/libnm-core-impl/nm-keyfile-utils.c src/libnm-core-impl/nm-keyfile.c src/libnm-core-impl/nm-setting-6lowpan.c @@ -132,6 +131,7 @@ src/libnm-crypto/nm-crypto-gnutls.c src/libnm-crypto/nm-crypto-nss.c src/libnm-crypto/nm-crypto-null.c src/libnm-crypto/nm-crypto.c +src/libnm-glib-aux/nm-dbus-aux.c src/libnm-glib-aux/nm-shared-utils.c src/libnm-log-core/nm-logging.c src/libnmc-base/nm-client-utils.c diff --git a/src/core/devices/wwan/nm-modem-ofono.c b/src/core/devices/wwan/nm-modem-ofono.c index 10e6d145b7..b374562189 100644 --- a/src/core/devices/wwan/nm-modem-ofono.c +++ b/src/core/devices/wwan/nm-modem-ofono.c @@ -7,6 +7,7 @@ #include "nm-modem-ofono.h" +#include "libnm-glib-aux/nm-dbus-aux.h" #include "libnm-core-intern/nm-core-internal.h" #include "libnm-glib-aux/nm-uuid.h" #include "devices/nm-device-private.h" @@ -453,11 +454,11 @@ _sim_proxy_new_cb(GObject *source, GAsyncResult *result, gpointer user_data) priv->sim_proxy = proxy; /* Watch for custom ofono PropertyChanged signals */ - _nm_dbus_signal_connect(priv->sim_proxy, - "PropertyChanged", - G_VARIANT_TYPE("(sv)"), - G_CALLBACK(sim_property_changed), - self); + _nm_dbus_proxy_signal_connect(priv->sim_proxy, + "PropertyChanged", + G_VARIANT_TYPE("(sv)"), + G_CALLBACK(sim_property_changed), + self); g_dbus_proxy_call(priv->sim_proxy, "GetProperties", @@ -833,11 +834,11 @@ _context_proxy_new_cb(GObject *source, GAsyncResult *result, gpointer user_data) _LOGD("recieved proxy for %s", g_dbus_proxy_get_object_path(proxy)); octx->proxy = proxy; - _nm_dbus_signal_connect(proxy, - "PropertyChanged", - G_VARIANT_TYPE("(sv)"), - G_CALLBACK(context_property_changed), - octx); + _nm_dbus_proxy_signal_connect(proxy, + "PropertyChanged", + G_VARIANT_TYPE("(sv)"), + G_CALLBACK(context_property_changed), + octx); uuid = _generate_uuid(priv->imsi, g_dbus_proxy_get_object_path(proxy)); g_hash_table_insert(priv->contexts, uuid, octx); @@ -972,23 +973,23 @@ _connman_proxy_new_cb(GObject *source, GAsyncResult *result, gpointer user_data) priv->connman_proxy = proxy; - _nm_dbus_signal_connect(priv->connman_proxy, - "PropertyChanged", - G_VARIANT_TYPE("(sv)"), - G_CALLBACK(connman_property_changed), - self); + _nm_dbus_proxy_signal_connect(priv->connman_proxy, + "PropertyChanged", + G_VARIANT_TYPE("(sv)"), + G_CALLBACK(connman_property_changed), + self); - _nm_dbus_signal_connect(priv->connman_proxy, - "ContextAdded", - G_VARIANT_TYPE("(oa{sv})"), - G_CALLBACK(connman_context_added), - self); + _nm_dbus_proxy_signal_connect(priv->connman_proxy, + "ContextAdded", + G_VARIANT_TYPE("(oa{sv})"), + G_CALLBACK(connman_context_added), + self); - _nm_dbus_signal_connect(priv->connman_proxy, - "ContextRemoved", - G_VARIANT_TYPE("(o)"), - G_CALLBACK(connman_context_removed), - self); + _nm_dbus_proxy_signal_connect(priv->connman_proxy, + "ContextRemoved", + G_VARIANT_TYPE("(o)"), + G_CALLBACK(connman_context_removed), + self); g_dbus_proxy_call(priv->connman_proxy, "GetProperties", @@ -1575,11 +1576,11 @@ modem_proxy_new_cb(GObject *source, GAsyncResult *result, gpointer user_data) priv->modem_proxy = proxy; - _nm_dbus_signal_connect(priv->modem_proxy, - "PropertyChanged", - G_VARIANT_TYPE("(sv)"), - G_CALLBACK(modem_property_changed), - self); + _nm_dbus_proxy_signal_connect(priv->modem_proxy, + "PropertyChanged", + G_VARIANT_TYPE("(sv)"), + G_CALLBACK(modem_property_changed), + self); g_dbus_proxy_call(priv->modem_proxy, "GetProperties", diff --git a/src/core/nm-dispatcher.c b/src/core/nm-dispatcher.c index 1617dc3667..ab361faa7b 100644 --- a/src/core/nm-dispatcher.c +++ b/src/core/nm-dispatcher.c @@ -8,6 +8,7 @@ #include "nm-dispatcher.h" +#include "libnm-glib-aux/nm-dbus-aux.h" #include "libnm-core-aux-extern/nm-dispatcher-api.h" #include "NetworkManagerUtils.h" #include "nm-utils.h" @@ -428,7 +429,7 @@ dispatcher_done_cb(GObject *source, GAsyncResult *result, gpointer user_data) if (!ret) { NMLogLevel log_level = LOGL_DEBUG; - if (_nm_dbus_error_has_name(error, "org.freedesktop.systemd1.LoadFailed")) { + if (nm_dbus_error_is(error, "org.freedesktop.systemd1.LoadFailed")) { g_dbus_error_strip_remote_error(error); log_level = LOGL_WARN; } diff --git a/src/core/nm-sleep-monitor.c b/src/core/nm-sleep-monitor.c index a7ea496de9..66ea2f6c71 100644 --- a/src/core/nm-sleep-monitor.c +++ b/src/core/nm-sleep-monitor.c @@ -11,6 +11,7 @@ #include <sys/stat.h> #include <gio/gunixfdlist.h> +#include "libnm-glib-aux/nm-dbus-aux.h" #include "libnm-core-intern/nm-core-internal.h" #include "NetworkManagerUtils.h" @@ -294,24 +295,24 @@ on_proxy_acquired(GObject *object, GAsyncResult *res, NMSleepMonitor *self) g_clear_object(&self->cancellable); #if USE_UPOWER - self->sig_id_1 = _nm_dbus_signal_connect(self->proxy, - "Sleeping", - NULL, - G_CALLBACK(upower_sleeping_cb), - self); - self->sig_id_2 = _nm_dbus_signal_connect(self->proxy, - "Resuming", - NULL, - G_CALLBACK(upower_resuming_cb), - self); + self->sig_id_1 = _nm_dbus_proxy_signal_connect(self->proxy, + "Sleeping", + NULL, + G_CALLBACK(upower_sleeping_cb), + self); + self->sig_id_2 = _nm_dbus_proxy_signal_connect(self->proxy, + "Resuming", + NULL, + G_CALLBACK(upower_resuming_cb), + self); #else self->sig_id_1 = g_signal_connect(self->proxy, "notify::g-name-owner", G_CALLBACK(name_owner_cb), self); - self->sig_id_2 = _nm_dbus_signal_connect(self->proxy, - "PrepareForSleep", - G_VARIANT_TYPE("(b)"), - G_CALLBACK(prepare_for_sleep_cb), - self); + self->sig_id_2 = _nm_dbus_proxy_signal_connect(self->proxy, + "PrepareForSleep", + G_VARIANT_TYPE("(b)"), + G_CALLBACK(prepare_for_sleep_cb), + self); { gs_free char *owner = NULL; diff --git a/src/core/supplicant/nm-supplicant-interface.c b/src/core/supplicant/nm-supplicant-interface.c index 5b5d86229c..18525724f4 100644 --- a/src/core/supplicant/nm-supplicant-interface.c +++ b/src/core/supplicant/nm-supplicant-interface.c @@ -2647,7 +2647,7 @@ scan_request_cb(GObject *source, GAsyncResult *result, gpointer user_data) _LOGD("request-scan: request cancelled"); else { if (error) { - if (_nm_dbus_error_has_name(error, "fi.w1.wpa_supplicant1.Interface.ScanError")) + if (nm_dbus_error_is(error, "fi.w1.wpa_supplicant1.Interface.ScanError")) _LOGD("request-scan: could not get scan request result: %s", error->message); else { g_dbus_error_strip_remote_error(error); diff --git a/src/core/supplicant/nm-supplicant-manager.c b/src/core/supplicant/nm-supplicant-manager.c index 2ec7db237a..f6927500dd 100644 --- a/src/core/supplicant/nm-supplicant-manager.c +++ b/src/core/supplicant/nm-supplicant-manager.c @@ -450,7 +450,7 @@ _create_iface_dbus_call_get_interface_cb(GObject *source, GAsyncResult *result, char ifname[NMP_IFNAMSIZ]; if (handle->create_iface_try_count < CREATE_IFACE_TRY_COUNT_MAX - && _nm_dbus_error_has_name(error, NM_WPAS_ERROR_UNKNOWN_IFACE) + && nm_dbus_error_is(error, NM_WPAS_ERROR_UNKNOWN_IFACE) && nm_platform_if_indextoname(NM_PLATFORM_GET, handle->ifindex, ifname)) { /* Before, supplicant told us the interface existed. Was there a race? * Try again. */ @@ -500,7 +500,7 @@ _create_iface_dbus_call_create_interface_cb(GObject *source, nm_assert(handle->self); TRUE; }) - && _nm_dbus_error_has_name(error, NM_WPAS_ERROR_EXISTS_ERROR) + && nm_dbus_error_is(error, NM_WPAS_ERROR_EXISTS_ERROR) && nm_platform_if_indextoname(NM_PLATFORM_GET, handle->ifindex, ifname)) { self = handle->self; _LOGT("create-iface[" NM_HASH_OBFUSCATE_PTR_FMT diff --git a/src/libnm-core-impl/meson.build b/src/libnm-core-impl/meson.build index 2de3ff0849..25d4c6b859 100644 --- a/src/libnm-core-impl/meson.build +++ b/src/libnm-core-impl/meson.build @@ -60,7 +60,6 @@ libnm_core_settings_sources = files( libnm_core_impl_sources = files( 'nm-connection.c', - 'nm-dbus-utils.c', 'nm-errors.c', 'nm-keyfile-utils.c', 'nm-keyfile.c', diff --git a/src/libnm-core-impl/nm-dbus-utils.c b/src/libnm-core-impl/nm-dbus-utils.c deleted file mode 100644 index c9443ff944..0000000000 --- a/src/libnm-core-impl/nm-dbus-utils.c +++ /dev/null @@ -1,259 +0,0 @@ -/* SPDX-License-Identifier: LGPL-2.1-or-later */ -/* - * Copyright (C) 2015 Red Hat, Inc. - */ - -#include "libnm-core-impl/nm-default-libnm-core.h" - -#include "libnm-core-intern/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 #int/#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(). - */ - -/** - * _nm_dbus_typecheck_response: - * @response: the #GVariant response to check. - * @reply_type: the expected reply type. It may be %NULL to perform no - * checking. - * @error: (allow-none): the error in case the @reply_type does not match. - * - * Returns: %TRUE, if @response is of the expected @reply_type. - */ -gboolean -_nm_dbus_typecheck_response(GVariant *response, const GVariantType *reply_type, GError **error) -{ - g_return_val_if_fail(response, FALSE); - - if (!reply_type) - return TRUE; - if (g_variant_is_of_type(response, reply_type)) - return TRUE; - - /* This is the same error code that g_dbus_connection_call() returns if - * @reply_type doesn't match. - */ - g_set_error(error, - G_IO_ERROR, - G_IO_ERROR_INVALID_ARGUMENT, - _("Method returned type '%s', but expected '%s'"), - g_variant_get_type_string(response), - g_variant_type_peek_string(reply_type)); - return FALSE; -} - -/** - * _nm_dbus_proxy_call_finish: - * @proxy: A #GDBusProxy. - * @res: A #GAsyncResult obtained from the #GAsyncReadyCallback passed to - * g_dbus_proxy_call(). - * @reply_type: (allow-none): the expected type of the reply, or %NULL - * @error: Return location for error or %NULL. - * - * Finishes an operation started with g_dbus_proxy_call(), as with - * g_dbus_proxy_call_finish(), except thatif @reply_type is non-%NULL, then it - * will also check that the response matches that type signature, and return - * an error if not. - * - * Returns: %NULL if @error is set. Otherwise, a #GVariant tuple with - * return values. Free with g_variant_unref(). - */ -GVariant * -_nm_dbus_proxy_call_finish(GDBusProxy *proxy, - GAsyncResult *res, - const GVariantType *reply_type, - GError **error) -{ - GVariant *variant; - - variant = g_dbus_proxy_call_finish(proxy, res, error); - if (variant && !_nm_dbus_typecheck_response(variant, reply_type, error)) - nm_clear_pointer(&variant, g_variant_unref); - return variant; -} - -GVariant * -_nm_dbus_connection_call_finish(GDBusConnection *dbus_connection, - GAsyncResult *result, - const GVariantType *reply_type, - GError **error) -{ - GVariant *variant; - - variant = g_dbus_connection_call_finish(dbus_connection, result, error); - if (variant && !_nm_dbus_typecheck_response(variant, reply_type, error)) - nm_clear_pointer(&variant, g_variant_unref); - return variant; -} - -/** - * _nm_dbus_error_has_name: - * @error: (allow-none): a #GError, or %NULL - * @dbus_error_name: a D-Bus error name - * - * Checks if @error is set and corresponds to the D-Bus error @dbus_error_name. - * - * This should only be used for "foreign" D-Bus errors (eg, errors - * from BlueZ or wpa_supplicant). All NetworkManager D-Bus errors - * should be properly mapped by gdbus to one of the domains/codes in - * nm-errors.h. - * - * Returns: %TRUE or %FALSE - */ -gboolean -_nm_dbus_error_has_name(GError *error, const char *dbus_error_name) -{ - gboolean has_name = FALSE; - - if (error && g_dbus_error_is_remote_error(error)) { - char *error_name; - - error_name = g_dbus_error_get_remote_error(error); - has_name = !g_strcmp0(error_name, dbus_error_name); - g_free(error_name); - } - - return has_name; -} diff --git a/src/libnm-core-intern/nm-core-internal.h b/src/libnm-core-intern/nm-core-internal.h index 21c994f033..df9a6d047b 100644 --- a/src/libnm-core-intern/nm-core-internal.h +++ b/src/libnm-core-intern/nm-core-internal.h @@ -367,31 +367,6 @@ void _nm_dbus_errors_init(void); extern gboolean _nm_utils_is_manager_process; -gboolean -_nm_dbus_typecheck_response(GVariant *response, const GVariantType *reply_type, GError **error); - -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) - -GVariant *_nm_dbus_proxy_call_finish(GDBusProxy *proxy, - GAsyncResult *res, - const GVariantType *reply_type, - GError **error); - -GVariant *_nm_dbus_connection_call_finish(GDBusConnection *dbus_connection, - GAsyncResult *result, - const GVariantType *reply_type, - GError **error); - -gboolean _nm_dbus_error_has_name(GError *error, const char *dbus_error_name); - /*****************************************************************************/ char *_nm_utils_ssid_to_utf8(GBytes *ssid); diff --git a/src/libnm-glib-aux/nm-dbus-aux.c b/src/libnm-glib-aux/nm-dbus-aux.c index c6597aea5a..3925da55bc 100644 --- a/src/libnm-glib-aux/nm-dbus-aux.c +++ b/src/libnm-glib-aux/nm-dbus-aux.c @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: LGPL-2.1-or-later */ /* - * Copyright (C) 2019 Red Hat, Inc. + * Copyright (C) 2015,2019 Red Hat, Inc. */ #include "libnm-glib-aux/nm-default-glib-i18n-lib.h" @@ -414,6 +414,12 @@ _nm_dbus_error_is(GError *error, ...) gs_free char *dbus_error = NULL; const char *name; va_list ap; + gboolean found = FALSE; + + /* This should only be used for "foreign" D-Bus errors (eg, errors + * from BlueZ or wpa_supplicant). All NetworkManager D-Bus errors + * should be properly mapped by gdbus to one of the domains/codes in + * nm-errors.h. */ dbus_error = g_dbus_error_get_remote_error(error); if (!dbus_error) @@ -422,13 +428,13 @@ _nm_dbus_error_is(GError *error, ...) va_start(ap, error); while ((name = va_arg(ap, const char *))) { if (nm_streq(dbus_error, name)) { - va_end(ap); - return TRUE; + found = TRUE; + break; } } va_end(ap); - return FALSE; + return found; } /*****************************************************************************/ @@ -517,3 +523,194 @@ nm_dbus_connection_call_blocking(NMDBusConnectionCallBlockingData *data, GError return g_steal_pointer(&result); } + +/*****************************************************************************/ + +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; + gs_free GValue *closure_params_free = NULL; + GValue *closure_params; + gsize n_params; + gsize 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 (!nm_streq(signal_name, sd->signal_name)) + 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 = nm_malloc0_maybe_a(240, sizeof(GValue) * n_params, &closure_params_free); + 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++) { + gs_unref_variant GVariant *param = NULL; + + 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_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]); +} + +/** + * _nm_dbus_proxy_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 #int/#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_proxy_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); +} + +/*****************************************************************************/ + +static gboolean +_nm_dbus_typecheck_response(GVariant *response, const GVariantType *reply_type, GError **error) +{ + g_return_val_if_fail(response, FALSE); + + if (!reply_type) + return TRUE; + if (g_variant_is_of_type(response, reply_type)) + return TRUE; + + /* This is the same error code that g_dbus_connection_call() returns if + * @reply_type doesn't match. + */ + g_set_error(error, + G_IO_ERROR, + G_IO_ERROR_INVALID_ARGUMENT, + _("Method returned type '%s', but expected '%s'"), + g_variant_get_type_string(response), + g_variant_type_peek_string(reply_type)); + return FALSE; +} + +/** + * _nm_dbus_proxy_call_finish: + * @proxy: A #GDBusProxy. + * @res: A #GAsyncResult obtained from the #GAsyncReadyCallback passed to + * g_dbus_proxy_call(). + * @reply_type: (allow-none): the expected type of the reply, or %NULL + * @error: Return location for error or %NULL. + * + * Finishes an operation started with g_dbus_proxy_call(), as with + * g_dbus_proxy_call_finish(), except thatif @reply_type is non-%NULL, then it + * will also check that the response matches that type signature, and return + * an error if not. + * + * Returns: %NULL if @error is set. Otherwise, a #GVariant tuple with + * return values. Free with g_variant_unref(). + */ +GVariant * +_nm_dbus_proxy_call_finish(GDBusProxy *proxy, + GAsyncResult *res, + const GVariantType *reply_type, + GError **error) +{ + GVariant *variant; + + variant = g_dbus_proxy_call_finish(proxy, res, error); + if (variant && !_nm_dbus_typecheck_response(variant, reply_type, error)) + nm_clear_pointer(&variant, g_variant_unref); + return variant; +} diff --git a/src/libnm-glib-aux/nm-dbus-aux.h b/src/libnm-glib-aux/nm-dbus-aux.h index b7cb0b8da4..5db79c08f7 100644 --- a/src/libnm-glib-aux/nm-dbus-aux.h +++ b/src/libnm-glib-aux/nm-dbus-aux.h @@ -274,4 +274,40 @@ nm_g_variant_tuple_get_u(GVariant *v, guint32 *out_u) return FALSE; } +/*****************************************************************************/ + +gulong _nm_dbus_proxy_signal_connect_data(GDBusProxy *proxy, + const char *signal_name, + const GVariantType *signature, + GCallback c_handler, + gpointer data, + GClosureNotify destroy_data, + GConnectFlags connect_flags); + +/** + * _nm_dbus_proxy_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_proxy_signal_connect_data() with fewer arguments. + * + * Returns: the signal handler ID, as with _nm_signal_connect_data(). + */ +#define _nm_dbus_proxy_signal_connect(proxy, name, signature, handler, data) \ + _nm_dbus_proxy_signal_connect_data(proxy, \ + name, \ + signature, \ + handler, \ + data, \ + NULL, \ + (GConnectFlags) 0) + +GVariant *_nm_dbus_proxy_call_finish(GDBusProxy *proxy, + GAsyncResult *res, + const GVariantType *reply_type, + GError **error); + #endif /* __NM_DBUS_AUX_H__ */ |