--- /dev/null
+/* -*- 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;
+}
--- /dev/null
+/* -*- 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;
+}