device: renew dhcp leases on awake for software devices
[NetworkManager.git] / libnm-core / nm-dbus-utils.c
1 /* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
2 /*
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.
7  *
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.
12  *
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.
17  *
18  * Copyright 2015 Red Hat, Inc.
19  */
20
21 #include "nm-default.h"
22
23 #include <string.h>
24
25 #include "nm-core-internal.h"
26
27 typedef struct {
28         char *signal_name;
29         const GVariantType *signature;
30 } NMDBusSignalData;
31
32 static void
33 dbus_signal_data_free (gpointer data, GClosure *closure)
34 {
35         NMDBusSignalData *sd = data;
36
37         g_free (sd->signal_name);
38         g_slice_free (NMDBusSignalData, sd);
39 }
40
41 static void
42 dbus_signal_meta_marshal (GClosure     *closure,
43                           GValue       *return_value,
44                           guint         n_param_values,
45                           const GValue *param_values,
46                           gpointer      invocation_hint,
47                           gpointer      marshal_data)
48 {
49         NMDBusSignalData *sd = marshal_data;
50         const char *signal_name;
51         GVariant *parameters, *param;
52         GValue *closure_params;
53         gsize n_params, i;
54
55         g_return_if_fail (n_param_values == 4);
56
57         signal_name = g_value_get_string (&param_values[2]);
58         parameters = g_value_get_variant (&param_values[3]);
59
60         if (strcmp (signal_name, sd->signal_name) != 0)
61                 return;
62
63         if (sd->signature) {
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 (&param_values[0]),
67                                    signal_name, g_variant_get_type_string (parameters),
68                                    g_variant_type_peek_string (sd->signature));
69                         return;
70                 }
71
72                 n_params = g_variant_n_children (parameters) + 1;
73         } else
74                 n_params = 1;
75
76         closure_params = g_new0 (GValue, n_params);
77         g_value_init (&closure_params[0], G_TYPE_OBJECT);
78         g_value_copy (&param_values[0], &closure_params[0]);
79
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);
87                 } else
88                         g_dbus_gvariant_to_gvalue (param, &closure_params[i]);
89                 g_variant_unref (param);
90         }
91
92         g_cclosure_marshal_generic (closure,
93                                     NULL,
94                                     n_params,
95                                     closure_params,
96                                     invocation_hint,
97                                     NULL);
98
99         for (i = 0; i < n_params; i++)
100                 g_value_unset (&closure_params[i]);
101         g_free (closure_params);
102 }
103
104 /**
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
113  *
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.
117  *
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
123  *
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.
126  *
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.
132  */
133 gulong
134 _nm_dbus_signal_connect_data (GDBusProxy *proxy,
135                               const char *signal_name,
136                               const GVariantType *signature,
137                               GCallback c_handler,
138                               gpointer data,
139                               GClosureNotify destroy_data,
140                               GConnectFlags connect_flags)
141 {
142         NMDBusSignalData *sd;
143         GClosure *closure;
144         gboolean swapped = !!(connect_flags & G_CONNECT_SWAPPED);
145         gboolean after = !!(connect_flags & G_CONNECT_AFTER);
146
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);
151
152         sd = g_slice_new (NMDBusSignalData);
153         sd->signal_name = g_strdup (signal_name);
154         sd->signature = signature;
155
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);
160
161         return g_signal_connect_closure (proxy, "g-signal", closure, after);
162 }
163
164 /**
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
171  *
172  * Simplified version of _nm_dbus_signal_connect_data() with fewer arguments.
173  *
174  * Returns: the signal handler ID, as with _nm_signal_connect_data().
175  */
176
177
178 static void
179 typecheck_response (GVariant           **response,
180                     const GVariantType  *reply_type,
181                     GError             **error)
182 {
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.
186                  */
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);
192         }
193 }
194
195 /**
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.
202  *
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
206  * an error if not.
207  *
208  * Returns: %NULL if @error is set. Otherwise a #GVariant tuple with
209  * return values. Free with g_variant_unref().
210  */
211 GVariant *
212 _nm_dbus_proxy_call_finish (GDBusProxy          *proxy,
213                             GAsyncResult        *res,
214                             const GVariantType  *reply_type,
215                             GError             **error)
216 {
217         GVariant *ret;
218
219         ret = g_dbus_proxy_call_finish (proxy, res, error);
220         typecheck_response (&ret, reply_type, error);
221         return ret;
222 }
223
224 /**
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.
236  *
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
240  * does not match.
241  *
242  * Returns: %NULL if @error is set. Otherwise a #GVariant tuple with
243  * return values. Free with g_variant_unref().
244  */
245 GVariant *
246 _nm_dbus_proxy_call_sync (GDBusProxy          *proxy,
247                           const gchar         *method_name,
248                           GVariant            *parameters,
249                           const GVariantType  *reply_type,
250                           GDBusCallFlags       flags,
251                           gint                 timeout_msec,
252                           GCancellable        *cancellable,
253                           GError             **error)
254 {
255         GVariant *ret;
256
257         ret = g_dbus_proxy_call_sync (proxy, method_name, parameters,
258                                       flags, timeout_msec,
259                                       cancellable, error);
260         typecheck_response (&ret, reply_type, error);
261         return ret;
262 }
263
264 /**
265  * _nm_dbus_error_has_name:
266  * @error: (allow-none): a #GError, or %NULL
267  * @dbus_error_name: a D-Bus error name
268  *
269  * Checks if @error is set and corresponds to the D-Bus error @dbus_error_name.
270  *
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
274  * nm-errors.h.
275  *
276  * Returns: %TRUE or %FALSE
277  */
278 gboolean
279 _nm_dbus_error_has_name (GError     *error,
280                          const char *dbus_error_name)
281 {
282         gboolean has_name = FALSE;
283
284         if (error && g_dbus_error_is_remote_error (error)) {
285                 char *error_name;
286
287                 error_name = g_dbus_error_get_remote_error (error);
288                 has_name = !g_strcmp0 (error_name, dbus_error_name);
289                 g_free (error_name);
290         }
291
292         return has_name;
293 }