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