1 /* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
3 * This library is free software; you can redistribute it and/or
4 * modify it under the terms of the GNU Lesser General Public
5 * License as published by the Free Software Foundation; either
6 * version 2 of the License, or (at your option) any later version.
8 * This library is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11 * Lesser General Public License for more details.
13 * You should have received a copy of the GNU Lesser General Public
14 * License along with this library; if not, write to the
15 * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
16 * Boston, MA 02110-1301 USA.
18 * Copyright 2015 Red Hat, Inc.
21 #include "nm-default.h"
25 #include "nm-core-internal.h"
29 const GVariantType *signature;
33 dbus_signal_data_free (gpointer data, GClosure *closure)
35 NMDBusSignalData *sd = data;
37 g_free (sd->signal_name);
38 g_slice_free (NMDBusSignalData, sd);
42 dbus_signal_meta_marshal (GClosure *closure,
45 const GValue *param_values,
46 gpointer invocation_hint,
47 gpointer marshal_data)
49 NMDBusSignalData *sd = marshal_data;
50 const char *signal_name;
51 GVariant *parameters, *param;
52 GValue *closure_params;
55 g_return_if_fail (n_param_values == 4);
57 signal_name = g_value_get_string (¶m_values[2]);
58 parameters = g_value_get_variant (¶m_values[3]);
60 if (strcmp (signal_name, sd->signal_name) != 0)
64 if (!g_variant_is_of_type (parameters, sd->signature)) {
65 g_warning ("%p: got signal '%s' but parameters were of type '%s', not '%s'",
66 g_value_get_object (¶m_values[0]),
67 signal_name, g_variant_get_type_string (parameters),
68 g_variant_type_peek_string (sd->signature));
72 n_params = g_variant_n_children (parameters) + 1;
76 closure_params = g_new0 (GValue, n_params);
77 g_value_init (&closure_params[0], G_TYPE_OBJECT);
78 g_value_copy (¶m_values[0], &closure_params[0]);
80 for (i = 1; i < n_params; i++) {
81 param = g_variant_get_child_value (parameters, i - 1);
82 if ( g_variant_is_of_type (param, G_VARIANT_TYPE ("ay"))
83 || g_variant_is_of_type (param, G_VARIANT_TYPE ("aay"))) {
84 /* g_dbus_gvariant_to_gvalue() thinks 'ay' means "non-UTF-8 NUL-terminated string" */
85 g_value_init (&closure_params[i], G_TYPE_VARIANT);
86 g_value_set_variant (&closure_params[i], param);
88 g_dbus_gvariant_to_gvalue (param, &closure_params[i]);
89 g_variant_unref (param);
92 g_cclosure_marshal_generic (closure,
99 for (i = 0; i < n_params; i++)
100 g_value_unset (&closure_params[i]);
101 g_free (closure_params);
105 * _nm_dbus_signal_connect_data:
106 * @proxy: a #GDBusProxy
107 * @signal_name: the D-Bus signal to connect to
108 * @signature: (allow-none): the signal's type signature (must be a tuple)
109 * @c_handler: the signal handler function
110 * @data: (allow-none): data to pass to @c_handler
111 * @destroy_data: (allow-none): closure destroy notify for @data
112 * @connect_flags: connection flags
114 * Connects to the D-Bus signal @signal_name on @proxy. @c_handler must be a
115 * void function whose first argument is a #GDBusProxy, followed by arguments
116 * for each element of @signature, ending with a #gpointer argument for @data.
118 * The argument types in @c_handler correspond to the types output by
119 * g_dbus_gvariant_to_gvalue(), except for 'ay' and 'aay'. In particular:
120 * - both 16-bit and 32-bit integers are passed as #gint/#guint
121 * - 'as' values are passed as #GStrv (char **)
122 * - all other array, tuple, and dict types are passed as #GVariant
124 * If @signature is %NULL, then the signal's parameters will be ignored, and
125 * @c_handler should take only the #GDBusProxy and #gpointer arguments.
127 * Returns: the signal handler ID, which can be used with
128 * g_signal_handler_remove(). Beware that because of the way the signal is
129 * connected, you will not be able to remove it with
130 * g_signal_handlers_disconnect_by_func(), although
131 * g_signal_handlers_disconnect_by_data() will work correctly.
134 _nm_dbus_signal_connect_data (GDBusProxy *proxy,
135 const char *signal_name,
136 const GVariantType *signature,
139 GClosureNotify destroy_data,
140 GConnectFlags connect_flags)
142 NMDBusSignalData *sd;
144 gboolean swapped = !!(connect_flags & G_CONNECT_SWAPPED);
145 gboolean after = !!(connect_flags & G_CONNECT_AFTER);
147 g_return_val_if_fail (G_IS_DBUS_PROXY (proxy), 0);
148 g_return_val_if_fail (signal_name != NULL, 0);
149 g_return_val_if_fail (signature == NULL || g_variant_type_is_tuple (signature), 0);
150 g_return_val_if_fail (c_handler != NULL, 0);
152 sd = g_slice_new (NMDBusSignalData);
153 sd->signal_name = g_strdup (signal_name);
154 sd->signature = signature;
156 closure = (swapped ? g_cclosure_new_swap : g_cclosure_new) (c_handler, data, destroy_data);
157 g_closure_set_marshal (closure, g_cclosure_marshal_generic);
158 g_closure_set_meta_marshal (closure, sd, dbus_signal_meta_marshal);
159 g_closure_add_finalize_notifier (closure, sd, dbus_signal_data_free);
161 return g_signal_connect_closure (proxy, "g-signal", closure, after);
165 * _nm_dbus_signal_connect:
166 * @proxy: a #GDBusProxy
167 * @signal_name: the D-Bus signal to connect to
168 * @signature: the signal's type signature (must be a tuple)
169 * @c_handler: the signal handler function
170 * @data: (allow-none): data to pass to @c_handler
172 * Simplified version of _nm_dbus_signal_connect_data() with fewer arguments.
174 * Returns: the signal handler ID, as with _nm_signal_connect_data().
179 typecheck_response (GVariant **response,
180 const GVariantType *reply_type,
183 if (*response && reply_type && !g_variant_is_of_type (*response, reply_type)) {
184 /* This is the same error code that g_dbus_connection_call() returns if
185 * @reply_type doesn't match.
187 g_set_error (error, G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT,
188 _("Method returned type '%s', but expected '%s'"),
189 g_variant_get_type_string (*response),
190 g_variant_type_peek_string (reply_type));
191 g_clear_pointer (response, g_variant_unref);
196 * _nm_dbus_proxy_call_finish:
197 * @proxy: A #GDBusProxy.
198 * @res: A #GAsyncResult obtained from the #GAsyncReadyCallback passed to
199 * g_dbus_proxy_call().
200 * @reply_type: (allow-none): the expected type of the reply, or %NULL
201 * @error: Return location for error or %NULL.
203 * Finishes an operation started with g_dbus_proxy_call(), as with
204 * g_dbus_proxy_call_finish(), except thatif @reply_type is non-%NULL, then it
205 * will also check that the response matches that type signature, and return
208 * Returns: %NULL if @error is set. Otherwise a #GVariant tuple with
209 * return values. Free with g_variant_unref().
212 _nm_dbus_proxy_call_finish (GDBusProxy *proxy,
214 const GVariantType *reply_type,
219 ret = g_dbus_proxy_call_finish (proxy, res, error);
220 typecheck_response (&ret, reply_type, error);
225 * _nm_dbus_proxy_call_sync:
226 * @proxy: A #GDBusProxy.
227 * @method_name: Name of method to invoke.
228 * @parameters: (allow-none): A #GVariant tuple with parameters for the signal
229 * or %NULL if not passing parameters.
230 * @reply_type: (allow-none): the expected type of the reply, or %NULL
231 * @flags: Flags from the #GDBusCallFlags enumeration.
232 * @timeout_msec: The timeout in milliseconds (with %G_MAXINT meaning
233 * "infinite") or -1 to use the proxy default timeout.
234 * @cancellable: (allow-none): A #GCancellable or %NULL.
235 * @error: Return location for error or %NULL.
237 * Synchronously invokes the @method_name method on @proxy, as with
238 * g_dbus_proxy_call_sync(), except that if @reply_type is non-%NULL, then the
239 * reply to the call will be checked against it, and an error returned if it
242 * Returns: %NULL if @error is set. Otherwise a #GVariant tuple with
243 * return values. Free with g_variant_unref().
246 _nm_dbus_proxy_call_sync (GDBusProxy *proxy,
247 const gchar *method_name,
248 GVariant *parameters,
249 const GVariantType *reply_type,
250 GDBusCallFlags flags,
252 GCancellable *cancellable,
257 ret = g_dbus_proxy_call_sync (proxy, method_name, parameters,
260 typecheck_response (&ret, reply_type, error);
265 * _nm_dbus_error_has_name:
266 * @error: (allow-none): a #GError, or %NULL
267 * @dbus_error_name: a D-Bus error name
269 * Checks if @error is set and corresponds to the D-Bus error @dbus_error_name.
271 * This should only be used for "foreign" D-Bus errors (eg, errors
272 * from BlueZ or wpa_supplicant). All NetworkManager D-Bus errors
273 * should be properly mapped by gdbus to one of the domains/codes in
276 * Returns: %TRUE or %FALSE
279 _nm_dbus_error_has_name (GError *error,
280 const char *dbus_error_name)
282 gboolean has_name = FALSE;
284 if (error && g_dbus_error_is_remote_error (error)) {
287 error_name = g_dbus_error_get_remote_error (error);
288 has_name = !g_strcmp0 (error_name, dbus_error_name);