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