{NULL, NULL}
};
+static struct test_case test_case_desc_16[] = {
+ {"", "Test (kdbus) async match"},
+ {NULL, NULL}
+};
+
/* This table is used to start binaries */
struct binary tests[] = {
/*path, name, TC_table, timeout in us, prepare_args_handler, parse_function_handler, init_handler, clean_handler*/
{"/usr/lib/dbus-tests/test-suites/systemd-tests/test-bus-server", "test-bus-server", test_case_desc_13, 5000*1000, prepare_args_for_binary, parse_one_test_one_binary, NULL, NULL},
{"/usr/lib/dbus-tests/test-suites/systemd-tests/test-bus-signature", "test-bus-signature", test_case_desc_14, 5000*1000, prepare_args_for_binary, parse_one_test_one_binary, NULL, NULL},
{"/usr/lib/dbus-tests/test-suites/systemd-tests/test-bus-zero-copy", "test-bus-zero-copy", test_case_desc_15, 5000*1000, prepare_args_for_binary, parse_one_test_one_binary, NULL, NULL},
+ {"/usr/lib/dbus-tests/test-suites/systemd-tests/test-bus-async-match", "test-bus-async-match", test_case_desc_16, 5000*1000, prepare_args_for_binary, parse_one_test_one_binary, NULL, NULL},
};
static char* args[3];
--- /dev/null
+#include <sd-event.h>
+#include <sd-bus.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+
+enum app_state {
+ APP_STATE_START = 0,
+ APP_STATE_MATCH_ADDED,
+ APP_STATE_SIGNAL_EMIT_DONE,
+ APP_STATE_FINISHED_OK,
+ APP_STATE_FINISHED_ERROR
+};
+struct app_data {
+ sd_event *event;
+ sd_bus *bus;
+ enum app_state state;
+};
+
+static void dump_msg(sd_bus_message *m)
+{
+ uint8_t t;
+ const char *type;
+ const char *sender;
+ const char *destination;
+ const char *path;
+ const char *interface;
+ const char *member;
+
+ if (sd_bus_message_get_type(m, &t) < 0) {
+ printf("could not fetch message type\n");
+ return;
+ }
+
+ sender = sd_bus_message_get_sender(m);
+ if (NULL == sender) {
+ sender = "unknown";
+ }
+
+ destination = sd_bus_message_get_destination(m);
+ if (NULL == destination) {
+ destination = "unknown";
+ }
+
+ path= sd_bus_message_get_path(m);
+ if (NULL == path) {
+ path = "unknown";
+ }
+
+ interface = sd_bus_message_get_interface(m);
+ if (NULL == interface) {
+ interface = "unknown";
+ }
+
+ member = sd_bus_message_get_member(m);
+ if (NULL == member) {
+ member = "unknown";
+ }
+
+ switch (t) {
+ case SD_BUS_MESSAGE_METHOD_CALL:
+ type = "method call";
+ break;
+ case SD_BUS_MESSAGE_METHOD_RETURN:
+ type = "method return";
+ break;
+ case SD_BUS_MESSAGE_METHOD_ERROR:
+ type = "method error";
+ break;
+ case SD_BUS_MESSAGE_SIGNAL:
+ type = "signal";
+ break;
+ default:
+ type = "???";
+ break;
+ }
+
+ printf("message type=%s sender=%s destination=%s path=%s interface=%s member=%s\n",
+ type, sender, destination, path, interface, member);
+}
+
+static int timeout_callback(sd_event_source *s, uint64_t usec, void *userdata)
+{
+ int r;
+ sd_bus_message *m;
+ struct app_data *app = (struct app_data *)userdata;
+
+ assert(app);
+ assert(app->bus);
+
+ printf("Test timed out\n");
+ app->state = APP_STATE_FINISHED_ERROR;
+ sd_event_exit(app->event, -1);
+
+ return 0;
+}
+
+static int install_match_callback(sd_bus_message *m, void *userdata,
+ sd_bus_error *ret_error)
+{
+ int r;
+ sd_bus_message *msg;
+ struct app_data *app = (struct app_data *)userdata;
+
+ assert(app);
+ assert(app->bus);
+ assert(app->event);
+
+ if (APP_STATE_MATCH_ADDED != app->state) {
+ fprintf(stderr, "Install match: wrong app state (%d)\n", app->state);
+ app->state = APP_STATE_FINISHED_ERROR;
+ sd_event_exit(app->event, sd_bus_error_get_errno(ret_error));
+ return 0;
+ }
+
+ if (NULL != ret_error && 0 != sd_bus_error_is_set(ret_error)) {
+ fprintf(stderr,
+ "Failed to add match callback: %s/%s (%s)\n",
+ ret_error->name,
+ ret_error->message,
+ strerror(sd_bus_error_get_errno(ret_error)));
+ app->state = APP_STATE_FINISHED_ERROR;
+ sd_event_exit(app->event, sd_bus_error_get_errno(ret_error));
+ return 0;
+ }
+
+ r = sd_bus_message_new_signal(app->bus, &msg,
+ "/org/freedesktop/systemd1",
+ "org.freedesktop.systemd1.Manager",
+ "SystemdAsyncMatchTestSignal");
+
+ if (r < 0) {
+ fprintf(stderr, "Failed to add signal: %s\n", strerror(-r));
+ app->state = APP_STATE_FINISHED_ERROR;
+ sd_event_exit(app->event, r);
+ return r;
+ }
+
+ r = sd_bus_send(app->bus, msg, NULL);
+ if (r < 0) {
+ fprintf(stderr, "Failed to emit signal: %s\n", strerror(-r));
+ app->state = APP_STATE_FINISHED_ERROR;
+ sd_event_exit(app->event, r);
+ return r;
+ }
+
+ app->state = APP_STATE_SIGNAL_EMIT_DONE;
+ return 0;
+}
+
+static int signal_match_callback(sd_bus_message *m, void *userdata,
+ sd_bus_error *ret_error)
+{
+ struct app_data *app = (struct app_data *)userdata;
+
+ assert(app);
+ assert(app->bus);
+ assert(app->event);
+
+ if (APP_STATE_SIGNAL_EMIT_DONE != app->state) {
+ fprintf(stderr, "Match callback: wrong app state (%d)\n", app->state);
+ app->state = APP_STATE_FINISHED_ERROR;
+ sd_event_exit(app->event, -1);
+ return 0;
+ }
+
+ dump_msg(m);
+ app->state = APP_STATE_FINISHED_OK;
+ sd_event_exit(app->event, 0);
+ return 0;
+}
+
+int main(int argc, char *argv[]) {
+ struct app_data app = {
+ .state = APP_STATE_START
+ };
+ sd_bus_slot *slot;
+ sd_event_source *timeout;
+ int r;
+ sigset_t ss;
+ uint64_t now;
+ const char *match = "type='signal',interface='org.freedesktop.systemd1.Manager',path='/org/freedesktop/systemd1',member='SystemdAsyncMatchTestSignal'";
+
+ r = sd_event_default(&app.event);
+ if (r < 0) {
+ app.state = APP_STATE_FINISHED_ERROR;
+ goto finish;
+ }
+
+ if (sigemptyset(&ss) < 0 ||
+ sigaddset(&ss, SIGTERM) < 0 ||
+ sigaddset(&ss, SIGINT) < 0) {
+ r = -errno;
+ app.state = APP_STATE_FINISHED_ERROR;
+ goto finish;
+ }
+
+ /* Block SIGTERM first, so that the event loop can handle it */
+ if (sigprocmask(SIG_BLOCK, &ss, NULL) < 0) {
+ r = -errno;
+ app.state = APP_STATE_FINISHED_ERROR;
+ goto finish;
+ }
+
+ r = sd_event_add_signal(app.event, NULL, SIGTERM, NULL, NULL);
+ if (r < 0) {
+ app.state = APP_STATE_FINISHED_ERROR;
+ goto finish;
+ }
+ r = sd_event_add_signal(app.event, NULL, SIGINT, NULL, NULL);
+ if (r < 0) {
+ app.state = APP_STATE_FINISHED_ERROR;
+ goto finish;
+ }
+
+ /* Connect to the system bus */
+ r = sd_bus_open_system(&app.bus);
+ if (r < 0) {
+ fprintf(stderr, "Failed to connect to system bus: %s\n", strerror(-r));
+ app.state = APP_STATE_FINISHED_ERROR;
+ goto finish;
+ }
+
+ /* Add global test timeout callback */
+ r = sd_event_now(app.event, CLOCK_MONOTONIC, &now);
+ if (r < 0) {
+ fprintf(stderr, "Failed to get current timestamp: %s\n", strerror(-r));
+ app.state = APP_STATE_FINISHED_ERROR;
+ goto finish;
+ }
+
+ r = sd_event_add_time(app.event,
+ &timeout,
+ CLOCK_MONOTONIC,
+ now + 5000000, /* 5 seconds */
+ 0,
+ timeout_callback,
+ &app);
+
+ if (r < 0) {
+ fprintf(stderr, "Failed to add global timeout: %s\n", strerror(-r));
+ app.state = APP_STATE_FINISHED_ERROR;
+ goto finish;
+ }
+
+ /* Add signal match callback */
+ r = sd_bus_add_match_async(app.bus, &slot, match, signal_match_callback,
+ install_match_callback, &app);
+ if (r < 0) {
+ fprintf(stderr, "Failed to add match: %s\n", strerror(-r));
+ app.state = APP_STATE_FINISHED_ERROR;
+ goto finish;
+ }
+ app.state = APP_STATE_MATCH_ADDED;
+
+ /* Attach system bus events to manloop */
+ r = sd_bus_attach_event(app.bus, app.event, SD_EVENT_PRIORITY_NORMAL);
+ if (r < 0) {
+ fprintf(stderr, "Failed to attach system bus to mainloop: %s\n", strerror(-r));
+ app.state = APP_STATE_FINISHED_ERROR;
+ goto finish;
+ }
+
+ r = sd_event_loop(app.event);
+
+finish:
+ sd_event_source_set_enabled(timeout, SD_EVENT_OFF);
+
+ app.event = sd_event_unref(app.event);
+ slot = sd_bus_slot_unref(slot);
+ app.bus = sd_bus_unref(app.bus);
+
+ assert(app.state == APP_STATE_FINISHED_OK);
+
+ if (r < 0)
+ fprintf(stderr, "Test failed\n");
+ else
+ fprintf(stderr, "Test passed\n");
+
+ return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
+}