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