summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSimon McVittie <simon.mcvittie@collabora.co.uk>2011-06-09 18:47:04 +0100
committerSimon McVittie <simon.mcvittie@collabora.co.uk>2011-06-10 18:32:43 +0100
commitbf421f5a30ef98731fa96e1826b76cf33904e8b3 (patch)
tree394e20cd8b6cbb88efbc76928aaed74b4ed69ed3
parent983fd362645beab59cf43fc5d68e4f6ac7a8bbeb (diff)
downloaddbus-bf421f5a30ef98731fa96e1826b76cf33904e8b3.tar.gz
Add a test for marshalling and endian-swapping
Reviewed-by: Will Thompson <will.thompson@collabora.co.uk> Bug: https://bugs.freedesktop.org/show_bug.cgi?id=38120
-rw-r--r--test/.gitignore1
-rw-r--r--test/Makefile.am8
-rw-r--r--test/marshal.c220
3 files changed, 229 insertions, 0 deletions
diff --git a/test/.gitignore b/test/.gitignore
index 77f38e57..1337de64 100644
--- a/test/.gitignore
+++ b/test/.gitignore
@@ -27,3 +27,4 @@ test-names
test-loopback
test-relay
test-dbus-daemon
+test-marshal
diff --git a/test/Makefile.am b/test/Makefile.am
index e74a8d39..afa99dc1 100644
--- a/test/Makefile.am
+++ b/test/Makefile.am
@@ -80,6 +80,7 @@ installable_tests = \
test-corrupt \
test-dbus-daemon \
test-loopback \
+ test-marshal \
test-relay \
$(NULL)
@@ -120,6 +121,13 @@ test_dbus_daemon_LDADD = $(top_builddir)/dbus/libdbus-1.la \
$(GLIB_LIBS) \
$(DBUS_GLIB_LIBS)
+test_marshal_SOURCES = marshal.c
+test_marshal_CPPFLAGS = $(GLIB_CFLAGS) $(DBUS_GLIB_CFLAGS)
+test_marshal_LDFLAGS = @R_DYNAMIC_LDFLAG@
+test_marshal_LDADD = $(top_builddir)/dbus/libdbus-1.la \
+ $(GLIB_LIBS) \
+ $(DBUS_GLIB_LIBS)
+
if DBUS_ENABLE_MODULAR_TESTS
TESTS += $(installable_tests)
installcheck_tests += $(installable_tests)
diff --git a/test/marshal.c b/test/marshal.c
new file mode 100644
index 00000000..d87e4406
--- /dev/null
+++ b/test/marshal.c
@@ -0,0 +1,220 @@
+/* Simple sanity-check for D-Bus message serialization.
+ *
+ * Author: Simon McVittie <simon.mcvittie@collabora.co.uk>
+ * Copyright © 2010-2011 Nokia Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation files
+ * (the "Software"), to deal in the Software without restriction,
+ * including without limitation the rights to use, copy, modify, merge,
+ * publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <config.h>
+
+#include <glib.h>
+
+#include <dbus/dbus.h>
+#include <dbus/dbus-glib-lowlevel.h>
+
+typedef struct {
+ DBusError e;
+} Fixture;
+
+static void
+assert_no_error (const DBusError *e)
+{
+ if (G_UNLIKELY (dbus_error_is_set (e)))
+ g_error ("expected success but got error: %s: %s", e->name, e->message);
+}
+
+static void
+setup (Fixture *f,
+ gconstpointer arg G_GNUC_UNUSED)
+{
+ dbus_error_init (&f->e);
+}
+
+/* this is meant to be obviously correct, not efficient! */
+static guint32
+get_uint32 (const gchar *blob,
+ gsize offset,
+ char endian)
+{
+ if (endian == 'l')
+ {
+ return
+ blob[offset] |
+ (blob[offset + 1] << 8) |
+ (blob[offset + 2] << 16) |
+ (blob[offset + 3] << 24);
+ }
+ else if (endian == 'B')
+ {
+ return
+ (blob[offset] << 24) |
+ (blob[offset + 1] << 16) |
+ (blob[offset + 2] << 8) |
+ blob[offset + 3];
+ }
+ else
+ {
+ g_assert_not_reached ();
+ }
+}
+
+#define BLOB_LENGTH (sizeof (le_blob) - 1)
+#define OFFSET_BODY_LENGTH (4)
+#define OFFSET_SERIAL (8)
+
+const gchar le_blob[] =
+ /* byte 0 */
+ /* yyyyuu fixed headers */
+ "l" /* little-endian */
+ "\2" /* reply (which is the simplest message) */
+ "\2" /* no auto-starting */
+ "\1" /* D-Bus version = 1 */
+ /* byte 4 */
+ "\4\0\0\0" /* bytes in body = 4 */
+ /* byte 8 */
+ "\x78\x56\x34\x12" /* serial number = 0x12345678 */
+ /* byte 12 */
+ /* a(uv) variable headers start here */
+ "\x0f\0\0\0" /* bytes in array of variable headers = 15 */
+ /* pad to 8-byte boundary = nothing */
+ /* byte 16 */
+ "\5" /* in reply to: */
+ "\1u\0" /* variant signature = u */
+ /* pad to 4-byte boundary = nothing */
+ "\x12\xef\xcd\xab" /* 0xabcdef12 */
+ /* pad to 8-byte boundary = nothing */
+ /* byte 24 */
+ "\x08" /* signature: */
+ "\1g\0" /* variant signature = g */
+ "\1u\0" /* 1 byte, u, NUL (no alignment needed) */
+ "\0" /* pad to 8-byte boundary for body */
+ /* body; byte 32 */
+ "\xef\xbe\xad\xde" /* 0xdeadbeef */
+ ;
+
+const gchar be_blob[] =
+ /* byte 0 */
+ /* yyyyuu fixed headers */
+ "B" /* big-endian */
+ "\2" /* reply (which is the simplest message) */
+ "\2" /* no auto-starting */
+ "\1" /* D-Bus version = 1 */
+ /* byte 4 */
+ "\0\0\0\4" /* bytes in body = 4 */
+ /* byte 8 */
+ "\x12\x34\x56\x78" /* serial number = 0x12345678 */
+ /* byte 12 */
+ /* a(uv) variable headers start here */
+ "\0\0\0\x0f" /* bytes in array of variable headers = 15 */
+ /* pad to 8-byte boundary = nothing */
+ /* byte 16 */
+ "\5" /* in reply to: */
+ "\1u\0" /* variant signature = u */
+ /* pad to 4-byte boundary = nothing */
+ "\xab\xcd\xef\x12" /* 0xabcdef12 */
+ /* pad to 8-byte boundary = nothing */
+ /* byte 24 */
+ "\x08" /* signature: */
+ "\1g\0" /* variant signature = g */
+ "\1u\0" /* 1 byte, u, NUL (no alignment needed) */
+ "\0" /* pad to 8-byte boundary for body */
+ /* body; byte 32 */
+ "\xde\xad\xbe\xef" /* 0xdeadbeef */
+ ;
+
+static void
+test_endian (Fixture *f,
+ gconstpointer arg)
+{
+ const gchar *blob = arg;
+ const gchar *native_blob;
+ char *output;
+ DBusMessage *m;
+ int len;
+ dbus_uint32_t u;
+ dbus_bool_t ok;
+
+ g_assert_cmpuint ((guint) sizeof (le_blob), ==, (guint) sizeof (be_blob));
+
+ g_assert_cmpuint (get_uint32 (blob, OFFSET_BODY_LENGTH, blob[0]), ==, 4);
+ g_assert_cmpuint (get_uint32 (blob, OFFSET_SERIAL, blob[0]), ==,
+ 0x12345678u);
+
+ len = dbus_message_demarshal_bytes_needed (blob, sizeof (le_blob));
+ /* everything in the string except the implicit "\0" at the end is part of
+ * the message */
+ g_assert_cmpint (len, ==, BLOB_LENGTH);
+
+ m = dbus_message_demarshal (blob, sizeof (le_blob), &f->e);
+ assert_no_error (&f->e);
+ g_assert (m != NULL);
+
+ g_assert_cmpuint (dbus_message_get_serial (m), ==, 0x12345678u);
+ g_assert_cmpuint (dbus_message_get_reply_serial (m), ==, 0xabcdef12u);
+ g_assert_cmpstr (dbus_message_get_signature (m), ==, "u");
+
+ /* Implementation detail: appending to the message results in it being
+ * byteswapped into compiler byte order, which exposed a bug in libdbus,
+ * fd.o #38120. (If that changes, this test might not exercise that
+ * particular bug but will still be valid.) */
+ u = 0xdecafbadu;
+ ok = dbus_message_append_args (m,
+ DBUS_TYPE_UINT32, &u,
+ DBUS_TYPE_INVALID);
+ g_assert (ok);
+
+ dbus_message_marshal (m, &output, &len);
+
+ g_assert (output[0] == 'l' || output[0] == 'B');
+ /* the single-byte fields are unaffected, even if the endianness was
+ * swapped */
+ g_assert_cmpint (output[1], ==, blob[1]);
+ g_assert_cmpint (output[2], ==, blob[2]);
+ g_assert_cmpint (output[3], ==, blob[3]);
+ /* the length and serial are in the new endianness, the length has expanded
+ * to 8, and the serial is correct */
+ g_assert_cmpuint (get_uint32 (output, OFFSET_BODY_LENGTH, output[0]), ==, 8);
+ g_assert_cmpuint (get_uint32 (output, OFFSET_SERIAL, output[0]), ==,
+ 0x12345678u);
+ /* the second "u" in the signature replaced a padding byte, so only
+ * the length of the body changed */
+ g_assert_cmpint (len, ==, BLOB_LENGTH + 4);
+}
+
+static void
+teardown (Fixture *f,
+ gconstpointer arg G_GNUC_UNUSED)
+{
+ dbus_error_free (&f->e);
+}
+
+int
+main (int argc,
+ char **argv)
+{
+ g_test_init (&argc, &argv, NULL);
+
+ g_test_add ("/demarshal/le", Fixture, le_blob, setup, test_endian, teardown);
+ g_test_add ("/demarshal/be", Fixture, be_blob, setup, test_endian, teardown);
+
+ return g_test_run ();
+}