/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 | | * 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 | 0 | { |
100 | 0 | GDBusMethodInvocation *invocation = G_DBUS_METHOD_INVOCATION (object); |
101 | |
|
102 | 0 | g_free (invocation->sender); |
103 | 0 | g_free (invocation->object_path); |
104 | 0 | g_free (invocation->interface_name); |
105 | 0 | g_free (invocation->method_name); |
106 | 0 | if (invocation->method_info) |
107 | 0 | g_dbus_method_info_unref (invocation->method_info); |
108 | 0 | if (invocation->property_info) |
109 | 0 | g_dbus_property_info_unref (invocation->property_info); |
110 | 0 | g_object_unref (invocation->connection); |
111 | 0 | g_object_unref (invocation->message); |
112 | 0 | g_variant_unref (invocation->parameters); |
113 | |
|
114 | 0 | G_OBJECT_CLASS (g_dbus_method_invocation_parent_class)->finalize (object); |
115 | 0 | } |
116 | | |
117 | | static void |
118 | | g_dbus_method_invocation_class_init (GDBusMethodInvocationClass *klass) |
119 | 0 | { |
120 | 0 | GObjectClass *gobject_class = G_OBJECT_CLASS (klass); |
121 | |
|
122 | 0 | gobject_class->finalize = g_dbus_method_invocation_finalize; |
123 | 0 | } |
124 | | |
125 | | static void |
126 | | g_dbus_method_invocation_init (GDBusMethodInvocation *invocation) |
127 | 0 | { |
128 | 0 | } |
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 | 0 | { |
143 | 0 | g_return_val_if_fail (G_IS_DBUS_METHOD_INVOCATION (invocation), NULL); |
144 | 0 | return invocation->sender; |
145 | 0 | } |
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 | 0 | { |
160 | 0 | g_return_val_if_fail (G_IS_DBUS_METHOD_INVOCATION (invocation), NULL); |
161 | 0 | return invocation->object_path; |
162 | 0 | } |
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 | 0 | { |
182 | 0 | g_return_val_if_fail (G_IS_DBUS_METHOD_INVOCATION (invocation), NULL); |
183 | 0 | return invocation->interface_name; |
184 | 0 | } |
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 | 0 | { |
204 | 0 | g_return_val_if_fail (G_IS_DBUS_METHOD_INVOCATION (invocation), NULL); |
205 | 0 | return invocation->method_info; |
206 | 0 | } |
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 | 0 | { |
231 | 0 | g_return_val_if_fail (G_IS_DBUS_METHOD_INVOCATION (invocation), NULL); |
232 | 0 | return invocation->property_info; |
233 | 0 | } |
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 | 0 | { |
248 | 0 | g_return_val_if_fail (G_IS_DBUS_METHOD_INVOCATION (invocation), NULL); |
249 | 0 | return invocation->method_name; |
250 | 0 | } |
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 | 0 | { |
265 | 0 | g_return_val_if_fail (G_IS_DBUS_METHOD_INVOCATION (invocation), NULL); |
266 | 0 | return invocation->connection; |
267 | 0 | } |
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 | 0 | { |
289 | 0 | g_return_val_if_fail (G_IS_DBUS_METHOD_INVOCATION (invocation), NULL); |
290 | 0 | return invocation->message; |
291 | 0 | } |
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 | 0 | { |
307 | 0 | g_return_val_if_fail (G_IS_DBUS_METHOD_INVOCATION (invocation), NULL); |
308 | 0 | return invocation->parameters; |
309 | 0 | } |
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 | 0 | { |
324 | 0 | g_return_val_if_fail (G_IS_DBUS_METHOD_INVOCATION (invocation), NULL); |
325 | 0 | return invocation->user_data; |
326 | 0 | } |
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 | 0 | { |
359 | 0 | GDBusMethodInvocation *invocation; |
360 | |
|
361 | 0 | g_return_val_if_fail (sender == NULL || g_dbus_is_name (sender), NULL); |
362 | 0 | g_return_val_if_fail (g_variant_is_object_path (object_path), NULL); |
363 | 0 | g_return_val_if_fail (interface_name == NULL || g_dbus_is_interface_name (interface_name), NULL); |
364 | 0 | g_return_val_if_fail (g_dbus_is_member_name (method_name), NULL); |
365 | 0 | g_return_val_if_fail (G_IS_DBUS_CONNECTION (connection), NULL); |
366 | 0 | g_return_val_if_fail (G_IS_DBUS_MESSAGE (message), NULL); |
367 | 0 | g_return_val_if_fail (g_variant_is_of_type (parameters, G_VARIANT_TYPE_TUPLE), NULL); |
368 | | |
369 | 0 | invocation = G_DBUS_METHOD_INVOCATION (g_object_new (G_TYPE_DBUS_METHOD_INVOCATION, NULL)); |
370 | 0 | invocation->sender = g_strdup (sender); |
371 | 0 | invocation->object_path = g_strdup (object_path); |
372 | 0 | invocation->interface_name = g_strdup (interface_name); |
373 | 0 | invocation->method_name = g_strdup (method_name); |
374 | 0 | if (method_info) |
375 | 0 | invocation->method_info = g_dbus_method_info_ref ((GDBusMethodInfo *)method_info); |
376 | 0 | if (property_info) |
377 | 0 | invocation->property_info = g_dbus_property_info_ref ((GDBusPropertyInfo *)property_info); |
378 | 0 | invocation->connection = g_object_ref (connection); |
379 | 0 | invocation->message = g_object_ref (message); |
380 | 0 | invocation->parameters = g_variant_ref (parameters); |
381 | 0 | invocation->user_data = user_data; |
382 | |
|
383 | 0 | return invocation; |
384 | 0 | } |
385 | | |
386 | | /* ---------------------------------------------------------------------------------------------------- */ |
387 | | |
388 | | static void |
389 | | g_dbus_method_invocation_return_value_internal (GDBusMethodInvocation *invocation, |
390 | | GVariant *parameters, |
391 | | GUnixFDList *fd_list) |
392 | 0 | { |
393 | 0 | GDBusMessage *reply; |
394 | 0 | GError *error; |
395 | |
|
396 | 0 | g_return_if_fail (G_IS_DBUS_METHOD_INVOCATION (invocation)); |
397 | 0 | g_return_if_fail ((parameters == NULL) || g_variant_is_of_type (parameters, G_VARIANT_TYPE_TUPLE)); |
398 | | |
399 | 0 | if (g_dbus_message_get_flags (invocation->message) & G_DBUS_MESSAGE_FLAGS_NO_REPLY_EXPECTED) |
400 | 0 | { |
401 | 0 | if (parameters != NULL) |
402 | 0 | { |
403 | 0 | g_variant_ref_sink (parameters); |
404 | 0 | g_variant_unref (parameters); |
405 | 0 | } |
406 | 0 | goto out; |
407 | 0 | } |
408 | | |
409 | 0 | if (parameters == NULL) |
410 | 0 | parameters = g_variant_new_tuple (NULL, 0); |
411 | | |
412 | | /* if we have introspection data, check that the signature of @parameters is correct */ |
413 | 0 | if (invocation->method_info != NULL) |
414 | 0 | { |
415 | 0 | GVariantType *type; |
416 | |
|
417 | 0 | type = _g_dbus_compute_complete_signature (invocation->method_info->out_args); |
418 | |
|
419 | 0 | if (!g_variant_is_of_type (parameters, type)) |
420 | 0 | { |
421 | 0 | gchar *type_string = g_variant_type_dup_string (type); |
422 | |
|
423 | 0 | g_warning ("Type of return value is incorrect: expected '%s', got '%s''", |
424 | 0 | type_string, g_variant_get_type_string (parameters)); |
425 | 0 | g_variant_type_free (type); |
426 | 0 | g_free (type_string); |
427 | 0 | goto out; |
428 | 0 | } |
429 | 0 | g_variant_type_free (type); |
430 | 0 | } |
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 | 0 | if (invocation->property_info != NULL) |
437 | 0 | { |
438 | 0 | if (g_str_equal (invocation->method_name, "Get")) |
439 | 0 | { |
440 | 0 | GVariant *nested; |
441 | |
|
442 | 0 | if (!g_variant_is_of_type (parameters, G_VARIANT_TYPE ("(v)"))) |
443 | 0 | { |
444 | 0 | g_warning ("Type of return value for property 'Get' call should be '(v)' but got '%s'", |
445 | 0 | g_variant_get_type_string (parameters)); |
446 | 0 | goto out; |
447 | 0 | } |
448 | | |
449 | | /* Go deeper and make sure that the value inside of the |
450 | | * variant matches the property type. |
451 | | */ |
452 | 0 | g_variant_get (parameters, "(v)", &nested); |
453 | 0 | if (!g_str_equal (g_variant_get_type_string (nested), invocation->property_info->signature)) |
454 | 0 | { |
455 | 0 | g_warning ("Value returned from property 'Get' call for '%s' should be '%s' but is '%s'", |
456 | 0 | invocation->property_info->name, invocation->property_info->signature, |
457 | 0 | g_variant_get_type_string (nested)); |
458 | 0 | g_variant_unref (nested); |
459 | 0 | goto out; |
460 | 0 | } |
461 | 0 | g_variant_unref (nested); |
462 | 0 | } |
463 | | |
464 | 0 | else if (g_str_equal (invocation->method_name, "GetAll")) |
465 | 0 | { |
466 | 0 | if (!g_variant_is_of_type (parameters, G_VARIANT_TYPE ("(a{sv})"))) |
467 | 0 | { |
468 | 0 | g_warning ("Type of return value for property 'GetAll' call should be '(a{sv})' but got '%s'", |
469 | 0 | g_variant_get_type_string (parameters)); |
470 | 0 | goto out; |
471 | 0 | } |
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 | 0 | } |
478 | | |
479 | 0 | else if (g_str_equal (invocation->method_name, "Set")) |
480 | 0 | { |
481 | 0 | if (!g_variant_is_of_type (parameters, G_VARIANT_TYPE_UNIT)) |
482 | 0 | { |
483 | 0 | g_warning ("Type of return value for property 'Set' call should be '()' but got '%s'", |
484 | 0 | g_variant_get_type_string (parameters)); |
485 | 0 | goto out; |
486 | 0 | } |
487 | 0 | } |
488 | | |
489 | 0 | else |
490 | 0 | g_assert_not_reached (); |
491 | 0 | } |
492 | | |
493 | 0 | if (G_UNLIKELY (_g_dbus_debug_return ())) |
494 | 0 | { |
495 | 0 | _g_dbus_debug_print_lock (); |
496 | 0 | g_print ("========================================================================\n" |
497 | 0 | "GDBus-debug:Return:\n" |
498 | 0 | " >>>> METHOD RETURN\n" |
499 | 0 | " in response to %s.%s()\n" |
500 | 0 | " on object %s\n" |
501 | 0 | " to name %s\n" |
502 | 0 | " reply-serial %d\n", |
503 | 0 | invocation->interface_name, invocation->method_name, |
504 | 0 | invocation->object_path, |
505 | 0 | invocation->sender, |
506 | 0 | g_dbus_message_get_serial (invocation->message)); |
507 | 0 | _g_dbus_debug_print_unlock (); |
508 | 0 | } |
509 | |
|
510 | 0 | reply = g_dbus_message_new_method_reply (invocation->message); |
511 | 0 | g_dbus_message_set_body (reply, parameters); |
512 | |
|
513 | 0 | #ifdef G_OS_UNIX |
514 | 0 | if (fd_list != NULL) |
515 | 0 | g_dbus_message_set_unix_fd_list (reply, fd_list); |
516 | 0 | #endif |
517 | |
|
518 | 0 | error = NULL; |
519 | 0 | if (!g_dbus_connection_send_message (g_dbus_method_invocation_get_connection (invocation), reply, G_DBUS_SEND_MESSAGE_FLAGS_NONE, NULL, &error)) |
520 | 0 | { |
521 | 0 | if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CLOSED)) |
522 | 0 | g_warning ("Error sending message: %s", error->message); |
523 | 0 | g_error_free (error); |
524 | 0 | } |
525 | 0 | g_object_unref (reply); |
526 | |
|
527 | 0 | out: |
528 | 0 | g_object_unref (invocation); |
529 | 0 | } |
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 | 0 | { |
575 | 0 | g_dbus_method_invocation_return_value_internal (invocation, parameters, NULL); |
576 | 0 | } |
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 | 0 | { |
600 | 0 | g_dbus_method_invocation_return_value_internal (invocation, parameters, fd_list); |
601 | 0 | } |
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 | 0 | { |
644 | 0 | va_list var_args; |
645 | |
|
646 | 0 | g_return_if_fail (G_IS_DBUS_METHOD_INVOCATION (invocation)); |
647 | 0 | g_return_if_fail (format != NULL); |
648 | | |
649 | 0 | va_start (var_args, format); |
650 | 0 | g_dbus_method_invocation_return_error_valist (invocation, |
651 | 0 | domain, |
652 | 0 | code, |
653 | 0 | format, |
654 | 0 | var_args); |
655 | 0 | va_end (var_args); |
656 | 0 | } |
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 | 0 | { |
682 | 0 | gchar *literal_message; |
683 | |
|
684 | 0 | g_return_if_fail (G_IS_DBUS_METHOD_INVOCATION (invocation)); |
685 | 0 | g_return_if_fail (format != NULL); |
686 | | |
687 | 0 | literal_message = g_strdup_vprintf (format, var_args); |
688 | 0 | g_dbus_method_invocation_return_error_literal (invocation, |
689 | 0 | domain, |
690 | 0 | code, |
691 | 0 | literal_message); |
692 | 0 | g_free (literal_message); |
693 | 0 | } |
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 | 0 | { |
716 | 0 | GError *error; |
717 | |
|
718 | 0 | g_return_if_fail (G_IS_DBUS_METHOD_INVOCATION (invocation)); |
719 | 0 | g_return_if_fail (message != NULL); |
720 | | |
721 | 0 | error = g_error_new_literal (domain, code, message); |
722 | 0 | g_dbus_method_invocation_return_gerror (invocation, error); |
723 | 0 | g_error_free (error); |
724 | 0 | } |
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 | 0 | { |
744 | 0 | gchar *dbus_error_name; |
745 | |
|
746 | 0 | g_return_if_fail (G_IS_DBUS_METHOD_INVOCATION (invocation)); |
747 | 0 | g_return_if_fail (error != NULL); |
748 | | |
749 | 0 | dbus_error_name = g_dbus_error_encode_gerror (error); |
750 | |
|
751 | 0 | g_dbus_method_invocation_return_dbus_error (invocation, |
752 | 0 | dbus_error_name, |
753 | 0 | error->message); |
754 | 0 | g_free (dbus_error_name); |
755 | 0 | } |
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 | 0 | { |
775 | 0 | g_return_if_fail (G_IS_DBUS_METHOD_INVOCATION (invocation)); |
776 | 0 | g_return_if_fail (error != NULL); |
777 | 0 | g_dbus_method_invocation_return_gerror (invocation, error); |
778 | 0 | g_error_free (error); |
779 | 0 | } |
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 | 0 | { |
800 | 0 | GDBusMessage *reply; |
801 | |
|
802 | 0 | g_return_if_fail (G_IS_DBUS_METHOD_INVOCATION (invocation)); |
803 | 0 | g_return_if_fail (error_name != NULL && g_dbus_is_name (error_name)); |
804 | 0 | g_return_if_fail (error_message != NULL); |
805 | | |
806 | 0 | if (g_dbus_message_get_flags (invocation->message) & G_DBUS_MESSAGE_FLAGS_NO_REPLY_EXPECTED) |
807 | 0 | goto out; |
808 | | |
809 | 0 | if (G_UNLIKELY (_g_dbus_debug_return ())) |
810 | 0 | { |
811 | 0 | _g_dbus_debug_print_lock (); |
812 | 0 | g_print ("========================================================================\n" |
813 | 0 | "GDBus-debug:Return:\n" |
814 | 0 | " >>>> METHOD ERROR %s\n" |
815 | 0 | " message '%s'\n" |
816 | 0 | " in response to %s.%s()\n" |
817 | 0 | " on object %s\n" |
818 | 0 | " to name %s\n" |
819 | 0 | " reply-serial %d\n", |
820 | 0 | error_name, |
821 | 0 | error_message, |
822 | 0 | invocation->interface_name, invocation->method_name, |
823 | 0 | invocation->object_path, |
824 | 0 | invocation->sender, |
825 | 0 | g_dbus_message_get_serial (invocation->message)); |
826 | 0 | _g_dbus_debug_print_unlock (); |
827 | 0 | } |
828 | |
|
829 | 0 | reply = g_dbus_message_new_method_error_literal (invocation->message, |
830 | 0 | error_name, |
831 | 0 | error_message); |
832 | 0 | g_dbus_connection_send_message (g_dbus_method_invocation_get_connection (invocation), reply, G_DBUS_SEND_MESSAGE_FLAGS_NONE, NULL, NULL); |
833 | 0 | g_object_unref (reply); |
834 | |
|
835 | 0 | out: |
836 | 0 | g_object_unref (invocation); |
837 | 0 | } |