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