[kdbus] KDBUS_ITEM_PAYLOAD_OFF items are (once again) relative to msg header
[platform/upstream/glib.git] / gio / tests / gdbus-serialization.c
1 /* GLib testing framework examples and tests
2  *
3  * Copyright (C) 2008-2010 Red Hat, Inc.
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Lesser General Public
7  * License as published by the Free Software Foundation; either
8  * version 2 of the License, or (at your option) any later version.
9  *
10  * This library is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * Lesser General Public License for more details.
14  *
15  * You should have received a copy of the GNU Lesser General
16  * Public License along with this library; if not, see <http://www.gnu.org/licenses/>.
17  *
18  * Author: David Zeuthen <davidz@redhat.com>
19  */
20
21 #include <locale.h>
22 #include <gio/gio.h>
23
24 #include <string.h>
25 #include <unistd.h>
26 #include <dbus/dbus.h>
27
28 /* ---------------------------------------------------------------------------------------------------- */
29
30 static void
31 hexdump (const guchar *str, gsize len)
32 {
33   const guchar *data = (const guchar *) str;
34   guint n, m;
35
36   for (n = 0; n < len; n += 16)
37     {
38       g_printerr ("%04x: ", n);
39
40       for (m = n; m < n + 16; m++)
41         {
42           if (m > n && (m%4) == 0)
43             g_printerr (" ");
44           if (m < len)
45             g_printerr ("%02x ", data[m]);
46           else
47             g_printerr ("   ");
48         }
49
50       g_printerr ("   ");
51
52       for (m = n; m < len && m < n + 16; m++)
53         g_printerr ("%c", g_ascii_isprint (data[m]) ? data[m] : '.');
54
55       g_printerr ("\n");
56     }
57 }
58
59 /* ---------------------------------------------------------------------------------------------------- */
60
61 static gboolean
62 append_gv_to_dbus_iter (DBusMessageIter  *iter,
63                         GVariant         *value,
64                         GError          **error)
65 {
66   const GVariantType *type;
67
68   type = g_variant_get_type (value);
69   if (g_variant_type_equal (type, G_VARIANT_TYPE_BOOLEAN))
70     {
71       dbus_bool_t v = g_variant_get_boolean (value);
72       dbus_message_iter_append_basic (iter, DBUS_TYPE_BOOLEAN, &v);
73     }
74   else if (g_variant_type_equal (type, G_VARIANT_TYPE_BYTE))
75     {
76       guint8 v = g_variant_get_byte (value);
77       dbus_message_iter_append_basic (iter, DBUS_TYPE_BYTE, &v);
78     }
79   else if (g_variant_type_equal (type, G_VARIANT_TYPE_INT16))
80     {
81       gint16 v = g_variant_get_int16 (value);
82       dbus_message_iter_append_basic (iter, DBUS_TYPE_INT16, &v);
83     }
84   else if (g_variant_type_equal (type, G_VARIANT_TYPE_UINT16))
85     {
86       guint16 v = g_variant_get_uint16 (value);
87       dbus_message_iter_append_basic (iter, DBUS_TYPE_UINT16, &v);
88     }
89   else if (g_variant_type_equal (type, G_VARIANT_TYPE_INT32))
90     {
91       gint32 v = g_variant_get_int32 (value);
92       dbus_message_iter_append_basic (iter, DBUS_TYPE_INT32, &v);
93     }
94   else if (g_variant_type_equal (type, G_VARIANT_TYPE_UINT32))
95     {
96       guint32 v = g_variant_get_uint32 (value);
97       dbus_message_iter_append_basic (iter, DBUS_TYPE_UINT32, &v);
98     }
99   else if (g_variant_type_equal (type, G_VARIANT_TYPE_INT64))
100     {
101       gint64 v = g_variant_get_int64 (value);
102       dbus_message_iter_append_basic (iter, DBUS_TYPE_INT64, &v);
103     }
104   else if (g_variant_type_equal (type, G_VARIANT_TYPE_UINT64))
105     {
106       guint64 v = g_variant_get_uint64 (value);
107       dbus_message_iter_append_basic (iter, DBUS_TYPE_UINT64, &v);
108     }
109   else if (g_variant_type_equal (type, G_VARIANT_TYPE_DOUBLE))
110     {
111       gdouble v = g_variant_get_double (value);
112       dbus_message_iter_append_basic (iter, DBUS_TYPE_DOUBLE, &v);
113     }
114   else if (g_variant_type_equal (type, G_VARIANT_TYPE_STRING))
115     {
116       const gchar *v = g_variant_get_string (value, NULL);
117       dbus_message_iter_append_basic (iter, DBUS_TYPE_STRING, &v);
118     }
119   else if (g_variant_type_equal (type, G_VARIANT_TYPE_OBJECT_PATH))
120     {
121       const gchar *v = g_variant_get_string (value, NULL);
122       dbus_message_iter_append_basic (iter, DBUS_TYPE_OBJECT_PATH, &v);
123     }
124   else if (g_variant_type_equal (type, G_VARIANT_TYPE_SIGNATURE))
125     {
126       const gchar *v = g_variant_get_string (value, NULL);
127       dbus_message_iter_append_basic (iter, DBUS_TYPE_SIGNATURE, &v);
128     }
129   else if (g_variant_type_is_variant (type))
130     {
131       DBusMessageIter sub;
132       GVariant *child;
133
134       child = g_variant_get_child_value (value, 0);
135       dbus_message_iter_open_container (iter, DBUS_TYPE_VARIANT,
136                                         g_variant_get_type_string (child),
137                                         &sub);
138       if (!append_gv_to_dbus_iter (&sub, child, error))
139         {
140             g_variant_unref (child);
141             goto fail;
142         }
143       dbus_message_iter_close_container (iter, &sub);
144       g_variant_unref (child);
145     }
146   else if (g_variant_type_is_array (type))
147     {
148       DBusMessageIter dbus_iter;
149       const gchar *type_string;
150       GVariantIter gv_iter;
151       GVariant *item;
152
153       type_string = g_variant_get_type_string (value);
154       type_string++; /* skip the 'a' */
155
156       dbus_message_iter_open_container (iter, DBUS_TYPE_ARRAY,
157                                         type_string, &dbus_iter);
158       g_variant_iter_init (&gv_iter, value);
159
160       while ((item = g_variant_iter_next_value (&gv_iter)))
161         {
162           if (!append_gv_to_dbus_iter (&dbus_iter, item, error))
163             {
164               goto fail;
165             }
166         }
167
168       dbus_message_iter_close_container (iter, &dbus_iter);
169     }
170   else if (g_variant_type_is_tuple (type))
171     {
172       DBusMessageIter dbus_iter;
173       GVariantIter gv_iter;
174       GVariant *item;
175
176       dbus_message_iter_open_container (iter, DBUS_TYPE_STRUCT,
177                                         NULL, &dbus_iter);
178       g_variant_iter_init (&gv_iter, value);
179
180       while ((item = g_variant_iter_next_value (&gv_iter)))
181         {
182           if (!append_gv_to_dbus_iter (&dbus_iter, item, error))
183             goto fail;
184         }
185
186       dbus_message_iter_close_container (iter, &dbus_iter);
187     }
188   else if (g_variant_type_is_dict_entry (type))
189     {
190       DBusMessageIter dbus_iter;
191       GVariant *key, *val;
192
193       dbus_message_iter_open_container (iter, DBUS_TYPE_DICT_ENTRY,
194                                         NULL, &dbus_iter);
195       key = g_variant_get_child_value (value, 0);
196       if (!append_gv_to_dbus_iter (&dbus_iter, key, error))
197         {
198           g_variant_unref (key);
199           goto fail;
200         }
201       g_variant_unref (key);
202
203       val = g_variant_get_child_value (value, 1);
204       if (!append_gv_to_dbus_iter (&dbus_iter, val, error))
205         {
206           g_variant_unref (val);
207           goto fail;
208         }
209       g_variant_unref (val);
210
211       dbus_message_iter_close_container (iter, &dbus_iter);
212     }
213   else
214     {
215       g_set_error (error,
216                    G_IO_ERROR,
217                    G_IO_ERROR_INVALID_ARGUMENT,
218                    "Error serializing GVariant with type-string '%s' to a D-Bus message",
219                    g_variant_get_type_string (value));
220       goto fail;
221     }
222
223   return TRUE;
224
225  fail:
226   return FALSE;
227 }
228
229 static gboolean
230 append_gv_to_dbus_message (DBusMessage  *message,
231                            GVariant     *value,
232                            GError      **error)
233 {
234   gboolean ret;
235   guint n;
236
237   ret = FALSE;
238
239   if (value != NULL)
240     {
241       DBusMessageIter iter;
242       GVariantIter gv_iter;
243       GVariant *item;
244
245       dbus_message_iter_init_append (message, &iter);
246
247       g_variant_iter_init (&gv_iter, value);
248       n = 0;
249       while ((item = g_variant_iter_next_value (&gv_iter)))
250         {
251           if (!append_gv_to_dbus_iter (&iter, item, error))
252             {
253               g_prefix_error (error,
254                               "Error encoding in-arg %d: ",
255                               n);
256               goto out;
257             }
258           n++;
259         }
260     }
261
262   ret = TRUE;
263
264  out:
265   return ret;
266 }
267
268 static void
269 print_gv_dbus_message (GVariant *value)
270 {
271   DBusMessage *message;
272   char *blob;
273   int blob_len;
274   GError *error;
275
276   message = dbus_message_new (DBUS_MESSAGE_TYPE_METHOD_CALL);
277   dbus_message_set_serial (message, 0x41);
278   dbus_message_set_path (message, "/foo/bar");
279   dbus_message_set_member (message, "Member");
280
281   error = NULL;
282   if (!append_gv_to_dbus_message (message, value, &error))
283     {
284       g_printerr ("Error printing GVariant as DBusMessage: %s", error->message);
285       g_error_free (error);
286       goto out;
287     }
288
289   dbus_message_marshal (message, &blob, &blob_len);
290   g_printerr ("\n");
291   hexdump ((guchar *) blob, blob_len);
292  out:
293   dbus_message_unref (message);
294 }
295
296 /* ---------------------------------------------------------------------------------------------------- */
297
298 static void
299 dbus_1_message_append (GString *s,
300                        guint indent,
301                        DBusMessageIter *iter)
302 {
303   gint arg_type;
304   DBusMessageIter sub;
305
306   g_string_append_printf (s, "%*s", indent, "");
307
308   arg_type = dbus_message_iter_get_arg_type (iter);
309   switch (arg_type)
310     {
311      case DBUS_TYPE_BOOLEAN:
312       {
313         dbus_bool_t value;
314         dbus_message_iter_get_basic (iter, &value);
315         g_string_append_printf (s, "bool: %s\n", value ? "true" : "false");
316         break;
317       }
318
319      case DBUS_TYPE_BYTE:
320       {
321         guchar value;
322         dbus_message_iter_get_basic (iter, &value);
323         g_string_append_printf (s, "byte: 0x%02x\n", (guint) value);
324         break;
325       }
326
327      case DBUS_TYPE_INT16:
328       {
329         gint16 value;
330         dbus_message_iter_get_basic (iter, &value);
331         g_string_append_printf (s, "int16: %" G_GINT16_FORMAT "\n", value);
332         break;
333       }
334
335      case DBUS_TYPE_UINT16:
336       {
337         guint16 value;
338         dbus_message_iter_get_basic (iter, &value);
339         g_string_append_printf (s, "uint16: %" G_GUINT16_FORMAT "\n", value);
340         break;
341       }
342
343      case DBUS_TYPE_INT32:
344       {
345         gint32 value;
346         dbus_message_iter_get_basic (iter, &value);
347         g_string_append_printf (s, "int32: %" G_GINT32_FORMAT "\n", value);
348         break;
349       }
350
351      case DBUS_TYPE_UINT32:
352       {
353         guint32 value;
354         dbus_message_iter_get_basic (iter, &value);
355         g_string_append_printf (s, "uint32: %" G_GUINT32_FORMAT "\n", value);
356         break;
357       }
358
359      case DBUS_TYPE_INT64:
360       {
361         gint64 value;
362         dbus_message_iter_get_basic (iter, &value);
363         g_string_append_printf (s, "int64: %" G_GINT64_FORMAT "\n", value);
364         break;
365       }
366
367      case DBUS_TYPE_UINT64:
368       {
369         guint64 value;
370         dbus_message_iter_get_basic (iter, &value);
371         g_string_append_printf (s, "uint64: %" G_GUINT64_FORMAT "\n", value);
372         break;
373       }
374
375      case DBUS_TYPE_DOUBLE:
376       {
377         gdouble value;
378         dbus_message_iter_get_basic (iter, &value);
379         g_string_append_printf (s, "double: %f\n", value);
380         break;
381       }
382
383      case DBUS_TYPE_STRING:
384       {
385         const gchar *value;
386         dbus_message_iter_get_basic (iter, &value);
387         g_string_append_printf (s, "string: '%s'\n", value);
388         break;
389       }
390
391      case DBUS_TYPE_OBJECT_PATH:
392       {
393         const gchar *value;
394         dbus_message_iter_get_basic (iter, &value);
395         g_string_append_printf (s, "object_path: '%s'\n", value);
396         break;
397       }
398
399      case DBUS_TYPE_SIGNATURE:
400       {
401         const gchar *value;
402         dbus_message_iter_get_basic (iter, &value);
403         g_string_append_printf (s, "signature: '%s'\n", value);
404         break;
405       }
406
407 #ifdef DBUS_TYPE_UNIX_FD
408     case DBUS_TYPE_UNIX_FD:
409       {
410         /* unfortunately there's currently no way to get just the
411          * protocol value, since dbus_message_iter_get_basic() wants
412          * to be 'helpful' and dup the fd for the user...
413          */
414         g_string_append (s, "unix-fd: (not extracted)\n");
415         break;
416       }
417 #endif
418
419      case DBUS_TYPE_VARIANT:
420        g_string_append_printf (s, "variant:\n");
421        dbus_message_iter_recurse (iter, &sub);
422        while (dbus_message_iter_get_arg_type (&sub))
423          {
424            dbus_1_message_append (s, indent + 2, &sub);
425            dbus_message_iter_next (&sub);
426          }
427        break;
428
429      case DBUS_TYPE_ARRAY:
430        g_string_append_printf (s, "array:\n");
431        dbus_message_iter_recurse (iter, &sub);
432        while (dbus_message_iter_get_arg_type (&sub))
433          {
434            dbus_1_message_append (s, indent + 2, &sub);
435            dbus_message_iter_next (&sub);
436          }
437        break;
438
439      case DBUS_TYPE_STRUCT:
440        g_string_append_printf (s, "struct:\n");
441        dbus_message_iter_recurse (iter, &sub);
442        while (dbus_message_iter_get_arg_type (&sub))
443          {
444            dbus_1_message_append (s, indent + 2, &sub);
445            dbus_message_iter_next (&sub);
446          }
447        break;
448
449      case DBUS_TYPE_DICT_ENTRY:
450        g_string_append_printf (s, "dict_entry:\n");
451        dbus_message_iter_recurse (iter, &sub);
452        while (dbus_message_iter_get_arg_type (&sub))
453          {
454            dbus_1_message_append (s, indent + 2, &sub);
455            dbus_message_iter_next (&sub);
456          }
457        break;
458
459      default:
460        g_printerr ("Error serializing D-Bus message to GVariant. Unsupported arg type '%c' (%d)",
461                    arg_type,
462                    arg_type);
463        g_assert_not_reached ();
464        break;
465     }
466 }
467
468 static gchar *
469 dbus_1_message_print (DBusMessage *message)
470 {
471   GString *s;
472   guint n;
473   DBusMessageIter iter;
474
475   s = g_string_new (NULL);
476   n = 0;
477   dbus_message_iter_init (message, &iter);
478   while (dbus_message_iter_get_arg_type (&iter) != DBUS_TYPE_INVALID)
479     {
480       g_string_append_printf (s, "value %d: ", n);
481       dbus_1_message_append (s, 2, &iter);
482       dbus_message_iter_next (&iter);
483       n++;
484     }
485
486   return g_string_free (s, FALSE);
487 }
488
489 /* ---------------------------------------------------------------------------------------------------- */
490
491 static gchar *
492 get_body_signature (GVariant *value)
493 {
494   const gchar *s;
495   gsize len;
496   gchar *ret;
497
498   if (value == NULL)
499     {
500       ret = g_strdup ("");
501       goto out;
502     }
503
504   s = g_variant_get_type_string (value);
505   len = strlen (s);
506   g_assert (len >= 2);
507
508   ret = g_strndup (s + 1, len - 2);
509
510  out:
511   return ret;
512 }
513
514 static void
515 check_serialization (GVariant *value,
516                      const gchar *expected_dbus_1_output)
517 {
518   guchar *blob;
519   gsize blob_size;
520   DBusMessage *dbus_1_message;
521   GDBusMessage *message;
522   GDBusMessage *recovered_message;
523   GError *error;
524   DBusError dbus_error;
525   gchar *s;
526   gchar *s1;
527   guint n;
528
529   message = g_dbus_message_new ();
530   g_dbus_message_set_body (message, value);
531   g_dbus_message_set_message_type (message, G_DBUS_MESSAGE_TYPE_METHOD_CALL);
532   g_dbus_message_set_serial (message, 0x41);
533   s = get_body_signature (value);
534   g_dbus_message_set_header (message, G_DBUS_MESSAGE_HEADER_FIELD_PATH, g_variant_new_object_path ("/foo/bar"));
535   g_dbus_message_set_header (message, G_DBUS_MESSAGE_HEADER_FIELD_MEMBER, g_variant_new_string ("Member"));
536   g_dbus_message_set_header (message, G_DBUS_MESSAGE_HEADER_FIELD_SIGNATURE, g_variant_new_signature (s));
537   g_free (s);
538
539   /* First check that the serialization to the D-Bus wire format is correct - do this for both byte orders */
540   for (n = 0; n < 2; n++)
541     {
542       GDBusMessageByteOrder byte_order;
543       switch (n)
544         {
545         case 0:
546           byte_order = G_DBUS_MESSAGE_BYTE_ORDER_BIG_ENDIAN;
547           break;
548         case 1:
549           byte_order = G_DBUS_MESSAGE_BYTE_ORDER_LITTLE_ENDIAN;
550           break;
551         case 2:
552           g_assert_not_reached ();
553           break;
554         }
555       g_dbus_message_set_byte_order (message, byte_order);
556
557       error = NULL;
558       blob = g_dbus_message_to_blob (message,
559                                      &blob_size,
560                                      G_DBUS_CAPABILITY_FLAGS_NONE,
561                                      &error);
562       g_assert_no_error (error);
563       g_assert (blob != NULL);
564
565       switch (byte_order)
566         {
567         case G_DBUS_MESSAGE_BYTE_ORDER_BIG_ENDIAN:
568           g_assert_cmpint (blob[0], ==, 'B');
569           break;
570         case G_DBUS_MESSAGE_BYTE_ORDER_LITTLE_ENDIAN:
571           g_assert_cmpint (blob[0], ==, 'l');
572           break;
573         }
574
575       dbus_error_init (&dbus_error);
576       dbus_1_message = dbus_message_demarshal ((char *) blob, blob_size, &dbus_error);
577       if (dbus_error_is_set (&dbus_error))
578         {
579           g_printerr ("Error calling dbus_message_demarshal() on this blob: %s: %s\n",
580                       dbus_error.name,
581                       dbus_error.message);
582           hexdump (blob, blob_size);
583           dbus_error_free (&dbus_error);
584
585           s = g_variant_print (value, TRUE);
586           g_printerr ("\nThe blob was generated from the following GVariant value:\n%s\n\n", s);
587           g_free (s);
588
589           g_printerr ("If the blob was encoded using DBusMessageIter, the payload would have been:\n");
590           print_gv_dbus_message (value);
591
592           g_assert_not_reached ();
593         }
594
595       s = dbus_1_message_print (dbus_1_message);
596       dbus_message_unref (dbus_1_message);
597
598       g_assert_cmpstr (s, ==, expected_dbus_1_output);
599       g_free (s);
600
601       /* Then serialize back and check that the body is identical */
602
603       error = NULL;
604       recovered_message = g_dbus_message_new_from_blob (blob,
605                                                         blob_size,
606                                                         G_DBUS_CAPABILITY_FLAGS_NONE,
607                                                         &error);
608       g_assert_no_error (error);
609       g_assert (recovered_message != NULL);
610
611       if (value == NULL)
612         {
613           g_assert (g_dbus_message_get_body (recovered_message) == NULL);
614         }
615       else
616         {
617           g_assert (g_dbus_message_get_body (recovered_message) != NULL);
618           if (!g_variant_equal (g_dbus_message_get_body (recovered_message), value))
619             {
620               s = g_variant_print (g_dbus_message_get_body (recovered_message), TRUE);
621               s1 = g_variant_print (value, TRUE);
622               g_printerr ("Recovered value:\n%s\ndoes not match given value\n%s\n",
623                           s,
624                           s1);
625               g_free (s);
626               g_free (s1);
627               g_assert_not_reached ();
628             }
629         }
630       g_object_unref (recovered_message);
631     }
632
633   g_object_unref (message);
634 }
635
636 static void
637 message_serialize_basic (void)
638 {
639   check_serialization (NULL, "");
640
641   check_serialization (g_variant_new ("(sogybnqiuxtd)",
642                                       "this is a string",
643                                       "/this/is/a/path",
644                                       "sad",
645                                       42,
646                                       TRUE,
647                                       -42,
648                                       60000,
649                                       -44,
650                                       100000,
651                                       -G_GINT64_CONSTANT(2)<<34,
652                                       G_GUINT64_CONSTANT(0xffffffffffffffff),
653                                       42.5),
654                        "value 0:   string: 'this is a string'\n"
655                        "value 1:   object_path: '/this/is/a/path'\n"
656                        "value 2:   signature: 'sad'\n"
657                        "value 3:   byte: 0x2a\n"
658                        "value 4:   bool: true\n"
659                        "value 5:   int16: -42\n"
660                        "value 6:   uint16: 60000\n"
661                        "value 7:   int32: -44\n"
662                        "value 8:   uint32: 100000\n"
663                        "value 9:   int64: -34359738368\n"
664                        "value 10:   uint64: 18446744073709551615\n"
665                        "value 11:   double: 42.500000\n");
666 }
667
668 /* ---------------------------------------------------------------------------------------------------- */
669
670 static void
671 message_serialize_complex (void)
672 {
673   GError *error;
674   GVariant *value;
675
676   error = NULL;
677
678   value = g_variant_parse (G_VARIANT_TYPE ("(aia{ss})"),
679                            "([1, 2, 3], {'one': 'white', 'two': 'black'})",
680                            NULL, NULL, &error);
681   g_assert_no_error (error);
682   g_assert (value != NULL);
683   check_serialization (value,
684                        "value 0:   array:\n"
685                        "    int32: 1\n"
686                        "    int32: 2\n"
687                        "    int32: 3\n"
688                        "value 1:   array:\n"
689                        "    dict_entry:\n"
690                        "      string: 'one'\n"
691                        "      string: 'white'\n"
692                        "    dict_entry:\n"
693                        "      string: 'two'\n"
694                        "      string: 'black'\n");
695
696   value = g_variant_parse (G_VARIANT_TYPE ("(sa{sv}as)"),
697                            "('01234567890123456', {}, ['Something'])",
698                            NULL, NULL, &error);
699   g_assert_no_error (error);
700   g_assert (value != NULL);
701   check_serialization (value,
702                        "value 0:   string: '01234567890123456'\n"
703                        "value 1:   array:\n"
704                        "value 2:   array:\n"
705                        "    string: 'Something'\n");
706
707   /* https://bugzilla.gnome.org/show_bug.cgi?id=621838 */
708   check_serialization (g_variant_new_parsed ("(@aay [], {'cwd': <'/home/davidz/Hacking/glib/gio/tests'>})"),
709                        "value 0:   array:\n"
710                        "value 1:   array:\n"
711                        "    dict_entry:\n"
712                        "      string: 'cwd'\n"
713                        "      variant:\n"
714                        "        string: '/home/davidz/Hacking/glib/gio/tests'\n");
715
716 #ifdef DBUS_TYPE_UNIX_FD
717   value = g_variant_parse (G_VARIANT_TYPE ("(hah)"),
718                            "(42, [43, 44])",
719                            NULL, NULL, &error);
720   g_assert_no_error (error);
721   g_assert (value != NULL);
722   /* about (not extracted), see comment in DBUS_TYPE_UNIX_FD case in
723    * dbus_1_message_append() above.
724    */
725   check_serialization (value,
726                        "value 0:   unix-fd: (not extracted)\n"
727                        "value 1:   array:\n"
728                        "    unix-fd: (not extracted)\n"
729                        "    unix-fd: (not extracted)\n");
730 #endif
731 }
732
733
734 /* ---------------------------------------------------------------------------------------------------- */
735
736 static void
737 replace (char       *blob,
738          gsize       len,
739          const char *before,
740          const char *after)
741 {
742   gsize i;
743   gsize slen = strlen (before) + 1;
744
745   g_assert_cmpuint (strlen (before), ==, strlen (after));
746   g_assert_cmpuint (len, >=, slen);
747
748   for (i = 0; i < (len - slen + 1); i++)
749     {
750       if (memcmp (blob + i, before, slen) == 0)
751         memcpy (blob + i, after, slen);
752     }
753 }
754
755 static void
756 message_serialize_invalid (void)
757 {
758   guint n;
759
760   /* Other things we could check (note that GDBus _does_ check for all
761    * these things - we just don't have test-suit coverage for it)
762    *
763    *  - array exceeding 64 MiB (2^26 bytes) - unfortunately libdbus-1 checks
764    *    this, e.g.
765    *
766    *      process 19620: arguments to dbus_message_iter_append_fixed_array() were incorrect,
767    *      assertion "n_elements <= DBUS_MAXIMUM_ARRAY_LENGTH / _dbus_type_get_alignment (element_type)"
768    *      failed in file dbus-message.c line 2344.
769    *      This is normally a bug in some application using the D-Bus library.
770    *      D-Bus not built with -rdynamic so unable to print a backtrace
771    *      Aborted (core dumped)
772    *
773    *  - message exceeding 128 MiB (2^27 bytes)
774    *
775    *  - endianness, message type, flags, protocol version
776    */
777
778   for (n = 0; n < 3; n++)
779     {
780       GDBusMessage *message;
781       GError *error;
782       DBusMessage *dbus_message;
783       char *blob;
784       int blob_len;
785       /* these are in pairs with matching length */
786       const gchar *valid_utf8_str = "this is valid...";
787       const gchar *invalid_utf8_str = "this is invalid\xff";
788       const gchar *valid_signature = "a{sv}a{sv}a{sv}aiai";
789       const gchar *invalid_signature = "not valid signature";
790       const gchar *valid_object_path = "/this/is/a/valid/dbus/object/path";
791       const gchar *invalid_object_path = "/this/is/not a valid object path!";
792
793       dbus_message = dbus_message_new (DBUS_MESSAGE_TYPE_METHOD_CALL);
794       dbus_message_set_serial (dbus_message, 0x41);
795       dbus_message_set_path (dbus_message, "/foo/bar");
796       dbus_message_set_member (dbus_message, "Member");
797       switch (n)
798         {
799         case 0:
800           /* invalid UTF-8 */
801           dbus_message_append_args (dbus_message,
802                                     DBUS_TYPE_STRING, &valid_utf8_str,
803                                     DBUS_TYPE_INVALID);
804           break;
805
806         case 1:
807           /* invalid object path */
808           dbus_message_append_args (dbus_message,
809                                     DBUS_TYPE_OBJECT_PATH, &valid_object_path,
810                                     DBUS_TYPE_INVALID);
811           break;
812
813         case 2:
814           /* invalid signature */
815           dbus_message_append_args (dbus_message,
816                                     DBUS_TYPE_SIGNATURE, &valid_signature,
817                                     DBUS_TYPE_INVALID);
818           break;
819
820         default:
821           g_assert_not_reached ();
822           break;
823         }
824       dbus_message_marshal (dbus_message, &blob, &blob_len);
825       /* hack up the message to be invalid by replacing each valid string
826        * with its invalid counterpart */
827       replace (blob, blob_len, valid_utf8_str, invalid_utf8_str);
828       replace (blob, blob_len, valid_object_path, invalid_object_path);
829       replace (blob, blob_len, valid_signature, invalid_signature);
830
831       error = NULL;
832       message = g_dbus_message_new_from_blob ((guchar *) blob,
833                                               blob_len,
834                                               G_DBUS_CAPABILITY_FLAGS_NONE,
835                                               &error);
836       g_assert_error (error, G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT);
837       g_error_free (error);
838       g_assert (message == NULL);
839
840       dbus_free (blob);
841     }
842
843 }
844
845 /* ---------------------------------------------------------------------------------------------------- */
846
847 static void
848 message_serialize_header_checks (void)
849 {
850   GDBusMessage *message;
851   GDBusMessage *reply;
852   GError *error;
853   guchar *blob;
854   gsize blob_size;
855
856   /*
857    * check we can't serialize messages with INVALID type
858    */
859   message = g_dbus_message_new ();
860   error = NULL;
861   blob = g_dbus_message_to_blob (message, &blob_size, G_DBUS_CAPABILITY_FLAGS_NONE, &error);
862   g_assert_error (error, G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT);
863   g_assert_cmpstr (error->message, ==, "Cannot serialize message: type is INVALID");
864   g_error_free (error);
865   g_assert (blob == NULL);
866   g_object_unref (message);
867
868   /*
869    * check we can't serialize signal messages with INTERFACE, PATH or MEMBER unset / set to reserved value
870    */
871   message = g_dbus_message_new_signal ("/the/path", "The.Interface", "TheMember");
872   /* ----- */
873   /* interface NULL => error */
874   g_dbus_message_set_interface (message, NULL);
875   error = NULL;
876   blob = g_dbus_message_to_blob (message, &blob_size, G_DBUS_CAPABILITY_FLAGS_NONE, &error);
877   g_assert_error (error, G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT);
878   g_assert_cmpstr (error->message, ==, "Cannot serialize message: SIGNAL message: PATH, INTERFACE or MEMBER header field is missing");
879   g_error_free (error);
880   g_assert (blob == NULL);
881   /* interface reserved value => error */
882   g_dbus_message_set_interface (message, "org.freedesktop.DBus.Local");
883   error = NULL;
884   blob = g_dbus_message_to_blob (message, &blob_size, G_DBUS_CAPABILITY_FLAGS_NONE, &error);
885   g_assert_error (error, G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT);
886   g_assert_cmpstr (error->message, ==, "Cannot serialize message: SIGNAL message: The INTERFACE header field is using the reserved value org.freedesktop.DBus.Local");
887   g_error_free (error);
888   g_assert (blob == NULL);
889   /* reset interface */
890   g_dbus_message_set_interface (message, "The.Interface");
891   /* ----- */
892   /* path NULL => error */
893   g_dbus_message_set_path (message, NULL);
894   error = NULL;
895   blob = g_dbus_message_to_blob (message, &blob_size, G_DBUS_CAPABILITY_FLAGS_NONE, &error);
896   g_assert_error (error, G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT);
897   g_assert_cmpstr (error->message, ==, "Cannot serialize message: SIGNAL message: PATH, INTERFACE or MEMBER header field is missing");
898   g_error_free (error);
899   g_assert (blob == NULL);
900   /* path reserved value => error */
901   g_dbus_message_set_path (message, "/org/freedesktop/DBus/Local");
902   error = NULL;
903   blob = g_dbus_message_to_blob (message, &blob_size, G_DBUS_CAPABILITY_FLAGS_NONE, &error);
904   g_assert_error (error, G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT);
905   g_assert_cmpstr (error->message, ==, "Cannot serialize message: SIGNAL message: The PATH header field is using the reserved value /org/freedesktop/DBus/Local");
906   g_error_free (error);
907   g_assert (blob == NULL);
908   /* reset path */
909   g_dbus_message_set_path (message, "/the/path");
910   /* ----- */
911   /* member NULL => error */
912   g_dbus_message_set_member (message, NULL);
913   error = NULL;
914   blob = g_dbus_message_to_blob (message, &blob_size, G_DBUS_CAPABILITY_FLAGS_NONE, &error);
915   g_assert_error (error, G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT);
916   g_assert_cmpstr (error->message, ==, "Cannot serialize message: SIGNAL message: PATH, INTERFACE or MEMBER header field is missing");
917   g_error_free (error);
918   g_assert (blob == NULL);
919   /* reset member */
920   g_dbus_message_set_member (message, "TheMember");
921   /* ----- */
922   /* done */
923   g_object_unref (message);
924
925   /*
926    * check that we can't serialize method call messages with PATH or MEMBER unset
927    */
928   message = g_dbus_message_new_method_call (NULL, "/the/path", NULL, "TheMember");
929   /* ----- */
930   /* path NULL => error */
931   g_dbus_message_set_path (message, NULL);
932   error = NULL;
933   blob = g_dbus_message_to_blob (message, &blob_size, G_DBUS_CAPABILITY_FLAGS_NONE, &error);
934   g_assert_error (error, G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT);
935   g_assert_cmpstr (error->message, ==, "Cannot serialize message: METHOD_CALL message: PATH or MEMBER header field is missing");
936   g_error_free (error);
937   g_assert (blob == NULL);
938   /* reset path */
939   g_dbus_message_set_path (message, "/the/path");
940   /* ----- */
941   /* member NULL => error */
942   g_dbus_message_set_member (message, NULL);
943   error = NULL;
944   blob = g_dbus_message_to_blob (message, &blob_size, G_DBUS_CAPABILITY_FLAGS_NONE, &error);
945   g_assert_error (error, G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT);
946   g_assert_cmpstr (error->message, ==, "Cannot serialize message: METHOD_CALL message: PATH or MEMBER header field is missing");
947   g_error_free (error);
948   g_assert (blob == NULL);
949   /* reset member */
950   g_dbus_message_set_member (message, "TheMember");
951   /* ----- */
952   /* done */
953   g_object_unref (message);
954
955   /*
956    * check that we can't serialize method reply messages with REPLY_SERIAL unset
957    */
958   message = g_dbus_message_new_method_call (NULL, "/the/path", NULL, "TheMember");
959   g_dbus_message_set_serial (message, 42);
960   /* method reply */
961   reply = g_dbus_message_new_method_reply (message);
962   g_assert_cmpint (g_dbus_message_get_reply_serial (reply), ==, 42);
963   g_dbus_message_set_header (reply, G_DBUS_MESSAGE_HEADER_FIELD_REPLY_SERIAL, NULL);
964   error = NULL;
965   blob = g_dbus_message_to_blob (reply, &blob_size, G_DBUS_CAPABILITY_FLAGS_NONE, &error);
966   g_assert_error (error, G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT);
967   g_assert_cmpstr (error->message, ==, "Cannot serialize message: METHOD_RETURN message: REPLY_SERIAL header field is missing");
968   g_error_free (error);
969   g_assert (blob == NULL);
970   g_object_unref (reply);
971   /* method error - first nuke ERROR_NAME, then REPLY_SERIAL */
972   reply = g_dbus_message_new_method_error (message, "Some.Error.Name", "the message");
973   g_assert_cmpint (g_dbus_message_get_reply_serial (reply), ==, 42);
974   /* nuke ERROR_NAME */
975   g_dbus_message_set_error_name (reply, NULL);
976   error = NULL;
977   blob = g_dbus_message_to_blob (reply, &blob_size, G_DBUS_CAPABILITY_FLAGS_NONE, &error);
978   g_assert_error (error, G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT);
979   g_assert_cmpstr (error->message, ==, "Cannot serialize message: ERROR message: REPLY_SERIAL or ERROR_NAME header field is missing");
980   g_error_free (error);
981   g_assert (blob == NULL);
982   /* reset ERROR_NAME */
983   g_dbus_message_set_error_name (reply, "Some.Error.Name");
984   /* nuke REPLY_SERIAL */
985   g_dbus_message_set_header (reply, G_DBUS_MESSAGE_HEADER_FIELD_REPLY_SERIAL, NULL);
986   error = NULL;
987   blob = g_dbus_message_to_blob (reply, &blob_size, G_DBUS_CAPABILITY_FLAGS_NONE, &error);
988   g_assert_error (error, G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT);
989   g_assert_cmpstr (error->message, ==, "Cannot serialize message: ERROR message: REPLY_SERIAL or ERROR_NAME header field is missing");
990   g_error_free (error);
991   g_assert (blob == NULL);
992   g_object_unref (reply);
993   g_object_unref (message);
994 }
995
996 /* ---------------------------------------------------------------------------------------------------- */
997
998 static void
999 message_parse_empty_arrays_of_arrays (void)
1000 {
1001   GVariant *body;
1002   GError *error = NULL;
1003
1004   g_test_bug ("673612");
1005   /* These three-element array of empty arrays were previously read back as a
1006    * two-element array of empty arrays, due to sometimes erroneously skipping
1007    * four bytes to align for the eight-byte-aligned grandchild types (x and
1008    * dict_entry).
1009    */
1010   body = g_variant_parse (G_VARIANT_TYPE ("(aaax)"),
1011       "([@aax [], [], []],)", NULL, NULL, &error);
1012   g_assert_no_error (error);
1013   check_serialization (body,
1014       "value 0:   array:\n"
1015       "    array:\n"
1016       "    array:\n"
1017       "    array:\n");
1018
1019   body = g_variant_parse (G_VARIANT_TYPE ("(aaa{uu})"),
1020       "([@aa{uu} [], [], []],)", NULL, NULL, &error);
1021   g_assert_no_error (error);
1022   check_serialization (body,
1023       "value 0:   array:\n"
1024       "    array:\n"
1025       "    array:\n"
1026       "    array:\n");
1027
1028   /* Due to the same bug, g_dbus_message_new_from_blob() would fail for this
1029    * message because it would try to read past the end of the string. Hence,
1030    * sending this to an application would make it fall off the bus. */
1031   body = g_variant_parse (G_VARIANT_TYPE ("(a(aa{sv}as))"),
1032       "([ ([], []),"
1033       "   ([], []),"
1034       "   ([], [])],)", NULL, NULL, &error);
1035   g_assert_no_error (error);
1036   check_serialization (body,
1037       "value 0:   array:\n"
1038       "    struct:\n"
1039       "      array:\n"
1040       "      array:\n"
1041       "    struct:\n"
1042       "      array:\n"
1043       "      array:\n"
1044       "    struct:\n"
1045       "      array:\n"
1046       "      array:\n");
1047 }
1048
1049 /* ---------------------------------------------------------------------------------------------------- */
1050
1051 static void
1052 test_double_array (void)
1053 {
1054   GDBusConnection *conn;
1055   GError *error = NULL;
1056   GVariantBuilder builder;
1057
1058   g_test_bug ("732754");
1059
1060   conn = g_bus_get_sync (G_BUS_TYPE_SESSION, NULL, &error);
1061   g_assert_no_error (error);
1062
1063   g_variant_builder_init (&builder, G_VARIANT_TYPE ("ad"));
1064   g_variant_builder_add (&builder, "d", (gdouble)0.0);
1065   g_variant_builder_add (&builder, "d", (gdouble)8.0);
1066   g_variant_builder_add (&builder, "d", (gdouble)22.0);
1067   g_variant_builder_add (&builder, "d", (gdouble)0.0);
1068
1069   /*
1070    * Some versions of glib encoded arrays of doubles wrong. Here we send such
1071    * a message and check that we didn't get bumped from the connection.
1072    */
1073   g_dbus_connection_call_sync (conn, "org.freedesktop.DBus", "/path",
1074                                "org.freedesktop.DBus", "InvalidNonExistantMethod",
1075                                g_variant_new ("(@ad)", g_variant_builder_end (&builder)),
1076                                NULL, G_DBUS_CALL_FLAGS_NO_AUTO_START, -1, NULL, &error);
1077   g_assert_error (error, G_DBUS_ERROR, G_DBUS_ERROR_UNKNOWN_METHOD);
1078
1079   g_object_unref (conn);
1080 }
1081
1082 /* ---------------------------------------------------------------------------------------------------- */
1083
1084 int
1085 main (int   argc,
1086       char *argv[])
1087 {
1088   setlocale (LC_ALL, "C");
1089
1090   g_test_init (&argc, &argv, NULL);
1091   g_test_bug_base ("https://bugzilla.gnome.org/show_bug.cgi?id=");
1092
1093   g_test_add_func ("/gdbus/message-serialize-basic", message_serialize_basic);
1094   g_test_add_func ("/gdbus/message-serialize-complex", message_serialize_complex);
1095   g_test_add_func ("/gdbus/message-serialize-invalid", message_serialize_invalid);
1096   g_test_add_func ("/gdbus/message-serialize-header-checks", message_serialize_header_checks);
1097
1098   g_test_add_func ("/gdbus/message-parse-empty-arrays-of-arrays",
1099       message_parse_empty_arrays_of_arrays);
1100
1101   g_test_add_func ("/gdbus/message-serialize/double-array", test_double_array);
1102
1103   return g_test_run();
1104 }
1105