#include <gio/gio.h>
#include <dbus/dbus.h>
-#include <dbus/dbus-glib-lowlevel.h>
+
+#include "test-utils.h"
typedef struct {
DBusError e;
+ TestMainContext *ctx;
DBusServer *server;
DBusConnection *server_conn;
g_assert (f->server_conn == NULL);
f->server_conn = dbus_connection_ref (server_conn);
- dbus_connection_setup_with_g_main (server_conn, NULL);
+ test_connection_setup (f->ctx, server_conn);
}
static void
setup (Fixture *f,
gconstpointer addr)
{
+ f->ctx = test_main_context_get ();
dbus_error_init (&f->e);
g_queue_init (&f->client_messages);
dbus_server_set_new_connection_function (f->server,
new_conn_cb, f, NULL);
- dbus_server_setup_with_g_main (f->server, NULL);
+ test_server_setup (f->ctx, f->server);
}
static void
dbus_server_get_address (f->server), &f->e);
assert_no_error (&f->e);
g_assert (f->client_conn != NULL);
- dbus_connection_setup_with_g_main (f->client_conn, NULL);
+ test_connection_setup (f->ctx, f->client_conn);
while (f->server_conn == NULL)
{
g_print (".");
- g_main_context_iteration (NULL, TRUE);
+ test_main_context_iterate (f->ctx, TRUE);
}
have_mem = dbus_connection_add_filter (f->client_conn,
while (g_queue_is_empty (&f->client_messages))
{
g_print (".");
- g_main_context_iteration (NULL, TRUE);
+ test_main_context_iterate (f->ctx, TRUE);
}
g_assert_cmpuint (g_queue_get_length (&f->client_messages), ==, 1);
dbus_message_unref (outgoing);
}
+static void
+send_n_bytes (GSocket *socket,
+ const gchar *blob,
+ gssize blob_len)
+{
+ gssize len, total_sent;
+ GError *gerror = NULL;
+
+ total_sent = 0;
+
+ while (total_sent < blob_len)
+ {
+ len = g_socket_send (socket,
+ blob + total_sent,
+ blob_len - total_sent,
+ NULL, &gerror);
+
+ /* this is NULL-safe: a NULL error does not match */
+ if (g_error_matches (gerror, G_IO_ERROR, G_IO_ERROR_WOULD_BLOCK))
+ {
+ /* we could wait for G_IO_OUT, but life's too short; just sleep */
+ g_clear_error (&gerror);
+ g_usleep (G_USEC_PER_SEC / 10);
+ continue;
+ }
+
+ g_assert_no_error (gerror);
+ g_assert (len >= 0);
+ total_sent += len;
+ }
+}
+
/* Enough bytes for it to be obvious that this connection is broken */
#define CORRUPT_LEN 1024
GSocket *socket;
GError *gerror = NULL;
int fd;
- gssize len, total_sent;
DBusMessage *incoming;
test_message (f, addr);
g_assert_no_error (gerror);
g_assert (socket != NULL);
- total_sent = 0;
-
- while (total_sent < CORRUPT_LEN)
- {
- len = g_socket_send_with_blocking (socket,
- not_a_dbus_message + total_sent, CORRUPT_LEN - total_sent,
- TRUE, NULL, &gerror);
- g_assert_no_error (gerror);
- g_assert (len >= 0);
- total_sent += len;
- }
+ send_n_bytes (socket, not_a_dbus_message, CORRUPT_LEN);
/* Now spin on the client connection: the server just sent it complete
* rubbish, so it should disconnect */
while (g_queue_is_empty (&f->client_messages))
{
g_print (".");
- g_main_context_iteration (NULL, TRUE);
+ test_main_context_iterate (f->ctx, TRUE);
}
incoming = g_queue_pop_head (&f->client_messages);
"/org/freedesktop/DBus/Local");
dbus_message_unref (incoming);
+
+ /* Free the DBusConnection before the GSocket, because GSocket is
+ * going to close our fd. GSocket tolerates closing an already-closed
+ * fd, whereas DBusLoop + DBusSocketSetEpoll doesn't. On Unix
+ * we could use dup() but that isn't portable to Windows :-(
+ */
+ dbus_connection_close (f->server_conn);
+ dbus_connection_unref (f->server_conn);
+ f->server_conn = NULL;
+
+ g_object_unref (socket);
+}
+
+static void
+test_byte_order (Fixture *f,
+ gconstpointer addr)
+{
+ GSocket *socket;
+ GError *gerror = NULL;
+ int fd;
+ char *blob;
+ const gchar *arg = not_a_dbus_message;
+ const gchar * const *args = &arg;
+ int blob_len;
+ DBusMessage *message;
+ dbus_bool_t mem;
+
+ test_message (f, addr);
+
+ message = dbus_message_new_signal ("/", "a.b", "c");
+ g_assert (message != NULL);
+ /* Append 0xFF bytes, so that the length of the body when byte-swapped
+ * is 0xFF000000, which is invalid */
+ mem = dbus_message_append_args (message,
+ DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE, &args, 0xFF,
+ DBUS_TYPE_INVALID);
+ g_assert (mem);
+ mem = dbus_message_marshal (message, &blob, &blob_len);
+ g_assert (mem);
+ g_assert_cmpuint (blob_len, >, 0xFF);
+ g_assert (blob != NULL);
+
+ dbus_message_unref (message);
+
+ /* Break the message by changing its claimed byte order, without actually
+ * byteswapping anything. We happen to know that byte order is the first
+ * byte. */
+ if (blob[0] == 'B')
+ blob[0] = 'l';
+ else
+ blob[0] = 'B';
+
+ /* OK, now the connection is working, let's break it */
+
+ dbus_connection_flush (f->server_conn);
+
+ if (!dbus_connection_get_socket (f->server_conn, &fd))
+ g_error ("failed to steal fd from server connection");
+
+ socket = g_socket_new_from_fd (fd, &gerror);
+ g_assert_no_error (gerror);
+ g_assert (socket != NULL);
+
+ send_n_bytes (socket, blob, blob_len);
+
+ dbus_free (blob);
+
+ /* Now spin on the client connection: the server just sent it a faulty
+ * message, so it should disconnect */
+ while (g_queue_is_empty (&f->client_messages))
+ {
+ g_print (".");
+ test_main_context_iterate (f->ctx, TRUE);
+ }
+
+ message = g_queue_pop_head (&f->client_messages);
+
+ g_assert (!dbus_message_contains_unix_fds (message));
+ g_assert_cmpstr (dbus_message_get_destination (message), ==, NULL);
+ g_assert_cmpstr (dbus_message_get_error_name (message), ==, NULL);
+ g_assert_cmpstr (dbus_message_get_interface (message), ==,
+ "org.freedesktop.DBus.Local");
+ g_assert_cmpstr (dbus_message_get_member (message), ==, "Disconnected");
+ g_assert_cmpstr (dbus_message_get_sender (message), ==, NULL);
+ g_assert_cmpstr (dbus_message_get_signature (message), ==, "");
+ g_assert_cmpstr (dbus_message_get_path (message), ==,
+ "/org/freedesktop/DBus/Local");
+
+ dbus_message_unref (message);
+
+ /* Free the DBusConnection before the GSocket, as above. */
+ dbus_connection_close (f->server_conn);
+ dbus_connection_unref (f->server_conn);
+ f->server_conn = NULL;
+
+ g_object_unref (socket);
}
static void
dbus_server_unref (f->server);
f->server = NULL;
}
+
+ test_main_context_unref (f->ctx);
}
int
test_corrupt, teardown);
#endif
+ g_test_add ("/corrupt/byte-order/tcp", Fixture, "tcp:host=127.0.0.1", setup,
+ test_byte_order, teardown);
+
return g_test_run ();
}