marshal.c revision 4299eb3c0907100fe95d2986984b48d40cc52841
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 31#include <dbus/dbus.h> 32#include <dbus/dbus-glib-lowlevel.h> 33 34typedef struct { 35 DBusError e; 36} Fixture; 37 38static void 39assert_no_error (const DBusError *e) 40{ 41 if (G_UNLIKELY (dbus_error_is_set (e))) 42 g_error ("expected success but got error: %s: %s", e->name, e->message); 43} 44 45static void 46setup (Fixture *f, 47 gconstpointer arg G_GNUC_UNUSED) 48{ 49 dbus_error_init (&f->e); 50} 51 52/* this is meant to be obviously correct, not efficient! */ 53static guint32 54get_uint32 (const gchar *blob, 55 gsize offset, 56 char endian) 57{ 58 if (endian == 'l') 59 { 60 return 61 blob[offset] | 62 (blob[offset + 1] << 8) | 63 (blob[offset + 2] << 16) | 64 (blob[offset + 3] << 24); 65 } 66 else if (endian == 'B') 67 { 68 return 69 (blob[offset] << 24) | 70 (blob[offset + 1] << 16) | 71 (blob[offset + 2] << 8) | 72 blob[offset + 3]; 73 } 74 else 75 { 76 g_assert_not_reached (); 77 } 78} 79 80#define BLOB_LENGTH (sizeof (le_blob) - 1) 81#define OFFSET_BODY_LENGTH (4) 82#define OFFSET_SERIAL (8) 83 84const gchar le_blob[] = 85 /* byte 0 */ 86 /* yyyyuu fixed headers */ 87 "l" /* little-endian */ 88 "\2" /* reply (which is the simplest message) */ 89 "\2" /* no auto-starting */ 90 "\1" /* D-Bus version = 1 */ 91 /* byte 4 */ 92 "\4\0\0\0" /* bytes in body = 4 */ 93 /* byte 8 */ 94 "\x78\x56\x34\x12" /* serial number = 0x12345678 */ 95 /* byte 12 */ 96 /* a(uv) variable headers start here */ 97 "\x0f\0\0\0" /* bytes in array of variable headers = 15 */ 98 /* pad to 8-byte boundary = nothing */ 99 /* byte 16 */ 100 "\5" /* in reply to: */ 101 "\1u\0" /* variant signature = u */ 102 /* pad to 4-byte boundary = nothing */ 103 "\x12\xef\xcd\xab" /* 0xabcdef12 */ 104 /* pad to 8-byte boundary = nothing */ 105 /* byte 24 */ 106 "\x08" /* signature: */ 107 "\1g\0" /* variant signature = g */ 108 "\1u\0" /* 1 byte, u, NUL (no alignment needed) */ 109 "\0" /* pad to 8-byte boundary for body */ 110 /* body; byte 32 */ 111 "\xef\xbe\xad\xde" /* 0xdeadbeef */ 112 ; 113 114const gchar be_blob[] = 115 /* byte 0 */ 116 /* yyyyuu fixed headers */ 117 "B" /* big-endian */ 118 "\2" /* reply (which is the simplest message) */ 119 "\2" /* no auto-starting */ 120 "\1" /* D-Bus version = 1 */ 121 /* byte 4 */ 122 "\0\0\0\4" /* bytes in body = 4 */ 123 /* byte 8 */ 124 "\x12\x34\x56\x78" /* serial number = 0x12345678 */ 125 /* byte 12 */ 126 /* a(uv) variable headers start here */ 127 "\0\0\0\x0f" /* bytes in array of variable headers = 15 */ 128 /* pad to 8-byte boundary = nothing */ 129 /* byte 16 */ 130 "\5" /* in reply to: */ 131 "\1u\0" /* variant signature = u */ 132 /* pad to 4-byte boundary = nothing */ 133 "\xab\xcd\xef\x12" /* 0xabcdef12 */ 134 /* pad to 8-byte boundary = nothing */ 135 /* byte 24 */ 136 "\x08" /* signature: */ 137 "\1g\0" /* variant signature = g */ 138 "\1u\0" /* 1 byte, u, NUL (no alignment needed) */ 139 "\0" /* pad to 8-byte boundary for body */ 140 /* body; byte 32 */ 141 "\xde\xad\xbe\xef" /* 0xdeadbeef */ 142 ; 143 144static void 145test_endian (Fixture *f, 146 gconstpointer arg) 147{ 148 const gchar *blob = arg; 149 char *output; 150 DBusMessage *m; 151 int len; 152 dbus_uint32_t u; 153 dbus_bool_t ok; 154 155 g_assert_cmpuint ((guint) sizeof (le_blob), ==, (guint) sizeof (be_blob)); 156 157 g_assert_cmpuint (get_uint32 (blob, OFFSET_BODY_LENGTH, blob[0]), ==, 4); 158 g_assert_cmpuint (get_uint32 (blob, OFFSET_SERIAL, blob[0]), ==, 159 0x12345678u); 160 161 len = dbus_message_demarshal_bytes_needed (blob, sizeof (le_blob)); 162 /* everything in the string except the implicit "\0" at the end is part of 163 * the message */ 164 g_assert_cmpint (len, ==, BLOB_LENGTH); 165 166 m = dbus_message_demarshal (blob, sizeof (le_blob), &f->e); 167 assert_no_error (&f->e); 168 g_assert (m != NULL); 169 170 g_assert_cmpuint (dbus_message_get_serial (m), ==, 0x12345678u); 171 g_assert_cmpuint (dbus_message_get_reply_serial (m), ==, 0xabcdef12u); 172 g_assert_cmpstr (dbus_message_get_signature (m), ==, "u"); 173 174 /* Implementation detail: appending to the message results in it being 175 * byteswapped into compiler byte order, which exposed a bug in libdbus, 176 * fd.o #38120. (If that changes, this test might not exercise that 177 * particular bug but will still be valid.) */ 178 u = 0xdecafbadu; 179 ok = dbus_message_append_args (m, 180 DBUS_TYPE_UINT32, &u, 181 DBUS_TYPE_INVALID); 182 g_assert (ok); 183 184 dbus_message_marshal (m, &output, &len); 185 186 g_assert (output[0] == 'l' || output[0] == 'B'); 187 /* the single-byte fields are unaffected, even if the endianness was 188 * swapped */ 189 g_assert_cmpint (output[1], ==, blob[1]); 190 g_assert_cmpint (output[2], ==, blob[2]); 191 g_assert_cmpint (output[3], ==, blob[3]); 192 /* the length and serial are in the new endianness, the length has expanded 193 * to 8, and the serial is correct */ 194 g_assert_cmpuint (get_uint32 (output, OFFSET_BODY_LENGTH, output[0]), ==, 8); 195 g_assert_cmpuint (get_uint32 (output, OFFSET_SERIAL, output[0]), ==, 196 0x12345678u); 197 /* the second "u" in the signature replaced a padding byte, so only 198 * the length of the body changed */ 199 g_assert_cmpint (len, ==, BLOB_LENGTH + 4); 200} 201 202static void 203test_needed (Fixture *f, 204 gconstpointer arg) 205{ 206 const gchar *blob = arg; 207 208 /* We need at least 16 bytes to know how long the message is - that's just 209 * a fact of the D-Bus protocol. */ 210 g_assert_cmpint ( 211 dbus_message_demarshal_bytes_needed (blob, 0), ==, 0); 212 g_assert_cmpint ( 213 dbus_message_demarshal_bytes_needed (blob, 15), ==, 0); 214 /* This is enough that we should be able to tell how much we need. */ 215 g_assert_cmpint ( 216 dbus_message_demarshal_bytes_needed (blob, 16), ==, BLOB_LENGTH); 217 /* The header is 32 bytes long (here), so that's another interesting 218 * boundary. */ 219 g_assert_cmpint ( 220 dbus_message_demarshal_bytes_needed (blob, 31), ==, BLOB_LENGTH); 221 g_assert_cmpint ( 222 dbus_message_demarshal_bytes_needed (blob, 32), ==, BLOB_LENGTH); 223 g_assert_cmpint ( 224 dbus_message_demarshal_bytes_needed (blob, 33), ==, BLOB_LENGTH); 225 g_assert_cmpint ( 226 dbus_message_demarshal_bytes_needed (blob, BLOB_LENGTH - 1), ==, 227 BLOB_LENGTH); 228 g_assert_cmpint ( 229 dbus_message_demarshal_bytes_needed (blob, BLOB_LENGTH), ==, 230 BLOB_LENGTH); 231 g_assert_cmpint ( 232 dbus_message_demarshal_bytes_needed (blob, sizeof (be_blob)), ==, 233 BLOB_LENGTH); 234} 235 236static void 237teardown (Fixture *f, 238 gconstpointer arg G_GNUC_UNUSED) 239{ 240 dbus_error_free (&f->e); 241} 242 243int 244main (int argc, 245 char **argv) 246{ 247 g_test_init (&argc, &argv, NULL); 248 249 g_test_add ("/demarshal/le", Fixture, le_blob, setup, test_endian, teardown); 250 g_test_add ("/demarshal/be", Fixture, be_blob, setup, test_endian, teardown); 251 g_test_add ("/demarshal/needed/le", Fixture, le_blob, setup, test_needed, 252 teardown); 253 g_test_add ("/demarshal/needed/be", Fixture, be_blob, setup, test_needed, 254 teardown); 255 256 return g_test_run (); 257} 258