Merge branch 'dbus-1.6'
[platform/upstream/dbus.git] / test / marshal.c
1 /* Simple sanity-check for D-Bus message serialization.
2  *
3  * Author: Simon McVittie <simon.mcvittie@collabora.co.uk>
4  * Copyright © 2010-2011 Nokia Corporation
5  *
6  * Permission is hereby granted, free of charge, to any person
7  * obtaining a copy of this software and associated documentation files
8  * (the "Software"), to deal in the Software without restriction,
9  * including without limitation the rights to use, copy, modify, merge,
10  * publish, distribute, sublicense, and/or sell copies of the Software,
11  * and to permit persons to whom the Software is furnished to do so,
12  * subject to the following conditions:
13  *
14  * The above copyright notice and this permission notice shall be
15  * included in all copies or substantial portions of the Software.
16  *
17  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
18  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
19  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
20  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
21  * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
22  * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
23  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
24  * SOFTWARE.
25  */
26
27 #include <config.h>
28
29 #include <glib.h>
30 #include <string.h>
31
32 #include <dbus/dbus.h>
33 #include <dbus/dbus-glib-lowlevel.h>
34
35 typedef struct {
36     DBusError e;
37 } Fixture;
38
39 static void
40 assert_no_error (const DBusError *e)
41 {
42   if (G_UNLIKELY (dbus_error_is_set (e)))
43     g_error ("expected success but got error: %s: %s", e->name, e->message);
44 }
45
46 static void
47 setup (Fixture *f,
48     gconstpointer arg G_GNUC_UNUSED)
49 {
50   dbus_error_init (&f->e);
51 }
52
53 /* this is meant to be obviously correct, not efficient! */
54 static guint32
55 get_uint32 (const gchar *blob,
56     gsize offset,
57     char endian)
58 {
59   if (endian == 'l')
60     {
61       return
62         blob[offset] |
63         (blob[offset + 1] << 8) |
64         (blob[offset + 2] << 16) |
65         (blob[offset + 3] << 24);
66     }
67   else if (endian == 'B')
68     {
69       return
70         (blob[offset] << 24) |
71         (blob[offset + 1] << 16) |
72         (blob[offset + 2] << 8) |
73         blob[offset + 3];
74     }
75   else
76     {
77       g_assert_not_reached ();
78     }
79 }
80
81 #define BLOB_LENGTH (sizeof (le_blob) - 1)
82 #define OFFSET_BODY_LENGTH (4)
83 #define OFFSET_SERIAL (8)
84
85 const gchar le_blob[] =
86     /* byte 0 */
87     /* yyyyuu fixed headers */
88     "l"                     /* little-endian */
89     "\2"                    /* reply (which is the simplest message) */
90     "\2"                    /* no auto-starting */
91     "\1"                    /* D-Bus version = 1 */
92     /* byte 4 */
93     "\4\0\0\0"              /* bytes in body = 4 */
94     /* byte 8 */
95     "\x78\x56\x34\x12"      /* serial number = 0x12345678 */
96     /* byte 12 */
97     /* a(uv) variable headers start here */
98     "\x0f\0\0\0"            /* bytes in array of variable headers = 15 */
99                             /* pad to 8-byte boundary = nothing */
100     /* byte 16 */
101     "\5"                    /* in reply to: */
102         "\1u\0"             /* variant signature = u */
103                             /* pad to 4-byte boundary = nothing */
104         "\x12\xef\xcd\xab"  /* 0xabcdef12 */
105                             /* pad to 8-byte boundary = nothing */
106     /* byte 24 */
107     "\x08"                  /* signature: */
108         "\1g\0"             /* variant signature = g */
109         "\1u\0"             /* 1 byte, u, NUL (no alignment needed) */
110         "\0"                /* pad to 8-byte boundary for body */
111     /* body; byte 32 */
112     "\xef\xbe\xad\xde"      /* 0xdeadbeef */
113     ;
114
115 const gchar be_blob[] =
116     /* byte 0 */
117     /* yyyyuu fixed headers */
118     "B"                     /* big-endian */
119     "\2"                    /* reply (which is the simplest message) */
120     "\2"                    /* no auto-starting */
121     "\1"                    /* D-Bus version = 1 */
122     /* byte 4 */
123     "\0\0\0\4"              /* bytes in body = 4 */
124     /* byte 8 */
125     "\x12\x34\x56\x78"      /* serial number = 0x12345678 */
126     /* byte 12 */
127     /* a(uv) variable headers start here */
128     "\0\0\0\x0f"            /* bytes in array of variable headers = 15 */
129                             /* pad to 8-byte boundary = nothing */
130     /* byte 16 */
131     "\5"                    /* in reply to: */
132         "\1u\0"             /* variant signature = u */
133                             /* pad to 4-byte boundary = nothing */
134         "\xab\xcd\xef\x12"  /* 0xabcdef12 */
135                             /* pad to 8-byte boundary = nothing */
136     /* byte 24 */
137     "\x08"                  /* signature: */
138         "\1g\0"             /* variant signature = g */
139         "\1u\0"             /* 1 byte, u, NUL (no alignment needed) */
140         "\0"                /* pad to 8-byte boundary for body */
141     /* body; byte 32 */
142     "\xde\xad\xbe\xef"      /* 0xdeadbeef */
143     ;
144
145 static void
146 test_endian (Fixture *f,
147     gconstpointer arg)
148 {
149   const gchar *blob = arg;
150   char *output;
151   DBusMessage *m;
152   int len;
153   dbus_uint32_t u;
154   dbus_bool_t ok;
155
156   g_assert_cmpuint ((guint) sizeof (le_blob), ==, (guint) sizeof (be_blob));
157
158   g_assert_cmpuint (get_uint32 (blob, OFFSET_BODY_LENGTH, blob[0]), ==, 4);
159   g_assert_cmpuint (get_uint32 (blob, OFFSET_SERIAL, blob[0]), ==,
160       0x12345678u);
161
162   len = dbus_message_demarshal_bytes_needed (blob, sizeof (le_blob));
163   /* everything in the string except the implicit "\0" at the end is part of
164    * the message */
165   g_assert_cmpint (len, ==, BLOB_LENGTH);
166
167   m = dbus_message_demarshal (blob, sizeof (le_blob), &f->e);
168   assert_no_error (&f->e);
169   g_assert (m != NULL);
170
171   g_assert_cmpuint (dbus_message_get_serial (m), ==, 0x12345678u);
172   g_assert_cmpuint (dbus_message_get_reply_serial (m), ==, 0xabcdef12u);
173   g_assert_cmpstr (dbus_message_get_signature (m), ==, "u");
174
175   /* Implementation detail: appending to the message results in it being
176    * byteswapped into compiler byte order, which exposed a bug in libdbus,
177    * fd.o #38120. (If that changes, this test might not exercise that
178    * particular bug but will still be valid.) */
179   u = 0xdecafbadu;
180   ok = dbus_message_append_args (m,
181       DBUS_TYPE_UINT32, &u,
182       DBUS_TYPE_INVALID);
183   g_assert (ok);
184
185   dbus_message_marshal (m, &output, &len);
186
187   g_assert (output[0] == 'l' || output[0] == 'B');
188   /* the single-byte fields are unaffected, even if the endianness was
189    * swapped */
190   g_assert_cmpint (output[1], ==, blob[1]);
191   g_assert_cmpint (output[2], ==, blob[2]);
192   g_assert_cmpint (output[3], ==, blob[3]);
193   /* the length and serial are in the new endianness, the length has expanded
194    * to 8, and the serial is correct */
195   g_assert_cmpuint (get_uint32 (output, OFFSET_BODY_LENGTH, output[0]), ==, 8);
196   g_assert_cmpuint (get_uint32 (output, OFFSET_SERIAL, output[0]), ==,
197       0x12345678u);
198   /* the second "u" in the signature replaced a padding byte, so only
199    * the length of the body changed */
200   g_assert_cmpint (len, ==, BLOB_LENGTH + 4);
201 }
202
203 static void
204 test_needed (Fixture *f,
205     gconstpointer arg)
206 {
207   const gchar *blob = arg;
208
209   /* We need at least 16 bytes to know how long the message is - that's just
210    * a fact of the D-Bus protocol. */
211   g_assert_cmpint (
212       dbus_message_demarshal_bytes_needed (blob, 0), ==, 0);
213   g_assert_cmpint (
214       dbus_message_demarshal_bytes_needed (blob, 15), ==, 0);
215   /* This is enough that we should be able to tell how much we need. */
216   g_assert_cmpint (
217       dbus_message_demarshal_bytes_needed (blob, 16), ==, BLOB_LENGTH);
218   /* The header is 32 bytes long (here), so that's another interesting
219    * boundary. */
220   g_assert_cmpint (
221       dbus_message_demarshal_bytes_needed (blob, 31), ==, BLOB_LENGTH);
222   g_assert_cmpint (
223       dbus_message_demarshal_bytes_needed (blob, 32), ==, BLOB_LENGTH);
224   g_assert_cmpint (
225       dbus_message_demarshal_bytes_needed (blob, 33), ==, BLOB_LENGTH);
226   g_assert_cmpint (
227       dbus_message_demarshal_bytes_needed (blob, BLOB_LENGTH - 1), ==,
228       BLOB_LENGTH);
229   g_assert_cmpint (
230       dbus_message_demarshal_bytes_needed (blob, BLOB_LENGTH), ==,
231       BLOB_LENGTH);
232   g_assert_cmpint (
233       dbus_message_demarshal_bytes_needed (blob, sizeof (be_blob)), ==,
234       BLOB_LENGTH);
235 }
236
237 static void
238 teardown (Fixture *f,
239     gconstpointer arg G_GNUC_UNUSED)
240 {
241   dbus_error_free (&f->e);
242 }
243
244 int
245 main (int argc,
246     char **argv)
247 {
248   int ret;
249   char *aligned_le_blob;
250   char *aligned_be_blob;
251
252   g_test_init (&argc, &argv, NULL);
253
254   /* We have to pass in a buffer that's at least "default aligned",
255    * i.e.  on GNU systems to 8 or 16.  The linker may have only given
256    * us byte-alignment for the char[] static variables.
257    */
258   aligned_le_blob = g_malloc (sizeof (le_blob));
259   memcpy (aligned_le_blob, le_blob, sizeof (le_blob));
260   aligned_be_blob = g_malloc (sizeof (be_blob));
261   memcpy (aligned_be_blob, be_blob, sizeof (be_blob));  
262
263   g_test_add ("/demarshal/le", Fixture, aligned_le_blob, setup, test_endian, teardown);
264   g_test_add ("/demarshal/be", Fixture, aligned_be_blob, setup, test_endian, teardown);
265   g_test_add ("/demarshal/needed/le", Fixture, aligned_le_blob, setup, test_needed,
266       teardown);
267   g_test_add ("/demarshal/needed/be", Fixture, aligned_be_blob, setup, test_needed,
268       teardown);
269
270   ret = g_test_run ();
271   g_free (aligned_le_blob);
272   g_free (aligned_be_blob);
273   return ret;
274 }