+2003-03-14 Havoc Pennington <hp@redhat.com>
+
+ * dbus/dbus-memory.c: add a "detect buffer overwrites on free"
+ cheesy hack
+
+ * dbus/dbus-transport-debug.c: rework this a good bit to be
+ less complicated. hopefully still works.
+
+ * dbus/dbus-server-debug.c (handle_new_client): remove timeout
+ manually
+
+ * glib/dbus-gmain.c (timeout_handler): don't remove timeout
+ after running it
+
+ * dbus/dbus-message.c (dbus_message_copy): rename from
+ dbus_message_new_from_message, fix it up to copy
+ all the message fields, add test case
+
+ * bus/dispatch.c (bus_dispatch_test): add some more test code,
+ not quite passing yet
+
2003-03-14 Havoc Pennington <hp@pobox.com>
* bus/loop.c (bus_loop_iterate): add this so we can "run loop
{
BusContext *context = data;
- dbus_server_handle_watch (context->server, watch, condition);
+ dbus_server_handle_watch (context->server, watch, condition);
}
static dbus_bool_t
bus_loop_remove_watch (watch, server_watch_callback, context);
}
+
static void
server_timeout_callback (DBusTimeout *timeout,
void *data)
if (!bus_connections_setup_connection (context->connections, new_connection))
_dbus_verbose ("No memory to setup new connection\n");
- /* on OOM, we won't have ref'd the connection so it will die */
+ /* on OOM, we won't have ref'd the connection so it will die. */
}
BusContext*
dbus_connection_handle_watch (connection, watch, condition);
- while (dbus_connection_dispatch_message (connection));
+ while (dbus_connection_dispatch_message (connection))
+ ;
dbus_connection_unref (connection);
}
connection_timeout_callback (DBusTimeout *timeout,
void *data)
{
+ DBusConnection *connection = data;
+
+ dbus_connection_ref (connection);
+
dbus_timeout_handle (timeout);
+
+ while (dbus_connection_dispatch_message (connection))
+ ;
+ dbus_connection_unref (connection);
}
static dbus_bool_t
#include "utils.h"
#include "bus.h"
#include "test.h"
+#include "loop.h"
#include <dbus/dbus-internals.h>
#include <string.h>
_dbus_assert (message_name != NULL); /* DBusMessageLoader is supposed to check this */
+ _dbus_verbose ("DISPATCH: %s to %s\n",
+ message_name, service_name ? service_name : "peer");
+
/* If service_name is NULL, this is a message to the bus daemon, not intended
* to actually go "on the bus"; e.g. a peer-to-peer ping. Handle these
* immediately, especially disconnection messages.
*/
if (service_name == NULL)
- {
+ {
if (strcmp (message_name, DBUS_MESSAGE_LOCAL_DISCONNECT) == 0)
bus_connection_disconnected (connection);
#ifdef DBUS_BUILD_TESTS
static void
-run_test_bus (BusContext *context)
+flush_bus (BusContext *context)
{
-
-
+ while (bus_loop_iterate (FALSE))
+ ;
}
+/* returns TRUE if the correct thing happens,
+ * but the correct thing may include OOM errors.
+ */
static dbus_bool_t
check_hello_message (BusContext *context,
DBusConnection *connection)
DBUS_MESSAGE_HELLO);
if (message == NULL)
- _dbus_assert_not_reached ("no memory");
+ return TRUE;
if (!dbus_connection_send (connection, message, &serial))
- _dbus_assert_not_reached ("no memory");
+ return TRUE;
+
+ dbus_message_unref (message);
+
+ flush_bus (context);
+ message = dbus_connection_pop_message (connection);
+ if (message == NULL)
+ {
+ _dbus_warn ("Did not receive a reply to %s %d on %p\n",
+ DBUS_MESSAGE_HELLO, serial, connection);
+ return FALSE;
+ }
+
+ _dbus_verbose ("Received %s on %p\n",
+ dbus_message_get_name (message), connection);
+
+ dbus_message_unref (message);
+
return TRUE;
}
DBusConnection *baz;
DBusResultCode result;
- return TRUE; /* FIXME */
-
dbus_error_init (&error);
context = bus_context_new ("debug:name=test-server",
activation_dirs,
if (baz == NULL)
_dbus_assert_not_reached ("could not alloc connection");
-
+ if (!check_hello_message (context, foo))
+ _dbus_assert_not_reached ("hello message failed");
+ if (!check_hello_message (context, bar))
+ _dbus_assert_not_reached ("hello message failed");
+ if (!check_hello_message (context, baz))
+ _dbus_assert_not_reached ("hello message failed");
return TRUE;
}
timeout, function, data);
}
-/* Returns TRUE if we dispatch any callbacks, which is just used in
- * test code as a debug hack
+/* Returns TRUE if we have any timeouts or ready file descriptors,
+ * which is just used in test code as a debug hack
*/
dbus_bool_t
fds = NULL;
watches_for_fds = NULL;
-
+
+#if 0
+ _dbus_verbose (" iterate %d timeouts %d watches\n",
+ timeout_count, watch_count);
+#endif
+
if (callbacks == NULL)
{
bus_loop_quit ();
{
unsigned long tv_sec;
unsigned long tv_usec;
-
+
+ retval = TRUE;
+
_dbus_get_current_time (&tv_sec, &tv_usec);
link = _dbus_list_get_first_link (&callbacks);
(tv_sec - tcb->last_tv_sec) * 1000 +
(tv_usec - tcb->last_tv_usec) / 1000;
+#if 0
+ _dbus_verbose (" interval = %lu elapsed = %lu\n",
+ interval, elapsed);
+#endif
+
if (interval <= elapsed)
{
/* Save last callback time and fire this timeout */
tcb->last_tv_sec = tv_sec;
tcb->last_tv_usec = tv_usec;
-
+
+#if 0
+ _dbus_verbose (" invoking timeout\n");
+#endif
+
(* tcb->function) (tcb->timeout,
cb->data);
-
- retval = TRUE;
}
}
(* wcb->function) (wcb->watch,
condition,
((Callback*)wcb)->data);
+
retval = TRUE;
}
}
if (!bus_dispatch_test (&test_data_dir))
die ("dispatch");
+
+ printf ("Success\n");
return 0;
#else /* DBUS_BUILD_TESTS */
-
+
+ printf ("Not compiled with test support\n");
+
return 0;
#endif
}
"
if test x$enable_tests = xyes; then
- echo "NOTE: building with unit tests increases the size of the installed library"
+ echo "NOTE: building with unit tests increases the size of the installed library and renders it insecure"
fi
if test x$enable_gcov = xyes; then
echo "NOTE: building with coverage profiling is definitely for developers only"
fi
if test x$enable_verbose_mode = xyes; then
- echo "NOTE: building with verbose mode increases library size, but is probably a good idea anyway."
+ echo "NOTE: building with verbose mode increases library size and may slightly increase security risk, but aids debugging."
fi
if test x$enable_asserts = xyes; then
echo "NOTE: building with assertions increases library size, but is probably a good idea anyway."
_dbus_connection_wakeup_mainloop (connection);
_dbus_assert (dbus_message_get_name (message) != NULL);
- _dbus_verbose ("Incoming message %p (%s) added to queue, %d incoming\n",
+ _dbus_verbose ("Message %p (%s) added to incoming queue %p, %d incoming\n",
message, dbus_message_get_name (message),
+ connection,
connection->n_incoming);
return TRUE;
_dbus_connection_wakeup_mainloop (connection);
- _dbus_verbose ("Incoming synthesized message %p added to queue, %d incoming\n",
- link->data, connection->n_incoming);
+ _dbus_verbose ("Synthesized message %p added to incoming queue %p, %d incoming\n",
+ link->data, connection, connection->n_incoming);
}
connection->n_outgoing -= 1;
- _dbus_verbose ("Message %p removed from outgoing queue, %d left to send\n",
- message, connection->n_outgoing);
+ _dbus_verbose ("Message %p removed from outgoing queue %p, %d left to send\n",
+ message, connection, connection->n_outgoing);
if (connection->n_outgoing == 0)
_dbus_transport_messages_pending (connection->transport,
* available. Otherwise records the timeout to be added when said
* function is available. Also re-adds the timeout if the
* DBusAddTimeoutFunction changes. May fail due to lack of memory.
- * The timeout will fire only one time.
+ * The timeout will fire repeatedly until removed.
*
* @param connection the connection.
* @param timeout the timeout to add.
dbus_message_ref (message);
connection->n_outgoing += 1;
- _dbus_verbose ("Message %p (%s) added to outgoing queue, %d pending to send\n",
+ _dbus_verbose ("Message %p (%s) added to outgoing queue %p, %d pending to send\n",
message,
dbus_message_get_name (message),
+ connection,
connection->n_outgoing);
if (dbus_message_get_serial (message) == -1)
message = _dbus_list_pop_first (&connection->incoming_messages);
connection->n_incoming -= 1;
- _dbus_verbose ("Incoming message %p removed from queue, %d incoming\n",
- message, connection->n_incoming);
+ _dbus_verbose ("Message %p removed from incoming queue %p, %d incoming\n",
+ message, connection, connection->n_incoming);
return message;
}
* g_timeout_add.
*
* The DBusTimeout can be queried for the timer interval using
- * dbus_timeout_get_interval.
- *
- * Once a timeout occurs, dbus_timeout_handle should be called to invoke
- * the timeout's callback, and the timeout should be automatically
- * removed. i.e. timeouts are one-shot.
+ * dbus_timeout_get_interval(). dbus_timeout_handle() should
+ * be called repeatedly, each time the interval elapses, starting
+ * after it has elapsed once. The timeout stops firing when
+ * it is removed with the given remove_function.
*
* @param connection the connection.
* @param add_function function to add a timeout.
static dbus_bool_t inited = FALSE;
static int fail_counts = -1;
static size_t fail_size = 0;
+static dbus_bool_t guards = FALSE;
+#define GUARD_VALUE 0xdeadbeef
+#define GUARD_INFO_SIZE 8
+#define GUARD_START_PAD 16
+#define GUARD_END_PAD 16
+#define GUARD_START_OFFSET (GUARD_START_PAD + GUARD_INFO_SIZE)
+#define GUARD_EXTRA_SIZE (GUARD_START_OFFSET + GUARD_END_PAD)
#endif
#ifdef DBUS_BUILD_TESTS
if (_dbus_getenv ("DBUS_MALLOC_FAIL_GREATER_THAN") != NULL)
fail_size = atoi (_dbus_getenv ("DBUS_MALLOC_FAIL_GREATER_THAN"));
+
+ if (_dbus_getenv ("DBUS_MALLOC_GUARDS") != NULL)
+ guards = TRUE;
inited = TRUE;
}
}
+
+typedef enum
+{
+ SOURCE_UNKNOWN,
+ SOURCE_MALLOC,
+ SOURCE_REALLOC,
+ SOURCE_MALLOC_ZERO,
+ SOURCE_REALLOC_NULL
+} BlockSource;
+
+static const char*
+source_string (BlockSource source)
+{
+ switch (source)
+ {
+ case SOURCE_UNKNOWN:
+ return "unknown";
+ case SOURCE_MALLOC:
+ return "malloc";
+ case SOURCE_REALLOC:
+ return "realloc";
+ case SOURCE_MALLOC_ZERO:
+ return "malloc0";
+ case SOURCE_REALLOC_NULL:
+ return "realloc(NULL)";
+ }
+ _dbus_assert_not_reached ("Invalid malloc block source ID");
+ return "invalid!";
+}
+
+static void
+check_guards (void *free_block)
+{
+ if (free_block != NULL)
+ {
+ unsigned char *block = ((unsigned char*)free_block) - GUARD_START_OFFSET;
+ size_t requested_bytes = *(dbus_uint32_t*)block;
+ BlockSource source = *(dbus_uint32_t*)(block + 4);
+ unsigned int i;
+ dbus_bool_t failed;
+
+ failed = FALSE;
+
+#if 0
+ _dbus_verbose ("Checking %d bytes request from source %s\n",
+ requested_bytes, source_string (source));
+#endif
+
+ i = GUARD_INFO_SIZE;
+ while (i < GUARD_START_OFFSET)
+ {
+ dbus_uint32_t value = *(dbus_uint32_t*) &block[i];
+ if (value != GUARD_VALUE)
+ {
+ _dbus_warn ("Block of %u bytes from %s had start guard value 0x%x at %d expected 0x%x\n",
+ requested_bytes, source_string (source),
+ value, i, GUARD_VALUE);
+ failed = TRUE;
+ }
+
+ i += 4;
+ }
+
+ i = GUARD_START_OFFSET + requested_bytes;
+ while (i < (GUARD_START_OFFSET + requested_bytes + GUARD_END_PAD))
+ {
+ dbus_uint32_t value = *(dbus_uint32_t*) &block[i];
+ if (value != GUARD_VALUE)
+ {
+ _dbus_warn ("Block of %u bytes from %s had end guard value 0x%x at %d expected 0x%x\n",
+ requested_bytes, source_string (source),
+ value, i, GUARD_VALUE);
+ failed = TRUE;
+ }
+
+ i += 4;
+ }
+
+ if (failed)
+ _dbus_assert_not_reached ("guard value corruption");
+ }
+}
+
+static void*
+set_guards (void *real_block,
+ size_t requested_bytes,
+ BlockSource source)
+{
+ unsigned char *block = real_block;
+ unsigned int i;
+
+ if (block == NULL)
+ return NULL;
+
+ _dbus_assert (GUARD_START_OFFSET + GUARD_END_PAD == GUARD_EXTRA_SIZE);
+
+ *((dbus_uint32_t*)block) = requested_bytes;
+ *((dbus_uint32_t*)(block + 4)) = source;
+
+ i = GUARD_INFO_SIZE;
+ while (i < GUARD_START_OFFSET)
+ {
+ (*(dbus_uint32_t*) &block[i]) = GUARD_VALUE;
+
+ i += 4;
+ }
+
+ i = GUARD_START_OFFSET + requested_bytes;
+ while (i < (GUARD_START_OFFSET + requested_bytes + GUARD_END_PAD))
+ {
+ (*(dbus_uint32_t*) &block[i]) = GUARD_VALUE;
+
+ i += 4;
+ }
+
+ check_guards (block + GUARD_START_OFFSET);
+
+ return block + GUARD_START_OFFSET;
+}
+
#endif
/**
#if DBUS_BUILD_TESTS
else if (fail_size != 0 && bytes > fail_size)
return NULL;
+ else if (guards)
+ {
+ void *block;
+
+ block = malloc (bytes + GUARD_EXTRA_SIZE);
+ return set_guards (block, bytes, SOURCE_MALLOC);
+ }
#endif
else
return malloc (bytes);
#if DBUS_BUILD_TESTS
else if (fail_size != 0 && bytes > fail_size)
return NULL;
+ else if (guards)
+ {
+ void *block;
+
+ block = calloc (bytes + GUARD_EXTRA_SIZE, 1);
+ return set_guards (block, bytes, SOURCE_MALLOC_ZERO);
+ }
#endif
else
return calloc (bytes, 1);
#if DBUS_BUILD_TESTS
else if (fail_size != 0 && bytes > fail_size)
return NULL;
+ else if (guards)
+ {
+ if (memory)
+ {
+ void *block;
+
+ check_guards (memory);
+
+ block = realloc (((unsigned char*)memory) - GUARD_START_OFFSET,
+ bytes + GUARD_EXTRA_SIZE);
+
+ /* old guards shouldn't have moved */
+ check_guards (((unsigned char*)block) + GUARD_START_OFFSET);
+
+ return set_guards (block, bytes, SOURCE_REALLOC);
+ }
+ else
+ {
+ void *block;
+
+ block = malloc (bytes + GUARD_EXTRA_SIZE);
+ return set_guards (block, bytes, SOURCE_REALLOC_NULL);
+ }
+ }
#endif
else
{
void
dbus_free (void *memory)
{
+#ifdef DBUS_BUILD_TESTS
+ if (guards)
+ {
+ check_guards (memory);
+ if (memory)
+ free (((unsigned char*)memory) - GUARD_START_OFFSET);
+ return;
+ }
+#endif
+
if (memory) /* we guarantee it's safe to free (NULL) */
free (memory);
}
* @returns the new message.
*/
DBusMessage *
-dbus_message_new_from_message (const DBusMessage *message)
+dbus_message_copy (const DBusMessage *message)
{
DBusMessage *retval;
int i;
retval->refcount = 1;
retval->byte_order = message->byte_order;
-
+ retval->client_serial = message->client_serial;
+ retval->reply_serial = message->reply_serial;
+ retval->header_padding = message->header_padding;
+ retval->locked = FALSE;
+
if (!_dbus_string_init (&retval->header, _DBUS_INT_MAX))
{
dbus_free (retval);
return retval;
}
+static void
+verify_test_message (DBusMessage *message)
+{
+ dbus_int32_t our_int;
+ char *our_str;
+ double our_double;
+ dbus_bool_t our_bool;
+
+ if (!dbus_message_get_args (message, NULL,
+ DBUS_TYPE_INT32, &our_int,
+ DBUS_TYPE_STRING, &our_str,
+ DBUS_TYPE_DOUBLE, &our_double,
+ DBUS_TYPE_BOOLEAN, &our_bool,
+ 0))
+ _dbus_assert_not_reached ("Could not get arguments");
+
+ if (our_int != -0x12345678)
+ _dbus_assert_not_reached ("integers differ!");
+
+ if (our_double != 3.14159)
+ _dbus_assert_not_reached ("doubles differ!");
+
+ if (strcmp (our_str, "Test string") != 0)
+ _dbus_assert_not_reached ("strings differ!");
+
+ if (!our_bool)
+ _dbus_assert_not_reached ("booleans differ");
+
+ dbus_free (our_str);
+}
+
/**
* @ingroup DBusMessageInternals
* Unit test for DBusMessage.
DBusMessageLoader *loader;
int i;
const char *data;
- dbus_int32_t our_int;
- char *our_str;
- double our_double;
- dbus_bool_t our_bool;
+ DBusMessage *copy;
+ const char *name1;
+ const char *name2;
/* Test the vararg functions */
message = dbus_message_new ("org.freedesktop.DBus.Test", "testMessage");
_dbus_verbose_bytes_of_string (&message->body, 0,
_dbus_string_get_length (&message->body));
- if (!dbus_message_get_args (message, NULL,
- DBUS_TYPE_INT32, &our_int,
- DBUS_TYPE_STRING, &our_str,
- DBUS_TYPE_DOUBLE, &our_double,
- DBUS_TYPE_BOOLEAN, &our_bool,
- 0))
- _dbus_assert_not_reached ("Could not get arguments");
+ verify_test_message (message);
- if (our_int != -0x12345678)
- _dbus_assert_not_reached ("integers differ!");
+ copy = dbus_message_copy (message);
+
+ _dbus_assert (message->client_serial == copy->client_serial);
+ _dbus_assert (message->reply_serial == copy->reply_serial);
+ _dbus_assert (message->header_padding == copy->header_padding);
+
+ _dbus_assert (_dbus_string_get_length (&message->header) ==
+ _dbus_string_get_length (©->header));
- if (our_double != 3.14159)
- _dbus_assert_not_reached ("doubles differ!");
+ _dbus_assert (_dbus_string_get_length (&message->body) ==
+ _dbus_string_get_length (©->body));
- if (strcmp (our_str, "Test string") != 0)
- _dbus_assert_not_reached ("strings differ!");
+ verify_test_message (copy);
- if (!our_bool)
- _dbus_assert_not_reached ("booleans differ");
+ name1 = dbus_message_get_name (message);
+ name2 = dbus_message_get_name (copy);
+
+ _dbus_assert (strcmp (name1, name2) == 0);
- dbus_free (our_str);
dbus_message_unref (message);
+ dbus_message_unref (copy);
message = dbus_message_new ("org.freedesktop.DBus.Test", "testMessage");
_dbus_message_set_serial (message, 1);
DBusMessage* dbus_message_new_error_reply (DBusMessage *original_message,
const char *error_name,
const char *error_message);
-DBusMessage *dbus_message_new_from_message (const DBusMessage *message);
+DBusMessage *dbus_message_copy (const DBusMessage *message);
void dbus_message_ref (DBusMessage *message);
void dbus_message_unref (DBusMessage *message);
{
DBusServer *server;
DBusTransport *transport;
-
+ DBusTimeout *timeout;
} ServerAndTransport;
static void
ServerAndTransport *st = data;
DBusTransport *transport;
DBusConnection *connection;
+
+ _dbus_verbose (" new debug client transport %p connecting to server\n",
+ st->transport);
transport = _dbus_transport_debug_server_new (st->transport);
if (transport == NULL)
- {
- return;
- }
+ return;
connection = _dbus_connection_new_for_transport (transport);
_dbus_transport_unref (transport);
st->server->new_connection_data);
dbus_server_unref (st->server);
}
+
+ _dbus_server_remove_timeout (st->server, st->timeout);
/* If no one grabbed a reference, the connection will die. */
dbus_connection_unref (connection);
+
+ /* killing timeout frees both "st" and "timeout" */
+ _dbus_timeout_unref (st->timeout);
}
/**
_dbus_server_debug_accept_transport (DBusServer *server,
DBusTransport *transport)
{
- DBusTimeout *timeout = NULL;
ServerAndTransport *st = NULL;
st = dbus_new (ServerAndTransport, 1);
st->transport = transport;
st->server = server;
- timeout = _dbus_timeout_new (DEFAULT_INTERVAL, handle_new_client, st, dbus_free);
+ st->timeout = _dbus_timeout_new (DEFAULT_INTERVAL, handle_new_client, st,
+ dbus_free);
- if (timeout == NULL)
+ if (st->timeout == NULL)
goto failed;
- if (!_dbus_server_add_timeout (server, timeout))
+ if (!_dbus_server_add_timeout (server, st->timeout))
goto failed;
-
- _dbus_timeout_unref (timeout);
return TRUE;
failed:
+ if (st->timeout)
+ _dbus_timeout_unref (st->timeout);
dbus_free (st);
- if (timeout)
- _dbus_timeout_unref (timeout);
return FALSE;
}
}
/**
- * Adds a timeout for this server, chaining out to application-provided
- * timeout handlers. The timeout will fire only one time.
+ * Adds a timeout for this server, chaining out to
+ * application-provided timeout handlers. The timeout should be
+ * repeatedly handled with dbus_timeout_handle() at its given interval
+ * until it is removed.
*
* @param server the server.
* @param timeout the timeout to add.
*/
/**
- * Gets the timeout interval.
+ * Gets the timeout interval. The dbus_timeout_handle()
+ * should be called each time this interval elapses,
+ * starting after it elapses once.
+ *
* @param timeout the DBusTimeout object.
* @returns the interval in milliseconds.
*/
void _dbus_timeout_ref (DBusTimeout *timeout);
void _dbus_timeout_unref (DBusTimeout *timeout);
-
DBusTimeoutList *_dbus_timeout_list_new (void);
void _dbus_timeout_list_free (DBusTimeoutList *timeout_list);
dbus_bool_t _dbus_timeout_list_set_functions (DBusTimeoutList *timeout_list,
/* dbus-transport-debug.c In-proc debug subclass of DBusTransport
*
* Copyright (C) 2003 CodeFactory AB
+ * Copyright (C) 2003 Red Hat, Inc.
*
* Licensed under the Academic Free License version 1.2
*
#define DEFAULT_INTERVAL 1
/**
+ * Hack due to lack of OOM handling in a couple places
+ */
+#define WAIT_FOR_MEMORY() _dbus_sleep_milliseconds (250)
+
+static void check_timeout (DBusTransport *transport);
+
+/**
* Opaque object representing a debug transport.
*
*/
{
DBusTransport base; /**< Parent instance */
- DBusTimeout *write_timeout; /**< Timeout for reading. */
- DBusTimeout *read_timeout; /**< Timeout for writing. */
+ DBusTimeout *timeout; /**< Timeout for moving messages. */
DBusTransport *other_end; /**< The transport that this transport is connected to. */
-};
-
-static void
-debug_finalize (DBusTransport *transport)
-{
- _dbus_transport_finalize_base (transport);
- dbus_free (transport);
-}
-
-static void
-do_reading (DBusTransport *transport)
-{
- DBusTransportDebug *debug_transport = (DBusTransportDebug*) transport;
-
- if (transport->disconnected)
- return;
-
- /* Now dispatch the messages */
- if (dbus_connection_dispatch_message (transport->connection))
- {
- debug_transport->read_timeout =
- _dbus_timeout_new (DEFAULT_INTERVAL, (DBusTimeoutHandler)do_reading,
- transport, NULL);
- if (!_dbus_connection_add_timeout (transport->connection,
- debug_transport->read_timeout))
- {
- _dbus_timeout_unref (debug_transport->read_timeout);
- debug_transport->read_timeout = NULL;
- }
- }
-}
+ unsigned int timeout_added : 1; /**< Whether timeout has been added */
+};
-static void
-check_read_timeout (DBusTransport *transport)
+/* move messages in both directions */
+static dbus_bool_t
+move_messages (DBusTransport *transport)
{
DBusTransportDebug *debug_transport = (DBusTransportDebug*) transport;
- dbus_bool_t need_read_timeout;
-
- if (transport->connection == NULL)
- return;
-
- _dbus_transport_ref (transport);
-
- need_read_timeout = dbus_connection_get_n_messages (transport->connection) > 0;
if (transport->disconnected)
- need_read_timeout = FALSE;
-
- if (need_read_timeout &&
- debug_transport->read_timeout == NULL)
- {
- debug_transport->read_timeout =
- _dbus_timeout_new (DEFAULT_INTERVAL, (DBusTimeoutHandler)do_reading,
- transport, NULL);
-
- if (debug_transport->read_timeout == NULL)
- goto out;
-
- if (!_dbus_connection_add_timeout (transport->connection,
- debug_transport->read_timeout))
- {
- _dbus_timeout_unref (debug_transport->read_timeout);
- debug_transport->read_timeout = NULL;
-
- goto out;
- }
- }
- else if (!need_read_timeout &&
- debug_transport->read_timeout != NULL)
- {
- _dbus_connection_remove_timeout (transport->connection,
- debug_transport->read_timeout);
- _dbus_timeout_unref (debug_transport->read_timeout);
- debug_transport->read_timeout = NULL;
- }
-
- out:
- _dbus_transport_unref (transport);
-}
-
-static void
-do_writing (DBusTransport *transport)
-{
- if (transport->disconnected)
- return;
+ return TRUE;
while (!transport->disconnected &&
_dbus_connection_have_messages_to_send (transport->connection))
DBusMessage *message, *copy;
message = _dbus_connection_get_message_to_send (transport->connection);
- _dbus_message_lock (message);
+ _dbus_assert (message != NULL);
- copy = dbus_message_new_from_message (message);
+ copy = dbus_message_copy (message);
+ if (copy == NULL)
+ return FALSE;
+
+ _dbus_message_lock (message);
_dbus_connection_message_sent (transport->connection,
message);
+
+ _dbus_verbose (" -->transporting message %s from %s %p to %s %p\n",
+ dbus_message_get_name (copy),
+ transport->is_server ? "server" : "client",
+ transport->connection,
+ debug_transport->other_end->is_server ? "server" : "client",
+ debug_transport->other_end->connection);
- _dbus_connection_queue_received_message (((DBusTransportDebug *)transport)->other_end->connection,
+ _dbus_connection_queue_received_message (debug_transport->other_end->connection,
copy);
dbus_message_unref (copy);
}
- check_read_timeout (((DBusTransportDebug *)transport)->other_end);
+ if (debug_transport->other_end &&
+ !debug_transport->other_end->disconnected &&
+ _dbus_connection_have_messages_to_send (debug_transport->other_end->connection))
+ {
+ if (!move_messages (debug_transport->other_end))
+ return FALSE;
+ }
+
+ return TRUE;
}
static void
-check_write_timeout (DBusTransport *transport)
+timeout_handler (void *data)
{
- DBusTransportDebug *debug_transport = (DBusTransportDebug *)transport;
- dbus_bool_t need_write_timeout;
+ DBusTransport *transport = data;
- if (transport->connection == NULL)
- return;
+ while (!move_messages (transport))
+ WAIT_FOR_MEMORY ();
- _dbus_transport_ref (transport);
+ check_timeout (transport);
+}
- need_write_timeout = transport->messages_need_sending;
+static void
+check_timeout (DBusTransport *transport)
+{
+ DBusTransportDebug *debug_transport = (DBusTransportDebug*) transport;
- if (transport->disconnected)
- need_write_timeout = FALSE;
-
- if (need_write_timeout &&
- debug_transport->write_timeout == NULL)
+ if (transport->connection &&
+ transport->authenticated &&
+ (transport->messages_need_sending ||
+ (debug_transport->other_end &&
+ debug_transport->other_end->messages_need_sending)))
{
- debug_transport->write_timeout =
- _dbus_timeout_new (DEFAULT_INTERVAL, (DBusTimeoutHandler)do_writing,
- transport, NULL);
-
- if (debug_transport->write_timeout == NULL)
- goto out;
-
- if (!_dbus_connection_add_timeout (transport->connection,
- debug_transport->write_timeout))
- {
- _dbus_timeout_unref (debug_transport->write_timeout);
- debug_transport->write_timeout = NULL;
- }
+ if (!debug_transport->timeout_added)
+ {
+ /* FIXME; messages_pending is going to have to
+ * handle OOM somehow (probably being part of
+ * PreallocatedSend). See also dbus-transport-unix.c
+ * check_write_watch()
+ */
+ while (!_dbus_connection_add_timeout (transport->connection,
+ debug_transport->timeout))
+ WAIT_FOR_MEMORY ();
+ debug_transport->timeout_added = TRUE;
+ }
}
- else if (!need_write_timeout &&
- debug_transport->write_timeout != NULL)
+ else
{
- _dbus_connection_remove_timeout (transport->connection,
- debug_transport->write_timeout);
- _dbus_timeout_unref (debug_transport->write_timeout);
- debug_transport->write_timeout = NULL;
+ if (debug_transport->timeout_added)
+ {
+ _dbus_connection_remove_timeout (transport->connection,
+ debug_transport->timeout);
+ debug_transport->timeout_added = FALSE;
+ }
}
+}
- out:
- _dbus_transport_unref (transport);
+static void
+debug_finalize (DBusTransport *transport)
+{
+ DBusTransportDebug *debug_transport = (DBusTransportDebug*) transport;
+
+ if (debug_transport->timeout_added)
+ _dbus_connection_remove_timeout (transport->connection,
+ debug_transport->timeout);
+
+ if (debug_transport->other_end)
+ {
+ _dbus_transport_disconnect (debug_transport->other_end);
+ debug_transport->other_end = NULL;
+ }
+
+ _dbus_transport_finalize_base (transport);
+
+ _dbus_timeout_unref (debug_transport->timeout);
+
+ dbus_free (transport);
}
static void
static void
debug_connection_set (DBusTransport *transport)
{
+ check_timeout (transport);
}
static void
debug_messages_pending (DBusTransport *transport,
int messages_pending)
{
- check_write_timeout (transport);
+ check_timeout (transport);
}
static void
unsigned int flags,
int timeout_milliseconds)
{
+ move_messages (transport);
}
static void
debug_live_messages_changed
};
+static dbus_bool_t
+create_timeout_object (DBusTransportDebug *debug_transport)
+{
+ debug_transport->timeout = _dbus_timeout_new (DEFAULT_INTERVAL,
+ timeout_handler,
+ debug_transport, NULL);
+
+ return debug_transport->timeout != NULL;
+}
+
/**
* Creates a new debug server transport.
*
return NULL;
}
+ if (!create_timeout_object (debug_transport))
+ {
+ _dbus_transport_finalize_base (&debug_transport->base);
+ dbus_free (debug_transport);
+ return NULL;
+ }
+
debug_transport->base.authenticated = TRUE;
/* Connect the two transports */
debug_transport->other_end = client;
((DBusTransportDebug *)client)->other_end = (DBusTransport *)debug_transport;
+
+ _dbus_verbose (" new debug server transport %p created, other end %p\n",
+ debug_transport, debug_transport->other_end);
return (DBusTransport *)debug_transport;
}
dbus_set_result (result, DBUS_RESULT_NO_MEMORY);
return NULL;
}
-
- if (!_dbus_server_debug_accept_transport (debug_server, (DBusTransport *)debug_transport))
+
+ if (!create_timeout_object (debug_transport))
{
_dbus_transport_finalize_base (&debug_transport->base);
-
- dbus_free (debug_transport);
- dbus_set_result (result, DBUS_RESULT_IO_ERROR);
+ dbus_free (debug_transport);
+ dbus_set_result (result, DBUS_RESULT_NO_MEMORY);
+ return NULL;
+ }
+
+ if (!_dbus_server_debug_accept_transport (debug_server,
+ (DBusTransport *)debug_transport))
+ {
+ _dbus_timeout_unref (debug_transport->timeout);
+ _dbus_transport_finalize_base (&debug_transport->base);
+ dbus_free (debug_transport);
+ dbus_set_result (result, DBUS_RESULT_NO_MEMORY);
return NULL;
-
}
/* FIXME: Prolly wrong to do this. */
debug_transport->base.authenticated = TRUE;
+
+ _dbus_verbose (" new debug client transport %p created, other end %p\n",
+ debug_transport, debug_transport->other_end);
return (DBusTransport *)debug_transport;
}
_dbus_watch_new (unix_transport->fd,
DBUS_WATCH_WRITABLE);
- /* we can maybe add it some other time, just silently bomb */
+ /* FIXME this is total crack. The proper fix is probably to
+ * allocate the write watch on transport creation, keep it
+ * allocated. But that doesn't solve needing memory to add the
+ * watch. messages_pending is going to have to handle OOM
+ * somehow (probably being part of PreallocatedSend)
+ */
if (unix_transport->write_watch == NULL)
goto out;
dbus_timeout_handle (timeout);
- return FALSE;
+ return TRUE;
}
static dbus_bool_t