/src/glib/gio/gdbusmethodinvocation.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* GDBus - GLib D-Bus Library |
2 | | * |
3 | | * Copyright (C) 2008-2010 Red Hat, Inc. |
4 | | * |
5 | | * SPDX-License-Identifier: LGPL-2.1-or-later |
6 | | * |
7 | | * This library is free software; you can redistribute it and/or |
8 | | * modify it under the terms of the GNU Lesser General Public |
9 | | * License as published by the Free Software Foundation; either |
10 | | * version 2.1 of the License, or (at your option) any later version. |
11 | | * |
12 | | * This library is distributed in the hope that it will be useful, |
13 | | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
14 | | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
15 | | * Lesser General Public License for more details. |
16 | | * |
17 | | * You should have received a copy of the GNU Lesser General |
18 | | * Public License along with this library; if not, see <http://www.gnu.org/licenses/>. |
19 | | * |
20 | | * Author: David Zeuthen <davidz@redhat.com> |
21 | | */ |
22 | | |
23 | | #include "config.h" |
24 | | |
25 | | #include <stdlib.h> |
26 | | |
27 | | #include "gdbusutils.h" |
28 | | #include "gdbusconnection.h" |
29 | | #include "gdbusmessage.h" |
30 | | #include "gdbusmethodinvocation.h" |
31 | | #include "gdbusintrospection.h" |
32 | | #include "gdbuserror.h" |
33 | | #include "gdbusprivate.h" |
34 | | #include "gioerror.h" |
35 | | |
36 | | #ifdef G_OS_UNIX |
37 | | #include "gunixfdlist.h" |
38 | | #endif |
39 | | |
40 | | #include "glibintl.h" |
41 | | |
42 | | /** |
43 | | * GDBusMethodInvocation: |
44 | | * |
45 | | * Instances of the `GDBusMethodInvocation` class are used when |
46 | | * handling D-Bus method calls. It provides a way to asynchronously |
47 | | * return results and errors. |
48 | | * |
49 | | * The normal way to obtain a `GDBusMethodInvocation` object is to receive |
50 | | * it as an argument to the `handle_method_call()` function in a |
51 | | * [type@Gio.DBusInterfaceVTable] that was passed to |
52 | | * [method@Gio.DBusConnection.register_object]. |
53 | | * |
54 | | * Since: 2.26 |
55 | | */ |
56 | | |
57 | | typedef struct _GDBusMethodInvocationClass GDBusMethodInvocationClass; |
58 | | |
59 | | /** |
60 | | * GDBusMethodInvocationClass: |
61 | | * |
62 | | * Class structure for #GDBusMethodInvocation. |
63 | | * |
64 | | * Since: 2.26 |
65 | | */ |
66 | | struct _GDBusMethodInvocationClass |
67 | | { |
68 | | /*< private >*/ |
69 | | GObjectClass parent_class; |
70 | | }; |
71 | | |
72 | | struct _GDBusMethodInvocation |
73 | | { |
74 | | /*< private >*/ |
75 | | GObject parent_instance; |
76 | | |
77 | | /* construct-only properties */ |
78 | | gchar *sender; |
79 | | gchar *object_path; |
80 | | gchar *interface_name; |
81 | | gchar *method_name; |
82 | | GDBusMethodInfo *method_info; |
83 | | GDBusPropertyInfo *property_info; |
84 | | GDBusConnection *connection; |
85 | | GDBusMessage *message; |
86 | | GVariant *parameters; |
87 | | gpointer user_data; |
88 | | }; |
89 | | |
90 | | G_DEFINE_TYPE (GDBusMethodInvocation, g_dbus_method_invocation, G_TYPE_OBJECT) |
91 | | |
92 | | static void |
93 | | g_dbus_method_invocation_finalize (GObject *object) |
94 | 0 | { |
95 | 0 | GDBusMethodInvocation *invocation = G_DBUS_METHOD_INVOCATION (object); |
96 | |
|
97 | 0 | g_free (invocation->sender); |
98 | 0 | g_free (invocation->object_path); |
99 | 0 | g_free (invocation->interface_name); |
100 | 0 | g_free (invocation->method_name); |
101 | 0 | if (invocation->method_info) |
102 | 0 | g_dbus_method_info_unref (invocation->method_info); |
103 | 0 | if (invocation->property_info) |
104 | 0 | g_dbus_property_info_unref (invocation->property_info); |
105 | 0 | g_object_unref (invocation->connection); |
106 | 0 | g_object_unref (invocation->message); |
107 | 0 | g_variant_unref (invocation->parameters); |
108 | |
|
109 | 0 | G_OBJECT_CLASS (g_dbus_method_invocation_parent_class)->finalize (object); |
110 | 0 | } |
111 | | |
112 | | static void |
113 | | g_dbus_method_invocation_class_init (GDBusMethodInvocationClass *klass) |
114 | 0 | { |
115 | 0 | GObjectClass *gobject_class = G_OBJECT_CLASS (klass); |
116 | |
|
117 | 0 | gobject_class->finalize = g_dbus_method_invocation_finalize; |
118 | 0 | } |
119 | | |
120 | | static void |
121 | | g_dbus_method_invocation_init (GDBusMethodInvocation *invocation) |
122 | 0 | { |
123 | 0 | } |
124 | | |
125 | | /** |
126 | | * g_dbus_method_invocation_get_sender: |
127 | | * @invocation: A #GDBusMethodInvocation. |
128 | | * |
129 | | * Gets the bus name that invoked the method. |
130 | | * |
131 | | * This can return %NULL if not specified by the caller, e.g. on peer-to-peer |
132 | | * connections. |
133 | | * |
134 | | * Returns: (nullable): A string. Do not free, it is owned by @invocation. |
135 | | * |
136 | | * Since: 2.26 |
137 | | */ |
138 | | const gchar * |
139 | | g_dbus_method_invocation_get_sender (GDBusMethodInvocation *invocation) |
140 | 0 | { |
141 | 0 | g_return_val_if_fail (G_IS_DBUS_METHOD_INVOCATION (invocation), NULL); |
142 | 0 | return invocation->sender; |
143 | 0 | } |
144 | | |
145 | | /** |
146 | | * g_dbus_method_invocation_get_object_path: |
147 | | * @invocation: A #GDBusMethodInvocation. |
148 | | * |
149 | | * Gets the object path the method was invoked on. |
150 | | * |
151 | | * Returns: A string. Do not free, it is owned by @invocation. |
152 | | * |
153 | | * Since: 2.26 |
154 | | */ |
155 | | const gchar * |
156 | | g_dbus_method_invocation_get_object_path (GDBusMethodInvocation *invocation) |
157 | 0 | { |
158 | 0 | g_return_val_if_fail (G_IS_DBUS_METHOD_INVOCATION (invocation), NULL); |
159 | 0 | return invocation->object_path; |
160 | 0 | } |
161 | | |
162 | | /** |
163 | | * g_dbus_method_invocation_get_interface_name: |
164 | | * @invocation: A #GDBusMethodInvocation. |
165 | | * |
166 | | * Gets the name of the D-Bus interface the method was invoked on. |
167 | | * |
168 | | * This can be `NULL` if it was not specified by the sender. See |
169 | | * [callback@Gio.DBusInterfaceMethodCallFunc] or the |
170 | | * [D-Bus Specification](https://dbus.freedesktop.org/doc/dbus-specification.html#message-protocol-types-method) |
171 | | * for details on when this can happen and how it should be handled. |
172 | | * |
173 | | * If this method call is a property Get, Set or GetAll call that has |
174 | | * been redirected to the method call handler then |
175 | | * "org.freedesktop.DBus.Properties" will be returned. See |
176 | | * #GDBusInterfaceVTable for more information. |
177 | | * |
178 | | * Returns: (nullable): A string. Do not free, it is owned by @invocation. |
179 | | * |
180 | | * Since: 2.26 |
181 | | */ |
182 | | const gchar * |
183 | | g_dbus_method_invocation_get_interface_name (GDBusMethodInvocation *invocation) |
184 | 0 | { |
185 | 0 | g_return_val_if_fail (G_IS_DBUS_METHOD_INVOCATION (invocation), NULL); |
186 | 0 | return invocation->interface_name; |
187 | 0 | } |
188 | | |
189 | | /** |
190 | | * g_dbus_method_invocation_get_method_info: |
191 | | * @invocation: A #GDBusMethodInvocation. |
192 | | * |
193 | | * Gets information about the method call, if any. |
194 | | * |
195 | | * If this method invocation is a property Get, Set or GetAll call that |
196 | | * has been redirected to the method call handler then %NULL will be |
197 | | * returned. See g_dbus_method_invocation_get_property_info() and |
198 | | * #GDBusInterfaceVTable for more information. |
199 | | * |
200 | | * Returns: (nullable): A #GDBusMethodInfo or %NULL. Do not free, it is owned by @invocation. |
201 | | * |
202 | | * Since: 2.26 |
203 | | */ |
204 | | const GDBusMethodInfo * |
205 | | g_dbus_method_invocation_get_method_info (GDBusMethodInvocation *invocation) |
206 | 0 | { |
207 | 0 | g_return_val_if_fail (G_IS_DBUS_METHOD_INVOCATION (invocation), NULL); |
208 | 0 | return invocation->method_info; |
209 | 0 | } |
210 | | |
211 | | /** |
212 | | * g_dbus_method_invocation_get_property_info: |
213 | | * @invocation: A #GDBusMethodInvocation |
214 | | * |
215 | | * Gets information about the property that this method call is for, if |
216 | | * any. |
217 | | * |
218 | | * This will only be set in the case of an invocation in response to a |
219 | | * property Get or Set call that has been directed to the method call |
220 | | * handler for an object on account of its property_get() or |
221 | | * property_set() vtable pointers being unset. |
222 | | * |
223 | | * See #GDBusInterfaceVTable for more information. |
224 | | * |
225 | | * If the call was GetAll, %NULL will be returned. |
226 | | * |
227 | | * Returns: (nullable) (transfer none): a #GDBusPropertyInfo or %NULL |
228 | | * |
229 | | * Since: 2.38 |
230 | | */ |
231 | | const GDBusPropertyInfo * |
232 | | g_dbus_method_invocation_get_property_info (GDBusMethodInvocation *invocation) |
233 | 0 | { |
234 | 0 | g_return_val_if_fail (G_IS_DBUS_METHOD_INVOCATION (invocation), NULL); |
235 | 0 | return invocation->property_info; |
236 | 0 | } |
237 | | |
238 | | /** |
239 | | * g_dbus_method_invocation_get_method_name: |
240 | | * @invocation: A #GDBusMethodInvocation. |
241 | | * |
242 | | * Gets the name of the method that was invoked. |
243 | | * |
244 | | * Returns: A string. Do not free, it is owned by @invocation. |
245 | | * |
246 | | * Since: 2.26 |
247 | | */ |
248 | | const gchar * |
249 | | g_dbus_method_invocation_get_method_name (GDBusMethodInvocation *invocation) |
250 | 0 | { |
251 | 0 | g_return_val_if_fail (G_IS_DBUS_METHOD_INVOCATION (invocation), NULL); |
252 | 0 | return invocation->method_name; |
253 | 0 | } |
254 | | |
255 | | /** |
256 | | * g_dbus_method_invocation_get_connection: |
257 | | * @invocation: A #GDBusMethodInvocation. |
258 | | * |
259 | | * Gets the #GDBusConnection the method was invoked on. |
260 | | * |
261 | | * Returns: (transfer none):A #GDBusConnection. Do not free, it is owned by @invocation. |
262 | | * |
263 | | * Since: 2.26 |
264 | | */ |
265 | | GDBusConnection * |
266 | | g_dbus_method_invocation_get_connection (GDBusMethodInvocation *invocation) |
267 | 0 | { |
268 | 0 | g_return_val_if_fail (G_IS_DBUS_METHOD_INVOCATION (invocation), NULL); |
269 | 0 | return invocation->connection; |
270 | 0 | } |
271 | | |
272 | | /** |
273 | | * g_dbus_method_invocation_get_message: |
274 | | * @invocation: A #GDBusMethodInvocation. |
275 | | * |
276 | | * Gets the #GDBusMessage for the method invocation. This is useful if |
277 | | * you need to use low-level protocol features, such as UNIX file |
278 | | * descriptor passing, that cannot be properly expressed in the |
279 | | * #GVariant API. |
280 | | * |
281 | | * See this [server][class@Gio.DBusConnection#an-example-d-bus-server] |
282 | | * and [client][class@Gio.DBusConnection#an-example-for-file-descriptor-passing] |
283 | | * for an example of how to use this low-level API to send and receive |
284 | | * UNIX file descriptors. |
285 | | * |
286 | | * Returns: (transfer none): #GDBusMessage. Do not free, it is owned by @invocation. |
287 | | * |
288 | | * Since: 2.26 |
289 | | */ |
290 | | GDBusMessage * |
291 | | g_dbus_method_invocation_get_message (GDBusMethodInvocation *invocation) |
292 | 0 | { |
293 | 0 | g_return_val_if_fail (G_IS_DBUS_METHOD_INVOCATION (invocation), NULL); |
294 | 0 | return invocation->message; |
295 | 0 | } |
296 | | |
297 | | /** |
298 | | * g_dbus_method_invocation_get_parameters: |
299 | | * @invocation: A #GDBusMethodInvocation. |
300 | | * |
301 | | * Gets the parameters of the method invocation. If there are no input |
302 | | * parameters then this will return a GVariant with 0 children rather than NULL. |
303 | | * |
304 | | * Returns: (transfer none): A #GVariant tuple. Do not unref this because it is owned by @invocation. |
305 | | * |
306 | | * Since: 2.26 |
307 | | */ |
308 | | GVariant * |
309 | | g_dbus_method_invocation_get_parameters (GDBusMethodInvocation *invocation) |
310 | 0 | { |
311 | 0 | g_return_val_if_fail (G_IS_DBUS_METHOD_INVOCATION (invocation), NULL); |
312 | 0 | return invocation->parameters; |
313 | 0 | } |
314 | | |
315 | | /** |
316 | | * g_dbus_method_invocation_get_user_data: (skip) |
317 | | * @invocation: A #GDBusMethodInvocation. |
318 | | * |
319 | | * Gets the @user_data #gpointer passed to g_dbus_connection_register_object(). |
320 | | * |
321 | | * Returns: A #gpointer. |
322 | | * |
323 | | * Since: 2.26 |
324 | | */ |
325 | | gpointer |
326 | | g_dbus_method_invocation_get_user_data (GDBusMethodInvocation *invocation) |
327 | 0 | { |
328 | 0 | g_return_val_if_fail (G_IS_DBUS_METHOD_INVOCATION (invocation), NULL); |
329 | 0 | return invocation->user_data; |
330 | 0 | } |
331 | | |
332 | | /* < internal > |
333 | | * _g_dbus_method_invocation_new: |
334 | | * @sender: (nullable): The bus name that invoked the method or %NULL if @connection is not a bus connection. |
335 | | * @object_path: The object path the method was invoked on. |
336 | | * @interface_name: The name of the D-Bus interface the method was invoked on. |
337 | | * @method_name: The name of the method that was invoked. |
338 | | * @method_info: (nullable): Information about the method call or %NULL. |
339 | | * @property_info: (nullable): Information about the property or %NULL. |
340 | | * @connection: The #GDBusConnection the method was invoked on. |
341 | | * @message: The D-Bus message as a #GDBusMessage. |
342 | | * @parameters: The parameters as a #GVariant tuple. |
343 | | * @user_data: The @user_data #gpointer passed to g_dbus_connection_register_object(). |
344 | | * |
345 | | * Creates a new #GDBusMethodInvocation object. |
346 | | * |
347 | | * Returns: A #GDBusMethodInvocation. Free with g_object_unref(). |
348 | | * |
349 | | * Since: 2.26 |
350 | | */ |
351 | | GDBusMethodInvocation * |
352 | | _g_dbus_method_invocation_new (const gchar *sender, |
353 | | const gchar *object_path, |
354 | | const gchar *interface_name, |
355 | | const gchar *method_name, |
356 | | const GDBusMethodInfo *method_info, |
357 | | const GDBusPropertyInfo *property_info, |
358 | | GDBusConnection *connection, |
359 | | GDBusMessage *message, |
360 | | GVariant *parameters, |
361 | | gpointer user_data) |
362 | 0 | { |
363 | 0 | GDBusMethodInvocation *invocation; |
364 | |
|
365 | 0 | g_return_val_if_fail (sender == NULL || g_dbus_is_name (sender), NULL); |
366 | 0 | g_return_val_if_fail (g_variant_is_object_path (object_path), NULL); |
367 | 0 | g_return_val_if_fail (interface_name == NULL || g_dbus_is_interface_name (interface_name), NULL); |
368 | 0 | g_return_val_if_fail (g_dbus_is_member_name (method_name), NULL); |
369 | 0 | g_return_val_if_fail (G_IS_DBUS_CONNECTION (connection), NULL); |
370 | 0 | g_return_val_if_fail (G_IS_DBUS_MESSAGE (message), NULL); |
371 | 0 | g_return_val_if_fail (g_variant_is_of_type (parameters, G_VARIANT_TYPE_TUPLE), NULL); |
372 | | |
373 | 0 | invocation = G_DBUS_METHOD_INVOCATION (g_object_new (G_TYPE_DBUS_METHOD_INVOCATION, NULL)); |
374 | 0 | invocation->sender = g_strdup (sender); |
375 | 0 | invocation->object_path = g_strdup (object_path); |
376 | 0 | invocation->interface_name = g_strdup (interface_name); |
377 | 0 | invocation->method_name = g_strdup (method_name); |
378 | 0 | if (method_info) |
379 | 0 | invocation->method_info = g_dbus_method_info_ref ((GDBusMethodInfo *)method_info); |
380 | 0 | if (property_info) |
381 | 0 | invocation->property_info = g_dbus_property_info_ref ((GDBusPropertyInfo *)property_info); |
382 | 0 | invocation->connection = g_object_ref (connection); |
383 | 0 | invocation->message = g_object_ref (message); |
384 | 0 | invocation->parameters = g_variant_ref (parameters); |
385 | 0 | invocation->user_data = user_data; |
386 | |
|
387 | 0 | return invocation; |
388 | 0 | } |
389 | | |
390 | | /* ---------------------------------------------------------------------------------------------------- */ |
391 | | |
392 | | static void |
393 | | g_dbus_method_invocation_return_value_internal (GDBusMethodInvocation *invocation, |
394 | | GVariant *parameters, |
395 | | GUnixFDList *fd_list) |
396 | 0 | { |
397 | 0 | GDBusMessage *reply; |
398 | 0 | GError *error; |
399 | |
|
400 | 0 | g_return_if_fail (G_IS_DBUS_METHOD_INVOCATION (invocation)); |
401 | 0 | g_return_if_fail ((parameters == NULL) || g_variant_is_of_type (parameters, G_VARIANT_TYPE_TUPLE)); |
402 | | |
403 | 0 | if (g_dbus_message_get_flags (invocation->message) & G_DBUS_MESSAGE_FLAGS_NO_REPLY_EXPECTED) |
404 | 0 | goto out; |
405 | | |
406 | 0 | if (parameters == NULL) |
407 | 0 | parameters = g_variant_new_tuple (NULL, 0); |
408 | | |
409 | | /* if we have introspection data, check that the signature of @parameters is correct */ |
410 | 0 | if (invocation->method_info != NULL) |
411 | 0 | { |
412 | 0 | GVariantType *type; |
413 | |
|
414 | 0 | type = _g_dbus_compute_complete_signature (invocation->method_info->out_args); |
415 | |
|
416 | 0 | if (!g_variant_is_of_type (parameters, type)) |
417 | 0 | { |
418 | 0 | gchar *type_string = g_variant_type_dup_string (type); |
419 | |
|
420 | 0 | g_warning ("Type of return value is incorrect: expected '%s', got '%s'", |
421 | 0 | type_string, g_variant_get_type_string (parameters)); |
422 | 0 | g_variant_type_free (type); |
423 | 0 | g_free (type_string); |
424 | 0 | goto out; |
425 | 0 | } |
426 | 0 | g_variant_type_free (type); |
427 | 0 | } |
428 | | |
429 | | /* property_info is only non-NULL if set that way from |
430 | | * GDBusConnection, so this must be the case of async property |
431 | | * handling on either 'Get' or 'Set'. |
432 | | * |
433 | | * property_info is NULL for 'GetAll'. |
434 | | */ |
435 | 0 | if (invocation->property_info != NULL) |
436 | 0 | { |
437 | 0 | if (g_str_equal (invocation->method_name, "Get")) |
438 | 0 | { |
439 | 0 | GVariant *nested; |
440 | |
|
441 | 0 | if (!g_variant_is_of_type (parameters, G_VARIANT_TYPE ("(v)"))) |
442 | 0 | { |
443 | 0 | g_warning ("Type of return value for property 'Get' call should be '(v)' but got '%s'", |
444 | 0 | g_variant_get_type_string (parameters)); |
445 | 0 | goto out; |
446 | 0 | } |
447 | | |
448 | | /* Go deeper and make sure that the value inside of the |
449 | | * variant matches the property type. |
450 | | */ |
451 | 0 | g_variant_get (parameters, "(v)", &nested); |
452 | 0 | if (!g_str_equal (g_variant_get_type_string (nested), invocation->property_info->signature)) |
453 | 0 | { |
454 | 0 | g_warning ("Value returned from property 'Get' call for '%s' should be '%s' but is '%s'", |
455 | 0 | invocation->property_info->name, invocation->property_info->signature, |
456 | 0 | g_variant_get_type_string (nested)); |
457 | 0 | g_variant_unref (nested); |
458 | 0 | goto out; |
459 | 0 | } |
460 | 0 | g_variant_unref (nested); |
461 | 0 | } |
462 | | |
463 | 0 | else if (g_str_equal (invocation->method_name, "Set")) |
464 | 0 | { |
465 | 0 | if (!g_variant_is_of_type (parameters, G_VARIANT_TYPE_UNIT)) |
466 | 0 | { |
467 | 0 | g_warning ("Type of return value for property 'Set' call should be '()' but got '%s'", |
468 | 0 | g_variant_get_type_string (parameters)); |
469 | 0 | goto out; |
470 | 0 | } |
471 | 0 | } |
472 | | |
473 | 0 | else |
474 | 0 | g_assert_not_reached (); |
475 | 0 | } |
476 | 0 | else if (g_str_equal (invocation->interface_name, DBUS_INTERFACE_PROPERTIES) && |
477 | 0 | g_str_equal (invocation->method_name, "GetAll")) |
478 | 0 | { |
479 | 0 | if (!g_variant_is_of_type (parameters, G_VARIANT_TYPE ("(a{sv})"))) |
480 | 0 | { |
481 | 0 | g_warning ("Type of return value for property 'GetAll' call should be '(a{sv})' but got '%s'", |
482 | 0 | g_variant_get_type_string (parameters)); |
483 | 0 | goto out; |
484 | 0 | } |
485 | | |
486 | | /* Could iterate the list of properties and make sure that all |
487 | | * of them are actually on the interface and with the correct |
488 | | * types, but let's not do that for now... |
489 | | */ |
490 | 0 | } |
491 | | |
492 | 0 | if (G_UNLIKELY (_g_dbus_debug_return ())) |
493 | 0 | { |
494 | 0 | _g_dbus_debug_print_lock (); |
495 | 0 | g_print ("========================================================================\n" |
496 | 0 | "GDBus-debug:Return:\n" |
497 | 0 | " >>>> METHOD RETURN\n" |
498 | 0 | " in response to %s.%s()\n" |
499 | 0 | " on object %s\n" |
500 | 0 | " to name %s\n" |
501 | 0 | " reply-serial %d\n", |
502 | 0 | invocation->interface_name, invocation->method_name, |
503 | 0 | invocation->object_path, |
504 | 0 | invocation->sender, |
505 | 0 | g_dbus_message_get_serial (invocation->message)); |
506 | 0 | _g_dbus_debug_print_unlock (); |
507 | 0 | } |
508 | |
|
509 | 0 | reply = g_dbus_message_new_method_reply (invocation->message); |
510 | 0 | g_dbus_message_set_body (reply, g_steal_pointer (¶meters)); |
511 | |
|
512 | 0 | #ifdef G_OS_UNIX |
513 | 0 | if (fd_list != NULL) |
514 | 0 | g_dbus_message_set_unix_fd_list (reply, fd_list); |
515 | 0 | #endif |
516 | |
|
517 | 0 | error = NULL; |
518 | 0 | if (!g_dbus_connection_send_message (g_dbus_method_invocation_get_connection (invocation), reply, G_DBUS_SEND_MESSAGE_FLAGS_NONE, NULL, &error)) |
519 | 0 | { |
520 | 0 | if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CLOSED)) |
521 | 0 | g_warning ("Error sending message: %s", error->message); |
522 | 0 | g_error_free (error); |
523 | 0 | } |
524 | 0 | g_object_unref (reply); |
525 | |
|
526 | 0 | out: |
527 | 0 | if (parameters != NULL) |
528 | 0 | { |
529 | 0 | g_variant_ref_sink (parameters); |
530 | 0 | g_variant_unref (parameters); |
531 | 0 | } |
532 | |
|
533 | 0 | g_object_unref (invocation); |
534 | 0 | } |
535 | | |
536 | | /** |
537 | | * g_dbus_method_invocation_return_value: |
538 | | * @invocation: (transfer full): A #GDBusMethodInvocation. |
539 | | * @parameters: (nullable): A #GVariant tuple with out parameters for the method or %NULL if not passing any parameters. |
540 | | * |
541 | | * Finishes handling a D-Bus method call by returning @parameters. |
542 | | * If the @parameters GVariant is floating, it is consumed. |
543 | | * |
544 | | * It is an error if @parameters is not of the right format: it must be a tuple |
545 | | * containing the out-parameters of the D-Bus method. Even if the method has a |
546 | | * single out-parameter, it must be contained in a tuple. If the method has no |
547 | | * out-parameters, @parameters may be %NULL or an empty tuple. |
548 | | * |
549 | | * |[<!-- language="C" --> |
550 | | * GDBusMethodInvocation *invocation = some_invocation; |
551 | | * g_autofree gchar *result_string = NULL; |
552 | | * g_autoptr (GError) error = NULL; |
553 | | * |
554 | | * result_string = calculate_result (&error); |
555 | | * |
556 | | * if (error != NULL) |
557 | | * g_dbus_method_invocation_return_gerror (invocation, error); |
558 | | * else |
559 | | * g_dbus_method_invocation_return_value (invocation, |
560 | | * g_variant_new ("(s)", result_string)); |
561 | | * |
562 | | * // Do not free @invocation here; returning a value does that |
563 | | * ]| |
564 | | * |
565 | | * This method will take ownership of @invocation. See |
566 | | * #GDBusInterfaceVTable for more information about the ownership of |
567 | | * @invocation. |
568 | | * |
569 | | * Since 2.48, if the method call requested for a reply not to be sent |
570 | | * then this call will sink @parameters and free @invocation, but |
571 | | * otherwise do nothing (as per the recommendations of the D-Bus |
572 | | * specification). |
573 | | * |
574 | | * Since: 2.26 |
575 | | */ |
576 | | void |
577 | | g_dbus_method_invocation_return_value (GDBusMethodInvocation *invocation, |
578 | | GVariant *parameters) |
579 | 0 | { |
580 | 0 | g_dbus_method_invocation_return_value_internal (invocation, parameters, NULL); |
581 | 0 | } |
582 | | |
583 | | #ifdef G_OS_UNIX |
584 | | /** |
585 | | * g_dbus_method_invocation_return_value_with_unix_fd_list: |
586 | | * @invocation: (transfer full): A #GDBusMethodInvocation. |
587 | | * @parameters: (nullable): A #GVariant tuple with out parameters for the method or %NULL if not passing any parameters. |
588 | | * @fd_list: (nullable): A #GUnixFDList or %NULL. |
589 | | * |
590 | | * Like g_dbus_method_invocation_return_value() but also takes a #GUnixFDList. |
591 | | * |
592 | | * This method is only available on UNIX. |
593 | | * |
594 | | * This method will take ownership of @invocation. See |
595 | | * #GDBusInterfaceVTable for more information about the ownership of |
596 | | * @invocation. |
597 | | * |
598 | | * Since: 2.30 |
599 | | */ |
600 | | void |
601 | | g_dbus_method_invocation_return_value_with_unix_fd_list (GDBusMethodInvocation *invocation, |
602 | | GVariant *parameters, |
603 | | GUnixFDList *fd_list) |
604 | 0 | { |
605 | 0 | g_dbus_method_invocation_return_value_internal (invocation, parameters, fd_list); |
606 | 0 | } |
607 | | #endif |
608 | | |
609 | | /* ---------------------------------------------------------------------------------------------------- */ |
610 | | |
611 | | /** |
612 | | * g_dbus_method_invocation_return_error: |
613 | | * @invocation: (transfer full): A #GDBusMethodInvocation. |
614 | | * @domain: A #GQuark for the #GError error domain. |
615 | | * @code: The error code. |
616 | | * @format: printf()-style format. |
617 | | * @...: Parameters for @format. |
618 | | * |
619 | | * Finishes handling a D-Bus method call by returning an error. |
620 | | * |
621 | | * See g_dbus_error_encode_gerror() for details about what error name |
622 | | * will be returned on the wire. In a nutshell, if the given error is |
623 | | * registered using g_dbus_error_register_error() the name given |
624 | | * during registration is used. Otherwise, a name of the form |
625 | | * `org.gtk.GDBus.UnmappedGError.Quark...` is used. This provides |
626 | | * transparent mapping of #GError between applications using GDBus. |
627 | | * |
628 | | * If you are writing an application intended to be portable, |
629 | | * always register errors with g_dbus_error_register_error() |
630 | | * or use g_dbus_method_invocation_return_dbus_error(). |
631 | | * |
632 | | * This method will take ownership of @invocation. See |
633 | | * #GDBusInterfaceVTable for more information about the ownership of |
634 | | * @invocation. |
635 | | * |
636 | | * Since 2.48, if the method call requested for a reply not to be sent |
637 | | * then this call will free @invocation but otherwise do nothing (as per |
638 | | * the recommendations of the D-Bus specification). |
639 | | * |
640 | | * Since: 2.26 |
641 | | */ |
642 | | void |
643 | | g_dbus_method_invocation_return_error (GDBusMethodInvocation *invocation, |
644 | | GQuark domain, |
645 | | gint code, |
646 | | const gchar *format, |
647 | | ...) |
648 | 0 | { |
649 | 0 | va_list var_args; |
650 | |
|
651 | 0 | g_return_if_fail (G_IS_DBUS_METHOD_INVOCATION (invocation)); |
652 | 0 | g_return_if_fail (format != NULL); |
653 | | |
654 | 0 | va_start (var_args, format); |
655 | 0 | g_dbus_method_invocation_return_error_valist (invocation, |
656 | 0 | domain, |
657 | 0 | code, |
658 | 0 | format, |
659 | 0 | var_args); |
660 | 0 | va_end (var_args); |
661 | 0 | } |
662 | | |
663 | | /** |
664 | | * g_dbus_method_invocation_return_error_valist: |
665 | | * @invocation: (transfer full): A #GDBusMethodInvocation. |
666 | | * @domain: A #GQuark for the #GError error domain. |
667 | | * @code: The error code. |
668 | | * @format: printf()-style format. |
669 | | * @var_args: #va_list of parameters for @format. |
670 | | * |
671 | | * Like g_dbus_method_invocation_return_error() but intended for |
672 | | * language bindings. |
673 | | * |
674 | | * This method will take ownership of @invocation. See |
675 | | * #GDBusInterfaceVTable for more information about the ownership of |
676 | | * @invocation. |
677 | | * |
678 | | * Since: 2.26 |
679 | | */ |
680 | | void |
681 | | g_dbus_method_invocation_return_error_valist (GDBusMethodInvocation *invocation, |
682 | | GQuark domain, |
683 | | gint code, |
684 | | const gchar *format, |
685 | | va_list var_args) |
686 | 0 | { |
687 | 0 | gchar *literal_message; |
688 | |
|
689 | 0 | g_return_if_fail (G_IS_DBUS_METHOD_INVOCATION (invocation)); |
690 | 0 | g_return_if_fail (format != NULL); |
691 | | |
692 | 0 | literal_message = g_strdup_vprintf (format, var_args); |
693 | 0 | g_dbus_method_invocation_return_error_literal (invocation, |
694 | 0 | domain, |
695 | 0 | code, |
696 | 0 | literal_message); |
697 | 0 | g_free (literal_message); |
698 | 0 | } |
699 | | |
700 | | /** |
701 | | * g_dbus_method_invocation_return_error_literal: |
702 | | * @invocation: (transfer full): A #GDBusMethodInvocation. |
703 | | * @domain: A #GQuark for the #GError error domain. |
704 | | * @code: The error code. |
705 | | * @message: The error message. |
706 | | * |
707 | | * Like g_dbus_method_invocation_return_error() but without printf()-style formatting. |
708 | | * |
709 | | * This method will take ownership of @invocation. See |
710 | | * #GDBusInterfaceVTable for more information about the ownership of |
711 | | * @invocation. |
712 | | * |
713 | | * Since: 2.26 |
714 | | */ |
715 | | void |
716 | | g_dbus_method_invocation_return_error_literal (GDBusMethodInvocation *invocation, |
717 | | GQuark domain, |
718 | | gint code, |
719 | | const gchar *message) |
720 | 0 | { |
721 | 0 | GError *error; |
722 | |
|
723 | 0 | g_return_if_fail (G_IS_DBUS_METHOD_INVOCATION (invocation)); |
724 | 0 | g_return_if_fail (message != NULL); |
725 | | |
726 | 0 | error = g_error_new_literal (domain, code, message); |
727 | 0 | g_dbus_method_invocation_return_gerror (invocation, error); |
728 | 0 | g_error_free (error); |
729 | 0 | } |
730 | | |
731 | | /** |
732 | | * g_dbus_method_invocation_return_gerror: |
733 | | * @invocation: (transfer full): A #GDBusMethodInvocation. |
734 | | * @error: A #GError. |
735 | | * |
736 | | * Like g_dbus_method_invocation_return_error() but takes a #GError |
737 | | * instead of the error domain, error code and message. |
738 | | * |
739 | | * This method will take ownership of @invocation. See |
740 | | * #GDBusInterfaceVTable for more information about the ownership of |
741 | | * @invocation. |
742 | | * |
743 | | * Since: 2.26 |
744 | | */ |
745 | | void |
746 | | g_dbus_method_invocation_return_gerror (GDBusMethodInvocation *invocation, |
747 | | const GError *error) |
748 | 0 | { |
749 | 0 | gchar *dbus_error_name; |
750 | |
|
751 | 0 | g_return_if_fail (G_IS_DBUS_METHOD_INVOCATION (invocation)); |
752 | 0 | g_return_if_fail (error != NULL); |
753 | | |
754 | 0 | dbus_error_name = g_dbus_error_encode_gerror (error); |
755 | |
|
756 | 0 | g_dbus_method_invocation_return_dbus_error (invocation, |
757 | 0 | dbus_error_name, |
758 | 0 | error->message); |
759 | 0 | g_free (dbus_error_name); |
760 | 0 | } |
761 | | |
762 | | /** |
763 | | * g_dbus_method_invocation_take_error: (skip) |
764 | | * @invocation: (transfer full): A #GDBusMethodInvocation. |
765 | | * @error: (transfer full): A #GError. |
766 | | * |
767 | | * Like g_dbus_method_invocation_return_gerror() but takes ownership |
768 | | * of @error so the caller does not need to free it. |
769 | | * |
770 | | * This method will take ownership of @invocation. See |
771 | | * #GDBusInterfaceVTable for more information about the ownership of |
772 | | * @invocation. |
773 | | * |
774 | | * Since: 2.30 |
775 | | */ |
776 | | void |
777 | | g_dbus_method_invocation_take_error (GDBusMethodInvocation *invocation, |
778 | | GError *error) |
779 | 0 | { |
780 | 0 | g_return_if_fail (G_IS_DBUS_METHOD_INVOCATION (invocation)); |
781 | 0 | g_return_if_fail (error != NULL); |
782 | 0 | g_dbus_method_invocation_return_gerror (invocation, error); |
783 | 0 | g_error_free (error); |
784 | 0 | } |
785 | | |
786 | | /** |
787 | | * g_dbus_method_invocation_return_dbus_error: |
788 | | * @invocation: (transfer full): A #GDBusMethodInvocation. |
789 | | * @error_name: A valid D-Bus error name. |
790 | | * @error_message: A valid D-Bus error message. |
791 | | * |
792 | | * Finishes handling a D-Bus method call by returning an error. |
793 | | * |
794 | | * This method will take ownership of @invocation. See |
795 | | * #GDBusInterfaceVTable for more information about the ownership of |
796 | | * @invocation. |
797 | | * |
798 | | * Since: 2.26 |
799 | | */ |
800 | | void |
801 | | g_dbus_method_invocation_return_dbus_error (GDBusMethodInvocation *invocation, |
802 | | const gchar *error_name, |
803 | | const gchar *error_message) |
804 | 0 | { |
805 | 0 | GDBusMessage *reply; |
806 | |
|
807 | 0 | g_return_if_fail (G_IS_DBUS_METHOD_INVOCATION (invocation)); |
808 | 0 | g_return_if_fail (error_name != NULL && g_dbus_is_name (error_name)); |
809 | 0 | g_return_if_fail (error_message != NULL); |
810 | | |
811 | 0 | if (g_dbus_message_get_flags (invocation->message) & G_DBUS_MESSAGE_FLAGS_NO_REPLY_EXPECTED) |
812 | 0 | goto out; |
813 | | |
814 | 0 | if (G_UNLIKELY (_g_dbus_debug_return ())) |
815 | 0 | { |
816 | 0 | _g_dbus_debug_print_lock (); |
817 | 0 | g_print ("========================================================================\n" |
818 | 0 | "GDBus-debug:Return:\n" |
819 | 0 | " >>>> METHOD ERROR %s\n" |
820 | 0 | " message '%s'\n" |
821 | 0 | " in response to %s.%s()\n" |
822 | 0 | " on object %s\n" |
823 | 0 | " to name %s\n" |
824 | 0 | " reply-serial %d\n", |
825 | 0 | error_name, |
826 | 0 | error_message, |
827 | 0 | invocation->interface_name, invocation->method_name, |
828 | 0 | invocation->object_path, |
829 | 0 | invocation->sender, |
830 | 0 | g_dbus_message_get_serial (invocation->message)); |
831 | 0 | _g_dbus_debug_print_unlock (); |
832 | 0 | } |
833 | |
|
834 | 0 | reply = g_dbus_message_new_method_error_literal (invocation->message, |
835 | 0 | error_name, |
836 | 0 | error_message); |
837 | 0 | g_dbus_connection_send_message (g_dbus_method_invocation_get_connection (invocation), reply, G_DBUS_SEND_MESSAGE_FLAGS_NONE, NULL, NULL); |
838 | 0 | g_object_unref (reply); |
839 | |
|
840 | 0 | out: |
841 | 0 | g_object_unref (invocation); |
842 | 0 | } |