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), "/value/a/x", "org.freedesktop.systemd.ValueTest", 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), "/value/a/x", "org.freedesktop.systemd.ValueTest", 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), "/value/a/x") >= 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), "/value/a/x") >= 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 int enumerator2_callback(sd_bus *bus, const char *path, void *userdata, char ***nodes, sd_bus_error *error) {
233 if (object_path_startswith("/value/a", path))
234 assert_se(*nodes = strv_new("/value/a/x", "/value/a/y", "/value/a/z", NULL));
239 static void *server(void *p) {
240 struct context *c = p;
247 assert_se(sd_id128_randomize(&id) >= 0);
249 assert_se(sd_bus_new(&bus) >= 0);
250 assert_se(sd_bus_set_fd(bus, c->fds[0], c->fds[0]) >= 0);
251 assert_se(sd_bus_set_server(bus, 1, id) >= 0);
253 assert_se(sd_bus_add_object_vtable(bus, NULL, "/foo", "org.freedesktop.systemd.test", vtable, c) >= 0);
254 assert_se(sd_bus_add_object_vtable(bus, NULL, "/foo", "org.freedesktop.systemd.test2", vtable, c) >= 0);
255 assert_se(sd_bus_add_fallback_vtable(bus, NULL, "/value", "org.freedesktop.systemd.ValueTest", vtable2, NULL, UINT_TO_PTR(20)) >= 0);
256 assert_se(sd_bus_add_node_enumerator(bus, NULL, "/value", enumerator_callback, NULL) >= 0);
257 assert_se(sd_bus_add_node_enumerator(bus, NULL, "/value/a", enumerator2_callback, NULL) >= 0);
258 assert_se(sd_bus_add_object_manager(bus, NULL, "/value") >= 0);
259 assert_se(sd_bus_add_object_manager(bus, NULL, "/value/a") >= 0);
261 assert_se(sd_bus_start(bus) >= 0);
263 log_error("Entering event loop on server");
268 r = sd_bus_process(bus, NULL);
270 log_error_errno(r, "Failed to process requests: %m");
275 r = sd_bus_wait(bus, (uint64_t) -1);
277 log_error_errno(r, "Failed to wait: %m");
293 return INT_TO_PTR(r);
296 static int client(struct context *c) {
297 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
298 _cleanup_bus_unref_ sd_bus *bus = NULL;
299 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
303 assert_se(sd_bus_new(&bus) >= 0);
304 assert_se(sd_bus_set_fd(bus, c->fds[1], c->fds[1]) >= 0);
305 assert_se(sd_bus_start(bus) >= 0);
307 r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.systemd.test", "NoOperation", &error, NULL, NULL);
310 r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.systemd.test", "AlterSomething", &error, &reply, "s", "hallo");
313 r = sd_bus_message_read(reply, "s", &s);
315 assert_se(streq(s, "<<<hallo>>>"));
317 sd_bus_message_unref(reply);
320 r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.systemd.test", "Doesntexist", &error, &reply, "");
322 assert_se(sd_bus_error_has_name(&error, SD_BUS_ERROR_UNKNOWN_METHOD));
324 sd_bus_error_free(&error);
326 r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.systemd.test", "AlterSomething", &error, &reply, "as", 1, "hallo");
328 assert_se(sd_bus_error_has_name(&error, SD_BUS_ERROR_INVALID_ARGS));
330 sd_bus_error_free(&error);
332 r = sd_bus_get_property(bus, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.systemd.test", "Something", &error, &reply, "s");
335 r = sd_bus_message_read(reply, "s", &s);
337 assert_se(streq(s, "<<<hallo>>>"));
339 sd_bus_message_unref(reply);
342 r = sd_bus_set_property(bus, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.systemd.test", "Something", &error, "s", "test");
345 r = sd_bus_get_property(bus, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.systemd.test", "Something", &error, &reply, "s");
348 r = sd_bus_message_read(reply, "s", &s);
350 assert_se(streq(s, "test"));
352 sd_bus_message_unref(reply);
355 r = sd_bus_set_property(bus, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.systemd.test", "AutomaticIntegerProperty", &error, "u", 815);
358 assert_se(c->automatic_integer_property == 815);
360 r = sd_bus_set_property(bus, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.systemd.test", "AutomaticStringProperty", &error, "s", "Du Dödel, Du!");
363 assert_se(streq(c->automatic_string_property, "Du Dödel, Du!"));
365 r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.DBus.Introspectable", "Introspect", &error, &reply, "");
368 r = sd_bus_message_read(reply, "s", &s);
372 sd_bus_message_unref(reply);
375 r = sd_bus_get_property(bus, "org.freedesktop.systemd.test", "/value/xuzz", "org.freedesktop.systemd.ValueTest", "Value", &error, &reply, "s");
378 r = sd_bus_message_read(reply, "s", &s);
380 log_info("read %s", s);
382 sd_bus_message_unref(reply);
385 r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/", "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", "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", "/value/a", "org.freedesktop.DBus.Introspectable", "Introspect", &error, &reply, "");
408 r = sd_bus_message_read(reply, "s", &s);
412 sd_bus_message_unref(reply);
415 r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.DBus.Properties", "GetAll", &error, &reply, "s", "");
418 bus_message_dump(reply, stdout, BUS_MESSAGE_DUMP_WITH_HEADER);
420 sd_bus_message_unref(reply);
423 r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/value/a", "org.freedesktop.DBus.Properties", "GetAll", &error, &reply, "s", "org.freedesktop.systemd.ValueTest2");
425 assert_se(sd_bus_error_has_name(&error, SD_BUS_ERROR_UNKNOWN_INTERFACE));
426 sd_bus_error_free(&error);
428 r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.DBus.ObjectManager", "GetManagedObjects", &error, &reply, "");
430 assert_se(sd_bus_error_has_name(&error, SD_BUS_ERROR_UNKNOWN_METHOD));
431 sd_bus_error_free(&error);
433 r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/value", "org.freedesktop.DBus.ObjectManager", "GetManagedObjects", &error, &reply, "");
436 bus_message_dump(reply, stdout, BUS_MESSAGE_DUMP_WITH_HEADER);
438 sd_bus_message_unref(reply);
441 r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/value/a", "org.freedesktop.systemd.ValueTest", "NotifyTest", &error, NULL, "");
444 r = sd_bus_process(bus, &reply);
447 assert_se(sd_bus_message_is_signal(reply, "org.freedesktop.DBus.Properties", "PropertiesChanged"));
448 bus_message_dump(reply, stdout, BUS_MESSAGE_DUMP_WITH_HEADER);
450 sd_bus_message_unref(reply);
453 r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/value/a", "org.freedesktop.systemd.ValueTest", "NotifyTest2", &error, NULL, "");
456 r = sd_bus_process(bus, &reply);
459 assert_se(sd_bus_message_is_signal(reply, "org.freedesktop.DBus.Properties", "PropertiesChanged"));
460 bus_message_dump(reply, stdout, BUS_MESSAGE_DUMP_WITH_HEADER);
462 sd_bus_message_unref(reply);
465 r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.systemd.test", "EmitInterfacesAdded", &error, NULL, "");
468 r = sd_bus_process(bus, &reply);
471 assert_se(sd_bus_message_is_signal(reply, "org.freedesktop.DBus.ObjectManager", "InterfacesAdded"));
472 bus_message_dump(reply, stdout, BUS_MESSAGE_DUMP_WITH_HEADER);
474 sd_bus_message_unref(reply);
477 r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.systemd.test", "EmitInterfacesRemoved", &error, NULL, "");
480 r = sd_bus_process(bus, &reply);
483 assert_se(sd_bus_message_is_signal(reply, "org.freedesktop.DBus.ObjectManager", "InterfacesRemoved"));
484 bus_message_dump(reply, stdout, BUS_MESSAGE_DUMP_WITH_HEADER);
486 sd_bus_message_unref(reply);
489 r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.systemd.test", "EmitObjectAdded", &error, NULL, "");
492 r = sd_bus_process(bus, &reply);
495 assert_se(sd_bus_message_is_signal(reply, "org.freedesktop.DBus.ObjectManager", "InterfacesAdded"));
496 bus_message_dump(reply, stdout, BUS_MESSAGE_DUMP_WITH_HEADER);
498 sd_bus_message_unref(reply);
501 r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.systemd.test", "EmitObjectRemoved", &error, NULL, "");
504 r = sd_bus_process(bus, &reply);
507 assert_se(sd_bus_message_is_signal(reply, "org.freedesktop.DBus.ObjectManager", "InterfacesRemoved"));
508 bus_message_dump(reply, stdout, BUS_MESSAGE_DUMP_WITH_HEADER);
510 sd_bus_message_unref(reply);
513 r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.systemd.test", "Exit", &error, NULL, "");
521 int main(int argc, char *argv[]) {
522 struct context c = {};
529 c.automatic_integer_property = 4711;
530 assert_se(c.automatic_string_property = strdup("dudeldu"));
532 assert_se(socketpair(AF_UNIX, SOCK_STREAM, 0, c.fds) >= 0);
534 r = pthread_create(&s, NULL, server, &c);
540 q = pthread_join(s, &p);
547 if (PTR_TO_INT(p) < 0)
548 return PTR_TO_INT(p);
551 free(c.automatic_string_property);