summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlban Crequy <alban.crequy@collabora.co.uk>2011-09-26 11:02:59 +0100
committerSimon McVittie <simon.mcvittie@collabora.co.uk>2014-10-14 13:53:54 +0100
commit10f8b67a9f1875f83ac5b81b844c1f3f151a68cf (patch)
treefd7a85ccd0d26002d5105906185aaba9c4fc3bfb
parentc88525f815d17933e2c00cb20f9eb3804a860257 (diff)
downloaddbus-10f8b67a9f1875f83ac5b81b844c1f3f151a68cf.tar.gz
Add dbus-test-tool, currently with "echo" and "spam" modes
This is installed by default, but easy to filter out for embedded systems or whatever. Based on earlier work by Simon McVittie and Will Thompson Bug: https://bugs.freedesktop.org/show_bug.cgi?id=34140 Reviewed-by: Simon McVittie <simon.mcvittie@collabora.co.uk>
-rw-r--r--tools/.gitignore1
-rw-r--r--tools/Makefile.am11
-rw-r--r--tools/dbus-echo.c154
-rw-r--r--tools/dbus-spam.c461
-rw-r--r--tools/test-tool.c87
-rw-r--r--tools/test-tool.h30
-rw-r--r--tools/tool-common.c60
-rw-r--r--tools/tool-common.h38
8 files changed, 842 insertions, 0 deletions
diff --git a/tools/.gitignore b/tools/.gitignore
index d7c21afe..1e0d987a 100644
--- a/tools/.gitignore
+++ b/tools/.gitignore
@@ -19,3 +19,4 @@ dbus-glib-bindings.h
run-with-tmp-session-bus.conf
print-introspect
dbus-bus-introspect.xml
+dbus-test-tool
diff --git a/tools/Makefile.am b/tools/Makefile.am
index 2ec19eda..05d1dcb5 100644
--- a/tools/Makefile.am
+++ b/tools/Makefile.am
@@ -15,6 +15,7 @@ bin_PROGRAMS = \
dbus-launch \
dbus-monitor \
dbus-send \
+ dbus-test-tool \
$(NULL)
if DBUS_UNIX
@@ -81,6 +82,16 @@ dist_examples_SCRIPTS = \
GetAllMatchRules.py \
$(NULL)
+dbus_test_tool_SOURCES = \
+ dbus-echo.c \
+ dbus-spam.c \
+ tool-common.c \
+ tool-common.h \
+ test-tool.c \
+ test-tool.h \
+ $(NULL)
+dbus_test_tool_LDADD = $(top_builddir)/dbus/libdbus-1.la
+
EXTRA_DIST = run-with-tmp-session-bus.sh strtoll.c strtoull.c
CLEANFILES = \
run-with-tmp-session-bus.conf
diff --git a/tools/dbus-echo.c b/tools/dbus-echo.c
new file mode 100644
index 00000000..05af6011
--- /dev/null
+++ b/tools/dbus-echo.c
@@ -0,0 +1,154 @@
+/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
+/* dbus-echo.c - a plain libdbus echo server
+ *
+ * Copyright © 2003 Philip Blundell <philb@gnu.org>
+ * Copyright © 2011 Nokia Corporation
+ * Copyright © 2014 Collabora Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#include <config.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <dbus/dbus.h>
+
+#include "test-tool.h"
+#include "tool-common.h"
+
+static void
+usage (int exit_with)
+{
+ fprintf (stderr,
+ "Usage: dbus-test-tool echo [OPTIONS]\n"
+ "\n"
+ "Respond to all method calls with an empty reply.\n"
+ "\n"
+ "Options:\n"
+ "\n"
+ " --name=NAME claim this well-known name first\n"
+ "\n"
+ " --sleep=N sleep N milliseconds before sending each reply\n"
+ "\n"
+ " --session use the session bus (default)\n"
+ " --system use the system bus\n"
+ );
+ exit (exit_with);
+}
+
+static DBusHandlerResult
+filter (DBusConnection *connection,
+ DBusMessage *message,
+ void *user_data)
+{
+ DBusMessage *reply;
+ int *sleep_ms = user_data;
+
+ if (dbus_message_get_type (message) != DBUS_MESSAGE_TYPE_METHOD_CALL)
+ return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+
+ if (*sleep_ms > 0)
+ {
+ tool_millisleep (*sleep_ms);
+ }
+
+ reply = dbus_message_new_method_return (message);
+
+ if (reply == NULL)
+ tool_oom ("allocating reply");
+
+ if (!dbus_connection_send (connection, reply, NULL))
+ tool_oom ("sending reply");
+
+ dbus_message_unref (reply);
+
+ return DBUS_HANDLER_RESULT_HANDLED;
+}
+
+int
+dbus_test_tool_echo (int argc, char **argv)
+{
+ DBusConnection *connection;
+ DBusError error = DBUS_ERROR_INIT;
+ DBusBusType type = DBUS_BUS_SESSION;
+ int i;
+ int sleep_ms = -1;
+ const char *name = NULL;
+
+ /* argv[1] is the tool name, so start from 2 */
+
+ for (i = 2; i < argc; i++)
+ {
+ const char *arg = argv[i];
+
+ if (strcmp (arg, "--system") == 0)
+ {
+ type = DBUS_BUS_SYSTEM;
+ }
+ else if (strcmp (arg, "--session") == 0)
+ {
+ type = DBUS_BUS_SESSION;
+ }
+ else if (strstr (arg, "--name=") == arg)
+ {
+ name = arg + strlen ("--name=");
+ }
+ else if (strstr (arg, "--sleep-ms=") == arg)
+ {
+ sleep_ms = atoi (arg + strlen ("--sleep-ms="));
+ }
+ else
+ {
+ usage (2);
+ }
+ }
+
+ connection = dbus_bus_get (type, &error);
+
+ if (connection == NULL)
+ {
+ fprintf (stderr, "Failed to connect to bus: %s: %s\n",
+ error.name, error.message);
+ dbus_error_free (&error);
+ return 1;
+ }
+
+ if (name != NULL)
+ {
+ if (dbus_bus_request_name (connection, name, DBUS_NAME_FLAG_DO_NOT_QUEUE,
+ NULL) != DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER)
+ {
+ fprintf (stderr, "failed to take bus name %s\n", name);
+ exit (1);
+ }
+ }
+ else
+ {
+ printf ("%s\n", dbus_bus_get_unique_name (connection));
+ }
+
+ if (!dbus_connection_add_filter (connection, filter, &sleep_ms, NULL))
+ tool_oom ("adding message filter");
+
+ while (dbus_connection_read_write_dispatch (connection, -1))
+ {}
+
+ dbus_connection_unref (connection);
+ return 0;
+}
diff --git a/tools/dbus-spam.c b/tools/dbus-spam.c
new file mode 100644
index 00000000..76f0e061
--- /dev/null
+++ b/tools/dbus-spam.c
@@ -0,0 +1,461 @@
+/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
+/* dbus-spam.c - a plain libdbus message-sender, loosely based on dbus-send
+ *
+ * Copyright © 2003 Philip Blundell <philb@gnu.org>
+ * Copyright © 2011 Nokia Corporation
+ * Copyright © 2014 Collabora Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#include <config.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+
+#include <dbus/dbus.h>
+
+#include "test-tool.h"
+#include "tool-common.h"
+
+static dbus_bool_t ignore_errors = FALSE;
+
+static void
+usage (int ecode)
+{
+ fprintf (stderr,
+ "Usage: dbus-test-tool spam [OPTIONS]\n"
+ "\n"
+ "Repeatedly call com.example.Spam() on the given D-Bus service.\n"
+ "\n"
+ "Options:\n"
+ "\n"
+ " --session use the session bus (default)\n"
+ " --system use the system bus\n"
+ "\n"
+ " --ignore-errors ignore errors\n"
+ " --dest=NAME call methods on NAME (default " DBUS_SERVICE_DBUS ")\n"
+ "\n"
+ " --count=N send N messages (default 1)\n"
+ " --queue=N queue up N messages at a time (default 1)\n"
+ " --flood send all messages immediately\n"
+ " --no-reply set the NO_REPLY flag (implies --flood)\n"
+ "\n"
+ " --string send payload as a string (default)\n"
+ " --bytes send payload as a byte-array\n"
+ " --empty send an empty payload\n"
+ "\n"
+ " --payload=S use S as payload (default \"hello, world!\")\n"
+ " --stdin read payload from stdin, until EOF\n"
+ " --message-stdin read a complete D-Bus message from stdin\n"
+ " --random-size read whitespace-separated ASCII decimal\n"
+ " payload sizes from stdin and pick one randomly\n"
+ " for each message\n"
+ "\n"
+ " --seed=SEED seed for srand (default is time())\n"
+ "\n"
+ );
+ exit (ecode);
+}
+
+static void
+pc_notify (DBusPendingCall *pc,
+ void *data)
+{
+ DBusMessage *message;
+ int *received_p = data;
+ DBusError error;
+
+ dbus_error_init (&error);
+
+ message = dbus_pending_call_steal_reply (pc);
+
+ if (!ignore_errors && dbus_message_get_type (message) == DBUS_MESSAGE_TYPE_ERROR)
+ {
+ dbus_set_error_from_message (&error, message);
+ fprintf (stderr, "Failed to receive reply #%d: %s: %s\n", *received_p,
+ error.name, error.message);
+ }
+ else
+ {
+ VERBOSE (stderr, "received message #%d\n", *received_p);
+ }
+
+ (*received_p)++;
+}
+
+static void
+consume_stdin (char **payload_p,
+ size_t *len_p)
+{
+ const size_t BLOCK_SIZE = 4096;
+ size_t len = BLOCK_SIZE;
+ size_t pos = 0;
+ size_t n;
+ char *buf;
+
+ buf = dbus_malloc (len);
+
+ if (buf == NULL)
+ tool_oom ("reading payload from stdin");
+
+ while (1)
+ {
+ if (len - pos < BLOCK_SIZE)
+ {
+ char *tmp = dbus_realloc (buf, len + BLOCK_SIZE);
+
+ if (tmp == NULL)
+ tool_oom ("reading payload from stdin");
+
+ buf = tmp;
+ len += BLOCK_SIZE;
+ }
+
+ n = fread (buf + pos, 1, len - pos, stdin);
+
+ if (n <= 0)
+ {
+ /* EOF or error - treat as EOF */
+ break;
+ }
+
+ pos += n;
+ }
+
+ *len_p = pos;
+ *payload_p = buf;
+}
+
+int
+dbus_test_tool_spam (int argc, char **argv)
+{
+ DBusConnection *connection;
+ DBusError error = DBUS_ERROR_INIT;
+ DBusBusType type = DBUS_BUS_SESSION;
+ const char *destination = DBUS_SERVICE_DBUS;
+ int i;
+ int count = 1;
+ int sent = 0;
+ int received = 0;
+ int queue_len = 1;
+ const char *payload = NULL;
+ char *payload_buf = NULL;
+ size_t payload_len;
+ int payload_type = DBUS_TYPE_STRING;
+ DBusMessage *template = NULL;
+ dbus_bool_t no_reply = FALSE;
+ unsigned int seed = time (NULL);
+ int n_random_sizes = 0;
+ unsigned int *random_sizes = NULL;
+
+ /* argv[1] is the tool name, so start from 2 */
+
+ for (i = 2; i < argc; i++)
+ {
+ const char *arg = argv[i];
+
+ if (strcmp (arg, "--system") == 0)
+ {
+ type = DBUS_BUS_SYSTEM;
+ }
+ else if (strcmp (arg, "--session") == 0)
+ {
+ type = DBUS_BUS_SESSION;
+ }
+ else if (strstr (arg, "--count=") == arg)
+ {
+ count = atoi (arg + strlen ("--count="));
+
+ if (count < 1)
+ usage (2);
+ }
+ else if (strcmp (arg, "--ignore-errors") == 0)
+ {
+ ignore_errors = TRUE;
+ }
+ else if (strstr (arg, "--dest=") == arg)
+ {
+ destination = arg + strlen ("--dest=");
+ }
+ else if (strstr (arg, "--payload=") == arg)
+ {
+ payload = arg + strlen ("--payload=");
+ }
+ else if (strcmp (arg, "--stdin") == 0)
+ {
+ consume_stdin (&payload_buf, &payload_len);
+ payload = payload_buf;
+ }
+ else if (strcmp (arg, "--message-stdin") == 0)
+ {
+ consume_stdin (&payload_buf, &payload_len);
+ payload = payload_buf;
+ template = dbus_message_demarshal (payload, payload_len, &error);
+
+ if (template == NULL)
+ {
+ fprintf (stderr, "Unable to demarshal template message: %s: %s",
+ error.name, error.message);
+ exit (1);
+ }
+
+ if (dbus_message_get_type (template) != DBUS_MESSAGE_TYPE_METHOD_CALL)
+ {
+ fprintf (stderr, "Template message must be a method call\n");
+ exit (1);
+ }
+ }
+ else if (strcmp (arg, "--random-size") == 0)
+ {
+ unsigned int len, max = 0;
+ int j, consumed = 0;
+ const char *p;
+
+ consume_stdin (&payload_buf, &payload_len);
+
+ for (p = payload_buf; p < payload_buf + payload_len; p += consumed)
+ {
+ /* the space character matches any (or no) whitespace */
+ if (sscanf (p, " %u %n", &len, &consumed) == 0)
+ break;
+
+ n_random_sizes++;
+ }
+
+ random_sizes = dbus_new0 (int, n_random_sizes);
+
+ if (random_sizes == NULL)
+ tool_oom ("allocating array of message lengths");
+
+ for (p = payload_buf, j = 0;
+ p < payload_buf + payload_len && j < n_random_sizes;
+ p += consumed, j++)
+ {
+ sscanf (p, " %u %n", &len, &consumed);
+ random_sizes[j] = len;
+
+ if (len > max)
+ max = len;
+ }
+
+ dbus_free (payload_buf);
+ payload_len = max + 1;
+ payload_buf = dbus_new (char, payload_len);
+ payload = payload_buf;
+
+ if (payload_buf == NULL)
+ tool_oom ("allocating maximum-sized payload");
+
+ memset (payload_buf, 'X', payload_len);
+ payload_buf[payload_len - 1] = '\0';
+ }
+ else if (strcmp (arg, "--empty") == 0)
+ {
+ payload_type = DBUS_TYPE_INVALID;
+ }
+ else if (strcmp (arg, "--string") == 0)
+ {
+ payload_type = DBUS_TYPE_STRING;
+ }
+ else if (strcmp (arg, "--bytes") == 0)
+ {
+ payload_type = DBUS_TYPE_ARRAY;
+ }
+ else if (strcmp (arg, "--flood") == 0)
+ {
+ queue_len = -1;
+ }
+ else if (strcmp (arg, "--no-reply") == 0)
+ {
+ queue_len = -1;
+ no_reply = TRUE;
+ }
+ else if (strstr (arg, "--queue=") == arg)
+ {
+ queue_len = atoi (arg + strlen ("--queue="));
+
+ if (queue_len < 1)
+ usage (2);
+ }
+ else if (strstr (arg, "--seed=") == arg)
+ {
+ seed = strtoul (arg + strlen ("--seed="), NULL, 10);
+ }
+ else
+ {
+ usage (2);
+ }
+ }
+
+ srand (seed);
+
+ if (payload == NULL)
+ {
+ payload = "hello, world!";
+ payload_len = strlen (payload);
+ }
+
+ VERBOSE (stderr, "Will send up to %d messages, with up to %d queued\n",
+ count, queue_len);
+
+ connection = dbus_bus_get_private (type, &error);
+
+ if (connection == NULL)
+ {
+ fprintf (stderr, "Failed to connect to bus: %s: %s\n",
+ error.name, error.message);
+ dbus_error_free (&error);
+ return 1;
+ }
+
+ while (no_reply ? sent < count : received < count)
+ {
+ while (sent < count &&
+ (queue_len == -1 || sent < queue_len + received))
+ {
+ DBusMessage *message;
+
+ if (template != NULL)
+ {
+ message = dbus_message_copy (template);
+
+ if (message == NULL)
+ tool_oom ("copying message");
+
+ dbus_message_set_no_reply (message, no_reply);
+ }
+ else
+ {
+ dbus_bool_t mem;
+ unsigned int len = 0;
+
+ message = dbus_message_new_method_call (destination,
+ "/",
+ "com.example",
+ "Spam");
+
+ if (message == NULL)
+ tool_oom ("allocating message");
+
+ dbus_message_set_no_reply (message, no_reply);
+
+ switch (payload_type)
+ {
+ case DBUS_TYPE_STRING:
+ if (random_sizes != NULL)
+ {
+ /* this isn't fair, strictly speaking - the first few
+ * are a bit more likely to be chosen, unless
+ * RAND_MAX is divisible by n_random_sizes - but it's
+ * good enough for traffic-generation */
+ len = random_sizes[rand () % n_random_sizes];
+ payload_buf[len] = '\0';
+ }
+
+ mem = dbus_message_append_args (message,
+ DBUS_TYPE_STRING, &payload,
+ DBUS_TYPE_INVALID);
+
+ if (random_sizes != NULL)
+ {
+ /* undo the truncation above */
+ payload_buf[len] = 'X';
+ }
+
+ break;
+
+ case DBUS_TYPE_ARRAY:
+ len = payload_len;
+
+ /* as above, not strictly fair, but close enough */
+ if (random_sizes != NULL)
+ len = random_sizes[rand () % n_random_sizes];
+
+ mem = dbus_message_append_args (message,
+ DBUS_TYPE_ARRAY,
+ DBUS_TYPE_BYTE,
+ &payload,
+ (dbus_uint32_t) len,
+ DBUS_TYPE_INVALID);
+ break;
+
+ default:
+ mem = TRUE;
+ }
+
+ if (!mem)
+ tool_oom ("building message");
+ }
+
+ if (no_reply)
+ {
+ if (!dbus_connection_send (connection, message, NULL))
+ tool_oom ("sending message");
+
+ sent++;
+ }
+ else
+ {
+ DBusPendingCall *pc;
+
+ if (!dbus_connection_send_with_reply (connection,
+ message,
+ &pc,
+ DBUS_TIMEOUT_INFINITE))
+ tool_oom ("sending message");
+
+ VERBOSE (stderr, "sent message #%d\n", sent);
+ sent++;
+
+ if (pc == NULL)
+ tool_oom ("sending message");
+
+ if (dbus_pending_call_get_completed (pc))
+ pc_notify (pc, &received);
+ else if (!dbus_pending_call_set_notify (pc, pc_notify, &received,
+ NULL))
+ tool_oom ("setting pending call notifier");
+
+ dbus_pending_call_unref (pc);
+ }
+
+ dbus_message_unref (message);
+ }
+
+ if (!dbus_connection_read_write_dispatch (connection, -1))
+ {
+ fprintf (stderr, "Disconnected from bus\n");
+ exit (1);
+ }
+ }
+
+ dbus_connection_flush (connection);
+
+ VERBOSE (stderr, "Done\n");
+
+ dbus_free (payload_buf);
+
+ if (template != NULL)
+ dbus_message_unref (template);
+
+ dbus_connection_close (connection);
+ dbus_connection_unref (connection);
+ dbus_shutdown ();
+ return 0;
+}
diff --git a/tools/test-tool.c b/tools/test-tool.c
new file mode 100644
index 00000000..1893b78c
--- /dev/null
+++ b/tools/test-tool.c
@@ -0,0 +1,87 @@
+/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
+/* dbus-test-tool - D-Bus swiss army knife
+ *
+ * Copyright © 2003 Philip Blundell <philb@gnu.org>
+ * Copyright © 2011 Nokia Corporation
+ * Copyright © 2014 Collabora Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#include <config.h>
+#include "test-tool.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <dbus/dbus.h>
+
+static struct {
+ const char *name;
+ int (*callback) (int, char **);
+} subcommands[] = {
+ { "echo", dbus_test_tool_echo },
+ { "spam", dbus_test_tool_spam },
+ { NULL, NULL }
+};
+
+static void usage (int exit_with) _DBUS_GNUC_NORETURN;
+
+static void
+usage (int exit_with)
+{
+ int i;
+
+ fprintf (stderr,
+ "Usage: dbus-test-tool SUBCOMMAND [OPTIONS]\n"
+ "\n"
+ "Known SUBCOMMANDs are:\n"
+ "\n"
+ );
+
+ for (i = 0; subcommands[i].name != NULL; i++)
+ {
+ fprintf (stderr, "- %s\n", subcommands[i].name);
+ }
+
+ fprintf (stderr,
+ "\n"
+ "For more information: dbus-test-tool SUBCOMMAND --help\n"
+ );
+
+ exit (exit_with);
+}
+
+int
+main (int argc, char **argv)
+{
+ int i;
+
+ if (argc < 2)
+ {
+ usage (2);
+ }
+
+ for (i = 0; subcommands[i].name != NULL; i++)
+ {
+ if (!strcmp (argv[1], subcommands[i].name))
+ return subcommands[i].callback (argc, argv);
+ }
+
+ usage (2);
+ return 2;
+}
diff --git a/tools/test-tool.h b/tools/test-tool.h
new file mode 100644
index 00000000..b6d51c22
--- /dev/null
+++ b/tools/test-tool.h
@@ -0,0 +1,30 @@
+/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
+/* dbus-test-tool - D-Bus swiss army knife
+ *
+ * Copyright © 2003 Philip Blundell <philb@gnu.org>
+ * Copyright © 2011 Nokia Corporation
+ * Copyright © 2014 Collabora Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#ifndef DBUS_TEST_TOOL_H
+#define DBUS_TEST_TOOL_H
+
+int dbus_test_tool_echo (int argc, char **argv);
+int dbus_test_tool_spam (int argc, char **argv);
+
+#endif
diff --git a/tools/tool-common.c b/tools/tool-common.c
new file mode 100644
index 00000000..b6af629f
--- /dev/null
+++ b/tools/tool-common.c
@@ -0,0 +1,60 @@
+/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
+/* tool-common - common functionality for dbus-test-tool modules
+ *
+ * Copyright © 2003 Philip Blundell <philb@gnu.org>
+ * Copyright © 2011 Nokia Corporation
+ * Copyright © 2014 Collabora Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#include <config.h>
+#include "tool-common.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+
+#ifdef DBUS_WIN
+#include <windows.h>
+#endif
+
+/* a hack to avoid having to depend on the static -util version of libdbus;
+ * it's useful for ancillary programs to be able to use the shared library */
+void
+tool_millisleep (int ms)
+{
+#ifdef DBUS_WIN
+ Sleep (ms);
+#else
+ fd_set nothing;
+ struct timeval tv;
+
+ tv.tv_sec = ms / 1000;
+ tv.tv_usec = (ms % 1000) * 1000;
+
+ FD_ZERO (&nothing);
+ select (1, &nothing, &nothing, &nothing, &tv);
+#endif
+}
+
+void
+tool_oom (const char *doing)
+{
+ fprintf (stderr, "OOM while %s\n", doing);
+ exit (1);
+}
diff --git a/tools/tool-common.h b/tools/tool-common.h
new file mode 100644
index 00000000..f31076fe
--- /dev/null
+++ b/tools/tool-common.h
@@ -0,0 +1,38 @@
+/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
+/* tool-common - common functionality for dbus-test-tool modules
+ *
+ * Copyright © 2003 Philip Blundell <philb@gnu.org>
+ * Copyright © 2011 Nokia Corporation
+ * Copyright © 2014 Collabora Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#ifndef DBUS_TOOL_COMMON_H
+#define DBUS_TOOL_COMMON_H
+
+#include <dbus/dbus.h>
+
+#if 0
+#define VERBOSE fprintf
+#else
+#define VERBOSE(...) do {} while (0)
+#endif
+
+void tool_millisleep (int ms);
+void tool_oom (const char *doing);
+
+#endif