Branch data Line data Source code
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 : : /* Uncomment to debug serializer code */
24 : : /* #define DEBUG_SERIALIZER */
25 : :
26 : : #include "config.h"
27 : :
28 : : #include <string.h>
29 : : #include <errno.h>
30 : : #include <sys/types.h>
31 : : #include <sys/stat.h>
32 : :
33 : : #if MAJOR_IN_MKDEV
34 : : #include <sys/mkdev.h>
35 : : #elif MAJOR_IN_SYSMACROS
36 : : #include <sys/sysmacros.h>
37 : : #elif MAJOR_IN_TYPES
38 : : #include <sys/types.h>
39 : : #else
40 : : #define MAJOR_MINOR_NOT_FOUND 1
41 : : #endif
42 : :
43 : : #include "gdbusutils.h"
44 : : #include "gdbusmessage.h"
45 : : #include "gdbuserror.h"
46 : : #include "gioenumtypes.h"
47 : : #include "ginputstream.h"
48 : : #include "gdatainputstream.h"
49 : : #include "gmemoryinputstream.h"
50 : : #include "goutputstream.h"
51 : : #include "gdataoutputstream.h"
52 : : #include "gmemoryoutputstream.h"
53 : : #include "gseekable.h"
54 : : #include "gioerror.h"
55 : : #include "gdbusprivate.h"
56 : : #include "gutilsprivate.h"
57 : :
58 : : #ifdef G_OS_UNIX
59 : : #include "gunixfdlist.h"
60 : : #endif
61 : :
62 : : #include "glibintl.h"
63 : :
64 : : /* See https://dbus.freedesktop.org/doc/dbus-specification.html#message-protocol-marshaling-signature
65 : : * This is 64 containers plus 1 value within them. */
66 : : #define G_DBUS_MAX_TYPE_DEPTH (64 + 1)
67 : :
68 : : typedef struct _GMemoryBuffer GMemoryBuffer;
69 : : struct _GMemoryBuffer
70 : : {
71 : : gsize len;
72 : : gsize valid_len;
73 : : gsize pos;
74 : : gchar *data;
75 : : GDataStreamByteOrder byte_order;
76 : : };
77 : :
78 : : static gboolean
79 : 252426 : g_memory_buffer_is_byteswapped (GMemoryBuffer *mbuf)
80 : : {
81 : : #if G_BYTE_ORDER == G_LITTLE_ENDIAN
82 : 252426 : return mbuf->byte_order == G_DATA_STREAM_BYTE_ORDER_BIG_ENDIAN;
83 : : #else
84 : : return mbuf->byte_order == G_DATA_STREAM_BYTE_ORDER_LITTLE_ENDIAN;
85 : : #endif
86 : : }
87 : :
88 : : static guchar
89 : 431928 : g_memory_buffer_read_byte (GMemoryBuffer *mbuf,
90 : : GError **error)
91 : : {
92 : 431928 : g_return_val_if_fail (error == NULL || *error == NULL, 0);
93 : :
94 : 431928 : if (mbuf->pos >= mbuf->valid_len)
95 : : {
96 : 22 : g_set_error (error,
97 : : G_IO_ERROR,
98 : : G_IO_ERROR_INVALID_ARGUMENT,
99 : : "Unexpected end of message while reading byte.");
100 : 22 : return 0;
101 : : }
102 : 431906 : return mbuf->data [mbuf->pos++];
103 : : }
104 : :
105 : : static gint16
106 : 95 : g_memory_buffer_read_int16 (GMemoryBuffer *mbuf,
107 : : GError **error)
108 : : {
109 : : gint16 v;
110 : :
111 : 95 : g_return_val_if_fail (error == NULL || *error == NULL, -1);
112 : :
113 : 95 : if (mbuf->pos > mbuf->valid_len - 2)
114 : : {
115 : 3 : g_set_error (error,
116 : : G_IO_ERROR,
117 : : G_IO_ERROR_INVALID_ARGUMENT,
118 : : "Unexpected end of message while reading int16.");
119 : 3 : return 0;
120 : : }
121 : :
122 : 92 : memcpy (&v, mbuf->data + mbuf->pos, 2);
123 : 92 : mbuf->pos += 2;
124 : :
125 : 92 : if (g_memory_buffer_is_byteswapped (mbuf))
126 : 1 : v = GUINT16_SWAP_LE_BE (v);
127 : :
128 : 92 : return v;
129 : : }
130 : :
131 : : static guint16
132 : 86 : g_memory_buffer_read_uint16 (GMemoryBuffer *mbuf,
133 : : GError **error)
134 : : {
135 : : guint16 v;
136 : :
137 : 86 : g_return_val_if_fail (error == NULL || *error == NULL, 0);
138 : :
139 : 86 : if (mbuf->pos > mbuf->valid_len - 2)
140 : : {
141 : 2 : g_set_error (error,
142 : : G_IO_ERROR,
143 : : G_IO_ERROR_INVALID_ARGUMENT,
144 : : "Unexpected end of message while reading uint16.");
145 : 2 : return 0;
146 : : }
147 : :
148 : 84 : memcpy (&v, mbuf->data + mbuf->pos, 2);
149 : 84 : mbuf->pos += 2;
150 : :
151 : 84 : if (g_memory_buffer_is_byteswapped (mbuf))
152 : 1 : v = GUINT16_SWAP_LE_BE (v);
153 : :
154 : 84 : return v;
155 : : }
156 : :
157 : : static gint32
158 : 335 : g_memory_buffer_read_int32 (GMemoryBuffer *mbuf,
159 : : GError **error)
160 : : {
161 : : gint32 v;
162 : :
163 : 335 : g_return_val_if_fail (error == NULL || *error == NULL, -1);
164 : :
165 : 335 : if (mbuf->pos > mbuf->valid_len - 4)
166 : : {
167 : 6 : g_set_error (error,
168 : : G_IO_ERROR,
169 : : G_IO_ERROR_INVALID_ARGUMENT,
170 : : "Unexpected end of message while reading int32.");
171 : 6 : return 0;
172 : : }
173 : :
174 : 329 : memcpy (&v, mbuf->data + mbuf->pos, 4);
175 : 329 : mbuf->pos += 4;
176 : :
177 : 329 : if (g_memory_buffer_is_byteswapped (mbuf))
178 : 2 : v = GUINT32_SWAP_LE_BE (v);
179 : :
180 : 329 : return v;
181 : : }
182 : :
183 : : static guint32
184 : 250288 : g_memory_buffer_read_uint32 (GMemoryBuffer *mbuf,
185 : : GError **error)
186 : : {
187 : : guint32 v;
188 : :
189 : 250288 : g_return_val_if_fail (error == NULL || *error == NULL, 0);
190 : :
191 : 250288 : if (mbuf->pos > mbuf->valid_len - 4)
192 : : {
193 : 27 : g_set_error (error,
194 : : G_IO_ERROR,
195 : : G_IO_ERROR_INVALID_ARGUMENT,
196 : : "Unexpected end of message while reading uint32.");
197 : 27 : return 0;
198 : : }
199 : :
200 : 250261 : memcpy (&v, mbuf->data + mbuf->pos, 4);
201 : 250261 : mbuf->pos += 4;
202 : :
203 : 250261 : if (g_memory_buffer_is_byteswapped (mbuf))
204 : 129 : v = GUINT32_SWAP_LE_BE (v);
205 : :
206 : 250261 : return v;
207 : : }
208 : :
209 : : static gint64
210 : 92 : g_memory_buffer_read_int64 (GMemoryBuffer *mbuf,
211 : : GError **error)
212 : : {
213 : : gint64 v;
214 : :
215 : 92 : g_return_val_if_fail (error == NULL || *error == NULL, -1);
216 : :
217 : 92 : if (mbuf->pos > mbuf->valid_len - 8)
218 : : {
219 : 8 : g_set_error (error,
220 : : G_IO_ERROR,
221 : : G_IO_ERROR_INVALID_ARGUMENT,
222 : : "Unexpected end of message while reading int64.");
223 : 8 : return 0;
224 : : }
225 : :
226 : 84 : memcpy (&v, mbuf->data + mbuf->pos, 8);
227 : 84 : mbuf->pos += 8;
228 : :
229 : 84 : if (g_memory_buffer_is_byteswapped (mbuf))
230 : 1 : v = GUINT64_SWAP_LE_BE (v);
231 : :
232 : 84 : return v;
233 : : }
234 : :
235 : : static guint64
236 : 174 : g_memory_buffer_read_uint64 (GMemoryBuffer *mbuf,
237 : : GError **error)
238 : : {
239 : : guint64 v;
240 : :
241 : 174 : g_return_val_if_fail (error == NULL || *error == NULL, 0);
242 : :
243 : 174 : if (mbuf->pos > mbuf->valid_len - 8)
244 : : {
245 : 16 : g_set_error (error,
246 : : G_IO_ERROR,
247 : : G_IO_ERROR_INVALID_ARGUMENT,
248 : : "Unexpected end of message while reading uint64.");
249 : 16 : return 0;
250 : : }
251 : :
252 : 158 : memcpy (&v, mbuf->data + mbuf->pos, 8);
253 : 158 : mbuf->pos += 8;
254 : :
255 : 158 : if (g_memory_buffer_is_byteswapped (mbuf))
256 : 2 : v = GUINT64_SWAP_LE_BE (v);
257 : :
258 : 158 : return v;
259 : : }
260 : :
261 : : #define MIN_ARRAY_SIZE 128
262 : :
263 : : static void
264 : 10602 : array_resize (GMemoryBuffer *mbuf,
265 : : gsize size)
266 : : {
267 : : gpointer data;
268 : : gsize len;
269 : :
270 : 10602 : if (mbuf->len == size)
271 : 0 : return;
272 : :
273 : 10602 : len = mbuf->len;
274 : 10602 : data = g_realloc (mbuf->data, size);
275 : :
276 : 10602 : if (size > len)
277 : 10602 : memset ((guint8 *)data + len, 0, size - len);
278 : :
279 : 10602 : mbuf->data = data;
280 : 10602 : mbuf->len = size;
281 : :
282 : 10602 : if (mbuf->len < mbuf->valid_len)
283 : 0 : mbuf->valid_len = mbuf->len;
284 : : }
285 : :
286 : : static gboolean
287 : 947397 : g_memory_buffer_write (GMemoryBuffer *mbuf,
288 : : const void *buffer,
289 : : gsize count)
290 : : {
291 : : guint8 *dest;
292 : : gsize new_size;
293 : :
294 : 947397 : if (count == 0)
295 : 473 : return TRUE;
296 : :
297 : : /* Check for address space overflow, but only if the buffer is resizable.
298 : : Otherwise we just do a short write and don't worry. */
299 : 946924 : if (mbuf->pos + count < mbuf->pos)
300 : 0 : return FALSE;
301 : :
302 : 946924 : if (mbuf->pos + count > mbuf->len)
303 : : {
304 : : /* At least enough to fit the write, rounded up
305 : : for greater than linear growth.
306 : : TODO: This wastes a lot of memory at large buffer sizes.
307 : : Figure out a more rational allocation strategy. */
308 : 10602 : new_size = g_nearest_pow (mbuf->pos + count);
309 : : /* Check for overflow again. We have checked if
310 : : pos + count > G_MAXSIZE, but now check if g_nearest_pow () has
311 : : overflowed */
312 : 10602 : if (new_size == 0)
313 : 0 : return FALSE;
314 : :
315 : 10602 : new_size = MAX (new_size, MIN_ARRAY_SIZE);
316 : 10602 : array_resize (mbuf, new_size);
317 : : }
318 : :
319 : 946924 : dest = (guint8 *)mbuf->data + mbuf->pos;
320 : 946924 : memcpy (dest, buffer, count);
321 : 946924 : mbuf->pos += count;
322 : :
323 : 946924 : if (mbuf->pos > mbuf->valid_len)
324 : 908624 : mbuf->valid_len = mbuf->pos;
325 : :
326 : 946924 : return TRUE;
327 : : }
328 : :
329 : : static gboolean
330 : 602493 : g_memory_buffer_put_byte (GMemoryBuffer *mbuf,
331 : : guchar data)
332 : : {
333 : 602493 : return g_memory_buffer_write (mbuf, &data, 1);
334 : : }
335 : :
336 : : static gboolean
337 : 50 : g_memory_buffer_put_int16 (GMemoryBuffer *mbuf,
338 : : gint16 data)
339 : : {
340 : 50 : switch (mbuf->byte_order)
341 : : {
342 : 1 : case G_DATA_STREAM_BYTE_ORDER_BIG_ENDIAN:
343 : 1 : data = GINT16_TO_BE (data);
344 : 1 : break;
345 : 49 : case G_DATA_STREAM_BYTE_ORDER_LITTLE_ENDIAN:
346 : 49 : data = GINT16_TO_LE (data);
347 : 49 : break;
348 : 0 : case G_DATA_STREAM_BYTE_ORDER_HOST_ENDIAN:
349 : : default:
350 : 0 : break;
351 : : }
352 : :
353 : 50 : return g_memory_buffer_write (mbuf, &data, 2);
354 : : }
355 : :
356 : : static gboolean
357 : 44 : g_memory_buffer_put_uint16 (GMemoryBuffer *mbuf,
358 : : guint16 data)
359 : : {
360 : 44 : switch (mbuf->byte_order)
361 : : {
362 : 1 : case G_DATA_STREAM_BYTE_ORDER_BIG_ENDIAN:
363 : 1 : data = GUINT16_TO_BE (data);
364 : 1 : break;
365 : 43 : case G_DATA_STREAM_BYTE_ORDER_LITTLE_ENDIAN:
366 : 43 : data = GUINT16_TO_LE (data);
367 : 43 : break;
368 : 0 : case G_DATA_STREAM_BYTE_ORDER_HOST_ENDIAN:
369 : : default:
370 : 0 : break;
371 : : }
372 : :
373 : 44 : return g_memory_buffer_write (mbuf, &data, 2);
374 : : }
375 : :
376 : : static gboolean
377 : 321 : g_memory_buffer_put_int32 (GMemoryBuffer *mbuf,
378 : : gint32 data)
379 : : {
380 : 321 : switch (mbuf->byte_order)
381 : : {
382 : 2 : case G_DATA_STREAM_BYTE_ORDER_BIG_ENDIAN:
383 : 2 : data = GINT32_TO_BE (data);
384 : 2 : break;
385 : 319 : case G_DATA_STREAM_BYTE_ORDER_LITTLE_ENDIAN:
386 : 319 : data = GINT32_TO_LE (data);
387 : 319 : break;
388 : 0 : case G_DATA_STREAM_BYTE_ORDER_HOST_ENDIAN:
389 : : default:
390 : 0 : break;
391 : : }
392 : :
393 : 321 : return g_memory_buffer_write (mbuf, &data, 4);
394 : : }
395 : :
396 : : static gboolean
397 : 177547 : g_memory_buffer_put_uint32 (GMemoryBuffer *mbuf,
398 : : guint32 data)
399 : : {
400 : 177547 : switch (mbuf->byte_order)
401 : : {
402 : 208 : case G_DATA_STREAM_BYTE_ORDER_BIG_ENDIAN:
403 : 208 : data = GUINT32_TO_BE (data);
404 : 208 : break;
405 : 177339 : case G_DATA_STREAM_BYTE_ORDER_LITTLE_ENDIAN:
406 : 177339 : data = GUINT32_TO_LE (data);
407 : 177339 : break;
408 : 0 : case G_DATA_STREAM_BYTE_ORDER_HOST_ENDIAN:
409 : : default:
410 : 0 : break;
411 : : }
412 : :
413 : 177547 : return g_memory_buffer_write (mbuf, &data, 4);
414 : : }
415 : :
416 : : static gboolean
417 : 458 : g_memory_buffer_put_int64 (GMemoryBuffer *mbuf,
418 : : gint64 data)
419 : : {
420 : 458 : switch (mbuf->byte_order)
421 : : {
422 : 1 : case G_DATA_STREAM_BYTE_ORDER_BIG_ENDIAN:
423 : 1 : data = GINT64_TO_BE (data);
424 : 1 : break;
425 : 457 : case G_DATA_STREAM_BYTE_ORDER_LITTLE_ENDIAN:
426 : 457 : data = GINT64_TO_LE (data);
427 : 457 : break;
428 : 0 : case G_DATA_STREAM_BYTE_ORDER_HOST_ENDIAN:
429 : : default:
430 : 0 : break;
431 : : }
432 : :
433 : 458 : return g_memory_buffer_write (mbuf, &data, 8);
434 : : }
435 : :
436 : : static gboolean
437 : 136 : g_memory_buffer_put_uint64 (GMemoryBuffer *mbuf,
438 : : guint64 data)
439 : : {
440 : 136 : switch (mbuf->byte_order)
441 : : {
442 : 2 : case G_DATA_STREAM_BYTE_ORDER_BIG_ENDIAN:
443 : 2 : data = GUINT64_TO_BE (data);
444 : 2 : break;
445 : 134 : case G_DATA_STREAM_BYTE_ORDER_LITTLE_ENDIAN:
446 : 134 : data = GUINT64_TO_LE (data);
447 : 134 : break;
448 : 0 : case G_DATA_STREAM_BYTE_ORDER_HOST_ENDIAN:
449 : : default:
450 : 0 : break;
451 : : }
452 : :
453 : 136 : return g_memory_buffer_write (mbuf, &data, 8);
454 : : }
455 : :
456 : : static gboolean
457 : 165659 : g_memory_buffer_put_string (GMemoryBuffer *mbuf,
458 : : const char *str)
459 : : {
460 : 165659 : g_return_val_if_fail (str != NULL, FALSE);
461 : :
462 : 165659 : return g_memory_buffer_write (mbuf, str, strlen (str));
463 : : }
464 : :
465 : : typedef struct _GDBusMessageClass GDBusMessageClass;
466 : :
467 : : /**
468 : : * GDBusMessageClass:
469 : : *
470 : : * Class structure for [class@Gio.DBusMessage].
471 : : *
472 : : * Since: 2.26
473 : : */
474 : : struct _GDBusMessageClass
475 : : {
476 : : /*< private >*/
477 : : GObjectClass parent_class;
478 : : };
479 : :
480 : : /**
481 : : * GDBusMessage:
482 : : *
483 : : * A type for representing D-Bus messages that can be sent or received
484 : : * on a [class@Gio.DBusConnection].
485 : : *
486 : : * Since: 2.26
487 : : */
488 : : struct _GDBusMessage
489 : : {
490 : : /*< private >*/
491 : : GObject parent_instance;
492 : :
493 : : GDBusMessageType type;
494 : : GDBusMessageFlags flags;
495 : : gboolean locked;
496 : : GDBusMessageByteOrder byte_order;
497 : : guchar major_protocol_version;
498 : : guint32 serial;
499 : : GHashTable *headers;
500 : : GVariant *body;
501 : : GVariant *arg0_cache; /* (nullable) (owned) */
502 : : #ifdef G_OS_UNIX
503 : : GUnixFDList *fd_list;
504 : : #endif
505 : : };
506 : :
507 : : enum
508 : : {
509 : : PROP_0,
510 : : PROP_LOCKED
511 : : };
512 : :
513 : 1070648 : G_DEFINE_TYPE (GDBusMessage, g_dbus_message, G_TYPE_OBJECT)
514 : :
515 : : static void
516 : 46047 : g_dbus_message_finalize (GObject *object)
517 : : {
518 : 46047 : GDBusMessage *message = G_DBUS_MESSAGE (object);
519 : :
520 : 46047 : if (message->headers != NULL)
521 : 46047 : g_hash_table_unref (message->headers);
522 : 46047 : if (message->body != NULL)
523 : 39305 : g_variant_unref (message->body);
524 : 46047 : g_clear_pointer (&message->arg0_cache, g_variant_unref);
525 : : #ifdef G_OS_UNIX
526 : 46047 : if (message->fd_list != NULL)
527 : 47 : g_object_unref (message->fd_list);
528 : : #endif
529 : :
530 : 46047 : if (G_OBJECT_CLASS (g_dbus_message_parent_class)->finalize != NULL)
531 : 46047 : G_OBJECT_CLASS (g_dbus_message_parent_class)->finalize (object);
532 : 46047 : }
533 : :
534 : : static void
535 : 1 : g_dbus_message_get_property (GObject *object,
536 : : guint prop_id,
537 : : GValue *value,
538 : : GParamSpec *pspec)
539 : : {
540 : 1 : GDBusMessage *message = G_DBUS_MESSAGE (object);
541 : :
542 : 1 : switch (prop_id)
543 : : {
544 : 1 : case PROP_LOCKED:
545 : 1 : g_value_set_boolean (value, g_dbus_message_get_locked (message));
546 : 1 : break;
547 : :
548 : 0 : default:
549 : 0 : G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
550 : 0 : break;
551 : : }
552 : 1 : }
553 : :
554 : : static void
555 : 103 : g_dbus_message_class_init (GDBusMessageClass *klass)
556 : : {
557 : : GObjectClass *gobject_class;
558 : :
559 : 103 : gobject_class = G_OBJECT_CLASS (klass);
560 : 103 : gobject_class->finalize = g_dbus_message_finalize;
561 : 103 : gobject_class->get_property = g_dbus_message_get_property;
562 : :
563 : : /**
564 : : * GDBusConnection:locked:
565 : : *
566 : : * A boolean specifying whether the message is locked.
567 : : *
568 : : * Since: 2.26
569 : : */
570 : 103 : g_object_class_install_property (gobject_class,
571 : : PROP_LOCKED,
572 : : g_param_spec_boolean ("locked", NULL, NULL,
573 : : FALSE,
574 : : G_PARAM_READABLE |
575 : : G_PARAM_STATIC_NAME |
576 : : G_PARAM_STATIC_BLURB |
577 : : G_PARAM_STATIC_NICK));
578 : 103 : }
579 : :
580 : : static void
581 : 46146 : g_dbus_message_init (GDBusMessage *message)
582 : : {
583 : : /* Any D-Bus implementation is supposed to handle both Big and
584 : : * Little Endian encodings and the Endianness is part of the D-Bus
585 : : * message - we prefer to use Big Endian (since it's Network Byte
586 : : * Order and just easier to read for humans) but if the machine is
587 : : * Little Endian we use that for performance reasons.
588 : : */
589 : : #if G_BYTE_ORDER == G_LITTLE_ENDIAN
590 : 46146 : message->byte_order = G_DBUS_MESSAGE_BYTE_ORDER_LITTLE_ENDIAN;
591 : : #else
592 : : /* this could also be G_PDP_ENDIAN */
593 : : message->byte_order = G_DBUS_MESSAGE_BYTE_ORDER_BIG_ENDIAN;
594 : : #endif
595 : 46146 : message->headers = g_hash_table_new_full (g_direct_hash,
596 : : g_direct_equal,
597 : : NULL,
598 : : (GDestroyNotify) g_variant_unref);
599 : 46146 : }
600 : :
601 : : /**
602 : : * g_dbus_message_new:
603 : : *
604 : : * Creates a new empty D-Bus message.
605 : : *
606 : : * Returns: (transfer full): The D-Bus message
607 : : * Since: 2.26
608 : : */
609 : : GDBusMessage *
610 : 46145 : g_dbus_message_new (void)
611 : : {
612 : 46145 : return g_object_new (G_TYPE_DBUS_MESSAGE, NULL);
613 : : }
614 : :
615 : : /**
616 : : * g_dbus_message_new_method_call:
617 : : * @name: (nullable): a valid D-Bus name, or `NULL` if no destination is needed
618 : : * @path: a valid object path
619 : : * @interface_: (nullable): a valid D-Bus interface name, or `NULL` if none is
620 : : * needed
621 : : * @method: a valid method name
622 : : *
623 : : * Creates a new D-Bus message for a method call.
624 : : *
625 : : * Returns: (transfer full): The D-Bus message
626 : : * Since: 2.26
627 : : */
628 : : GDBusMessage *
629 : 13469 : g_dbus_message_new_method_call (const gchar *name,
630 : : const gchar *path,
631 : : const gchar *interface_,
632 : : const gchar *method)
633 : : {
634 : : GDBusMessage *message;
635 : :
636 : 13469 : g_return_val_if_fail (name == NULL || g_dbus_is_name (name), NULL);
637 : 13469 : g_return_val_if_fail (g_variant_is_object_path (path), NULL);
638 : 13469 : g_return_val_if_fail (g_dbus_is_member_name (method), NULL);
639 : 13469 : g_return_val_if_fail (interface_ == NULL || g_dbus_is_interface_name (interface_), NULL);
640 : :
641 : 13469 : message = g_dbus_message_new ();
642 : 13469 : message->type = G_DBUS_MESSAGE_TYPE_METHOD_CALL;
643 : :
644 : 13469 : if (name != NULL)
645 : 13219 : g_dbus_message_set_destination (message, name);
646 : 13469 : g_dbus_message_set_path (message, path);
647 : 13469 : g_dbus_message_set_member (message, method);
648 : 13469 : if (interface_ != NULL)
649 : 13467 : g_dbus_message_set_interface (message, interface_);
650 : :
651 : 13469 : return message;
652 : : }
653 : :
654 : : /**
655 : : * g_dbus_message_new_signal:
656 : : * @path: a valid object path
657 : : * @interface_: a valid D-Bus interface name
658 : : * @signal: a valid signal name
659 : : *
660 : : * Creates a new D-Bus message for a signal emission.
661 : : *
662 : : * Returns: (transfer full): The D-Bus message
663 : : * Since: 2.26
664 : : */
665 : : GDBusMessage *
666 : 949 : g_dbus_message_new_signal (const gchar *path,
667 : : const gchar *interface_,
668 : : const gchar *signal)
669 : : {
670 : : GDBusMessage *message;
671 : :
672 : 949 : g_return_val_if_fail (g_variant_is_object_path (path), NULL);
673 : 949 : g_return_val_if_fail (g_dbus_is_member_name (signal), NULL);
674 : 949 : g_return_val_if_fail (g_dbus_is_interface_name (interface_), NULL);
675 : :
676 : 949 : message = g_dbus_message_new ();
677 : 949 : message->type = G_DBUS_MESSAGE_TYPE_SIGNAL;
678 : 949 : message->flags = G_DBUS_MESSAGE_FLAGS_NO_REPLY_EXPECTED;
679 : :
680 : 949 : g_dbus_message_set_path (message, path);
681 : 949 : g_dbus_message_set_member (message, signal);
682 : 949 : g_dbus_message_set_interface (message, interface_);
683 : :
684 : 949 : return message;
685 : : }
686 : :
687 : :
688 : : /**
689 : : * g_dbus_message_new_method_reply:
690 : : * @method_call_message: a message of type [enum@Gio.DBusMessageType.METHOD_CALL]
691 : : * to create a reply message to
692 : : *
693 : : * Creates a new D-Bus message that is a reply to @method_call_message.
694 : : *
695 : : * Returns: (transfer full): The D-Bus message
696 : : * Since: 2.26
697 : : */
698 : : GDBusMessage *
699 : 964 : g_dbus_message_new_method_reply (GDBusMessage *method_call_message)
700 : : {
701 : : GDBusMessage *message;
702 : : const gchar *sender;
703 : :
704 : 964 : g_return_val_if_fail (G_IS_DBUS_MESSAGE (method_call_message), NULL);
705 : 964 : g_return_val_if_fail (g_dbus_message_get_message_type (method_call_message) == G_DBUS_MESSAGE_TYPE_METHOD_CALL, NULL);
706 : 964 : g_return_val_if_fail (g_dbus_message_get_serial (method_call_message) != 0, NULL);
707 : :
708 : 964 : message = g_dbus_message_new ();
709 : 964 : message->type = G_DBUS_MESSAGE_TYPE_METHOD_RETURN;
710 : 964 : message->flags = G_DBUS_MESSAGE_FLAGS_NO_REPLY_EXPECTED;
711 : : /* reply with same endianness */
712 : 964 : message->byte_order = method_call_message->byte_order;
713 : :
714 : 964 : g_dbus_message_set_reply_serial (message, g_dbus_message_get_serial (method_call_message));
715 : 964 : sender = g_dbus_message_get_sender (method_call_message);
716 : 964 : if (sender != NULL)
717 : 643 : g_dbus_message_set_destination (message, sender);
718 : :
719 : 964 : return message;
720 : : }
721 : :
722 : : /**
723 : : * g_dbus_message_new_method_error: (constructor)
724 : : * @method_call_message: a message of type [enum@Gio.DBusMessageType.METHOD_CALL]
725 : : * to create a reply message to
726 : : * @error_name: a valid D-Bus error name
727 : : * @error_message_format: the D-Bus error message in a `printf()` format
728 : : * @...: arguments for @error_message_format
729 : : *
730 : : * Creates a new D-Bus message that is an error reply to @method_call_message.
731 : : *
732 : : * Returns: (transfer full): The D-Bus message
733 : : * Since: 2.26
734 : : */
735 : : GDBusMessage *
736 : 1587 : g_dbus_message_new_method_error (GDBusMessage *method_call_message,
737 : : const gchar *error_name,
738 : : const gchar *error_message_format,
739 : : ...)
740 : : {
741 : : GDBusMessage *ret;
742 : : va_list var_args;
743 : :
744 : 1587 : va_start (var_args, error_message_format);
745 : 1587 : ret = g_dbus_message_new_method_error_valist (method_call_message,
746 : : error_name,
747 : : error_message_format,
748 : : var_args);
749 : 1587 : va_end (var_args);
750 : :
751 : 1587 : return ret;
752 : : }
753 : :
754 : : /**
755 : : * g_dbus_message_new_method_error_literal:
756 : : * @method_call_message: a message of type [enum@Gio.DBusMessageType.METHOD_CALL]
757 : : * to create a reply message to
758 : : * @error_name: a valid D-Bus error name
759 : : * @error_message: the D-Bus error message
760 : : *
761 : : * Creates a new D-Bus message that is an error reply to @method_call_message.
762 : : *
763 : : * Returns: (transfer full): The D-Bus message
764 : : * Since: 2.26
765 : : */
766 : : GDBusMessage *
767 : 1622 : g_dbus_message_new_method_error_literal (GDBusMessage *method_call_message,
768 : : const gchar *error_name,
769 : : const gchar *error_message)
770 : : {
771 : : GDBusMessage *message;
772 : : const gchar *sender;
773 : :
774 : 1622 : g_return_val_if_fail (G_IS_DBUS_MESSAGE (method_call_message), NULL);
775 : 1622 : g_return_val_if_fail (g_dbus_message_get_message_type (method_call_message) == G_DBUS_MESSAGE_TYPE_METHOD_CALL, NULL);
776 : 1622 : g_return_val_if_fail (g_dbus_message_get_serial (method_call_message) != 0, NULL);
777 : 1622 : g_return_val_if_fail (g_dbus_is_name (error_name), NULL);
778 : 1622 : g_return_val_if_fail (error_message != NULL, NULL);
779 : :
780 : 1622 : message = g_dbus_message_new ();
781 : 1622 : message->type = G_DBUS_MESSAGE_TYPE_ERROR;
782 : 1622 : message->flags = G_DBUS_MESSAGE_FLAGS_NO_REPLY_EXPECTED;
783 : : /* reply with same endianness */
784 : 1622 : message->byte_order = method_call_message->byte_order;
785 : :
786 : 1622 : g_dbus_message_set_reply_serial (message, g_dbus_message_get_serial (method_call_message));
787 : 1622 : g_dbus_message_set_error_name (message, error_name);
788 : 1622 : g_dbus_message_set_body (message, g_variant_new ("(s)", error_message));
789 : :
790 : 1622 : sender = g_dbus_message_get_sender (method_call_message);
791 : 1622 : if (sender != NULL)
792 : 1619 : g_dbus_message_set_destination (message, sender);
793 : :
794 : 1622 : return message;
795 : : }
796 : :
797 : : /**
798 : : * g_dbus_message_new_method_error_valist:
799 : : * @method_call_message: a message of type [enum@Gio.DBusMessageType.METHOD_CALL]
800 : : * to create a reply message to
801 : : * @error_name: a valid D-Bus error name
802 : : * @error_message_format: the D-Bus error message in a `printf()` format
803 : : * @var_args: arguments for @error_message_format
804 : : *
805 : : * Like [ctor@Gio.DBusMessage.new_method_error] but intended for language
806 : : * bindings.
807 : : *
808 : : * Returns: (transfer full): The D-Bus message
809 : : * Since: 2.26
810 : : */
811 : : G_GNUC_PRINTF(3, 0)
812 : : GDBusMessage *
813 : 1587 : g_dbus_message_new_method_error_valist (GDBusMessage *method_call_message,
814 : : const gchar *error_name,
815 : : const gchar *error_message_format,
816 : : va_list var_args)
817 : : {
818 : : GDBusMessage *ret;
819 : : gchar *error_message;
820 : 1587 : error_message = g_strdup_vprintf (error_message_format, var_args);
821 : 1587 : ret = g_dbus_message_new_method_error_literal (method_call_message,
822 : : error_name,
823 : : error_message);
824 : 1587 : g_free (error_message);
825 : 1587 : return ret;
826 : : }
827 : :
828 : : /* ---------------------------------------------------------------------------------------------------- */
829 : :
830 : : /**
831 : : * g_dbus_message_get_byte_order:
832 : : * @message: a D-Bus message
833 : : *
834 : : * Gets the byte order of @message.
835 : : *
836 : : * Returns: The byte order
837 : : */
838 : : GDBusMessageByteOrder
839 : 2 : g_dbus_message_get_byte_order (GDBusMessage *message)
840 : : {
841 : 2 : g_return_val_if_fail (G_IS_DBUS_MESSAGE (message), (GDBusMessageByteOrder) 0);
842 : 2 : return message->byte_order;
843 : : }
844 : :
845 : : /**
846 : : * g_dbus_message_set_byte_order:
847 : : * @message: a D-Bus message
848 : : * @byte_order: the byte order
849 : : *
850 : : * Sets the byte order of @message.
851 : : */
852 : : void
853 : 26 : g_dbus_message_set_byte_order (GDBusMessage *message,
854 : : GDBusMessageByteOrder byte_order)
855 : : {
856 : 26 : g_return_if_fail (G_IS_DBUS_MESSAGE (message));
857 : :
858 : 26 : if (message->locked)
859 : : {
860 : 1 : g_warning ("%s: Attempted to modify a locked message", G_STRFUNC);
861 : 1 : return;
862 : : }
863 : :
864 : 25 : message->byte_order = byte_order;
865 : : }
866 : :
867 : : /* ---------------------------------------------------------------------------------------------------- */
868 : :
869 : : /* TODO: need GI annotations to specify that any guchar value goes for the type */
870 : :
871 : : /**
872 : : * g_dbus_message_get_message_type:
873 : : * @message: a D-Bus message
874 : : *
875 : : * Gets the type of @message.
876 : : *
877 : : * Returns: A 8-bit unsigned integer (typically a value from the
878 : : * [enum@Gio.DBusMessageType] enumeration)
879 : : * Since: 2.26
880 : : */
881 : : GDBusMessageType
882 : 54942 : g_dbus_message_get_message_type (GDBusMessage *message)
883 : : {
884 : 54942 : g_return_val_if_fail (G_IS_DBUS_MESSAGE (message), G_DBUS_MESSAGE_TYPE_INVALID);
885 : 54942 : return message->type;
886 : : }
887 : :
888 : : /**
889 : : * g_dbus_message_set_message_type:
890 : : * @message: a D-Bus message
891 : : * @type: a 8-bit unsigned integer (typically a value from the
892 : : * [enum@Gio.DBusMessageType] enumeration)
893 : : *
894 : : * Sets @message to be of @type.
895 : : *
896 : : * Since: 2.26
897 : : */
898 : : void
899 : 17 : g_dbus_message_set_message_type (GDBusMessage *message,
900 : : GDBusMessageType type)
901 : : {
902 : 17 : g_return_if_fail (G_IS_DBUS_MESSAGE (message));
903 : 17 : g_return_if_fail ((guint) type < 256);
904 : :
905 : 17 : if (message->locked)
906 : : {
907 : 1 : g_warning ("%s: Attempted to modify a locked message", G_STRFUNC);
908 : 1 : return;
909 : : }
910 : :
911 : 16 : message->type = type;
912 : : }
913 : :
914 : : /* ---------------------------------------------------------------------------------------------------- */
915 : :
916 : : /* TODO: need GI annotations to specify that any guchar value goes for flags */
917 : :
918 : : /**
919 : : * g_dbus_message_get_flags:
920 : : * @message: a D-Bus message
921 : : *
922 : : * Gets the flags for @message.
923 : : *
924 : : * Returns: Flags that are set (typically values from the
925 : : * [flags@Gio.DBusMessageFlags] enumeration bitwise ORed together)
926 : : * Since: 2.26
927 : : */
928 : : GDBusMessageFlags
929 : 5970 : g_dbus_message_get_flags (GDBusMessage *message)
930 : : {
931 : 5970 : g_return_val_if_fail (G_IS_DBUS_MESSAGE (message), G_DBUS_MESSAGE_FLAGS_NONE);
932 : 5970 : return message->flags;
933 : : }
934 : :
935 : : /**
936 : : * g_dbus_message_set_flags:
937 : : * @message: a D-Bus message
938 : : * @flags: flags for @message that are set (typically values from the
939 : : * [flags@Gio.DBusMessageFlags] enumeration bitwise ORed together)
940 : : *
941 : : * Sets the flags to set on @message.
942 : : *
943 : : * Since: 2.26
944 : : */
945 : : void
946 : 5188 : g_dbus_message_set_flags (GDBusMessage *message,
947 : : GDBusMessageFlags flags)
948 : : {
949 : 5188 : g_return_if_fail (G_IS_DBUS_MESSAGE (message));
950 : 5188 : g_return_if_fail ((guint) flags < 256);
951 : :
952 : 5188 : if (message->locked)
953 : : {
954 : 1 : g_warning ("%s: Attempted to modify a locked message", G_STRFUNC);
955 : 1 : return;
956 : : }
957 : :
958 : 5187 : message->flags = flags;
959 : : }
960 : :
961 : : /* ---------------------------------------------------------------------------------------------------- */
962 : :
963 : : /**
964 : : * g_dbus_message_get_serial:
965 : : * @message: a D-Bus message
966 : : *
967 : : * Gets the serial for @message.
968 : : *
969 : : * Returns: The serial number, which should not be zero
970 : : * Since: 2.26
971 : : */
972 : : guint32
973 : 5175 : g_dbus_message_get_serial (GDBusMessage *message)
974 : : {
975 : 5175 : g_return_val_if_fail (G_IS_DBUS_MESSAGE (message), 0);
976 : 5175 : return message->serial;
977 : : }
978 : :
979 : : /**
980 : : * g_dbus_message_set_serial:
981 : : * @message: a D-Bus message
982 : : * @serial: a serial number, which must not be zero
983 : : *
984 : : * Sets the serial for @message.
985 : : *
986 : : * The [D-Bus specification](https://dbus.freedesktop.org/doc/dbus-specification.html#message-protocol-messages)
987 : : * does not allow the @serial to be zero.
988 : : *
989 : : * Since: 2.26
990 : : */
991 : : void
992 : 16998 : g_dbus_message_set_serial (GDBusMessage *message,
993 : : guint32 serial)
994 : : {
995 : 16998 : g_return_if_fail (G_IS_DBUS_MESSAGE (message));
996 : :
997 : : /* As per https://dbus.freedesktop.org/doc/dbus-specification.html#message-protocol-messages,
998 : : * this must not be zero. */
999 : 16998 : g_return_if_fail (serial != 0);
1000 : :
1001 : 16998 : if (message->locked)
1002 : : {
1003 : 1 : g_warning ("%s: Attempted to modify a locked message", G_STRFUNC);
1004 : 1 : return;
1005 : : }
1006 : :
1007 : 16997 : message->serial = serial;
1008 : : }
1009 : :
1010 : : /* ---------------------------------------------------------------------------------------------------- */
1011 : :
1012 : : /* TODO: need GI annotations to specify that any guchar value goes for header_field */
1013 : :
1014 : : /**
1015 : : * g_dbus_message_get_header:
1016 : : * @message: a D-Bus message
1017 : : * @header_field: a 8-bit unsigned integer (typically a value from the
1018 : : * [enum@Gio.DBusMessageHeaderField] enumeration)
1019 : : *
1020 : : * Gets a header field on @message.
1021 : : *
1022 : : * The caller is responsible for checking the type of the returned
1023 : : * [type@GLib.Variant] matches what is expected.
1024 : : *
1025 : : * Returns: (transfer none) (nullable): A [type@GLib.Variant] with the value, or
1026 : : * `NULL` if the header was not found
1027 : : * Since: 2.26
1028 : : */
1029 : : GVariant *
1030 : 139991 : g_dbus_message_get_header (GDBusMessage *message,
1031 : : GDBusMessageHeaderField header_field)
1032 : : {
1033 : 139991 : g_return_val_if_fail (G_IS_DBUS_MESSAGE (message), NULL);
1034 : 139991 : g_return_val_if_fail ((guint) header_field < 256, NULL);
1035 : 139991 : return g_hash_table_lookup (message->headers, GUINT_TO_POINTER (header_field));
1036 : : }
1037 : :
1038 : : /**
1039 : : * g_dbus_message_set_header:
1040 : : * @message: a D-Bus message
1041 : : * @header_field: a 8-bit unsigned integer (typically a value from the
1042 : : * [enum@Gio.DBusMessageHeaderField enumeration)
1043 : : * @value: (nullable): a [type@GLib.Variant] to set the header field, or `NULL`
1044 : : * to clear the header field.
1045 : : *
1046 : : * Sets a header field on @message.
1047 : : *
1048 : : * If @value is floating, @message assumes ownership of @value.
1049 : : *
1050 : : * Since: 2.26
1051 : : */
1052 : : void
1053 : 216633 : g_dbus_message_set_header (GDBusMessage *message,
1054 : : GDBusMessageHeaderField header_field,
1055 : : GVariant *value)
1056 : : {
1057 : 216633 : g_return_if_fail (G_IS_DBUS_MESSAGE (message));
1058 : 216633 : g_return_if_fail ((guint) header_field < 256);
1059 : :
1060 : 216633 : if (message->locked)
1061 : : {
1062 : 1 : g_warning ("%s: Attempted to modify a locked message", G_STRFUNC);
1063 : 1 : return;
1064 : : }
1065 : :
1066 : 216632 : if (value == NULL)
1067 : : {
1068 : 9 : g_hash_table_remove (message->headers, GUINT_TO_POINTER (header_field));
1069 : : }
1070 : : else
1071 : : {
1072 : 216623 : g_hash_table_insert (message->headers, GUINT_TO_POINTER (header_field), g_variant_ref_sink (value));
1073 : : }
1074 : : }
1075 : :
1076 : : /**
1077 : : * g_dbus_message_get_header_fields:
1078 : : * @message: a D-Bus message
1079 : : *
1080 : : * Gets an array of all header fields on @message that are set.
1081 : : *
1082 : : * Each element in the array is an `unsigned char`.
1083 : : *
1084 : : * Returns: (array zero-terminated=1) (transfer container): An array of header
1085 : : * fields terminated by [enum@Gio.DBusMessageHeaderField.INVALID]
1086 : : * Since: 2.26
1087 : : */
1088 : : guchar *
1089 : 2 : g_dbus_message_get_header_fields (GDBusMessage *message)
1090 : : {
1091 : : GPtrArray *keys;
1092 : : GArray *array;
1093 : :
1094 : 2 : g_return_val_if_fail (G_IS_DBUS_MESSAGE (message), NULL);
1095 : :
1096 : 2 : keys = g_hash_table_get_keys_as_ptr_array (message->headers);
1097 : 2 : array = g_array_sized_new (FALSE, FALSE, sizeof (guchar), keys->len + 1);
1098 : :
1099 : 10 : for (guint i = 0; i < keys->len; ++i)
1100 : : {
1101 : 8 : guchar val = GPOINTER_TO_UINT (g_ptr_array_index (keys, i));
1102 : 8 : g_array_append_val (array, val);
1103 : : }
1104 : :
1105 : 2 : g_assert (array->len == keys->len);
1106 : 2 : g_clear_pointer (&keys, g_ptr_array_unref);
1107 : :
1108 : 2 : guchar invalid_field = G_DBUS_MESSAGE_HEADER_FIELD_INVALID;
1109 : 2 : g_array_append_val (array, invalid_field);
1110 : :
1111 : 2 : return (guchar *) g_array_free (array, FALSE);
1112 : : }
1113 : :
1114 : : /* ---------------------------------------------------------------------------------------------------- */
1115 : :
1116 : : /**
1117 : : * g_dbus_message_get_body:
1118 : : * @message: a D-Bus message
1119 : : *
1120 : : * Gets the body of a message.
1121 : : *
1122 : : * Returns: (nullable) (transfer none): A [type@GLib.Variant], or `NULL` if the
1123 : : * body is empty
1124 : : * Since: 2.26
1125 : : */
1126 : : GVariant *
1127 : 24626 : g_dbus_message_get_body (GDBusMessage *message)
1128 : : {
1129 : 24626 : g_return_val_if_fail (G_IS_DBUS_MESSAGE (message), NULL);
1130 : 24626 : return message->body;
1131 : : }
1132 : :
1133 : : /**
1134 : : * g_dbus_message_set_body:
1135 : : * @message: a D-Bus message
1136 : : * @body: a [type@GLib.Variant] containing a tuple, or `NULL` if no body is
1137 : : * needed
1138 : : *
1139 : : * Sets the body of @message.
1140 : : *
1141 : : * As a side-effect the [enum@Gio.DBusMessageHeaderField.SIGNATURE] header field
1142 : : * is set to the type string of @body (or cleared if @body is `NULL`).
1143 : : *
1144 : : * If @body is floating, @message assumes ownership of @body.
1145 : : *
1146 : : * Since: 2.26
1147 : : */
1148 : : void
1149 : 11749 : g_dbus_message_set_body (GDBusMessage *message,
1150 : : GVariant *body)
1151 : : {
1152 : 11749 : g_return_if_fail (G_IS_DBUS_MESSAGE (message));
1153 : 11749 : g_return_if_fail ((body == NULL) || g_variant_is_of_type (body, G_VARIANT_TYPE_TUPLE));
1154 : :
1155 : 11749 : if (message->locked)
1156 : : {
1157 : 1 : g_warning ("%s: Attempted to modify a locked message", G_STRFUNC);
1158 : 1 : return;
1159 : : }
1160 : :
1161 : 11748 : if (message->body != NULL)
1162 : 2 : g_variant_unref (message->body);
1163 : :
1164 : 11748 : g_clear_pointer (&message->arg0_cache, g_variant_unref);
1165 : :
1166 : 11748 : if (body == NULL)
1167 : : {
1168 : 1 : message->body = NULL;
1169 : 1 : g_dbus_message_set_signature (message, NULL);
1170 : : }
1171 : : else
1172 : : {
1173 : : const gchar *type_string;
1174 : : gsize type_string_len;
1175 : : gchar *signature;
1176 : :
1177 : 11747 : message->body = g_variant_ref_sink (body);
1178 : :
1179 : 23494 : if (g_variant_is_of_type (message->body, G_VARIANT_TYPE_TUPLE) &&
1180 : 11747 : g_variant_n_children (message->body) > 0)
1181 : 11570 : message->arg0_cache = g_variant_get_child_value (message->body, 0);
1182 : :
1183 : 11747 : type_string = g_variant_get_type_string (body);
1184 : 11747 : type_string_len = strlen (type_string);
1185 : 11747 : g_assert (type_string_len >= 2);
1186 : 11747 : signature = g_strndup (type_string + 1, type_string_len - 2);
1187 : 11747 : g_dbus_message_set_signature (message, signature);
1188 : 11747 : g_free (signature);
1189 : : }
1190 : : }
1191 : :
1192 : : /* ---------------------------------------------------------------------------------------------------- */
1193 : :
1194 : : #ifdef G_OS_UNIX
1195 : : /**
1196 : : * g_dbus_message_get_unix_fd_list:
1197 : : * @message: a D-Bus message
1198 : : *
1199 : : * Gets the UNIX file descriptors associated with @message, if any.
1200 : : *
1201 : : * This method is only available on UNIX.
1202 : : *
1203 : : * The file descriptors normally correspond to `G_VARIANT_TYPE_HANDLE`
1204 : : * values in the body of the message. For example, if
1205 : : * [method@GLib.Variant.get_handle] returns 5, that is intended to be a
1206 : : * reference to the file descriptor that can be accessed by
1207 : : * `g_unix_fd_list_get (list, 5, ...)`.
1208 : : *
1209 : : * Returns: (nullable) (transfer none): A [class@Gio.UnixFDList] or `NULL` if no
1210 : : * file descriptors are associated
1211 : : * Since: 2.26
1212 : : */
1213 : : GUnixFDList *
1214 : 18152 : g_dbus_message_get_unix_fd_list (GDBusMessage *message)
1215 : : {
1216 : 18152 : g_return_val_if_fail (G_IS_DBUS_MESSAGE (message), NULL);
1217 : 18152 : return message->fd_list;
1218 : : }
1219 : :
1220 : : /**
1221 : : * g_dbus_message_set_unix_fd_list:
1222 : : * @message: a D-Bus message
1223 : : * @fd_list: (nullable): A [class@Gio.UnixFDList], or `NULL` to clear
1224 : : *
1225 : : * Sets the UNIX file descriptors associated with @message.
1226 : : *
1227 : : * As a side-effect the [enum@Gio.DBusMessageHeaderField.NUM_UNIX_FDS] header
1228 : : * field is set to the number of fds in @fd_list (or cleared if
1229 : : * @fd_list is `NULL`).
1230 : : *
1231 : : * This method is only available on UNIX.
1232 : : *
1233 : : * When designing D-Bus APIs that are intended to be interoperable,
1234 : : * please note that non-GDBus implementations of D-Bus can usually only
1235 : : * access file descriptors if they are referenced by a value of type
1236 : : * `G_VARIANT_TYPE_HANDLE` in the body of the message.
1237 : : *
1238 : : * Since: 2.26
1239 : : */
1240 : : void
1241 : 47 : g_dbus_message_set_unix_fd_list (GDBusMessage *message,
1242 : : GUnixFDList *fd_list)
1243 : : {
1244 : 47 : g_return_if_fail (G_IS_DBUS_MESSAGE (message));
1245 : 47 : g_return_if_fail (fd_list == NULL || G_IS_UNIX_FD_LIST (fd_list));
1246 : :
1247 : 47 : if (message->locked)
1248 : : {
1249 : 0 : g_warning ("%s: Attempted to modify a locked message", G_STRFUNC);
1250 : 0 : return;
1251 : : }
1252 : :
1253 : 47 : if (message->fd_list != NULL)
1254 : 0 : g_object_unref (message->fd_list);
1255 : 47 : if (fd_list != NULL)
1256 : : {
1257 : 47 : message->fd_list = g_object_ref (fd_list);
1258 : 47 : g_dbus_message_set_num_unix_fds (message, g_unix_fd_list_get_length (fd_list));
1259 : : }
1260 : : else
1261 : : {
1262 : 0 : message->fd_list = NULL;
1263 : 0 : g_dbus_message_set_num_unix_fds (message, 0);
1264 : : }
1265 : : }
1266 : : #endif
1267 : :
1268 : : /* ---------------------------------------------------------------------------------------------------- */
1269 : :
1270 : : static guint
1271 : 54715 : get_type_fixed_size (const GVariantType *type)
1272 : : {
1273 : : /* NB: we do not treat 'b' as fixed-size here because GVariant and
1274 : : * D-Bus disagree about the size.
1275 : : */
1276 : 54715 : switch (*g_variant_type_peek_string (type))
1277 : : {
1278 : 375 : case 'y':
1279 : 375 : return 1;
1280 : 68 : case 'n': case 'q':
1281 : 68 : return 2;
1282 : 902 : case 'i': case 'u': case 'h':
1283 : 902 : return 4;
1284 : 106 : case 'x': case 't': case 'd':
1285 : 106 : return 8;
1286 : 53264 : default:
1287 : 53264 : return 0;
1288 : : }
1289 : : }
1290 : :
1291 : : static const char *
1292 : 25 : message_type_to_string (GDBusMessageType message_type)
1293 : : {
1294 : 25 : switch (message_type)
1295 : : {
1296 : 0 : case G_DBUS_MESSAGE_TYPE_INVALID:
1297 : 0 : return "INVALID";
1298 : 4 : case G_DBUS_MESSAGE_TYPE_METHOD_CALL:
1299 : 4 : return "METHOD_CALL";
1300 : 1 : case G_DBUS_MESSAGE_TYPE_METHOD_RETURN:
1301 : 1 : return "METHOD_RETURN";
1302 : 2 : case G_DBUS_MESSAGE_TYPE_ERROR:
1303 : 2 : return "ERROR";
1304 : 18 : case G_DBUS_MESSAGE_TYPE_SIGNAL:
1305 : 18 : return "SIGNAL";
1306 : 0 : default:
1307 : 0 : return "unknown-type";
1308 : : }
1309 : : }
1310 : :
1311 : : static const char *
1312 : 19 : message_header_field_to_string (GDBusMessageHeaderField field)
1313 : : {
1314 : 19 : switch (field)
1315 : : {
1316 : 0 : case G_DBUS_MESSAGE_HEADER_FIELD_INVALID:
1317 : 0 : return "INVALID";
1318 : 3 : case G_DBUS_MESSAGE_HEADER_FIELD_PATH:
1319 : 3 : return "PATH";
1320 : 2 : case G_DBUS_MESSAGE_HEADER_FIELD_INTERFACE:
1321 : 2 : return "INTERFACE";
1322 : 5 : case G_DBUS_MESSAGE_HEADER_FIELD_MEMBER:
1323 : 5 : return "MEMBER";
1324 : 2 : case G_DBUS_MESSAGE_HEADER_FIELD_ERROR_NAME:
1325 : 2 : return "ERROR_NAME";
1326 : 3 : case G_DBUS_MESSAGE_HEADER_FIELD_REPLY_SERIAL:
1327 : 3 : return "REPLY_SERIAL";
1328 : 1 : case G_DBUS_MESSAGE_HEADER_FIELD_DESTINATION:
1329 : 1 : return "DESTINATION";
1330 : 1 : case G_DBUS_MESSAGE_HEADER_FIELD_SENDER:
1331 : 1 : return "SENDER";
1332 : 1 : case G_DBUS_MESSAGE_HEADER_FIELD_SIGNATURE:
1333 : 1 : return "SIGNATURE";
1334 : 1 : case G_DBUS_MESSAGE_HEADER_FIELD_NUM_UNIX_FDS:
1335 : 1 : return "NUM_UNIX_FDS";
1336 : 0 : default:
1337 : 0 : return "unknown-field";
1338 : : }
1339 : : }
1340 : :
1341 : : static gboolean
1342 : 216399 : validate_header (GDBusMessage *message,
1343 : : GDBusMessageHeaderField field,
1344 : : GVariant *header_value,
1345 : : const GVariantType *expected_type,
1346 : : GError **error)
1347 : : {
1348 : 216399 : g_assert (header_value != NULL);
1349 : :
1350 : 216399 : if (!g_variant_is_of_type (header_value, expected_type))
1351 : : {
1352 : 10 : char *expected_type_string = g_variant_type_dup_string (expected_type);
1353 : 10 : g_set_error (error,
1354 : : G_IO_ERROR,
1355 : : G_IO_ERROR_INVALID_ARGUMENT,
1356 : : _("%s message: %s header field is invalid; expected a value of type ‘%s’"),
1357 : : message_type_to_string (message->type),
1358 : : message_header_field_to_string (field),
1359 : : expected_type_string);
1360 : 10 : g_free (expected_type_string);
1361 : 10 : return FALSE;
1362 : : }
1363 : :
1364 : 216389 : return TRUE;
1365 : : }
1366 : :
1367 : : static gboolean
1368 : 93919 : require_header (GDBusMessage *message,
1369 : : GDBusMessageHeaderField field,
1370 : : GError **error)
1371 : : {
1372 : 93919 : GVariant *header_value = g_dbus_message_get_header (message, field);
1373 : :
1374 : 93919 : if (header_value == NULL)
1375 : : {
1376 : 9 : g_set_error (error,
1377 : : G_IO_ERROR,
1378 : : G_IO_ERROR_INVALID_ARGUMENT,
1379 : : _("%s message: %s header field is missing or invalid"),
1380 : : message_type_to_string (message->type),
1381 : : message_header_field_to_string (field));
1382 : 9 : return FALSE;
1383 : : }
1384 : :
1385 : 93910 : return TRUE;
1386 : : }
1387 : :
1388 : : /* Implement the validation rules given in
1389 : : * https://dbus.freedesktop.org/doc/dbus-specification.html#message-protocol-header-fields */
1390 : : static gboolean
1391 : 46017 : validate_headers (GDBusMessage *message,
1392 : : GError **error)
1393 : : {
1394 : : gboolean ret;
1395 : : GHashTableIter headers_iter;
1396 : : gpointer key;
1397 : : GVariant *header_value;
1398 : :
1399 : 46017 : g_return_val_if_fail (G_IS_DBUS_MESSAGE (message), FALSE);
1400 : 46017 : g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
1401 : :
1402 : 46017 : ret = FALSE;
1403 : :
1404 : : /* Validate the types of all known headers. */
1405 : 46017 : g_hash_table_iter_init (&headers_iter, message->headers);
1406 : 262402 : while (g_hash_table_iter_next (&headers_iter, &key, (gpointer) &header_value))
1407 : : {
1408 : 216401 : GDBusMessageHeaderField field_type = GPOINTER_TO_INT (key);
1409 : :
1410 : 216401 : switch (field_type)
1411 : : {
1412 : 1 : case G_DBUS_MESSAGE_HEADER_FIELD_INVALID:
1413 : : /* The invalid header must be rejected as per
1414 : : * https://dbus.freedesktop.org/doc/dbus-specification.html#message-protocol-header-fields */
1415 : 1 : g_set_error (error,
1416 : : G_IO_ERROR,
1417 : : G_IO_ERROR_INVALID_ARGUMENT,
1418 : : _("%s message: INVALID header field supplied"),
1419 : : message_type_to_string (message->type));
1420 : 1 : goto out;
1421 : 30422 : case G_DBUS_MESSAGE_HEADER_FIELD_PATH:
1422 : 30422 : if (!validate_header (message, field_type, header_value, G_VARIANT_TYPE_OBJECT_PATH, error))
1423 : 1 : goto out;
1424 : 30421 : if (g_strcmp0 (g_variant_get_string (header_value, NULL), DBUS_PATH_LOCAL) == 0)
1425 : : {
1426 : 1 : g_set_error (error,
1427 : : G_IO_ERROR,
1428 : : G_IO_ERROR_INVALID_ARGUMENT,
1429 : : /* Translators: The first placeholder is a D-Bus message type,
1430 : : * the second is the name of a header field and the third is
1431 : : * a value that is reserved for the given field. */
1432 : : _("%s message: %s header field is using the reserved value %s"),
1433 : : message_type_to_string (message->type),
1434 : : "PATH",
1435 : : DBUS_PATH_LOCAL);
1436 : 1 : goto out;
1437 : : }
1438 : 30420 : break;
1439 : 30366 : case G_DBUS_MESSAGE_HEADER_FIELD_INTERFACE:
1440 : 30366 : if (!validate_header (message, field_type, header_value, G_VARIANT_TYPE_STRING, error))
1441 : 1 : goto out;
1442 : 30365 : if (!g_dbus_is_interface_name (g_variant_get_string (header_value, NULL)))
1443 : : {
1444 : 1 : g_set_error (error,
1445 : : G_IO_ERROR,
1446 : : G_IO_ERROR_INVALID_ARGUMENT,
1447 : : _("%s message: INTERFACE header field does not contain a valid interface name"),
1448 : : message_type_to_string (message->type));
1449 : 1 : goto out;
1450 : : }
1451 : 30364 : if (g_strcmp0 (g_variant_get_string (header_value, NULL), DBUS_INTERFACE_LOCAL) == 0)
1452 : : {
1453 : 1 : g_set_error (error,
1454 : : G_IO_ERROR,
1455 : : G_IO_ERROR_INVALID_ARGUMENT,
1456 : : _("%s message: %s header field is using the reserved value %s"),
1457 : : message_type_to_string (message->type),
1458 : : "INTERFACE",
1459 : : DBUS_INTERFACE_LOCAL);
1460 : 1 : goto out;
1461 : : }
1462 : 30363 : break;
1463 : 30410 : case G_DBUS_MESSAGE_HEADER_FIELD_MEMBER:
1464 : 30410 : if (!validate_header (message, field_type, header_value, G_VARIANT_TYPE_STRING, error))
1465 : 2 : goto out;
1466 : 30408 : if (!g_dbus_is_member_name (g_variant_get_string (header_value, NULL)))
1467 : : {
1468 : 1 : g_set_error (error,
1469 : : G_IO_ERROR,
1470 : : G_IO_ERROR_INVALID_ARGUMENT,
1471 : : _("%s message: MEMBER header field does not contain a valid member name"),
1472 : : message_type_to_string (message->type));
1473 : 1 : goto out;
1474 : : }
1475 : 30407 : break;
1476 : 3452 : case G_DBUS_MESSAGE_HEADER_FIELD_ERROR_NAME:
1477 : 3452 : if (!validate_header (message, field_type, header_value, G_VARIANT_TYPE_STRING, error))
1478 : 1 : goto out;
1479 : 3451 : if (!g_dbus_is_error_name (g_variant_get_string (header_value, NULL)))
1480 : : {
1481 : 1 : g_set_error (error,
1482 : : G_IO_ERROR,
1483 : : G_IO_ERROR_INVALID_ARGUMENT,
1484 : : _("%s message: ERROR_NAME header field does not contain a valid error name"),
1485 : : message_type_to_string (message->type));
1486 : 1 : goto out;
1487 : : }
1488 : 3450 : break;
1489 : 15588 : case G_DBUS_MESSAGE_HEADER_FIELD_REPLY_SERIAL:
1490 : 15588 : if (!validate_header (message, field_type, header_value, G_VARIANT_TYPE_UINT32, error))
1491 : 1 : goto out;
1492 : 15587 : break;
1493 : 38289 : case G_DBUS_MESSAGE_HEADER_FIELD_DESTINATION:
1494 : 38289 : if (!validate_header (message, field_type, header_value, G_VARIANT_TYPE_STRING, error))
1495 : 1 : goto out;
1496 : 38288 : break;
1497 : 28217 : case G_DBUS_MESSAGE_HEADER_FIELD_SENDER:
1498 : 28217 : if (!validate_header (message, field_type, header_value, G_VARIANT_TYPE_STRING, error))
1499 : 1 : goto out;
1500 : 28216 : break;
1501 : 39606 : case G_DBUS_MESSAGE_HEADER_FIELD_SIGNATURE:
1502 : 39606 : if (!validate_header (message, field_type, header_value, G_VARIANT_TYPE_SIGNATURE, error))
1503 : 1 : goto out;
1504 : 39605 : break;
1505 : 49 : case G_DBUS_MESSAGE_HEADER_FIELD_NUM_UNIX_FDS:
1506 : 49 : if (!validate_header (message, field_type, header_value, G_VARIANT_TYPE_UINT32, error))
1507 : 1 : goto out;
1508 : 48 : break;
1509 : 1 : default:
1510 : : /* Ignore unknown fields as per
1511 : : * https://dbus.freedesktop.org/doc/dbus-specification.html#message-protocol-header-fields. */
1512 : 1 : continue;
1513 : : }
1514 : : }
1515 : :
1516 : : /* Check for message-type-specific required headers. */
1517 : 46001 : switch (message->type)
1518 : : {
1519 : 1 : case G_DBUS_MESSAGE_TYPE_INVALID:
1520 : 1 : g_set_error_literal (error,
1521 : : G_IO_ERROR,
1522 : : G_IO_ERROR_INVALID_ARGUMENT,
1523 : : _("type is INVALID"));
1524 : 1 : goto out;
1525 : :
1526 : 16343 : case G_DBUS_MESSAGE_TYPE_METHOD_CALL:
1527 : 32685 : if (!require_header (message, G_DBUS_MESSAGE_HEADER_FIELD_PATH, error) ||
1528 : 16342 : !require_header (message, G_DBUS_MESSAGE_HEADER_FIELD_MEMBER, error))
1529 : 3 : goto out;
1530 : 16340 : break;
1531 : :
1532 : 12138 : case G_DBUS_MESSAGE_TYPE_METHOD_RETURN:
1533 : 12138 : if (!require_header (message, G_DBUS_MESSAGE_HEADER_FIELD_REPLY_SERIAL, error))
1534 : 1 : goto out;
1535 : 12137 : break;
1536 : :
1537 : 3451 : case G_DBUS_MESSAGE_TYPE_ERROR:
1538 : 6901 : if (!require_header (message, G_DBUS_MESSAGE_HEADER_FIELD_ERROR_NAME, error) ||
1539 : 3450 : !require_header (message, G_DBUS_MESSAGE_HEADER_FIELD_REPLY_SERIAL, error))
1540 : 2 : goto out;
1541 : 3449 : break;
1542 : :
1543 : 14066 : case G_DBUS_MESSAGE_TYPE_SIGNAL:
1544 : 28131 : if (!require_header (message, G_DBUS_MESSAGE_HEADER_FIELD_PATH, error) ||
1545 : 28129 : !require_header (message, G_DBUS_MESSAGE_HEADER_FIELD_INTERFACE, error) ||
1546 : 14064 : !require_header (message, G_DBUS_MESSAGE_HEADER_FIELD_MEMBER, error))
1547 : 3 : goto out;
1548 : 14063 : break;
1549 : :
1550 : 2 : default:
1551 : : /* hitherto unknown type - nothing to check */
1552 : 2 : break;
1553 : : }
1554 : :
1555 : 45991 : ret = TRUE;
1556 : :
1557 : 46017 : out:
1558 : 46017 : g_assert (ret || (error == NULL || *error != NULL));
1559 : 46017 : return ret;
1560 : : }
1561 : :
1562 : : /* ---------------------------------------------------------------------------------------------------- */
1563 : :
1564 : : static gboolean
1565 : 367933 : ensure_input_padding (GMemoryBuffer *buf,
1566 : : gsize padding_size)
1567 : : {
1568 : : gsize offset;
1569 : : gsize wanted_offset;
1570 : :
1571 : 367933 : offset = buf->pos;
1572 : 367933 : wanted_offset = ((offset + padding_size - 1) / padding_size) * padding_size;
1573 : 367933 : buf->pos = wanted_offset;
1574 : 367933 : return TRUE;
1575 : : }
1576 : :
1577 : : static const gchar *
1578 : 311033 : read_string (GMemoryBuffer *mbuf,
1579 : : gsize len,
1580 : : GError **error)
1581 : : {
1582 : : gchar *str;
1583 : : const gchar *end_valid;
1584 : :
1585 : 311033 : if G_UNLIKELY (mbuf->pos + len >= mbuf->valid_len || mbuf->pos + len < mbuf->pos)
1586 : : {
1587 : 45 : mbuf->pos = mbuf->valid_len;
1588 : : /* G_GSIZE_FORMAT doesn't work with gettext, so we use %lu */
1589 : 45 : g_set_error (error,
1590 : : G_IO_ERROR,
1591 : : G_IO_ERROR_INVALID_ARGUMENT,
1592 : : g_dngettext (GETTEXT_PACKAGE,
1593 : : "Wanted to read %lu byte but only got %lu",
1594 : : "Wanted to read %lu bytes but only got %lu",
1595 : : (gulong)len),
1596 : : (gulong)len,
1597 : 45 : (gulong)(mbuf->valid_len - mbuf->pos));
1598 : 45 : return NULL;
1599 : : }
1600 : :
1601 : 310988 : if G_UNLIKELY (mbuf->data[mbuf->pos + len] != '\0')
1602 : : {
1603 : 0 : str = g_strndup (mbuf->data + mbuf->pos, len);
1604 : 0 : g_set_error (error,
1605 : : G_IO_ERROR,
1606 : : G_IO_ERROR_INVALID_ARGUMENT,
1607 : : _("Expected NUL byte after the string “%s” but found byte %d"),
1608 : 0 : str, mbuf->data[mbuf->pos + len]);
1609 : 0 : g_free (str);
1610 : 0 : mbuf->pos += len + 1;
1611 : 0 : return NULL;
1612 : : }
1613 : :
1614 : 310988 : str = mbuf->data + mbuf->pos;
1615 : 310988 : mbuf->pos += len + 1;
1616 : :
1617 : 310988 : if G_UNLIKELY (!g_utf8_validate (str, -1, &end_valid))
1618 : : {
1619 : : gint offset;
1620 : : gchar *valid_str;
1621 : 1 : offset = (gint) (end_valid - str);
1622 : 1 : valid_str = g_strndup (str, offset);
1623 : 1 : g_set_error (error,
1624 : : G_IO_ERROR,
1625 : : G_IO_ERROR_INVALID_ARGUMENT,
1626 : : _("Expected valid UTF-8 string but found invalid bytes at byte offset %d (length of string is %d). "
1627 : : "The valid UTF-8 string up until that point was “%s”"),
1628 : : offset,
1629 : : (gint) len,
1630 : : valid_str);
1631 : 1 : g_free (valid_str);
1632 : 1 : return NULL;
1633 : : }
1634 : :
1635 : 310987 : return str;
1636 : : }
1637 : :
1638 : : static gconstpointer
1639 : 729 : read_bytes (GMemoryBuffer *mbuf,
1640 : : gsize len,
1641 : : GError **error)
1642 : : {
1643 : : gconstpointer result;
1644 : :
1645 : 729 : if G_UNLIKELY (mbuf->pos + len > mbuf->valid_len || mbuf->pos + len < mbuf->pos)
1646 : : {
1647 : 0 : mbuf->pos = mbuf->valid_len;
1648 : : /* G_GSIZE_FORMAT doesn't work with gettext, so we use %lu */
1649 : 0 : g_set_error (error,
1650 : : G_IO_ERROR,
1651 : : G_IO_ERROR_INVALID_ARGUMENT,
1652 : : g_dngettext (GETTEXT_PACKAGE,
1653 : : "Wanted to read %lu byte but only got %lu",
1654 : : "Wanted to read %lu bytes but only got %lu",
1655 : : (gulong)len),
1656 : : (gulong)len,
1657 : 0 : (gulong)(mbuf->valid_len - mbuf->pos));
1658 : 0 : return NULL;
1659 : : }
1660 : :
1661 : 729 : result = mbuf->data + mbuf->pos;
1662 : 729 : mbuf->pos += len;
1663 : :
1664 : 729 : return result;
1665 : : }
1666 : :
1667 : : /* if just_align==TRUE, don't read a value, just align the input stream wrt padding */
1668 : :
1669 : : /* returns a non-floating GVariant! */
1670 : : static GVariant *
1671 : 682750 : parse_value_from_blob (GMemoryBuffer *buf,
1672 : : const GVariantType *type,
1673 : : guint max_depth,
1674 : : gboolean just_align,
1675 : : guint indent,
1676 : : GError **error)
1677 : : {
1678 : 682750 : GVariant *ret = NULL;
1679 : 682750 : GError *local_error = NULL;
1680 : : #ifdef DEBUG_SERIALIZER
1681 : : gboolean is_leaf;
1682 : : #endif /* DEBUG_SERIALIZER */
1683 : : const gchar *type_string;
1684 : :
1685 : 682750 : if (max_depth == 0)
1686 : : {
1687 : 0 : g_set_error_literal (&local_error,
1688 : : G_IO_ERROR,
1689 : : G_IO_ERROR_INVALID_ARGUMENT,
1690 : : _("Value nested too deeply"));
1691 : 0 : goto fail;
1692 : : }
1693 : :
1694 : 682750 : type_string = g_variant_type_peek_string (type);
1695 : :
1696 : : #ifdef DEBUG_SERIALIZER
1697 : : {
1698 : : gchar *s;
1699 : : s = g_variant_type_dup_string (type);
1700 : : g_print ("%*s%s type %s from offset 0x%04x",
1701 : : indent, "",
1702 : : just_align ? "Aligning" : "Reading",
1703 : : s,
1704 : : (gint) buf->pos);
1705 : : g_free (s);
1706 : : }
1707 : : #endif /* DEBUG_SERIALIZER */
1708 : :
1709 : : #ifdef DEBUG_SERIALIZER
1710 : : is_leaf = TRUE;
1711 : : #endif /* DEBUG_SERIALIZER */
1712 : 682750 : switch (type_string[0])
1713 : : {
1714 : 166 : case 'b': /* G_VARIANT_TYPE_BOOLEAN */
1715 : 166 : ensure_input_padding (buf, 4);
1716 : 166 : if (!just_align)
1717 : : {
1718 : : gboolean v;
1719 : 166 : v = g_memory_buffer_read_uint32 (buf, &local_error);
1720 : 166 : if (local_error)
1721 : 6 : goto fail;
1722 : 160 : ret = g_variant_new_boolean (v);
1723 : : }
1724 : 160 : break;
1725 : :
1726 : 142037 : case 'y': /* G_VARIANT_TYPE_BYTE */
1727 : 142037 : if (!just_align)
1728 : : {
1729 : : guchar v;
1730 : 142037 : v = g_memory_buffer_read_byte (buf, &local_error);
1731 : 142037 : if (local_error)
1732 : 18 : goto fail;
1733 : 142019 : ret = g_variant_new_byte (v);
1734 : : }
1735 : 142019 : break;
1736 : :
1737 : 95 : case 'n': /* G_VARIANT_TYPE_INT16 */
1738 : 95 : ensure_input_padding (buf, 2);
1739 : 95 : if (!just_align)
1740 : : {
1741 : : gint16 v;
1742 : 95 : v = g_memory_buffer_read_int16 (buf, &local_error);
1743 : 95 : if (local_error)
1744 : 3 : goto fail;
1745 : 92 : ret = g_variant_new_int16 (v);
1746 : : }
1747 : 92 : break;
1748 : :
1749 : 86 : case 'q': /* G_VARIANT_TYPE_UINT16 */
1750 : 86 : ensure_input_padding (buf, 2);
1751 : 86 : if (!just_align)
1752 : : {
1753 : : guint16 v;
1754 : 86 : v = g_memory_buffer_read_uint16 (buf, &local_error);
1755 : 86 : if (local_error)
1756 : 2 : goto fail;
1757 : 84 : ret = g_variant_new_uint16 (v);
1758 : : }
1759 : 84 : break;
1760 : :
1761 : 328 : case 'i': /* G_VARIANT_TYPE_INT32 */
1762 : 328 : ensure_input_padding (buf, 4);
1763 : 328 : if (!just_align)
1764 : : {
1765 : : gint32 v;
1766 : 328 : v = g_memory_buffer_read_int32 (buf, &local_error);
1767 : 328 : if (local_error)
1768 : 6 : goto fail;
1769 : 322 : ret = g_variant_new_int32 (v);
1770 : : }
1771 : 322 : break;
1772 : :
1773 : 20835 : case 'u': /* G_VARIANT_TYPE_UINT32 */
1774 : 20835 : ensure_input_padding (buf, 4);
1775 : 20835 : if (!just_align)
1776 : : {
1777 : : guint32 v;
1778 : 20835 : v = g_memory_buffer_read_uint32 (buf, &local_error);
1779 : 20835 : if (local_error)
1780 : 4 : goto fail;
1781 : 20831 : ret = g_variant_new_uint32 (v);
1782 : : }
1783 : 20831 : break;
1784 : :
1785 : 92 : case 'x': /* G_VARIANT_TYPE_INT64 */
1786 : 92 : ensure_input_padding (buf, 8);
1787 : 92 : if (!just_align)
1788 : : {
1789 : : gint64 v;
1790 : 92 : v = g_memory_buffer_read_int64 (buf, &local_error);
1791 : 92 : if (local_error)
1792 : 8 : goto fail;
1793 : 84 : ret = g_variant_new_int64 (v);
1794 : : }
1795 : 84 : break;
1796 : :
1797 : 67 : case 't': /* G_VARIANT_TYPE_UINT64 */
1798 : 67 : ensure_input_padding (buf, 8);
1799 : 67 : if (!just_align)
1800 : : {
1801 : : guint64 v;
1802 : 67 : v = g_memory_buffer_read_uint64 (buf, &local_error);
1803 : 67 : if (local_error)
1804 : 8 : goto fail;
1805 : 59 : ret = g_variant_new_uint64 (v);
1806 : : }
1807 : 59 : break;
1808 : :
1809 : 107 : case 'd': /* G_VARIANT_TYPE_DOUBLE */
1810 : 107 : ensure_input_padding (buf, 8);
1811 : 107 : if (!just_align)
1812 : : {
1813 : : union {
1814 : : guint64 v_uint64;
1815 : : gdouble v_double;
1816 : : } u;
1817 : : G_STATIC_ASSERT (sizeof (gdouble) == sizeof (guint64));
1818 : 107 : u.v_uint64 = g_memory_buffer_read_uint64 (buf, &local_error);
1819 : 107 : if (local_error)
1820 : 8 : goto fail;
1821 : 99 : ret = g_variant_new_double (u.v_double);
1822 : : }
1823 : 99 : break;
1824 : :
1825 : 121403 : case 's': /* G_VARIANT_TYPE_STRING */
1826 : 121403 : ensure_input_padding (buf, 4);
1827 : 121403 : if (!just_align)
1828 : : {
1829 : : guint32 len;
1830 : : const gchar *v;
1831 : 121254 : len = g_memory_buffer_read_uint32 (buf, &local_error);
1832 : 121254 : if (local_error)
1833 : 8 : goto fail;
1834 : 121246 : v = read_string (buf, (gsize) len, &local_error);
1835 : 121246 : if (v == NULL)
1836 : 18 : goto fail;
1837 : 121228 : ret = g_variant_new_string (v);
1838 : : }
1839 : 121377 : break;
1840 : :
1841 : 16431 : case 'o': /* G_VARIANT_TYPE_OBJECT_PATH */
1842 : 16431 : ensure_input_padding (buf, 4);
1843 : 16431 : if (!just_align)
1844 : : {
1845 : : guint32 len;
1846 : : const gchar *v;
1847 : 16368 : len = g_memory_buffer_read_uint32 (buf, &local_error);
1848 : 16368 : if (local_error)
1849 : 4 : goto fail;
1850 : 16364 : v = read_string (buf, (gsize) len, &local_error);
1851 : 16364 : if (v == NULL)
1852 : 9 : goto fail;
1853 : 16355 : if (!g_variant_is_object_path (v))
1854 : : {
1855 : 1 : g_set_error (&local_error,
1856 : : G_IO_ERROR,
1857 : : G_IO_ERROR_INVALID_ARGUMENT,
1858 : : _("Parsed value “%s” is not a valid D-Bus object path"),
1859 : : v);
1860 : 1 : goto fail;
1861 : : }
1862 : 16354 : ret = g_variant_new_object_path (v);
1863 : : }
1864 : 16417 : break;
1865 : :
1866 : 28121 : case 'g': /* G_VARIANT_TYPE_SIGNATURE */
1867 : 28121 : if (!just_align)
1868 : : {
1869 : : guchar len;
1870 : : const gchar *v;
1871 : 28058 : len = g_memory_buffer_read_byte (buf, &local_error);
1872 : 28058 : if (local_error)
1873 : 1 : goto fail;
1874 : 28057 : v = read_string (buf, (gsize) len, &local_error);
1875 : 28057 : if (v == NULL)
1876 : 13 : goto fail;
1877 : 28044 : if (!g_variant_is_signature (v))
1878 : : {
1879 : 1 : g_set_error (&local_error,
1880 : : G_IO_ERROR,
1881 : : G_IO_ERROR_INVALID_ARGUMENT,
1882 : : _("Parsed value “%s” is not a valid D-Bus signature"),
1883 : : v);
1884 : 1 : goto fail;
1885 : : }
1886 : 28043 : ret = g_variant_new_signature (v);
1887 : : }
1888 : 28106 : break;
1889 : :
1890 : 7 : case 'h': /* G_VARIANT_TYPE_HANDLE */
1891 : 7 : ensure_input_padding (buf, 4);
1892 : 7 : if (!just_align)
1893 : : {
1894 : : gint32 v;
1895 : 7 : v = g_memory_buffer_read_int32 (buf, &local_error);
1896 : 7 : if (local_error)
1897 : 0 : goto fail;
1898 : 7 : ret = g_variant_new_handle (v);
1899 : : }
1900 : 7 : break;
1901 : :
1902 : 33527 : case 'a': /* G_VARIANT_TYPE_ARRAY */
1903 : 33527 : ensure_input_padding (buf, 4);
1904 : :
1905 : : /* If we are only aligning for this array type, it is the child type of
1906 : : * another array, which is empty. So, we do not need to add padding for
1907 : : * this nonexistent array's elements: we only need to align for this
1908 : : * array itself (4 bytes). See
1909 : : * <https://bugzilla.gnome.org/show_bug.cgi?id=673612>.
1910 : : */
1911 : 33527 : if (!just_align)
1912 : : {
1913 : : guint32 array_len;
1914 : : const GVariantType *element_type;
1915 : : guint fixed_size;
1916 : :
1917 : 33433 : array_len = g_memory_buffer_read_uint32 (buf, &local_error);
1918 : 33433 : if (local_error)
1919 : 5 : goto fail;
1920 : :
1921 : : #ifdef DEBUG_SERIALIZER
1922 : : is_leaf = FALSE;
1923 : : g_print (": array spans 0x%04x bytes\n", array_len);
1924 : : #endif /* DEBUG_SERIALIZER */
1925 : :
1926 : 33428 : if (array_len > (2<<26))
1927 : : {
1928 : : /* G_GUINT32_FORMAT doesn't work with gettext, so use u */
1929 : 0 : g_set_error (&local_error,
1930 : : G_IO_ERROR,
1931 : : G_IO_ERROR_INVALID_ARGUMENT,
1932 : : g_dngettext (GETTEXT_PACKAGE,
1933 : : "Encountered array of length %u byte. Maximum length is 2<<26 bytes (64 MiB).",
1934 : : "Encountered array of length %u bytes. Maximum length is 2<<26 bytes (64 MiB).",
1935 : : array_len),
1936 : : array_len);
1937 : 0 : goto fail;
1938 : : }
1939 : :
1940 : 33428 : element_type = g_variant_type_element (type);
1941 : 33428 : fixed_size = get_type_fixed_size (element_type);
1942 : :
1943 : : /* Fast-path the cases like 'ay', etc. */
1944 : 33428 : if (fixed_size != 0)
1945 : : {
1946 : : gconstpointer array_data;
1947 : :
1948 : 729 : if (array_len % fixed_size != 0)
1949 : : {
1950 : 0 : g_set_error (&local_error,
1951 : : G_IO_ERROR,
1952 : : G_IO_ERROR_INVALID_ARGUMENT,
1953 : : _("Encountered array of type “a%c”, expected to have a length a multiple "
1954 : : "of %u bytes, but found to be %u bytes in length"),
1955 : 0 : g_variant_type_peek_string (element_type)[0], fixed_size, array_len);
1956 : 0 : goto fail;
1957 : : }
1958 : :
1959 : 729 : if (max_depth == 1)
1960 : : {
1961 : : /* If we had recursed into parse_value_from_blob() again to
1962 : : * parse the array values, this would have been emitted. */
1963 : 0 : g_set_error_literal (&local_error,
1964 : : G_IO_ERROR,
1965 : : G_IO_ERROR_INVALID_ARGUMENT,
1966 : : _("Value nested too deeply"));
1967 : 0 : goto fail;
1968 : : }
1969 : :
1970 : 729 : ensure_input_padding (buf, fixed_size);
1971 : 729 : array_data = read_bytes (buf, array_len, &local_error);
1972 : 729 : if (array_data == NULL)
1973 : 0 : goto fail;
1974 : :
1975 : 729 : ret = g_variant_new_fixed_array (element_type, array_data, array_len / fixed_size, fixed_size);
1976 : :
1977 : 729 : if (g_memory_buffer_is_byteswapped (buf))
1978 : : {
1979 : 3 : GVariant *tmp = g_variant_ref_sink (ret);
1980 : 3 : ret = g_variant_byteswap (tmp);
1981 : 3 : g_variant_unref (tmp);
1982 : : }
1983 : : }
1984 : : else
1985 : : {
1986 : : GVariantBuilder builder;
1987 : : goffset offset;
1988 : : goffset target;
1989 : :
1990 : 32699 : g_variant_builder_init_static (&builder, type);
1991 : :
1992 : 32699 : if (array_len == 0)
1993 : : {
1994 : : GVariant *item G_GNUC_UNUSED /* when compiling with G_DISABLE_ASSERT */;
1995 : 484 : item = parse_value_from_blob (buf,
1996 : : element_type,
1997 : : max_depth - 1,
1998 : : TRUE,
1999 : : indent + 2,
2000 : : NULL);
2001 : 484 : g_assert (item == NULL);
2002 : : }
2003 : : else
2004 : : {
2005 : 32215 : offset = buf->pos;
2006 : 32215 : target = offset + array_len;
2007 : 179781 : while (offset < target)
2008 : : {
2009 : : GVariant *item;
2010 : 147648 : item = parse_value_from_blob (buf,
2011 : : element_type,
2012 : : max_depth - 1,
2013 : : FALSE,
2014 : : indent + 2,
2015 : : &local_error);
2016 : 147648 : if (item == NULL)
2017 : : {
2018 : 82 : g_variant_builder_clear (&builder);
2019 : 82 : goto fail;
2020 : : }
2021 : 147566 : g_variant_builder_add_value (&builder, item);
2022 : 147566 : g_variant_unref (item);
2023 : :
2024 : : /* Array elements must not be zero-length. There are no
2025 : : * valid zero-length serialisations of any types which
2026 : : * can be array elements in the D-Bus wire format, so this
2027 : : * assertion should always hold.
2028 : : *
2029 : : * See https://gitlab.gnome.org/GNOME/glib/-/issues/2557
2030 : : */
2031 : 147566 : g_assert (buf->pos > (gsize) offset);
2032 : :
2033 : 147566 : offset = buf->pos;
2034 : : }
2035 : : }
2036 : :
2037 : 32617 : ret = g_variant_builder_end (&builder);
2038 : : }
2039 : : }
2040 : 33440 : break;
2041 : :
2042 : 319448 : default:
2043 : 319448 : if (g_variant_type_is_dict_entry (type))
2044 : : {
2045 : : const GVariantType *key_type;
2046 : : const GVariantType *value_type;
2047 : : GVariant *key;
2048 : : GVariant *value;
2049 : :
2050 : 145233 : ensure_input_padding (buf, 8);
2051 : :
2052 : : #ifdef DEBUG_SERIALIZER
2053 : : is_leaf = FALSE;
2054 : : g_print ("\n");
2055 : : #endif /* DEBUG_SERIALIZER */
2056 : :
2057 : 145233 : if (!just_align)
2058 : : {
2059 : 145137 : key_type = g_variant_type_key (type);
2060 : 145137 : key = parse_value_from_blob (buf,
2061 : : key_type,
2062 : : max_depth - 1,
2063 : : FALSE,
2064 : : indent + 2,
2065 : : &local_error);
2066 : 145137 : if (key == NULL)
2067 : 17 : goto fail;
2068 : 145120 : value_type = g_variant_type_value (type);
2069 : 145120 : value = parse_value_from_blob (buf,
2070 : : value_type,
2071 : : max_depth - 1,
2072 : : FALSE,
2073 : : indent + 2,
2074 : : &local_error);
2075 : 145120 : if (value == NULL)
2076 : : {
2077 : 50 : g_variant_unref (key);
2078 : 50 : goto fail;
2079 : : }
2080 : 145070 : ret = g_variant_new_dict_entry (key, value);
2081 : 145070 : g_variant_unref (key);
2082 : 145070 : g_variant_unref (value);
2083 : : }
2084 : : }
2085 : 174215 : else if (g_variant_type_is_tuple (type))
2086 : : {
2087 : 28827 : ensure_input_padding (buf, 8);
2088 : :
2089 : : #ifdef DEBUG_SERIALIZER
2090 : : is_leaf = FALSE;
2091 : : g_print ("\n");
2092 : : #endif /* DEBUG_SERIALIZER */
2093 : :
2094 : 28827 : if (!just_align)
2095 : : {
2096 : : const GVariantType *element_type;
2097 : : GVariantBuilder builder;
2098 : :
2099 : 28827 : g_variant_builder_init_static (&builder, type);
2100 : 28827 : element_type = g_variant_type_first (type);
2101 : 28827 : if (!element_type)
2102 : : {
2103 : 1 : g_variant_builder_clear (&builder);
2104 : 1 : g_set_error_literal (&local_error,
2105 : : G_IO_ERROR,
2106 : : G_IO_ERROR_INVALID_ARGUMENT,
2107 : : _("Empty structures (tuples) are not allowed in D-Bus"));
2108 : 71 : goto fail;
2109 : : }
2110 : :
2111 : 70922 : while (element_type != NULL)
2112 : : {
2113 : : GVariant *item;
2114 : 42166 : item = parse_value_from_blob (buf,
2115 : : element_type,
2116 : : max_depth - 1,
2117 : : FALSE,
2118 : : indent + 2,
2119 : : &local_error);
2120 : 42166 : if (item == NULL)
2121 : : {
2122 : 70 : g_variant_builder_clear (&builder);
2123 : 70 : goto fail;
2124 : : }
2125 : 42096 : g_variant_builder_add_value (&builder, item);
2126 : 42096 : g_variant_unref (item);
2127 : :
2128 : 42096 : element_type = g_variant_type_next (element_type);
2129 : : }
2130 : 28756 : ret = g_variant_builder_end (&builder);
2131 : : }
2132 : : }
2133 : 145388 : else if (g_variant_type_is_variant (type))
2134 : : {
2135 : : #ifdef DEBUG_SERIALIZER
2136 : : is_leaf = FALSE;
2137 : : g_print ("\n");
2138 : : #endif /* DEBUG_SERIALIZER */
2139 : :
2140 : 145388 : if (!just_align)
2141 : : {
2142 : : guchar siglen;
2143 : : const gchar *sig;
2144 : : GVariantType *variant_type;
2145 : : GVariant *value;
2146 : :
2147 : 145369 : siglen = g_memory_buffer_read_byte (buf, &local_error);
2148 : 145369 : if (local_error)
2149 : 3 : goto fail;
2150 : 145366 : sig = read_string (buf, (gsize) siglen, &local_error);
2151 : 145366 : if (sig == NULL)
2152 : 6 : goto fail;
2153 : 145360 : if (!g_variant_is_signature (sig) ||
2154 : 145360 : !g_variant_type_string_is_valid (sig))
2155 : : {
2156 : : /* A D-Bus signature can contain zero or more complete types,
2157 : : * but a GVariant has to be exactly one complete type. */
2158 : 2 : g_set_error (&local_error,
2159 : : G_IO_ERROR,
2160 : : G_IO_ERROR_INVALID_ARGUMENT,
2161 : : _("Parsed value “%s” for variant is not a valid D-Bus signature"),
2162 : : sig);
2163 : 2 : goto fail;
2164 : : }
2165 : :
2166 : 145358 : if (max_depth <= g_variant_type_string_get_depth_ (sig))
2167 : : {
2168 : : /* Catch the type nesting being too deep without having to
2169 : : * parse the data. We don’t have to check this for static
2170 : : * container types (like arrays and tuples, above) because
2171 : : * the g_variant_type_string_is_valid() check performed before
2172 : : * the initial parse_value_from_blob() call should check the
2173 : : * static type nesting. */
2174 : 2 : g_set_error_literal (&local_error,
2175 : : G_IO_ERROR,
2176 : : G_IO_ERROR_INVALID_ARGUMENT,
2177 : : _("Value nested too deeply"));
2178 : 2 : goto fail;
2179 : : }
2180 : :
2181 : 145356 : variant_type = g_variant_type_new (sig);
2182 : 145356 : value = parse_value_from_blob (buf,
2183 : : variant_type,
2184 : : max_depth - 1,
2185 : : FALSE,
2186 : : indent + 2,
2187 : : &local_error);
2188 : 145356 : g_variant_type_free (variant_type);
2189 : 145356 : if (value == NULL)
2190 : 166 : goto fail;
2191 : 145190 : ret = g_variant_new_variant (value);
2192 : 145190 : g_variant_unref (value);
2193 : : }
2194 : : }
2195 : : else
2196 : : {
2197 : : gchar *s;
2198 : 0 : s = g_variant_type_dup_string (type);
2199 : 0 : g_set_error (&local_error,
2200 : : G_IO_ERROR,
2201 : : G_IO_ERROR_INVALID_ARGUMENT,
2202 : : _("Error deserializing GVariant with type string “%s” from the D-Bus wire format"),
2203 : : s);
2204 : 0 : g_free (s);
2205 : 0 : goto fail;
2206 : : }
2207 : 319131 : break;
2208 : : }
2209 : :
2210 : 682228 : g_assert ((just_align && ret == NULL) || (!just_align && ret != NULL));
2211 : :
2212 : : #ifdef DEBUG_SERIALIZER
2213 : : if (ret != NULL)
2214 : : {
2215 : : if (is_leaf)
2216 : : {
2217 : : gchar *s;
2218 : : if (g_variant_type_equal (type, G_VARIANT_TYPE_BYTE))
2219 : : {
2220 : : s = g_strdup_printf ("0x%02x '%c'", g_variant_get_byte (ret), g_variant_get_byte (ret));
2221 : : }
2222 : : else
2223 : : {
2224 : : s = g_variant_print (ret, FALSE);
2225 : : }
2226 : : g_print (": %s\n", s);
2227 : : g_free (s);
2228 : : }
2229 : : }
2230 : : #endif /* DEBUG_SERIALIZER */
2231 : :
2232 : : /* sink the reference, if floating */
2233 : 682228 : if (ret != NULL)
2234 : 681744 : g_variant_take_ref (ret);
2235 : 682228 : return ret;
2236 : :
2237 : 522 : fail:
2238 : : #ifdef DEBUG_SERIALIZER
2239 : : g_print ("\n"
2240 : : "%*sFAILURE: %s (%s, %d)\n",
2241 : : indent, "",
2242 : : local_error->message,
2243 : : g_quark_to_string (local_error->domain),
2244 : : local_error->code);
2245 : : #endif /* DEBUG_SERIALIZER */
2246 : 522 : g_propagate_error (error, local_error);
2247 : 522 : return NULL;
2248 : : }
2249 : :
2250 : : /* ---------------------------------------------------------------------------------------------------- */
2251 : :
2252 : : /* message_header must be at least 16 bytes */
2253 : : #define DBUS_MESSAGE_HEADER_MINIMUM_LENGTH_BYTES 16
2254 : :
2255 : : /**
2256 : : * g_dbus_message_bytes_needed:
2257 : : * @blob: (array length=blob_len) (element-type guint8): a blob representing a
2258 : : * binary D-Bus message.
2259 : : * @blob_len: the length of @blob (must be at least 16 bytes)
2260 : : * @error: return location for error, or `NULL`
2261 : : *
2262 : : * Utility function to calculate how many bytes are needed to
2263 : : * completely deserialize the D-Bus message stored at @blob.
2264 : : *
2265 : : * An error will be returned if @blob contains invalid data, or if not enough
2266 : : * data is available to determine the size.
2267 : : *
2268 : : * Returns: Number of bytes needed or `-1` if @error is set
2269 : : * Since: 2.26
2270 : : */
2271 : : gssize
2272 : 28962 : g_dbus_message_bytes_needed (guchar *blob,
2273 : : gsize blob_len,
2274 : : GError **error)
2275 : : {
2276 : : uint32_t header_len, body_len;
2277 : : size_t ret;
2278 : :
2279 : 28962 : g_return_val_if_fail (blob != NULL, -1);
2280 : 28962 : g_return_val_if_fail (error == NULL || *error == NULL, -1);
2281 : 28962 : g_return_val_if_fail (blob_len >= DBUS_MESSAGE_HEADER_MINIMUM_LENGTH_BYTES, -1);
2282 : :
2283 : 28962 : if (blob[0] == 'l')
2284 : : {
2285 : 28956 : header_len = GUINT32_FROM_LE (((guint32 *) blob)[3]);
2286 : 28956 : body_len = GUINT32_FROM_LE (((guint32 *) blob)[1]);
2287 : : }
2288 : 6 : else if (blob[0] == 'B')
2289 : : {
2290 : 4 : header_len = GUINT32_FROM_BE (((guint32 *) blob)[3]);
2291 : 4 : body_len = GUINT32_FROM_BE (((guint32 *) blob)[1]);
2292 : : }
2293 : : else
2294 : : {
2295 : 2 : g_set_error (error,
2296 : : G_IO_ERROR,
2297 : : G_IO_ERROR_INVALID_ARGUMENT,
2298 : : "Unable to determine message blob length - given blob is malformed");
2299 : 2 : return -1;
2300 : : }
2301 : :
2302 : : /* core header (12 bytes) + array length (4 bytes) + length of array.
2303 : : * Array elements are tuples: (byte, variant) */
2304 : 28960 : ret = 0;
2305 : 28960 : if (!g_size_checked_add (&ret, 12 + 4, header_len) ||
2306 : : /* round up so it's a multiple of 8: ret = 8 * ((ret + 7)/8) */
2307 : 28960 : !g_size_checked_add (&ret, ret, 7) ||
2308 : 28960 : !g_size_checked_mul (&ret, 8, ret/8) ||
2309 : : /* finally add the body size */
2310 : 28960 : !g_size_checked_add (&ret, ret, body_len) ||
2311 : 28960 : ret > (1 << 27))
2312 : : {
2313 : 5 : g_set_error (error,
2314 : : G_IO_ERROR,
2315 : : G_IO_ERROR_INVALID_ARGUMENT,
2316 : : "Blob indicates that message exceeds maximum message length (128MiB)");
2317 : 5 : return -1;
2318 : : }
2319 : :
2320 : 28955 : g_assert (ret <= G_MAXSSIZE);
2321 : 28955 : return (gssize) ret;
2322 : : }
2323 : :
2324 : : /* ---------------------------------------------------------------------------------------------------- */
2325 : :
2326 : : /**
2327 : : * g_dbus_message_new_from_blob:
2328 : : * @blob: (array length=blob_len) (element-type guint8): a blob representing a
2329 : : * binary D-Bus message
2330 : : * @blob_len: the length of @blob, in bytes
2331 : : * @capabilities: flags describing what protocol features are supported
2332 : : * @error: return location for error, or `NULL`
2333 : : *
2334 : : * Creates a new D-Bus message from the data stored at @blob.
2335 : : *
2336 : : * You must have previously called [func@Gio.DBusMessage.bytes_needed] on @blob,
2337 : : * and ensure that @blob is at least as long as the return value from that
2338 : : * function indicates. In particular, that means that @blob must be at least 16
2339 : : * bytes long (but will typically be much longer).
2340 : : *
2341 : : * The byte order that the message was in can be retrieved using
2342 : : * [method@Gio.DBusMessage.get_byte_order].
2343 : : *
2344 : : * If the @blob cannot be parsed, contains invalid fields, or contains invalid
2345 : : * headers, [error@Gio.IOErrorEnum.INVALID_ARGUMENT] will be returned.
2346 : : *
2347 : : * Returns: (transfer full): The D-Bus message
2348 : : * Since: 2.26
2349 : : */
2350 : : GDBusMessage *
2351 : 29132 : g_dbus_message_new_from_blob (guchar *blob,
2352 : : gsize blob_len,
2353 : : GDBusCapabilityFlags capabilities,
2354 : : GError **error)
2355 : : {
2356 : 29132 : GError *local_error = NULL;
2357 : : GMemoryBuffer mbuf;
2358 : : GDBusMessage *message;
2359 : : guchar endianness;
2360 : : guchar major_protocol_version;
2361 : : guint32 message_body_len;
2362 : : GVariant *headers;
2363 : : GVariant *item;
2364 : : GVariantIter iter;
2365 : : GVariant *signature;
2366 : :
2367 : : /* TODO: check against @capabilities */
2368 : :
2369 : 29132 : g_return_val_if_fail (blob != NULL, NULL);
2370 : 29132 : g_return_val_if_fail (error == NULL || *error == NULL, NULL);
2371 : :
2372 : : /* blob_len must actually be >= the value returned by
2373 : : * g_dbus_message_bytes_needed(), but this is a known minimum */
2374 : 29132 : if (blob_len < DBUS_MESSAGE_HEADER_MINIMUM_LENGTH_BYTES)
2375 : : {
2376 : 16 : g_set_error (error,
2377 : : G_IO_ERROR,
2378 : : G_IO_ERROR_INVALID_ARGUMENT,
2379 : : "Unexpectedly short message.");
2380 : 16 : return NULL;
2381 : : }
2382 : :
2383 : 29116 : message = g_dbus_message_new ();
2384 : :
2385 : 29116 : memset (&mbuf, 0, sizeof (mbuf));
2386 : 29116 : mbuf.data = (gchar *)blob;
2387 : 29116 : mbuf.len = mbuf.valid_len = blob_len;
2388 : :
2389 : 29116 : endianness = g_memory_buffer_read_byte (&mbuf, &local_error);
2390 : 29116 : if (local_error)
2391 : 0 : goto fail;
2392 : :
2393 : 29116 : switch (endianness)
2394 : : {
2395 : 29104 : case 'l':
2396 : 29104 : mbuf.byte_order = G_DATA_STREAM_BYTE_ORDER_LITTLE_ENDIAN;
2397 : 29104 : message->byte_order = G_DBUS_MESSAGE_BYTE_ORDER_LITTLE_ENDIAN;
2398 : 29104 : break;
2399 : 12 : case 'B':
2400 : 12 : mbuf.byte_order = G_DATA_STREAM_BYTE_ORDER_BIG_ENDIAN;
2401 : 12 : message->byte_order = G_DBUS_MESSAGE_BYTE_ORDER_BIG_ENDIAN;
2402 : 12 : break;
2403 : 0 : default:
2404 : 0 : g_set_error (&local_error,
2405 : : G_IO_ERROR,
2406 : : G_IO_ERROR_INVALID_ARGUMENT,
2407 : : _("Invalid endianness value. Expected 0x6c (“l”) or 0x42 (“B”) but found value 0x%02x"),
2408 : : endianness);
2409 : 0 : goto fail;
2410 : : }
2411 : :
2412 : 29116 : message->type = g_memory_buffer_read_byte (&mbuf, &local_error);
2413 : 29116 : if (local_error)
2414 : 0 : goto fail;
2415 : 29116 : message->flags = g_memory_buffer_read_byte (&mbuf, &local_error);
2416 : 29116 : if (local_error)
2417 : 0 : goto fail;
2418 : 29116 : major_protocol_version = g_memory_buffer_read_byte (&mbuf, &local_error);
2419 : 29116 : if (local_error)
2420 : 0 : goto fail;
2421 : 29116 : if (major_protocol_version != 1)
2422 : : {
2423 : 0 : g_set_error (&local_error,
2424 : : G_IO_ERROR,
2425 : : G_IO_ERROR_INVALID_ARGUMENT,
2426 : : _("Invalid major protocol version. Expected 1 but found %d"),
2427 : : major_protocol_version);
2428 : 0 : goto fail;
2429 : : }
2430 : 29116 : message_body_len = g_memory_buffer_read_uint32 (&mbuf, &local_error);
2431 : 29116 : if (local_error)
2432 : 0 : goto fail;
2433 : 29116 : message->serial = g_memory_buffer_read_uint32 (&mbuf, &local_error);
2434 : 29116 : if (local_error)
2435 : 0 : goto fail;
2436 : :
2437 : : #ifdef DEBUG_SERIALIZER
2438 : : g_print ("Parsing blob (blob_len = 0x%04x bytes)\n", (gint) blob_len);
2439 : : {
2440 : : gchar *s;
2441 : : s = _g_dbus_hexdump ((const gchar *) blob, blob_len, 2);
2442 : : g_print ("%s\n", s);
2443 : : g_free (s);
2444 : : }
2445 : : #endif /* DEBUG_SERIALIZER */
2446 : :
2447 : : #ifdef DEBUG_SERIALIZER
2448 : : g_print ("Parsing headers (blob_len = 0x%04x bytes)\n", (gint) blob_len);
2449 : : #endif /* DEBUG_SERIALIZER */
2450 : 29116 : headers = parse_value_from_blob (&mbuf,
2451 : : G_VARIANT_TYPE ("a{yv}"),
2452 : : G_DBUS_MAX_TYPE_DEPTH + 2 /* for the a{yv} */,
2453 : : FALSE,
2454 : : 2,
2455 : : &local_error);
2456 : 29116 : if (headers == NULL)
2457 : 67 : goto fail;
2458 : 29049 : g_variant_iter_init (&iter, headers);
2459 : 170845 : while ((item = g_variant_iter_next_value (&iter)) != NULL)
2460 : : {
2461 : : guchar header_field;
2462 : : GVariant *value;
2463 : 141796 : g_variant_get (item,
2464 : : "{yv}",
2465 : : &header_field,
2466 : : &value);
2467 : 141796 : g_dbus_message_set_header (message, header_field, value);
2468 : 141796 : g_variant_unref (value);
2469 : 141796 : g_variant_unref (item);
2470 : : }
2471 : 29049 : g_variant_unref (headers);
2472 : :
2473 : 29049 : signature = g_dbus_message_get_header (message, G_DBUS_MESSAGE_HEADER_FIELD_SIGNATURE);
2474 : 29049 : if (signature != NULL)
2475 : : {
2476 : : const gchar *signature_str;
2477 : : gsize signature_str_len;
2478 : :
2479 : 27912 : if (!g_variant_is_of_type (signature, G_VARIANT_TYPE_SIGNATURE))
2480 : : {
2481 : 1 : g_set_error_literal (&local_error,
2482 : : G_IO_ERROR,
2483 : : G_IO_ERROR_INVALID_ARGUMENT,
2484 : : _("Signature header found but is not of type signature"));
2485 : 71 : goto fail;
2486 : : }
2487 : :
2488 : 27911 : signature_str = g_variant_get_string (signature, &signature_str_len);
2489 : :
2490 : : /* signature but no body */
2491 : 27911 : if (message_body_len == 0 && signature_str_len > 0)
2492 : : {
2493 : 0 : g_set_error (&local_error,
2494 : : G_IO_ERROR,
2495 : : G_IO_ERROR_INVALID_ARGUMENT,
2496 : : _("Signature header with signature “%s” found but message body is empty"),
2497 : : signature_str);
2498 : 0 : goto fail;
2499 : : }
2500 : 27911 : else if (signature_str_len > 0)
2501 : : {
2502 : : GVariantType *variant_type;
2503 : 27723 : gchar *tupled_signature_str = g_strdup_printf ("(%s)", signature_str);
2504 : :
2505 : 27723 : if (!g_variant_is_signature (signature_str) ||
2506 : 27723 : !g_variant_type_string_is_valid (tupled_signature_str))
2507 : : {
2508 : 0 : g_set_error (&local_error,
2509 : : G_IO_ERROR,
2510 : : G_IO_ERROR_INVALID_ARGUMENT,
2511 : : _("Parsed value “%s” is not a valid D-Bus signature (for body)"),
2512 : : signature_str);
2513 : 0 : g_free (tupled_signature_str);
2514 : 0 : goto fail;
2515 : : }
2516 : :
2517 : 27723 : variant_type = g_variant_type_new (tupled_signature_str);
2518 : 27723 : g_free (tupled_signature_str);
2519 : : #ifdef DEBUG_SERIALIZER
2520 : : g_print ("Parsing body (blob_len = 0x%04x bytes)\n", (gint) blob_len);
2521 : : #endif /* DEBUG_SERIALIZER */
2522 : 27723 : message->body = parse_value_from_blob (&mbuf,
2523 : : variant_type,
2524 : : G_DBUS_MAX_TYPE_DEPTH + 1 /* for the surrounding tuple */,
2525 : : FALSE,
2526 : : 2,
2527 : : &local_error);
2528 : 27723 : g_variant_type_free (variant_type);
2529 : :
2530 : 55376 : if (message->body != NULL &&
2531 : 55306 : g_variant_is_of_type (message->body, G_VARIANT_TYPE_TUPLE) &&
2532 : 27653 : g_variant_n_children (message->body) > 0)
2533 : 27653 : message->arg0_cache = g_variant_get_child_value (message->body, 0);
2534 : : else
2535 : 70 : message->arg0_cache = NULL;
2536 : :
2537 : 27723 : if (message->body == NULL)
2538 : 70 : goto fail;
2539 : : }
2540 : : }
2541 : : else
2542 : : {
2543 : : /* no signature, this is only OK if the body is empty */
2544 : 1137 : if (message_body_len != 0)
2545 : : {
2546 : : /* G_GUINT32_FORMAT doesn't work with gettext, just use %u */
2547 : 0 : g_set_error (&local_error,
2548 : : G_IO_ERROR,
2549 : : G_IO_ERROR_INVALID_ARGUMENT,
2550 : : g_dngettext (GETTEXT_PACKAGE,
2551 : : "No signature header in message but the message body is %u byte",
2552 : : "No signature header in message but the message body is %u bytes",
2553 : : message_body_len),
2554 : : message_body_len);
2555 : 0 : goto fail;
2556 : : }
2557 : : }
2558 : :
2559 : 28978 : if (!validate_headers (message, &local_error))
2560 : : {
2561 : 2 : g_prefix_error (&local_error, _("Cannot deserialize message: "));
2562 : 2 : goto fail;
2563 : : }
2564 : :
2565 : 28976 : return message;
2566 : :
2567 : 140 : fail:
2568 : 140 : g_clear_object (&message);
2569 : 140 : g_propagate_error (error, local_error);
2570 : 140 : return NULL;
2571 : : }
2572 : :
2573 : : /* ---------------------------------------------------------------------------------------------------- */
2574 : :
2575 : : static gsize
2576 : 203302 : ensure_output_padding (GMemoryBuffer *mbuf,
2577 : : gsize padding_size)
2578 : : {
2579 : : gsize offset;
2580 : : gsize wanted_offset;
2581 : : gsize padding_needed;
2582 : : guint n;
2583 : :
2584 : 203302 : offset = mbuf->pos;
2585 : 203302 : wanted_offset = ((offset + padding_size - 1) / padding_size) * padding_size;
2586 : 203302 : padding_needed = wanted_offset - offset;
2587 : :
2588 : 407283 : for (n = 0; n < padding_needed; n++)
2589 : 203981 : g_memory_buffer_put_byte (mbuf, '\0');
2590 : :
2591 : 203302 : return padding_needed;
2592 : : }
2593 : :
2594 : : /* note that value can be NULL for e.g. empty arrays - type is never NULL */
2595 : : static gboolean
2596 : 350416 : append_value_to_blob (GVariant *value,
2597 : : const GVariantType *type,
2598 : : GMemoryBuffer *mbuf,
2599 : : gsize *out_padding_added,
2600 : : GError **error)
2601 : : {
2602 : : gsize padding_added;
2603 : : const gchar *type_string;
2604 : :
2605 : 350416 : type_string = g_variant_type_peek_string (type);
2606 : :
2607 : 350416 : padding_added = 0;
2608 : :
2609 : 350416 : switch (type_string[0])
2610 : : {
2611 : 116 : case 'b': /* G_VARIANT_TYPE_BOOLEAN */
2612 : 116 : padding_added = ensure_output_padding (mbuf, 4);
2613 : 116 : if (value != NULL)
2614 : : {
2615 : 116 : gboolean v = g_variant_get_boolean (value);
2616 : 116 : g_memory_buffer_put_uint32 (mbuf, v);
2617 : : }
2618 : 116 : break;
2619 : :
2620 : 74859 : case 'y': /* G_VARIANT_TYPE_BYTE */
2621 : 74859 : if (value != NULL)
2622 : : {
2623 : 74826 : guint8 v = g_variant_get_byte (value);
2624 : 74826 : g_memory_buffer_put_byte (mbuf, v);
2625 : : }
2626 : 74859 : break;
2627 : :
2628 : 50 : case 'n': /* G_VARIANT_TYPE_INT16 */
2629 : 50 : padding_added = ensure_output_padding (mbuf, 2);
2630 : 50 : if (value != NULL)
2631 : : {
2632 : 50 : gint16 v = g_variant_get_int16 (value);
2633 : 50 : g_memory_buffer_put_int16 (mbuf, v);
2634 : : }
2635 : 50 : break;
2636 : :
2637 : 44 : case 'q': /* G_VARIANT_TYPE_UINT16 */
2638 : 44 : padding_added = ensure_output_padding (mbuf, 2);
2639 : 44 : if (value != NULL)
2640 : : {
2641 : 44 : guint16 v = g_variant_get_uint16 (value);
2642 : 44 : g_memory_buffer_put_uint16 (mbuf, v);
2643 : : }
2644 : 44 : break;
2645 : :
2646 : 312 : case 'i': /* G_VARIANT_TYPE_INT32 */
2647 : 312 : padding_added = ensure_output_padding (mbuf, 4);
2648 : 312 : if (value != NULL)
2649 : : {
2650 : 312 : gint32 v = g_variant_get_int32 (value);
2651 : 312 : g_memory_buffer_put_int32 (mbuf, v);
2652 : : }
2653 : 312 : break;
2654 : :
2655 : 7978 : case 'u': /* G_VARIANT_TYPE_UINT32 */
2656 : 7978 : padding_added = ensure_output_padding (mbuf, 4);
2657 : 7978 : if (value != NULL)
2658 : : {
2659 : 7978 : guint32 v = g_variant_get_uint32 (value);
2660 : 7978 : g_memory_buffer_put_uint32 (mbuf, v);
2661 : : }
2662 : 7978 : break;
2663 : :
2664 : 458 : case 'x': /* G_VARIANT_TYPE_INT64 */
2665 : 458 : padding_added = ensure_output_padding (mbuf, 8);
2666 : 458 : if (value != NULL)
2667 : : {
2668 : 458 : gint64 v = g_variant_get_int64 (value);
2669 : 458 : g_memory_buffer_put_int64 (mbuf, v);
2670 : : }
2671 : 458 : break;
2672 : :
2673 : 44 : case 't': /* G_VARIANT_TYPE_UINT64 */
2674 : 44 : padding_added = ensure_output_padding (mbuf, 8);
2675 : 44 : if (value != NULL)
2676 : : {
2677 : 44 : guint64 v = g_variant_get_uint64 (value);
2678 : 44 : g_memory_buffer_put_uint64 (mbuf, v);
2679 : : }
2680 : 44 : break;
2681 : :
2682 : 92 : case 'd': /* G_VARIANT_TYPE_DOUBLE */
2683 : 92 : padding_added = ensure_output_padding (mbuf, 8);
2684 : 92 : if (value != NULL)
2685 : : {
2686 : : union {
2687 : : guint64 v_uint64;
2688 : : gdouble v_double;
2689 : : } u;
2690 : : G_STATIC_ASSERT (sizeof (gdouble) == sizeof (guint64));
2691 : 92 : u.v_double = g_variant_get_double (value);
2692 : 92 : g_memory_buffer_put_uint64 (mbuf, u.v_uint64);
2693 : : }
2694 : 92 : break;
2695 : :
2696 : 61282 : case 's': /* G_VARIANT_TYPE_STRING */
2697 : 61282 : padding_added = ensure_output_padding (mbuf, 4);
2698 : 61282 : if (value != NULL)
2699 : : {
2700 : : gsize len;
2701 : : const gchar *v;
2702 : : #ifndef G_DISABLE_ASSERT
2703 : : const gchar *end;
2704 : : #endif
2705 : :
2706 : 61114 : v = g_variant_get_string (value, &len);
2707 : 61114 : g_assert (g_utf8_validate (v, -1, &end) && (end == v + len));
2708 : 61114 : g_memory_buffer_put_uint32 (mbuf, len);
2709 : 61114 : g_memory_buffer_put_string (mbuf, v);
2710 : 61114 : g_memory_buffer_put_byte (mbuf, '\0');
2711 : : }
2712 : 61282 : break;
2713 : :
2714 : 14737 : case 'o': /* G_VARIANT_TYPE_OBJECT_PATH */
2715 : 14737 : padding_added = ensure_output_padding (mbuf, 4);
2716 : 14737 : if (value != NULL)
2717 : : {
2718 : : gsize len;
2719 : 14674 : const gchar *v = g_variant_get_string (value, &len);
2720 : 14674 : g_assert (g_variant_is_object_path (v));
2721 : 14674 : g_memory_buffer_put_uint32 (mbuf, len);
2722 : 14674 : g_memory_buffer_put_string (mbuf, v);
2723 : 14674 : g_memory_buffer_put_byte (mbuf, '\0');
2724 : : }
2725 : 14737 : break;
2726 : :
2727 : 11941 : case 'g': /* G_VARIANT_TYPE_SIGNATURE */
2728 : 11941 : if (value != NULL)
2729 : : {
2730 : : gsize len;
2731 : 11878 : const gchar *v = g_variant_get_string (value, &len);
2732 : 11878 : g_assert (g_variant_is_signature (v));
2733 : 11878 : g_memory_buffer_put_byte (mbuf, len);
2734 : 11878 : g_memory_buffer_put_string (mbuf, v);
2735 : 11878 : g_memory_buffer_put_byte (mbuf, '\0');
2736 : : }
2737 : 11941 : break;
2738 : :
2739 : 9 : case 'h': /* G_VARIANT_TYPE_HANDLE */
2740 : 9 : padding_added = ensure_output_padding (mbuf, 4);
2741 : 9 : if (value != NULL)
2742 : : {
2743 : 9 : gint32 v = g_variant_get_handle (value);
2744 : 9 : g_memory_buffer_put_int32 (mbuf, v);
2745 : : }
2746 : 9 : break;
2747 : :
2748 : 21381 : case 'a': /* G_VARIANT_TYPE_ARRAY */
2749 : : {
2750 : : const GVariantType *element_type;
2751 : : GVariant *item;
2752 : : GVariantIter iter;
2753 : : goffset array_len_offset;
2754 : : goffset array_payload_begin_offset;
2755 : : goffset cur_offset;
2756 : : gsize array_len;
2757 : : guint fixed_size;
2758 : :
2759 : 21381 : padding_added = ensure_output_padding (mbuf, 4);
2760 : 21381 : if (value != NULL)
2761 : : {
2762 : : /* array length - will be filled in later */
2763 : 21287 : array_len_offset = mbuf->valid_len;
2764 : 21287 : g_memory_buffer_put_uint32 (mbuf, 0xF00DFACE);
2765 : :
2766 : : /* From the D-Bus spec:
2767 : : *
2768 : : * "A UINT32 giving the length of the array data in bytes,
2769 : : * followed by alignment padding to the alignment boundary of
2770 : : * the array element type, followed by each array element. The
2771 : : * array length is from the end of the alignment padding to
2772 : : * the end of the last element, i.e. it does not include the
2773 : : * padding after the length, or any padding after the last
2774 : : * element."
2775 : : *
2776 : : * Thus, we need to count how much padding the first element
2777 : : * contributes and subtract that from the array length.
2778 : : */
2779 : 21287 : array_payload_begin_offset = mbuf->valid_len;
2780 : :
2781 : 21287 : element_type = g_variant_type_element (type);
2782 : 21287 : fixed_size = get_type_fixed_size (element_type);
2783 : :
2784 : 21287 : if (g_variant_n_children (value) == 0)
2785 : : {
2786 : : gsize padding_added_for_item;
2787 : 541 : if (!append_value_to_blob (NULL,
2788 : : element_type,
2789 : : mbuf,
2790 : : &padding_added_for_item,
2791 : : error))
2792 : 0 : goto fail;
2793 : 541 : array_payload_begin_offset += padding_added_for_item;
2794 : : }
2795 : 20746 : else if (fixed_size != 0)
2796 : : {
2797 : : GVariant *use_value;
2798 : :
2799 : 689 : if (g_memory_buffer_is_byteswapped (mbuf))
2800 : 3 : use_value = g_variant_byteswap (value);
2801 : : else
2802 : 686 : use_value = g_variant_ref (value);
2803 : :
2804 : 689 : array_payload_begin_offset += ensure_output_padding (mbuf, fixed_size);
2805 : :
2806 : 689 : array_len = g_variant_get_size (use_value);
2807 : 689 : g_memory_buffer_write (mbuf, g_variant_get_data (use_value), array_len);
2808 : 689 : g_variant_unref (use_value);
2809 : : }
2810 : : else
2811 : : {
2812 : : guint n;
2813 : 20057 : n = 0;
2814 : 20057 : g_variant_iter_init (&iter, value);
2815 : 100360 : while ((item = g_variant_iter_next_value (&iter)) != NULL)
2816 : : {
2817 : : gsize padding_added_for_item;
2818 : 80304 : if (!append_value_to_blob (item,
2819 : : g_variant_get_type (item),
2820 : : mbuf,
2821 : : &padding_added_for_item,
2822 : : error))
2823 : : {
2824 : 1 : g_variant_unref (item);
2825 : 1 : goto fail;
2826 : : }
2827 : 80303 : g_variant_unref (item);
2828 : 80303 : if (n == 0)
2829 : : {
2830 : 20056 : array_payload_begin_offset += padding_added_for_item;
2831 : : }
2832 : 80303 : n++;
2833 : : }
2834 : : }
2835 : :
2836 : 21286 : cur_offset = mbuf->valid_len;
2837 : 21286 : array_len = cur_offset - array_payload_begin_offset;
2838 : 21286 : mbuf->pos = array_len_offset;
2839 : :
2840 : 21286 : g_memory_buffer_put_uint32 (mbuf, array_len);
2841 : 21286 : mbuf->pos = cur_offset;
2842 : : }
2843 : : }
2844 : 21380 : break;
2845 : :
2846 : 157113 : default:
2847 : 157113 : if (g_variant_type_is_dict_entry (type) || g_variant_type_is_tuple (type))
2848 : : {
2849 : 79096 : if (!g_variant_type_first (type))
2850 : : {
2851 : 1 : g_set_error_literal (error,
2852 : : G_IO_ERROR,
2853 : : G_IO_ERROR_INVALID_ARGUMENT,
2854 : : _("Empty structures (tuples) are not allowed in D-Bus"));
2855 : 1 : goto fail;
2856 : : }
2857 : :
2858 : 79095 : padding_added = ensure_output_padding (mbuf, 8);
2859 : 79095 : if (value != NULL)
2860 : : {
2861 : : GVariant *item;
2862 : : GVariantIter iter;
2863 : 78999 : g_variant_iter_init (&iter, value);
2864 : 238317 : while ((item = g_variant_iter_next_value (&iter)) != NULL)
2865 : : {
2866 : 159318 : if (!append_value_to_blob (item,
2867 : : g_variant_get_type (item),
2868 : : mbuf,
2869 : : NULL,
2870 : : error))
2871 : : {
2872 : 0 : g_variant_unref (item);
2873 : 0 : goto fail;
2874 : : }
2875 : 159318 : g_variant_unref (item);
2876 : : }
2877 : : }
2878 : : }
2879 : 78017 : else if (g_variant_type_is_variant (type))
2880 : : {
2881 : 78017 : if (value != NULL)
2882 : : {
2883 : : GVariant *child;
2884 : : const gchar *signature;
2885 : 77993 : child = g_variant_get_child_value (value, 0);
2886 : 77993 : signature = g_variant_get_type_string (child);
2887 : 77993 : g_memory_buffer_put_byte (mbuf, (guint8) strlen (signature)); /* signature is already validated to be this short */
2888 : 77993 : g_memory_buffer_put_string (mbuf, signature);
2889 : 77993 : g_memory_buffer_put_byte (mbuf, '\0');
2890 : 77993 : if (!append_value_to_blob (child,
2891 : : g_variant_get_type (child),
2892 : : mbuf,
2893 : : NULL,
2894 : : error))
2895 : : {
2896 : 0 : g_variant_unref (child);
2897 : 0 : goto fail;
2898 : : }
2899 : 77993 : g_variant_unref (child);
2900 : : }
2901 : : }
2902 : : else
2903 : : {
2904 : 0 : g_set_error (error,
2905 : : G_IO_ERROR,
2906 : : G_IO_ERROR_INVALID_ARGUMENT,
2907 : : _("Error serializing GVariant with type string “%s” to the D-Bus wire format"),
2908 : : g_variant_get_type_string (value));
2909 : 0 : goto fail;
2910 : : }
2911 : 157112 : break;
2912 : : }
2913 : :
2914 : 350414 : if (out_padding_added != NULL)
2915 : 80844 : *out_padding_added = padding_added;
2916 : :
2917 : 350414 : return TRUE;
2918 : :
2919 : 2 : fail:
2920 : 2 : return FALSE;
2921 : : }
2922 : :
2923 : : static gboolean
2924 : 11760 : append_body_to_blob (GVariant *value,
2925 : : GMemoryBuffer *mbuf,
2926 : : GError **error)
2927 : : {
2928 : : GVariant *item;
2929 : : GVariantIter iter;
2930 : :
2931 : 11760 : if (!g_variant_is_of_type (value, G_VARIANT_TYPE_TUPLE))
2932 : : {
2933 : 0 : g_set_error (error,
2934 : : G_IO_ERROR,
2935 : : G_IO_ERROR_INVALID_ARGUMENT,
2936 : : "Expected a tuple for the body of the GDBusMessage.");
2937 : 0 : goto fail;
2938 : : }
2939 : :
2940 : 11760 : g_variant_iter_init (&iter, value);
2941 : 27004 : while ((item = g_variant_iter_next_value (&iter)) != NULL)
2942 : : {
2943 : 15245 : if (!append_value_to_blob (item,
2944 : : g_variant_get_type (item),
2945 : : mbuf,
2946 : : NULL,
2947 : : error))
2948 : : {
2949 : 1 : g_variant_unref (item);
2950 : 1 : goto fail;
2951 : : }
2952 : 15244 : g_variant_unref (item);
2953 : : }
2954 : 11759 : return TRUE;
2955 : :
2956 : 1 : fail:
2957 : 1 : return FALSE;
2958 : : }
2959 : :
2960 : : /* ---------------------------------------------------------------------------------------------------- */
2961 : :
2962 : : /**
2963 : : * g_dbus_message_to_blob:
2964 : : * @message: a D-Bus message
2965 : : * @out_size: (out caller-allocates): return location for size of generated blob, in bytes
2966 : : * @capabilities: flags describing what protocol features are supported
2967 : : * @error: return location for error
2968 : : *
2969 : : * Serializes @message to a blob.
2970 : : *
2971 : : * The byte order returned by [method@Gio.DBusMessage.get_byte_order] will be
2972 : : * used.
2973 : : *
2974 : : * Returns: (array length=out_size) (transfer full): A pointer to a
2975 : : * valid binary D-Bus message of @out_size bytes generated by @message
2976 : : * Since: 2.26
2977 : : */
2978 : : guchar *
2979 : 17039 : g_dbus_message_to_blob (GDBusMessage *message,
2980 : : gsize *out_size,
2981 : : GDBusCapabilityFlags capabilities,
2982 : : GError **error)
2983 : : {
2984 : : GMemoryBuffer mbuf;
2985 : : guchar *ret;
2986 : : gsize size;
2987 : : goffset body_len_offset;
2988 : : goffset body_start_offset;
2989 : : gsize body_size;
2990 : : GVariant *header_fields;
2991 : : GVariantBuilder builder;
2992 : : GHashTableIter hash_iter;
2993 : : gpointer key;
2994 : : GVariant *header_value;
2995 : : GVariant *signature;
2996 : : const gchar *signature_str;
2997 : : gint num_fds_in_message;
2998 : : gint num_fds_according_to_header;
2999 : :
3000 : : /* TODO: check against @capabilities */
3001 : :
3002 : 17039 : ret = NULL;
3003 : :
3004 : 17039 : g_return_val_if_fail (G_IS_DBUS_MESSAGE (message), NULL);
3005 : 17039 : g_return_val_if_fail (out_size != NULL, NULL);
3006 : 17039 : g_return_val_if_fail (error == NULL || *error == NULL, NULL);
3007 : :
3008 : 17039 : memset (&mbuf, 0, sizeof (mbuf));
3009 : 17039 : mbuf.len = MIN_ARRAY_SIZE;
3010 : 17039 : mbuf.data = g_malloc (mbuf.len);
3011 : :
3012 : 17039 : mbuf.byte_order = G_DATA_STREAM_BYTE_ORDER_HOST_ENDIAN;
3013 : 17039 : switch (message->byte_order)
3014 : : {
3015 : 12 : case G_DBUS_MESSAGE_BYTE_ORDER_BIG_ENDIAN:
3016 : 12 : mbuf.byte_order = G_DATA_STREAM_BYTE_ORDER_BIG_ENDIAN;
3017 : 12 : break;
3018 : 17027 : case G_DBUS_MESSAGE_BYTE_ORDER_LITTLE_ENDIAN:
3019 : 17027 : mbuf.byte_order = G_DATA_STREAM_BYTE_ORDER_LITTLE_ENDIAN;
3020 : 17027 : break;
3021 : : }
3022 : :
3023 : : /* Core header */
3024 : 17039 : g_memory_buffer_put_byte (&mbuf, (guchar) message->byte_order);
3025 : 17039 : g_memory_buffer_put_byte (&mbuf, message->type);
3026 : 17039 : g_memory_buffer_put_byte (&mbuf, message->flags);
3027 : 17039 : g_memory_buffer_put_byte (&mbuf, 1); /* major protocol version */
3028 : 17039 : body_len_offset = mbuf.valid_len;
3029 : : /* body length - will be filled in later */
3030 : 17039 : g_memory_buffer_put_uint32 (&mbuf, 0xF00DFACE);
3031 : 17039 : g_memory_buffer_put_uint32 (&mbuf, message->serial);
3032 : :
3033 : 17039 : num_fds_in_message = 0;
3034 : : #ifdef G_OS_UNIX
3035 : 17039 : if (message->fd_list != NULL)
3036 : 25 : num_fds_in_message = g_unix_fd_list_get_length (message->fd_list);
3037 : : #endif
3038 : 17039 : num_fds_according_to_header = g_dbus_message_get_num_unix_fds (message);
3039 : 17039 : if (num_fds_in_message != num_fds_according_to_header)
3040 : : {
3041 : 0 : g_set_error (error,
3042 : : G_IO_ERROR,
3043 : : G_IO_ERROR_INVALID_ARGUMENT,
3044 : : _("Number of file descriptors in message (%d) differs from header field (%d)"),
3045 : : num_fds_in_message,
3046 : : num_fds_according_to_header);
3047 : 0 : goto out;
3048 : : }
3049 : :
3050 : 17039 : if (!validate_headers (message, error))
3051 : : {
3052 : 24 : g_prefix_error (error, _("Cannot serialize message: "));
3053 : 24 : goto out;
3054 : : }
3055 : :
3056 : 17015 : g_variant_builder_init_static (&builder, G_VARIANT_TYPE ("a{yv}"));
3057 : 17015 : g_hash_table_iter_init (&hash_iter, message->headers);
3058 : 91781 : while (g_hash_table_iter_next (&hash_iter, &key, (gpointer) &header_value))
3059 : : {
3060 : 74766 : g_variant_builder_add (&builder,
3061 : : "{yv}",
3062 : 74766 : (guchar) GPOINTER_TO_UINT (key),
3063 : : header_value);
3064 : : }
3065 : 17015 : header_fields = g_variant_builder_end (&builder);
3066 : :
3067 : 17015 : if (!append_value_to_blob (header_fields,
3068 : : g_variant_get_type (header_fields),
3069 : : &mbuf,
3070 : : NULL,
3071 : : error))
3072 : : {
3073 : 0 : g_variant_unref (header_fields);
3074 : 0 : goto out;
3075 : : }
3076 : 17015 : g_variant_unref (header_fields);
3077 : :
3078 : : /* header size must be a multiple of 8 */
3079 : 17015 : ensure_output_padding (&mbuf, 8);
3080 : :
3081 : 17015 : body_start_offset = mbuf.valid_len;
3082 : :
3083 : 17015 : signature = g_dbus_message_get_header (message, G_DBUS_MESSAGE_HEADER_FIELD_SIGNATURE);
3084 : :
3085 : 17015 : if (signature != NULL && !g_variant_is_of_type (signature, G_VARIANT_TYPE_SIGNATURE))
3086 : : {
3087 : 0 : g_set_error_literal (error,
3088 : : G_IO_ERROR,
3089 : : G_IO_ERROR_INVALID_ARGUMENT,
3090 : : _("Signature header found but is not of type signature"));
3091 : 0 : goto out;
3092 : : }
3093 : :
3094 : 17015 : signature_str = NULL;
3095 : 17015 : if (signature != NULL)
3096 : 11762 : signature_str = g_variant_get_string (signature, NULL);
3097 : 17015 : if (message->body != NULL)
3098 : : {
3099 : : gchar *tupled_signature_str;
3100 : 11760 : if (signature == NULL)
3101 : : {
3102 : 0 : g_set_error (error,
3103 : : G_IO_ERROR,
3104 : : G_IO_ERROR_INVALID_ARGUMENT,
3105 : : _("Message body has signature “%s” but there is no signature header"),
3106 : : g_variant_get_type_string (message->body));
3107 : 0 : goto out;
3108 : : }
3109 : 11760 : tupled_signature_str = g_strdup_printf ("(%s)", signature_str);
3110 : 11760 : if (g_strcmp0 (tupled_signature_str, g_variant_get_type_string (message->body)) != 0)
3111 : : {
3112 : 0 : g_set_error (error,
3113 : : G_IO_ERROR,
3114 : : G_IO_ERROR_INVALID_ARGUMENT,
3115 : : _("Message body has type signature “%s” but signature in the header field is “%s”"),
3116 : : g_variant_get_type_string (message->body), tupled_signature_str);
3117 : 0 : g_free (tupled_signature_str);
3118 : 0 : goto out;
3119 : : }
3120 : 11760 : g_free (tupled_signature_str);
3121 : 11760 : if (!append_body_to_blob (message->body, &mbuf, error))
3122 : 1 : goto out;
3123 : : }
3124 : : else
3125 : : {
3126 : 5255 : if (signature != NULL && strlen (signature_str) > 0)
3127 : : {
3128 : 0 : g_set_error (error,
3129 : : G_IO_ERROR,
3130 : : G_IO_ERROR_INVALID_ARGUMENT,
3131 : : _("Message body is empty but signature in the header field is “(%s)”"),
3132 : : signature_str);
3133 : 0 : goto out;
3134 : : }
3135 : : }
3136 : :
3137 : : /* OK, we're done writing the message - set the body length */
3138 : 17014 : size = mbuf.valid_len;
3139 : 17014 : body_size = size - body_start_offset;
3140 : :
3141 : 17014 : mbuf.pos = body_len_offset;
3142 : :
3143 : 17014 : g_memory_buffer_put_uint32 (&mbuf, body_size);
3144 : :
3145 : 17014 : *out_size = size;
3146 : 17014 : ret = (guchar *)mbuf.data;
3147 : :
3148 : 17039 : out:
3149 : 17039 : if (ret == NULL)
3150 : 25 : g_free (mbuf.data);
3151 : :
3152 : 17039 : return ret;
3153 : : }
3154 : :
3155 : : /* ---------------------------------------------------------------------------------------------------- */
3156 : :
3157 : : static guint32
3158 : 30048 : get_uint32_header (GDBusMessage *message,
3159 : : GDBusMessageHeaderField header_field)
3160 : : {
3161 : : GVariant *value;
3162 : : guint32 ret;
3163 : :
3164 : 30048 : ret = 0;
3165 : 30048 : value = g_hash_table_lookup (message->headers, GUINT_TO_POINTER (header_field));
3166 : 30048 : if (value != NULL && g_variant_is_of_type (value, G_VARIANT_TYPE_UINT32))
3167 : 13034 : ret = g_variant_get_uint32 (value);
3168 : :
3169 : 30048 : return ret;
3170 : : }
3171 : :
3172 : : static const gchar *
3173 : 101681 : get_string_header (GDBusMessage *message,
3174 : : GDBusMessageHeaderField header_field)
3175 : : {
3176 : : GVariant *value;
3177 : : const gchar *ret;
3178 : :
3179 : 101681 : ret = NULL;
3180 : 101681 : value = g_hash_table_lookup (message->headers, GUINT_TO_POINTER (header_field));
3181 : 101681 : if (value != NULL && g_variant_is_of_type (value, G_VARIANT_TYPE_STRING))
3182 : 100947 : ret = g_variant_get_string (value, NULL);
3183 : :
3184 : 101681 : return ret;
3185 : : }
3186 : :
3187 : : static const gchar *
3188 : 39617 : get_object_path_header (GDBusMessage *message,
3189 : : GDBusMessageHeaderField header_field)
3190 : : {
3191 : : GVariant *value;
3192 : : const gchar *ret;
3193 : :
3194 : 39617 : ret = NULL;
3195 : 39617 : value = g_hash_table_lookup (message->headers, GUINT_TO_POINTER (header_field));
3196 : 39617 : if (value != NULL && g_variant_is_of_type (value, G_VARIANT_TYPE_OBJECT_PATH))
3197 : 39617 : ret = g_variant_get_string (value, NULL);
3198 : :
3199 : 39617 : return ret;
3200 : : }
3201 : :
3202 : : static const gchar *
3203 : 2648 : get_signature_header (GDBusMessage *message,
3204 : : GDBusMessageHeaderField header_field)
3205 : : {
3206 : : GVariant *value;
3207 : : const gchar *ret;
3208 : :
3209 : 2648 : ret = NULL;
3210 : 2648 : value = g_hash_table_lookup (message->headers, GUINT_TO_POINTER (header_field));
3211 : 2648 : if (value != NULL && g_variant_is_of_type (value, G_VARIANT_TYPE_SIGNATURE))
3212 : 2400 : ret = g_variant_get_string (value, NULL);
3213 : :
3214 : 2648 : return ret;
3215 : : }
3216 : :
3217 : : /* ---------------------------------------------------------------------------------------------------- */
3218 : :
3219 : : static void
3220 : 2633 : set_uint32_header (GDBusMessage *message,
3221 : : GDBusMessageHeaderField header_field,
3222 : : guint32 value)
3223 : : {
3224 : 2633 : g_dbus_message_set_header (message,
3225 : : header_field,
3226 : : g_variant_new_uint32 (value));
3227 : 2633 : }
3228 : :
3229 : : static void
3230 : 45949 : set_string_header (GDBusMessage *message,
3231 : : GDBusMessageHeaderField header_field,
3232 : : const gchar *value)
3233 : : {
3234 : 91894 : g_dbus_message_set_header (message,
3235 : : header_field,
3236 : 45945 : value == NULL ? NULL : g_variant_new_string (value));
3237 : 45949 : }
3238 : :
3239 : : static void
3240 : 14423 : set_object_path_header (GDBusMessage *message,
3241 : : GDBusMessageHeaderField header_field,
3242 : : const gchar *value)
3243 : : {
3244 : 28844 : g_dbus_message_set_header (message,
3245 : : header_field,
3246 : 14421 : value == NULL ? NULL : g_variant_new_object_path (value));
3247 : 14423 : }
3248 : :
3249 : : static void
3250 : 11748 : set_signature_header (GDBusMessage *message,
3251 : : GDBusMessageHeaderField header_field,
3252 : : const gchar *value)
3253 : : {
3254 : 23495 : g_dbus_message_set_header (message,
3255 : : header_field,
3256 : 11747 : value == NULL ? NULL : g_variant_new_signature (value));
3257 : 11748 : }
3258 : :
3259 : : /* ---------------------------------------------------------------------------------------------------- */
3260 : :
3261 : : /**
3262 : : * g_dbus_message_get_reply_serial:
3263 : : * @message: a D-Bus message
3264 : : *
3265 : : * Convenience getter for the [enum@Gio.DBusMessageHeaderField.REPLY_SERIAL]
3266 : : * header field.
3267 : : *
3268 : : * Returns: The value
3269 : : * Since: 2.26
3270 : : */
3271 : : guint32
3272 : 13009 : g_dbus_message_get_reply_serial (GDBusMessage *message)
3273 : : {
3274 : 13009 : g_return_val_if_fail (G_IS_DBUS_MESSAGE (message), 0);
3275 : 13009 : return get_uint32_header (message, G_DBUS_MESSAGE_HEADER_FIELD_REPLY_SERIAL);
3276 : : }
3277 : :
3278 : : /**
3279 : : * g_dbus_message_set_reply_serial:
3280 : : * @message: a D-Bus message
3281 : : * @value: the value to set
3282 : : *
3283 : : * Convenience setter for the [enum@Gio.DBusMessageHeaderField.REPLY_SERIAL]
3284 : : * header field.
3285 : : *
3286 : : * Since: 2.26
3287 : : */
3288 : : void
3289 : 2586 : g_dbus_message_set_reply_serial (GDBusMessage *message,
3290 : : guint32 value)
3291 : : {
3292 : 2586 : g_return_if_fail (G_IS_DBUS_MESSAGE (message));
3293 : 2586 : set_uint32_header (message, G_DBUS_MESSAGE_HEADER_FIELD_REPLY_SERIAL, value);
3294 : : }
3295 : :
3296 : : /* ---------------------------------------------------------------------------------------------------- */
3297 : :
3298 : : /**
3299 : : * g_dbus_message_get_interface:
3300 : : * @message: a D-Bus message
3301 : : *
3302 : : * Convenience getter for the [enum@Gio.DBusMessageHeaderField.INTERFACE] header
3303 : : * field.
3304 : : *
3305 : : * Returns: (nullable): The value
3306 : : * Since: 2.26
3307 : : */
3308 : : const gchar *
3309 : 40502 : g_dbus_message_get_interface (GDBusMessage *message)
3310 : : {
3311 : 40502 : g_return_val_if_fail (G_IS_DBUS_MESSAGE (message), NULL);
3312 : 40502 : return get_string_header (message, G_DBUS_MESSAGE_HEADER_FIELD_INTERFACE);
3313 : : }
3314 : :
3315 : : /**
3316 : : * g_dbus_message_set_interface:
3317 : : * @message: a D-Bus message
3318 : : * @value: (nullable): the value to set
3319 : : *
3320 : : * Convenience setter for the [enum@Gio.DBusMessageHeaderField.INTERFACE] header
3321 : : * field.
3322 : : *
3323 : : * Since: 2.26
3324 : : */
3325 : : void
3326 : 14419 : g_dbus_message_set_interface (GDBusMessage *message,
3327 : : const gchar *value)
3328 : : {
3329 : 14419 : g_return_if_fail (G_IS_DBUS_MESSAGE (message));
3330 : 14419 : g_return_if_fail (value == NULL || g_dbus_is_interface_name (value));
3331 : 14419 : set_string_header (message, G_DBUS_MESSAGE_HEADER_FIELD_INTERFACE, value);
3332 : : }
3333 : :
3334 : : /* ---------------------------------------------------------------------------------------------------- */
3335 : :
3336 : : /**
3337 : : * g_dbus_message_get_member:
3338 : : * @message: a D-Bus message
3339 : : *
3340 : : * Convenience getter for the [enum@Gio.DBusMessageHeaderField.MEMBER] header
3341 : : * field.
3342 : : *
3343 : : * Returns: (nullable): The value
3344 : : * Since: 2.26
3345 : : */
3346 : : const gchar *
3347 : 41553 : g_dbus_message_get_member (GDBusMessage *message)
3348 : : {
3349 : 41553 : g_return_val_if_fail (G_IS_DBUS_MESSAGE (message), NULL);
3350 : 41553 : return get_string_header (message, G_DBUS_MESSAGE_HEADER_FIELD_MEMBER);
3351 : : }
3352 : :
3353 : : /**
3354 : : * g_dbus_message_set_member:
3355 : : * @message: a D-Bus message
3356 : : * @value: (nullable): the value to set
3357 : : *
3358 : : * Convenience setter for the [enum@Gio.DBusMessageHeaderField.MEMBER] header
3359 : : * field.
3360 : : *
3361 : : * Since: 2.26
3362 : : */
3363 : : void
3364 : 14422 : g_dbus_message_set_member (GDBusMessage *message,
3365 : : const gchar *value)
3366 : : {
3367 : 14422 : g_return_if_fail (G_IS_DBUS_MESSAGE (message));
3368 : 14422 : g_return_if_fail (value == NULL || g_dbus_is_member_name (value));
3369 : 14422 : set_string_header (message, G_DBUS_MESSAGE_HEADER_FIELD_MEMBER, value);
3370 : : }
3371 : :
3372 : : /* ---------------------------------------------------------------------------------------------------- */
3373 : :
3374 : : /**
3375 : : * g_dbus_message_get_path:
3376 : : * @message: a D-Bus message
3377 : : *
3378 : : * Convenience getter for the [enum@Gio.DBusMessageHeaderField.PATH] header
3379 : : * field.
3380 : : *
3381 : : * Returns: (nullable): The value
3382 : : * Since: 2.26
3383 : : */
3384 : : const gchar *
3385 : 39617 : g_dbus_message_get_path (GDBusMessage *message)
3386 : : {
3387 : 39617 : g_return_val_if_fail (G_IS_DBUS_MESSAGE (message), NULL);
3388 : 39617 : return get_object_path_header (message, G_DBUS_MESSAGE_HEADER_FIELD_PATH);
3389 : : }
3390 : :
3391 : : /**
3392 : : * g_dbus_message_set_path:
3393 : : * @message: a D-Bus message
3394 : : * @value: (nullable): the value to set
3395 : : *
3396 : : * Convenience setter for the [enum@Gio.DBusMessageHeaderField.PATH] header
3397 : : * field.
3398 : : *
3399 : : * Since: 2.26
3400 : : */
3401 : : void
3402 : 14423 : g_dbus_message_set_path (GDBusMessage *message,
3403 : : const gchar *value)
3404 : : {
3405 : 14423 : g_return_if_fail (G_IS_DBUS_MESSAGE (message));
3406 : 14423 : g_return_if_fail (value == NULL || g_variant_is_object_path (value));
3407 : 14423 : set_object_path_header (message, G_DBUS_MESSAGE_HEADER_FIELD_PATH, value);
3408 : : }
3409 : :
3410 : : /* ---------------------------------------------------------------------------------------------------- */
3411 : :
3412 : : /**
3413 : : * g_dbus_message_get_sender:
3414 : : * @message: a D-Bus message
3415 : : *
3416 : : * Convenience getter for the [enum@Gio.DBusMessageHeaderField.SENDER] header
3417 : : * field.
3418 : : *
3419 : : * Returns: (nullable): The value
3420 : : * Since: 2.26
3421 : : */
3422 : : const gchar *
3423 : 17807 : g_dbus_message_get_sender (GDBusMessage *message)
3424 : : {
3425 : 17807 : g_return_val_if_fail (G_IS_DBUS_MESSAGE (message), NULL);
3426 : 17807 : return get_string_header (message, G_DBUS_MESSAGE_HEADER_FIELD_SENDER);
3427 : : }
3428 : :
3429 : : /**
3430 : : * g_dbus_message_set_sender:
3431 : : * @message: a D-Bus message
3432 : : * @value: (nullable): the value to set
3433 : : *
3434 : : * Convenience setter for the [enum@Gio.DBusMessageHeaderField.SENDER] header
3435 : : * field.
3436 : : *
3437 : : * Since: 2.26
3438 : : */
3439 : : void
3440 : 3 : g_dbus_message_set_sender (GDBusMessage *message,
3441 : : const gchar *value)
3442 : : {
3443 : 3 : g_return_if_fail (G_IS_DBUS_MESSAGE (message));
3444 : 3 : g_return_if_fail (value == NULL || g_dbus_is_name (value));
3445 : 3 : set_string_header (message, G_DBUS_MESSAGE_HEADER_FIELD_SENDER, value);
3446 : : }
3447 : :
3448 : : /* ---------------------------------------------------------------------------------------------------- */
3449 : :
3450 : : /**
3451 : : * g_dbus_message_get_destination:
3452 : : * @message: a D-Bus message
3453 : : *
3454 : : * Convenience getter for the [enum@Gio.DBusMessageHeaderField.DESTINATION]
3455 : : * header field.
3456 : : *
3457 : : * Returns: (nullable): The value
3458 : : * Since: 2.26
3459 : : */
3460 : : const gchar *
3461 : 0 : g_dbus_message_get_destination (GDBusMessage *message)
3462 : : {
3463 : 0 : g_return_val_if_fail (G_IS_DBUS_MESSAGE (message), NULL);
3464 : 0 : return get_string_header (message, G_DBUS_MESSAGE_HEADER_FIELD_DESTINATION);
3465 : : }
3466 : :
3467 : : /**
3468 : : * g_dbus_message_set_destination:
3469 : : * @message: a D-Bus message
3470 : : * @value: (nullable): the value to set
3471 : : *
3472 : : * Convenience setter for the [enum@Gio.DBusMessageHeaderField.DESTINATION]
3473 : : * header field.
3474 : : *
3475 : : * Since: 2.26
3476 : : */
3477 : : void
3478 : 15481 : g_dbus_message_set_destination (GDBusMessage *message,
3479 : : const gchar *value)
3480 : : {
3481 : 15481 : g_return_if_fail (G_IS_DBUS_MESSAGE (message));
3482 : 15481 : g_return_if_fail (value == NULL || g_dbus_is_name (value));
3483 : 15481 : set_string_header (message, G_DBUS_MESSAGE_HEADER_FIELD_DESTINATION, value);
3484 : : }
3485 : :
3486 : : /* ---------------------------------------------------------------------------------------------------- */
3487 : :
3488 : : /**
3489 : : * g_dbus_message_get_error_name:
3490 : : * @message: a D-Bus message
3491 : : *
3492 : : * Convenience getter for the [enum@Gio.DBusMessageHeaderField.ERROR_NAME]
3493 : : * header field.
3494 : : *
3495 : : * Returns: (nullable): The value
3496 : : * Since: 2.26
3497 : : */
3498 : : const gchar *
3499 : 1819 : g_dbus_message_get_error_name (GDBusMessage *message)
3500 : : {
3501 : 1819 : g_return_val_if_fail (G_IS_DBUS_MESSAGE (message), NULL);
3502 : 1819 : return get_string_header (message, G_DBUS_MESSAGE_HEADER_FIELD_ERROR_NAME);
3503 : : }
3504 : :
3505 : : /**
3506 : : * g_dbus_message_set_error_name:
3507 : : * @message: a D-Bus message
3508 : : * @value: (nullable): the value to set
3509 : : *
3510 : : * Convenience setter for the [enum@Gio.DBusMessageHeaderField.ERROR_NAME]
3511 : : * header field.
3512 : : *
3513 : : * Since: 2.26
3514 : : */
3515 : : void
3516 : 1624 : g_dbus_message_set_error_name (GDBusMessage *message,
3517 : : const gchar *value)
3518 : : {
3519 : 1624 : g_return_if_fail (G_IS_DBUS_MESSAGE (message));
3520 : 1624 : g_return_if_fail (value == NULL || g_dbus_is_error_name (value));
3521 : 1624 : set_string_header (message, G_DBUS_MESSAGE_HEADER_FIELD_ERROR_NAME, value);
3522 : : }
3523 : :
3524 : : /* ---------------------------------------------------------------------------------------------------- */
3525 : :
3526 : : /**
3527 : : * g_dbus_message_get_signature:
3528 : : * @message: a D-Bus message
3529 : : *
3530 : : * Convenience getter for the [enum@Gio.DBusMessageHeaderField.SIGNATURE header
3531 : : * field.
3532 : : *
3533 : : * This will always be non-`NULL`, but may be an empty string.
3534 : : *
3535 : : * Returns: (not nullable): The value
3536 : : * Since: 2.26
3537 : : */
3538 : : const gchar *
3539 : 2648 : g_dbus_message_get_signature (GDBusMessage *message)
3540 : : {
3541 : : const gchar *ret;
3542 : 2648 : g_return_val_if_fail (G_IS_DBUS_MESSAGE (message), NULL);
3543 : 2648 : ret = get_signature_header (message, G_DBUS_MESSAGE_HEADER_FIELD_SIGNATURE);
3544 : 2648 : if (ret == NULL)
3545 : 248 : ret = "";
3546 : 2648 : return ret;
3547 : : }
3548 : :
3549 : : /**
3550 : : * g_dbus_message_set_signature:
3551 : : * @message: a D-Bus message
3552 : : * @value: (nullable): the value to set
3553 : : *
3554 : : * Convenience setter for the [enum@Gio.DBusMessageHeaderField.SIGNATURE] header
3555 : : * field.
3556 : : *
3557 : : * Since: 2.26
3558 : : */
3559 : : void
3560 : 11748 : g_dbus_message_set_signature (GDBusMessage *message,
3561 : : const gchar *value)
3562 : : {
3563 : 11748 : g_return_if_fail (G_IS_DBUS_MESSAGE (message));
3564 : 11748 : g_return_if_fail (value == NULL || g_variant_is_signature (value));
3565 : 11748 : set_signature_header (message, G_DBUS_MESSAGE_HEADER_FIELD_SIGNATURE, value);
3566 : : }
3567 : :
3568 : : /* ---------------------------------------------------------------------------------------------------- */
3569 : :
3570 : : /**
3571 : : * g_dbus_message_get_arg0:
3572 : : * @message: a D-Bus message
3573 : : *
3574 : : * Convenience to get the first item in the body of @message.
3575 : : *
3576 : : * See [method@Gio.DBusMessage.get_arg0_path] for returning object-path-typed
3577 : : * arg0 values.
3578 : : *
3579 : : * Returns: (nullable): The string item, or `NULL` if the first item in the body
3580 : : * of @message is not a string
3581 : : * Since: 2.26
3582 : : */
3583 : : const gchar *
3584 : 20527 : g_dbus_message_get_arg0 (GDBusMessage *message)
3585 : : {
3586 : 20527 : g_return_val_if_fail (G_IS_DBUS_MESSAGE (message), NULL);
3587 : :
3588 : 40891 : if (message->arg0_cache != NULL &&
3589 : 20364 : g_variant_is_of_type (message->arg0_cache, G_VARIANT_TYPE_STRING))
3590 : 19889 : return g_variant_get_string (message->arg0_cache, NULL);
3591 : :
3592 : 638 : return NULL;
3593 : : }
3594 : :
3595 : : /**
3596 : : * g_dbus_message_get_arg0_path:
3597 : : * @message: a D-Bus message
3598 : : *
3599 : : * Convenience to get the first item in the body of @message.
3600 : : *
3601 : : * See [method@Gio.DBusMessage.get_arg0] for returning string-typed arg0 values.
3602 : : *
3603 : : * Returns: (nullable): The object path item, or `NULL` if the first item in the
3604 : : * body of @message is not an object path
3605 : : * Since: 2.80
3606 : : */
3607 : : const gchar *
3608 : 20527 : g_dbus_message_get_arg0_path (GDBusMessage *message)
3609 : : {
3610 : 20527 : g_return_val_if_fail (G_IS_DBUS_MESSAGE (message), NULL);
3611 : :
3612 : 40891 : if (message->arg0_cache != NULL &&
3613 : 20364 : g_variant_is_of_type (message->arg0_cache, G_VARIANT_TYPE_OBJECT_PATH))
3614 : 78 : return g_variant_get_string (message->arg0_cache, NULL);
3615 : :
3616 : 20449 : return NULL;
3617 : : }
3618 : :
3619 : : /* ---------------------------------------------------------------------------------------------------- */
3620 : :
3621 : : /**
3622 : : * g_dbus_message_get_num_unix_fds:
3623 : : * @message: a D-Bus message
3624 : : *
3625 : : * Convenience getter for the [enum@Gio.DBusMessageHeaderField.NUM_UNIX_FDS]
3626 : : * header field.
3627 : : *
3628 : : * Returns: The value
3629 : : * Since: 2.26
3630 : : */
3631 : : guint32
3632 : 17039 : g_dbus_message_get_num_unix_fds (GDBusMessage *message)
3633 : : {
3634 : 17039 : g_return_val_if_fail (G_IS_DBUS_MESSAGE (message), 0);
3635 : 17039 : return get_uint32_header (message, G_DBUS_MESSAGE_HEADER_FIELD_NUM_UNIX_FDS);
3636 : : }
3637 : :
3638 : : /**
3639 : : * g_dbus_message_set_num_unix_fds:
3640 : : * @message: a D-Bus message
3641 : : * @value: the value to set
3642 : : *
3643 : : * Convenience setter for the [enum@Gio.DBusMessageHeaderField.NUM_UNIX_FDS]
3644 : : * header field.
3645 : : *
3646 : : * Since: 2.26
3647 : : */
3648 : : void
3649 : 47 : g_dbus_message_set_num_unix_fds (GDBusMessage *message,
3650 : : guint32 value)
3651 : : {
3652 : 47 : g_return_if_fail (G_IS_DBUS_MESSAGE (message));
3653 : 47 : set_uint32_header (message, G_DBUS_MESSAGE_HEADER_FIELD_NUM_UNIX_FDS, value);
3654 : : }
3655 : :
3656 : : /* ---------------------------------------------------------------------------------------------------- */
3657 : :
3658 : : /**
3659 : : * g_dbus_message_to_gerror:
3660 : : * @message: a D-Bus message
3661 : : * @error: the [type@GLib.Error] to set
3662 : : *
3663 : : * Encodes the error in @message as a [type@GLib.Error].
3664 : : *
3665 : : * If @message is of type [enum@Gio.DBusMessageType.ERROR], this function
3666 : : * calls [func@Gio.DBusError.set_dbus_error] using the information in the
3667 : : * [enum@Gio.DBusMessageHeaderField.ERROR_NAME] header field of @message as
3668 : : * well as the first string item in @message’s body.
3669 : : *
3670 : : * If @message is not of type [enum@Gio.DBusMessageType.ERROR], this function
3671 : : * does nothing and returns false.
3672 : : *
3673 : : * Returns: true if @error was set, false otherwise
3674 : : * Since: 2.26
3675 : : */
3676 : : gboolean
3677 : 1806 : g_dbus_message_to_gerror (GDBusMessage *message,
3678 : : GError **error)
3679 : : {
3680 : : gboolean ret;
3681 : : const gchar *error_name;
3682 : :
3683 : 1806 : g_return_val_if_fail (G_IS_DBUS_MESSAGE (message), FALSE);
3684 : :
3685 : 1806 : ret = FALSE;
3686 : 1806 : if (message->type != G_DBUS_MESSAGE_TYPE_ERROR)
3687 : 0 : goto out;
3688 : :
3689 : 1806 : error_name = g_dbus_message_get_error_name (message);
3690 : 1806 : if (error_name != NULL)
3691 : : {
3692 : : GVariant *body;
3693 : :
3694 : 1806 : body = g_dbus_message_get_body (message);
3695 : :
3696 : 1806 : if (body != NULL && g_variant_is_of_type (body, G_VARIANT_TYPE ("(s)")))
3697 : 1806 : {
3698 : : const gchar *error_message;
3699 : 1806 : g_variant_get (body, "(&s)", &error_message);
3700 : 1806 : g_dbus_error_set_dbus_error (error,
3701 : : error_name,
3702 : : error_message,
3703 : : NULL);
3704 : : }
3705 : : else
3706 : : {
3707 : : /* these two situations are valid, yet pretty rare */
3708 : 0 : if (body != NULL)
3709 : : {
3710 : 0 : g_dbus_error_set_dbus_error (error,
3711 : : error_name,
3712 : : "",
3713 : : _("Error return with body of type “%s”"),
3714 : : g_variant_get_type_string (body));
3715 : : }
3716 : : else
3717 : : {
3718 : 0 : g_dbus_error_set_dbus_error (error,
3719 : : error_name,
3720 : : "",
3721 : : _("Error return with empty body"));
3722 : : }
3723 : : }
3724 : : }
3725 : : else
3726 : : {
3727 : : /* TODO: this shouldn't happen - should check this at message serialization
3728 : : * time and disconnect the peer.
3729 : : */
3730 : 0 : g_set_error (error,
3731 : : G_IO_ERROR,
3732 : : G_IO_ERROR_FAILED,
3733 : : "Error return without error-name header!");
3734 : : }
3735 : :
3736 : 1806 : ret = TRUE;
3737 : :
3738 : 1806 : out:
3739 : 1806 : return ret;
3740 : : }
3741 : :
3742 : : /* ---------------------------------------------------------------------------------------------------- */
3743 : :
3744 : : static gchar *
3745 : 0 : flags_to_string (GType flags_type, guint value)
3746 : : {
3747 : : GString *s;
3748 : : GFlagsClass *klass;
3749 : : guint n;
3750 : :
3751 : 0 : klass = g_type_class_ref (flags_type);
3752 : 0 : s = g_string_new (NULL);
3753 : 0 : for (n = 0; n < 32; n++)
3754 : : {
3755 : 0 : if ((value & (1<<n)) != 0)
3756 : : {
3757 : : GFlagsValue *flags_value;
3758 : 0 : flags_value = g_flags_get_first_value (klass, (1<<n));
3759 : 0 : if (s->len > 0)
3760 : : g_string_append_c (s, ',');
3761 : 0 : if (flags_value != NULL)
3762 : 0 : g_string_append (s, flags_value->value_nick);
3763 : : else
3764 : 0 : g_string_append_printf (s, "unknown (bit %d)", n);
3765 : : }
3766 : : }
3767 : 0 : if (s->len == 0)
3768 : 0 : g_string_append (s, "none");
3769 : 0 : g_type_class_unref (klass);
3770 : 0 : return g_string_free (s, FALSE);
3771 : : }
3772 : :
3773 : : static gint
3774 : 0 : _sort_keys_func (gconstpointer a,
3775 : : gconstpointer b)
3776 : : {
3777 : : gint ia;
3778 : : gint ib;
3779 : :
3780 : 0 : ia = GPOINTER_TO_INT (a);
3781 : 0 : ib = GPOINTER_TO_INT (b);
3782 : :
3783 : 0 : return ia - ib;
3784 : : }
3785 : :
3786 : : /**
3787 : : * g_dbus_message_print:
3788 : : * @message: a D-Bus message
3789 : : * @indent: indentation level
3790 : : *
3791 : : * Produces a human-readable multi-line description of @message.
3792 : : *
3793 : : * The contents and formatting are subject to change at any time and no ABI
3794 : : * guarantees are given. Typical output looks something like this:
3795 : : * ```
3796 : : * Type: method-call
3797 : : * Flags: none
3798 : : * Version: 0
3799 : : * Serial: 4
3800 : : * Headers:
3801 : : * path -> objectpath '/org/gtk/GDBus/TestObject'
3802 : : * interface -> 'org.gtk.GDBus.TestInterface'
3803 : : * member -> 'GimmeStdout'
3804 : : * destination -> ':1.146'
3805 : : * Body: ()
3806 : : * UNIX File Descriptors:
3807 : : * (none)
3808 : : * ```
3809 : : * or
3810 : : * ```
3811 : : * Type: method-return
3812 : : * Flags: no-reply-expected
3813 : : * Version: 0
3814 : : * Serial: 477
3815 : : * Headers:
3816 : : * reply-serial -> uint32 4
3817 : : * destination -> ':1.159'
3818 : : * sender -> ':1.146'
3819 : : * num-unix-fds -> uint32 1
3820 : : * Body: ()
3821 : : * UNIX File Descriptors:
3822 : : * fd 12: dev=0:10,mode=020620,ino=5,uid=500,gid=5,rdev=136:2,size=0,atime=1273085037,mtime=1273085851,ctime=1272982635
3823 : : * ```
3824 : : *
3825 : : * Returns: (not nullable) (transfer full): Human readable description
3826 : : * of @message
3827 : : * Since: 2.26
3828 : : */
3829 : : gchar *
3830 : 0 : g_dbus_message_print (GDBusMessage *message,
3831 : : guint indent)
3832 : : {
3833 : : GString *str;
3834 : : gchar *s;
3835 : : GList *keys;
3836 : : GList *l;
3837 : :
3838 : 0 : g_return_val_if_fail (G_IS_DBUS_MESSAGE (message), NULL);
3839 : :
3840 : 0 : str = g_string_new (NULL);
3841 : :
3842 : 0 : s = _g_dbus_enum_to_string (G_TYPE_DBUS_MESSAGE_TYPE, message->type);
3843 : 0 : g_string_append_printf (str, "%*sType: %s\n", indent, "", s);
3844 : 0 : g_free (s);
3845 : 0 : s = flags_to_string (G_TYPE_DBUS_MESSAGE_FLAGS, message->flags);
3846 : 0 : g_string_append_printf (str, "%*sFlags: %s\n", indent, "", s);
3847 : 0 : g_free (s);
3848 : 0 : g_string_append_printf (str, "%*sVersion: %d\n", indent, "", message->major_protocol_version);
3849 : 0 : g_string_append_printf (str, "%*sSerial: %d\n", indent, "", message->serial);
3850 : :
3851 : 0 : g_string_append_printf (str, "%*sHeaders:\n", indent, "");
3852 : 0 : keys = g_hash_table_get_keys (message->headers);
3853 : 0 : keys = g_list_sort (keys, _sort_keys_func);
3854 : 0 : if (keys != NULL)
3855 : : {
3856 : 0 : for (l = keys; l != NULL; l = l->next)
3857 : : {
3858 : 0 : gint key = GPOINTER_TO_INT (l->data);
3859 : : GVariant *value;
3860 : : gchar *value_str;
3861 : :
3862 : 0 : value = g_hash_table_lookup (message->headers, l->data);
3863 : 0 : g_assert (value != NULL);
3864 : :
3865 : 0 : s = _g_dbus_enum_to_string (G_TYPE_DBUS_MESSAGE_HEADER_FIELD, key);
3866 : 0 : value_str = g_variant_print (value, TRUE);
3867 : 0 : g_string_append_printf (str, "%*s %s -> %s\n", indent, "", s, value_str);
3868 : 0 : g_free (s);
3869 : 0 : g_free (value_str);
3870 : : }
3871 : : }
3872 : : else
3873 : : {
3874 : 0 : g_string_append_printf (str, "%*s (none)\n", indent, "");
3875 : : }
3876 : 0 : g_list_free (keys);
3877 : 0 : g_string_append_printf (str, "%*sBody: ", indent, "");
3878 : 0 : if (message->body != NULL)
3879 : : {
3880 : 0 : g_variant_print_string (message->body,
3881 : : str,
3882 : : TRUE);
3883 : : }
3884 : : else
3885 : : {
3886 : 0 : g_string_append (str, "()");
3887 : : }
3888 : 0 : g_string_append (str, "\n");
3889 : : #ifdef G_OS_UNIX
3890 : 0 : g_string_append_printf (str, "%*sUNIX File Descriptors:\n", indent, "");
3891 : 0 : if (message->fd_list != NULL)
3892 : : {
3893 : : gint num_fds;
3894 : : const gint *fds;
3895 : : gint n;
3896 : :
3897 : 0 : fds = g_unix_fd_list_peek_fds (message->fd_list, &num_fds);
3898 : 0 : if (num_fds > 0)
3899 : : {
3900 : 0 : for (n = 0; n < num_fds; n++)
3901 : : {
3902 : : GString *fs;
3903 : : struct stat statbuf;
3904 : 0 : fs = g_string_new (NULL);
3905 : 0 : if (fstat (fds[n], &statbuf) == 0)
3906 : : {
3907 : : #ifndef MAJOR_MINOR_NOT_FOUND
3908 : 0 : g_string_append_printf (fs, "%s" "dev=%d:%d", fs->len > 0 ? "," : "",
3909 : 0 : (gint) major (statbuf.st_dev), (gint) minor (statbuf.st_dev));
3910 : : #endif
3911 : 0 : g_string_append_printf (fs, "%s" "mode=0%o", fs->len > 0 ? "," : "",
3912 : 0 : (guint) statbuf.st_mode);
3913 : 0 : g_string_append_printf (fs, "%s" "ino=%" G_GUINT64_FORMAT, fs->len > 0 ? "," : "",
3914 : 0 : (guint64) statbuf.st_ino);
3915 : 0 : g_string_append_printf (fs, "%s" "uid=%u", fs->len > 0 ? "," : "",
3916 : 0 : (guint) statbuf.st_uid);
3917 : 0 : g_string_append_printf (fs, "%s" "gid=%u", fs->len > 0 ? "," : "",
3918 : 0 : (guint) statbuf.st_gid);
3919 : : #ifndef MAJOR_MINOR_NOT_FOUND
3920 : 0 : g_string_append_printf (fs, "%s" "rdev=%d:%d", fs->len > 0 ? "," : "",
3921 : 0 : (gint) major (statbuf.st_rdev), (gint) minor (statbuf.st_rdev));
3922 : : #endif
3923 : 0 : g_string_append_printf (fs, "%s" "size=%" G_GUINT64_FORMAT, fs->len > 0 ? "," : "",
3924 : 0 : (guint64) statbuf.st_size);
3925 : 0 : g_string_append_printf (fs, "%s" "atime=%" G_GUINT64_FORMAT, fs->len > 0 ? "," : "",
3926 : 0 : (guint64) statbuf.st_atime);
3927 : 0 : g_string_append_printf (fs, "%s" "mtime=%" G_GUINT64_FORMAT, fs->len > 0 ? "," : "",
3928 : 0 : (guint64) statbuf.st_mtime);
3929 : 0 : g_string_append_printf (fs, "%s" "ctime=%" G_GUINT64_FORMAT, fs->len > 0 ? "," : "",
3930 : 0 : (guint64) statbuf.st_ctime);
3931 : : }
3932 : : else
3933 : : {
3934 : 0 : int errsv = errno;
3935 : 0 : g_string_append_printf (fs, "(fstat failed: %s)", g_strerror (errsv));
3936 : : }
3937 : 0 : g_string_append_printf (str, "%*s fd %d: %s\n", indent, "", fds[n], fs->str);
3938 : 0 : g_string_free (fs, TRUE);
3939 : : }
3940 : : }
3941 : : else
3942 : : {
3943 : 0 : g_string_append_printf (str, "%*s (empty)\n", indent, "");
3944 : : }
3945 : : }
3946 : : else
3947 : : {
3948 : 0 : g_string_append_printf (str, "%*s (none)\n", indent, "");
3949 : : }
3950 : : #endif
3951 : :
3952 : 0 : return g_string_free (str, FALSE);
3953 : : }
3954 : :
3955 : : /**
3956 : : * g_dbus_message_get_locked:
3957 : : * @message: a D-Bus message
3958 : : *
3959 : : * Checks whether @message is locked.
3960 : : *
3961 : : * To monitor changes to this value, connect to the
3962 : : * [signal@GObject.Object::notify] signal to listen for changes on the
3963 : : * [property@Gio.DBusMessage:locked] property.
3964 : : *
3965 : : * Returns: true if @message is locked, false otherwise
3966 : : * Since: 2.26
3967 : : */
3968 : : gboolean
3969 : 20067 : g_dbus_message_get_locked (GDBusMessage *message)
3970 : : {
3971 : 20067 : g_return_val_if_fail (G_IS_DBUS_MESSAGE (message), FALSE);
3972 : 20067 : return message->locked;
3973 : : }
3974 : :
3975 : : /**
3976 : : * g_dbus_message_lock:
3977 : : * @message: a D-Bus message
3978 : : *
3979 : : * Locks the message.
3980 : : *
3981 : : * If @message is locked already, this does nothing.
3982 : : *
3983 : : * Since: 2.26
3984 : : */
3985 : : void
3986 : 46132 : g_dbus_message_lock (GDBusMessage *message)
3987 : : {
3988 : 46132 : g_return_if_fail (G_IS_DBUS_MESSAGE (message));
3989 : :
3990 : 46132 : if (message->locked)
3991 : 205 : goto out;
3992 : :
3993 : 45927 : message->locked = TRUE;
3994 : 45927 : g_object_notify (G_OBJECT (message), "locked");
3995 : :
3996 : 46132 : out:
3997 : : ;
3998 : : }
3999 : :
4000 : : /**
4001 : : * g_dbus_message_copy:
4002 : : * @message: a D-Bus message
4003 : : * @error: return location for error or `NULL`
4004 : : *
4005 : : * Copies @message with a deep copy.
4006 : : *
4007 : : * The returned D-Bus message is completely identical to @message except that it
4008 : : * is guaranteed to not be locked.
4009 : : *
4010 : : * This operation can fail if (for example) @message contains file descriptors
4011 : : * and the per-process or system-wide open files limit is reached.
4012 : : *
4013 : : * Returns: (transfer full): A new D-Bus message
4014 : : * Since: 2.26
4015 : : */
4016 : : GDBusMessage *
4017 : 7 : g_dbus_message_copy (GDBusMessage *message,
4018 : : GError **error)
4019 : : {
4020 : : GDBusMessage *ret;
4021 : : GHashTableIter iter;
4022 : : gpointer header_key;
4023 : : GVariant *header_value;
4024 : :
4025 : 7 : g_return_val_if_fail (G_IS_DBUS_MESSAGE (message), NULL);
4026 : 7 : g_return_val_if_fail (error == NULL || *error == NULL, NULL);
4027 : :
4028 : 7 : ret = g_dbus_message_new ();
4029 : 7 : ret->type = message->type;
4030 : 7 : ret->flags = message->flags;
4031 : 7 : ret->byte_order = message->byte_order;
4032 : 7 : ret->major_protocol_version = message->major_protocol_version;
4033 : 7 : ret->serial = message->serial;
4034 : :
4035 : : #ifdef G_OS_UNIX
4036 : 7 : if (message->fd_list != NULL)
4037 : : {
4038 : : gint n;
4039 : : gint num_fds;
4040 : : const gint *fds;
4041 : :
4042 : 0 : ret->fd_list = g_unix_fd_list_new ();
4043 : 0 : fds = g_unix_fd_list_peek_fds (message->fd_list, &num_fds);
4044 : 0 : for (n = 0; n < num_fds; n++)
4045 : : {
4046 : 0 : if (g_unix_fd_list_append (ret->fd_list,
4047 : 0 : fds[n],
4048 : : error) == -1)
4049 : : {
4050 : 0 : g_object_unref (ret);
4051 : 0 : ret = NULL;
4052 : 0 : goto out;
4053 : : }
4054 : : }
4055 : : }
4056 : : #endif
4057 : :
4058 : : /* see https://bugzilla.gnome.org/show_bug.cgi?id=624546#c8 for why it's fine
4059 : : * to just ref (as opposed to deep-copying) the GVariant instances
4060 : : */
4061 : 7 : ret->body = message->body != NULL ? g_variant_ref (message->body) : NULL;
4062 : 7 : ret->arg0_cache = message->arg0_cache != NULL ? g_variant_ref (message->arg0_cache) : NULL;
4063 : 7 : g_hash_table_iter_init (&iter, message->headers);
4064 : 40 : while (g_hash_table_iter_next (&iter, &header_key, (gpointer) &header_value))
4065 : 33 : g_hash_table_insert (ret->headers, header_key, g_variant_ref (header_value));
4066 : :
4067 : : #ifdef G_OS_UNIX
4068 : 7 : out:
4069 : : #endif
4070 : 7 : return ret;
4071 : : }
|