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