From 049153bc2e1e54b3c8b693bf3a709a8a53bdeb0e Mon Sep 17 00:00:00 2001 From: Simon McVittie Date: Fri, 25 Feb 2011 14:28:24 +0000 Subject: [PATCH 1/2] Add dbus-spam, dbus-echo tools --- tools/.gitignore | 2 + tools/Makefile.am | 16 +++- tools/dbus-echo.c | 188 +++++++++++++++++++++++++++ tools/dbus-spam.c | 363 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 568 insertions(+), 1 deletions(-) create mode 100644 tools/dbus-echo.c create mode 100644 tools/dbus-spam.c diff --git a/tools/.gitignore b/tools/.gitignore index 234cef9..84252df 100644 --- a/tools/.gitignore +++ b/tools/.gitignore @@ -18,3 +18,5 @@ dbus-glib-bindings.h run-with-tmp-session-bus.conf print-introspect dbus-bus-introspect.xml +dbus-spam +dbus-echo diff --git a/tools/Makefile.am b/tools/Makefile.am index ce88c85..46b3dec 100644 --- a/tools/Makefile.am +++ b/tools/Makefile.am @@ -7,7 +7,13 @@ if DBUS_UNIX extra_bin_programs += dbus-cleanup-sockets dbus-uuidgen endif -bin_PROGRAMS=dbus-launch dbus-send dbus-monitor $(extra_bin_programs) +bin_PROGRAMS = \ + dbus-launch \ + dbus-send \ + dbus-monitor \ + dbus-echo \ + dbus-spam \ + $(extra_bin_programs) dbus_send_SOURCES= \ dbus-print-message.c \ @@ -48,6 +54,14 @@ dbus_uuidgen_LDFLAGS=@R_DYNAMIC_LDFLAG@ dbus_launch_LDADD= $(DBUS_X_LIBS) $(DBUS_CLIENT_LIBS) dbus_launch_LDFLAGS=@R_DYNAMIC_LDFLAG@ +dbus_echo_SOURCES= \ + dbus-echo.c +dbus_echo_LDADD = $(top_builddir)/dbus/libdbus-1.la + +dbus_spam_SOURCES= \ + dbus-spam.c +dbus_spam_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 0000000..43723b3 --- /dev/null +++ b/tools/dbus-echo.c @@ -0,0 +1,188 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ +/* dbus-echo.c - a plain libdbus echo server + * + * Copyright © 2003 Philip Blundell + * Copyright © 2011 Nokia Corporation + * + * 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 + +#include +#include +#include + +#include + +#ifdef DBUS_WIN +#include +#endif + +static void +usage (int exit_with) +{ + fprintf (stderr, + "Usage: dbus-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); +} + +/* 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 */ +static void +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 (¬hing); + select (1, ¬hing, ¬hing, ¬hing, &tv); +#endif +} + +static DBusHandlerResult +filter (DBusConnection *connection, + DBusMessage *message, + void *user_data) +{ + DBusMessage *reply; + DBusError error = DBUS_ERROR_INIT; + 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) + { + millisleep (*sleep_ms); + } + + reply = dbus_message_new_method_return (message); + + if (reply == NULL) + { + fprintf (stderr, "OOM allocating reply!\n"); + exit (1); + } + + if (!dbus_connection_send (connection, reply, NULL)) + { + fprintf (stderr, "OOM sending reply!\n"); + exit (1); + } + + dbus_message_unref (reply); + + return DBUS_HANDLER_RESULT_HANDLED; +} + +typedef enum { + CONN_WELL_KNOWN, + CONN_BUS, + CONN_RAW +} ConnectionMode; + +int +main (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; + + for (i = 1; 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)) + { + fprintf (stderr, "OOM while adding message filter\n"); + return 1; + } + + 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 0000000..3476f30 --- /dev/null +++ b/tools/dbus-spam.c @@ -0,0 +1,363 @@ +/* -*- 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 + * Copyright © 2011 Nokia Corporation + * + * 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 + +#include +#include +#include + +#include + +#if 0 +#define VERBOSE fprintf +#else +#define VERBOSE(...) do {} while (0) +#endif + +static void +usage (int ecode) +{ + fprintf (stderr, + "Usage: dbus-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" + " --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" + ); + exit (ecode); +} + +static void +oom (const char *doing) +{ + fprintf (stderr, "OOM while %s\n", doing); + exit (1); +} + +static void +pc_notify (DBusPendingCall *pc, + void *data) +{ + int *received_p = data; + + 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) + oom ("reading payload from stdin"); + + while (1) + { + if (len - pos < BLOCK_SIZE) + { + char *tmp = dbus_realloc (buf, len + BLOCK_SIZE); + + if (tmp == NULL) + 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 +main (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; + + for (i = 1; 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 (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); + + 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, "--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 + { + usage (2); + } + } + + 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) + oom ("copying message"); + + dbus_message_set_no_reply (message, no_reply); + } + else + { + dbus_bool_t mem; + + message = dbus_message_new_method_call (destination, + "/", + "com.example", + "Spam"); + + if (message == NULL) + oom ("allocating message"); + + dbus_message_set_no_reply (message, no_reply); + + switch (payload_type) + { + case DBUS_TYPE_STRING: + mem = dbus_message_append_args (message, + DBUS_TYPE_STRING, &payload, + DBUS_TYPE_INVALID); + break; + + case DBUS_TYPE_ARRAY: + mem = dbus_message_append_args (message, + DBUS_TYPE_ARRAY, + DBUS_TYPE_BYTE, + &payload, + (dbus_uint32_t) payload_len, + DBUS_TYPE_INVALID); + break; + + default: + mem = TRUE; + } + + if (!mem) + oom ("building message"); + } + + if (no_reply) + { + if (!dbus_connection_send (connection, message, NULL)) + oom ("sending message"); + + sent++; + } + else + { + DBusPendingCall *pc; + + if (!dbus_connection_send_with_reply (connection, + message, + &pc, + 0x7FFFFFFF)) + oom ("sending message"); + + VERBOSE (stderr, "sent message #%d\n", sent); + sent++; + + if (pc == NULL) + 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)) + 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; +} + -- 1.7.4.1