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