1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
4 This file is part of systemd.
6 Copyright 2013 Lennart Poettering
8 systemd is free software; you can redistribute it and/or modify it
9 under the terms of the GNU Lesser General Public License as published by
10 the Free Software Foundation; either version 2.1 of the License, or
11 (at your option) any later version.
13 systemd is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 Lesser General Public License for more details.
18 You should have received a copy of the GNU Lesser General Public License
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
31 #include "bus-internal.h"
32 #include "bus-message.h"
40 char *automatic_string_property;
41 uint32_t automatic_integer_property;
44 static int something_handler(sd_bus_message *m, void *userdata, sd_bus_error *error) {
45 struct context *c = userdata;
50 r = sd_bus_message_read(m, "s", &s);
53 n = strjoin("<<<", s, ">>>", NULL);
59 log_info("AlterSomething() called, got %s, returning %s", s, n);
61 /* This should fail, since the return type doesn't match */
62 assert_se(sd_bus_reply_method_return(m, "u", 4711) == -ENOMSG);
64 r = sd_bus_reply_method_return(m, "s", n);
70 static int exit_handler(sd_bus_message *m, void *userdata, sd_bus_error *error) {
71 struct context *c = userdata;
76 log_info("Exit called");
78 r = sd_bus_reply_method_return(m, "");
84 static int get_handler(sd_bus *bus, const char *path, const char *interface, const char *property, sd_bus_message *reply, void *userdata, sd_bus_error *error) {
85 struct context *c = userdata;
88 log_info("property get for %s called, returning \"%s\".", property, c->something);
90 r = sd_bus_message_append(reply, "s", c->something);
96 static int set_handler(sd_bus *bus, const char *path, const char *interface, const char *property, sd_bus_message *value, void *userdata, sd_bus_error *error) {
97 struct context *c = userdata;
102 log_info("property set for %s called", property);
104 r = sd_bus_message_read(value, "s", &s);
116 static int value_handler(sd_bus *bus, const char *path, const char *interface, const char *property, sd_bus_message *reply, void *userdata, sd_bus_error *error) {
117 _cleanup_free_ char *s = NULL;
120 assert_se(asprintf(&s, "object %p, path %s", userdata, path) >= 0);
121 r = sd_bus_message_append(reply, "s", s);
124 assert_se(startswith(path, "/value/") != NULL || strcmp(path, "/value") == 0);
126 assert_se(PTR_TO_UINT(userdata) == 30);
131 static int notify_test(sd_bus_message *m, void *userdata, sd_bus_error *error) {
134 assert_se(sd_bus_emit_properties_changed(sd_bus_message_get_bus(m), m->path, "org.freedesktop.systemd.ValueTest", "Value", NULL) >= 0);
136 r = sd_bus_reply_method_return(m, NULL);
142 static int notify_test2(sd_bus_message *m, void *userdata, sd_bus_error *error) {
145 assert_se(sd_bus_emit_properties_changed_strv(sd_bus_message_get_bus(m), m->path, "org.freedesktop.systemd.ValueTest", NULL) >= 0);
147 r = sd_bus_reply_method_return(m, NULL);
153 static int emit_interfaces_added(sd_bus_message *m, void *userdata, sd_bus_error *error) {
156 assert_se(sd_bus_emit_interfaces_added(sd_bus_message_get_bus(m), m->path, "org.freedesktop.systemd.test", NULL) >= 0);
158 r = sd_bus_reply_method_return(m, NULL);
164 static int emit_interfaces_removed(sd_bus_message *m, void *userdata, sd_bus_error *error) {
167 assert_se(sd_bus_emit_interfaces_removed(sd_bus_message_get_bus(m), m->path, "org.freedesktop.systemd.test", NULL) >= 0);
169 r = sd_bus_reply_method_return(m, NULL);
175 static int emit_object_added(sd_bus_message *m, void *userdata, sd_bus_error *error) {
178 assert_se(sd_bus_emit_object_added(sd_bus_message_get_bus(m), m->path) >= 0);
180 r = sd_bus_reply_method_return(m, NULL);
186 static int emit_object_removed(sd_bus_message *m, void *userdata, sd_bus_error *error) {
189 assert_se(sd_bus_emit_object_removed(sd_bus_message_get_bus(m), m->path) >= 0);
191 r = sd_bus_reply_method_return(m, NULL);
197 static const sd_bus_vtable vtable[] = {
198 SD_BUS_VTABLE_START(0),
199 SD_BUS_METHOD("AlterSomething", "s", "s", something_handler, 0),
200 SD_BUS_METHOD("Exit", "", "", exit_handler, 0),
201 SD_BUS_WRITABLE_PROPERTY("Something", "s", get_handler, set_handler, 0, 0),
202 SD_BUS_WRITABLE_PROPERTY("AutomaticStringProperty", "s", NULL, NULL, offsetof(struct context, automatic_string_property), 0),
203 SD_BUS_WRITABLE_PROPERTY("AutomaticIntegerProperty", "u", NULL, NULL, offsetof(struct context, automatic_integer_property), 0),
204 SD_BUS_METHOD("NoOperation", NULL, NULL, NULL, 0),
205 SD_BUS_METHOD("EmitInterfacesAdded", NULL, NULL, emit_interfaces_added, 0),
206 SD_BUS_METHOD("EmitInterfacesRemoved", NULL, NULL, emit_interfaces_removed, 0),
207 SD_BUS_METHOD("EmitObjectAdded", NULL, NULL, emit_object_added, 0),
208 SD_BUS_METHOD("EmitObjectRemoved", NULL, NULL, emit_object_removed, 0),
212 static const sd_bus_vtable vtable2[] = {
213 SD_BUS_VTABLE_START(0),
214 SD_BUS_METHOD("NotifyTest", "", "", notify_test, 0),
215 SD_BUS_METHOD("NotifyTest2", "", "", notify_test2, 0),
216 SD_BUS_PROPERTY("Value", "s", value_handler, 10, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
217 SD_BUS_PROPERTY("Value2", "s", value_handler, 10, SD_BUS_VTABLE_PROPERTY_EMITS_INVALIDATION),
218 SD_BUS_PROPERTY("Value3", "s", value_handler, 10, SD_BUS_VTABLE_PROPERTY_CONST),
219 SD_BUS_PROPERTY("Value4", "s", value_handler, 10, 0),
223 static int enumerator_callback(sd_bus *bus, const char *path, void *userdata, char ***nodes, sd_bus_error *error) {
225 if (object_path_startswith("/value", path))
226 assert_se(*nodes = strv_new("/value/a", "/value/b", "/value/c", NULL));
231 static void *server(void *p) {
232 struct context *c = p;
239 assert_se(sd_id128_randomize(&id) >= 0);
241 assert_se(sd_bus_new(&bus) >= 0);
242 assert_se(sd_bus_set_fd(bus, c->fds[0], c->fds[0]) >= 0);
243 assert_se(sd_bus_set_server(bus, 1, id) >= 0);
245 assert_se(sd_bus_add_object_vtable(bus, NULL, "/foo", "org.freedesktop.systemd.test", vtable, c) >= 0);
246 assert_se(sd_bus_add_object_vtable(bus, NULL, "/foo", "org.freedesktop.systemd.test2", vtable, c) >= 0);
247 assert_se(sd_bus_add_fallback_vtable(bus, NULL, "/value", "org.freedesktop.systemd.ValueTest", vtable2, NULL, UINT_TO_PTR(20)) >= 0);
248 assert_se(sd_bus_add_node_enumerator(bus, NULL, "/value", enumerator_callback, NULL) >= 0);
249 assert_se(sd_bus_add_object_manager(bus, NULL, "/value") >= 0);
251 assert_se(sd_bus_start(bus) >= 0);
253 log_error("Entering event loop on server");
258 r = sd_bus_process(bus, NULL);
260 log_error_errno(r, "Failed to process requests: %m");
265 r = sd_bus_wait(bus, (uint64_t) -1);
267 log_error_errno(r, "Failed to wait: %m");
283 return INT_TO_PTR(r);
286 static int client(struct context *c) {
287 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
288 _cleanup_bus_unref_ sd_bus *bus = NULL;
289 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
293 assert_se(sd_bus_new(&bus) >= 0);
294 assert_se(sd_bus_set_fd(bus, c->fds[1], c->fds[1]) >= 0);
295 assert_se(sd_bus_start(bus) >= 0);
297 r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.systemd.test", "NoOperation", &error, NULL, NULL);
300 r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.systemd.test", "AlterSomething", &error, &reply, "s", "hallo");
303 r = sd_bus_message_read(reply, "s", &s);
305 assert_se(streq(s, "<<<hallo>>>"));
307 sd_bus_message_unref(reply);
310 r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.systemd.test", "Doesntexist", &error, &reply, "");
312 assert_se(sd_bus_error_has_name(&error, SD_BUS_ERROR_UNKNOWN_METHOD));
314 sd_bus_error_free(&error);
316 r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.systemd.test", "AlterSomething", &error, &reply, "as", 1, "hallo");
318 assert_se(sd_bus_error_has_name(&error, SD_BUS_ERROR_INVALID_ARGS));
320 sd_bus_error_free(&error);
322 r = sd_bus_get_property(bus, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.systemd.test", "Something", &error, &reply, "s");
325 r = sd_bus_message_read(reply, "s", &s);
327 assert_se(streq(s, "<<<hallo>>>"));
329 sd_bus_message_unref(reply);
332 r = sd_bus_set_property(bus, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.systemd.test", "Something", &error, "s", "test");
335 r = sd_bus_get_property(bus, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.systemd.test", "Something", &error, &reply, "s");
338 r = sd_bus_message_read(reply, "s", &s);
340 assert_se(streq(s, "test"));
342 sd_bus_message_unref(reply);
345 r = sd_bus_set_property(bus, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.systemd.test", "AutomaticIntegerProperty", &error, "u", 815);
348 assert_se(c->automatic_integer_property == 815);
350 r = sd_bus_set_property(bus, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.systemd.test", "AutomaticStringProperty", &error, "s", "Du Dödel, Du!");
353 assert_se(streq(c->automatic_string_property, "Du Dödel, Du!"));
355 r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.DBus.Introspectable", "Introspect", &error, &reply, "");
358 r = sd_bus_message_read(reply, "s", &s);
362 sd_bus_message_unref(reply);
365 r = sd_bus_get_property(bus, "org.freedesktop.systemd.test", "/value/xuzz", "org.freedesktop.systemd.ValueTest", "Value", &error, &reply, "s");
368 r = sd_bus_message_read(reply, "s", &s);
370 log_info("read %s", s);
372 sd_bus_message_unref(reply);
375 r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/", "org.freedesktop.DBus.Introspectable", "Introspect", &error, &reply, "");
378 r = sd_bus_message_read(reply, "s", &s);
382 sd_bus_message_unref(reply);
385 r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/value", "org.freedesktop.DBus.Introspectable", "Introspect", &error, &reply, "");
388 r = sd_bus_message_read(reply, "s", &s);
392 sd_bus_message_unref(reply);
395 r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/value/a", "org.freedesktop.DBus.Introspectable", "Introspect", &error, &reply, "");
398 r = sd_bus_message_read(reply, "s", &s);
402 sd_bus_message_unref(reply);
405 r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.DBus.Properties", "GetAll", &error, &reply, "s", "");
408 bus_message_dump(reply, stdout, BUS_MESSAGE_DUMP_WITH_HEADER);
410 sd_bus_message_unref(reply);
413 r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/value/a", "org.freedesktop.DBus.Properties", "GetAll", &error, &reply, "s", "org.freedesktop.systemd.ValueTest2");
415 assert_se(sd_bus_error_has_name(&error, SD_BUS_ERROR_UNKNOWN_INTERFACE));
416 sd_bus_error_free(&error);
418 r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.DBus.ObjectManager", "GetManagedObjects", &error, &reply, "");
420 assert_se(sd_bus_error_has_name(&error, SD_BUS_ERROR_UNKNOWN_METHOD));
421 sd_bus_error_free(&error);
423 r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/value", "org.freedesktop.DBus.ObjectManager", "GetManagedObjects", &error, &reply, "");
426 bus_message_dump(reply, stdout, BUS_MESSAGE_DUMP_WITH_HEADER);
428 sd_bus_message_unref(reply);
431 r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/value/a", "org.freedesktop.systemd.ValueTest", "NotifyTest", &error, NULL, "");
434 r = sd_bus_process(bus, &reply);
437 assert_se(sd_bus_message_is_signal(reply, "org.freedesktop.DBus.Properties", "PropertiesChanged"));
438 bus_message_dump(reply, stdout, BUS_MESSAGE_DUMP_WITH_HEADER);
440 sd_bus_message_unref(reply);
443 r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/value/a", "org.freedesktop.systemd.ValueTest", "NotifyTest2", &error, NULL, "");
446 r = sd_bus_process(bus, &reply);
449 assert_se(sd_bus_message_is_signal(reply, "org.freedesktop.DBus.Properties", "PropertiesChanged"));
450 bus_message_dump(reply, stdout, BUS_MESSAGE_DUMP_WITH_HEADER);
452 sd_bus_message_unref(reply);
455 r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.systemd.test", "EmitInterfacesAdded", &error, NULL, "");
458 r = sd_bus_process(bus, &reply);
461 assert_se(sd_bus_message_is_signal(reply, "org.freedesktop.DBus.ObjectManager", "InterfacesAdded"));
462 bus_message_dump(reply, stdout, BUS_MESSAGE_DUMP_WITH_HEADER);
464 sd_bus_message_unref(reply);
467 r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.systemd.test", "EmitInterfacesRemoved", &error, NULL, "");
470 r = sd_bus_process(bus, &reply);
473 assert_se(sd_bus_message_is_signal(reply, "org.freedesktop.DBus.ObjectManager", "InterfacesRemoved"));
474 bus_message_dump(reply, stdout, BUS_MESSAGE_DUMP_WITH_HEADER);
476 sd_bus_message_unref(reply);
479 r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.systemd.test", "EmitObjectAdded", &error, NULL, "");
482 r = sd_bus_process(bus, &reply);
485 assert_se(sd_bus_message_is_signal(reply, "org.freedesktop.DBus.ObjectManager", "InterfacesAdded"));
486 bus_message_dump(reply, stdout, BUS_MESSAGE_DUMP_WITH_HEADER);
488 sd_bus_message_unref(reply);
491 r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.systemd.test", "EmitObjectRemoved", &error, NULL, "");
494 r = sd_bus_process(bus, &reply);
497 assert_se(sd_bus_message_is_signal(reply, "org.freedesktop.DBus.ObjectManager", "InterfacesRemoved"));
498 bus_message_dump(reply, stdout, BUS_MESSAGE_DUMP_WITH_HEADER);
500 sd_bus_message_unref(reply);
503 r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.systemd.test", "Exit", &error, NULL, "");
511 int main(int argc, char *argv[]) {
512 struct context c = {};
519 c.automatic_integer_property = 4711;
520 assert_se(c.automatic_string_property = strdup("dudeldu"));
522 assert_se(socketpair(AF_UNIX, SOCK_STREAM, 0, c.fds) >= 0);
524 r = pthread_create(&s, NULL, server, &c);
530 q = pthread_join(s, &p);
537 if (PTR_TO_INT(p) < 0)
538 return PTR_TO_INT(p);
541 free(c.automatic_string_property);