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 *bus, 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 *bus, 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;
121 assert_se(asprintf(&s, "object %p, path %s", userdata, path) >= 0);
122 r = sd_bus_message_append(reply, "s", s);
125 assert_se(x = startswith(path, "/value/"));
127 assert_se(PTR_TO_UINT(userdata) == 30);
132 static int notify_test(sd_bus *bus, sd_bus_message *m, void *userdata, sd_bus_error *error) {
135 assert_se(sd_bus_emit_properties_changed(bus, m->path, "org.freedesktop.systemd.ValueTest", "Value", NULL) >= 0);
137 r = sd_bus_reply_method_return(m, NULL);
143 static int notify_test2(sd_bus *bus, sd_bus_message *m, void *userdata, sd_bus_error *error) {
146 assert_se(sd_bus_emit_properties_changed_strv(bus, m->path, "org.freedesktop.systemd.ValueTest", NULL) >= 0);
148 r = sd_bus_reply_method_return(m, NULL);
154 static int emit_interfaces_added(sd_bus *bus, sd_bus_message *m, void *userdata, sd_bus_error *error) {
157 assert_se(sd_bus_emit_interfaces_added(bus, m->path, "org.freedesktop.systemd.test", NULL) >= 0);
159 r = sd_bus_reply_method_return(m, NULL);
165 static int emit_interfaces_removed(sd_bus *bus, sd_bus_message *m, void *userdata, sd_bus_error *error) {
168 assert_se(sd_bus_emit_interfaces_removed(bus, m->path, "org.freedesktop.systemd.test", NULL) >= 0);
170 r = sd_bus_reply_method_return(m, NULL);
176 static int emit_object_added(sd_bus *bus, sd_bus_message *m, void *userdata, sd_bus_error *error) {
179 assert_se(sd_bus_emit_object_added(bus, m->path) >= 0);
181 r = sd_bus_reply_method_return(m, NULL);
187 static int emit_object_removed(sd_bus *bus, sd_bus_message *m, void *userdata, sd_bus_error *error) {
190 assert_se(sd_bus_emit_object_removed(bus, m->path) >= 0);
192 r = sd_bus_reply_method_return(m, NULL);
198 static const sd_bus_vtable vtable[] = {
199 SD_BUS_VTABLE_START(0),
200 SD_BUS_METHOD("AlterSomething", "s", "s", something_handler, 0),
201 SD_BUS_METHOD("Exit", "", "", exit_handler, 0),
202 SD_BUS_WRITABLE_PROPERTY("Something", "s", get_handler, set_handler, 0, 0),
203 SD_BUS_WRITABLE_PROPERTY("AutomaticStringProperty", "s", NULL, NULL, offsetof(struct context, automatic_string_property), 0),
204 SD_BUS_WRITABLE_PROPERTY("AutomaticIntegerProperty", "u", NULL, NULL, offsetof(struct context, automatic_integer_property), 0),
205 SD_BUS_METHOD("NoOperation", NULL, NULL, NULL, 0),
206 SD_BUS_METHOD("EmitInterfacesAdded", NULL, NULL, emit_interfaces_added, 0),
207 SD_BUS_METHOD("EmitInterfacesRemoved", NULL, NULL, emit_interfaces_removed, 0),
208 SD_BUS_METHOD("EmitObjectAdded", NULL, NULL, emit_object_added, 0),
209 SD_BUS_METHOD("EmitObjectRemoved", NULL, NULL, emit_object_removed, 0),
213 static const sd_bus_vtable vtable2[] = {
214 SD_BUS_VTABLE_START(0),
215 SD_BUS_METHOD("NotifyTest", "", "", notify_test, 0),
216 SD_BUS_METHOD("NotifyTest2", "", "", notify_test2, 0),
217 SD_BUS_PROPERTY("Value", "s", value_handler, 10, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
218 SD_BUS_PROPERTY("Value2", "s", value_handler, 10, SD_BUS_VTABLE_PROPERTY_EMITS_INVALIDATION),
219 SD_BUS_PROPERTY("Value3", "s", value_handler, 10, SD_BUS_VTABLE_PROPERTY_CONST),
220 SD_BUS_PROPERTY("Value4", "s", value_handler, 10, 0),
224 static int enumerator_callback(sd_bus *bus, const char *path, void *userdata, char ***nodes, sd_bus_error *error) {
226 if (object_path_startswith("/value", path))
227 assert_se(*nodes = strv_new("/value/a", "/value/b", "/value/c", NULL));
232 static void *server(void *p) {
233 struct context *c = p;
240 assert_se(sd_id128_randomize(&id) >= 0);
242 assert_se(sd_bus_new(&bus) >= 0);
243 assert_se(sd_bus_set_fd(bus, c->fds[0], c->fds[0]) >= 0);
244 assert_se(sd_bus_set_server(bus, 1, id) >= 0);
246 assert_se(sd_bus_add_object_vtable(bus, NULL, "/foo", "org.freedesktop.systemd.test", vtable, c) >= 0);
247 assert_se(sd_bus_add_object_vtable(bus, NULL, "/foo", "org.freedesktop.systemd.test2", vtable, c) >= 0);
248 assert_se(sd_bus_add_fallback_vtable(bus, NULL, "/value", "org.freedesktop.systemd.ValueTest", vtable2, NULL, UINT_TO_PTR(20)) >= 0);
249 assert_se(sd_bus_add_node_enumerator(bus, NULL, "/value", enumerator_callback, NULL) >= 0);
250 assert_se(sd_bus_add_object_manager(bus, NULL, "/value") >= 0);
252 assert_se(sd_bus_start(bus) >= 0);
254 log_error("Entering event loop on server");
259 r = sd_bus_process(bus, NULL);
261 log_error_errno(r, "Failed to process requests: %m");
266 r = sd_bus_wait(bus, (uint64_t) -1);
268 log_error_errno(r, "Failed to wait: %m");
284 return INT_TO_PTR(r);
287 static int client(struct context *c) {
288 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
289 _cleanup_bus_unref_ sd_bus *bus = NULL;
290 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
294 assert_se(sd_bus_new(&bus) >= 0);
295 assert_se(sd_bus_set_fd(bus, c->fds[1], c->fds[1]) >= 0);
296 assert_se(sd_bus_start(bus) >= 0);
298 r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.systemd.test", "NoOperation", &error, NULL, NULL);
301 r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.systemd.test", "AlterSomething", &error, &reply, "s", "hallo");
304 r = sd_bus_message_read(reply, "s", &s);
306 assert_se(streq(s, "<<<hallo>>>"));
308 sd_bus_message_unref(reply);
311 r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.systemd.test", "Doesntexist", &error, &reply, "");
313 assert_se(sd_bus_error_has_name(&error, SD_BUS_ERROR_UNKNOWN_METHOD));
315 sd_bus_error_free(&error);
317 r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.systemd.test", "AlterSomething", &error, &reply, "as", 1, "hallo");
319 assert_se(sd_bus_error_has_name(&error, SD_BUS_ERROR_INVALID_ARGS));
321 sd_bus_error_free(&error);
323 r = sd_bus_get_property(bus, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.systemd.test", "Something", &error, &reply, "s");
326 r = sd_bus_message_read(reply, "s", &s);
328 assert_se(streq(s, "<<<hallo>>>"));
330 sd_bus_message_unref(reply);
333 r = sd_bus_set_property(bus, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.systemd.test", "Something", &error, "s", "test");
336 r = sd_bus_get_property(bus, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.systemd.test", "Something", &error, &reply, "s");
339 r = sd_bus_message_read(reply, "s", &s);
341 assert_se(streq(s, "test"));
343 sd_bus_message_unref(reply);
346 r = sd_bus_set_property(bus, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.systemd.test", "AutomaticIntegerProperty", &error, "u", 815);
349 assert_se(c->automatic_integer_property == 815);
351 r = sd_bus_set_property(bus, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.systemd.test", "AutomaticStringProperty", &error, "s", "Du Dödel, Du!");
354 assert_se(streq(c->automatic_string_property, "Du Dödel, Du!"));
356 r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.DBus.Introspectable", "Introspect", &error, &reply, "");
359 r = sd_bus_message_read(reply, "s", &s);
363 sd_bus_message_unref(reply);
366 r = sd_bus_get_property(bus, "org.freedesktop.systemd.test", "/value/xuzz", "org.freedesktop.systemd.ValueTest", "Value", &error, &reply, "s");
369 r = sd_bus_message_read(reply, "s", &s);
371 log_info("read %s", s);
373 sd_bus_message_unref(reply);
376 r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/", "org.freedesktop.DBus.Introspectable", "Introspect", &error, &reply, "");
379 r = sd_bus_message_read(reply, "s", &s);
383 sd_bus_message_unref(reply);
386 r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/value", "org.freedesktop.DBus.Introspectable", "Introspect", &error, &reply, "");
389 r = sd_bus_message_read(reply, "s", &s);
393 sd_bus_message_unref(reply);
396 r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/value/a", "org.freedesktop.DBus.Introspectable", "Introspect", &error, &reply, "");
399 r = sd_bus_message_read(reply, "s", &s);
403 sd_bus_message_unref(reply);
406 r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.DBus.Properties", "GetAll", &error, &reply, "s", "");
409 bus_message_dump(reply, stdout, BUS_MESSAGE_DUMP_WITH_HEADER);
411 sd_bus_message_unref(reply);
414 r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/value/a", "org.freedesktop.DBus.Properties", "GetAll", &error, &reply, "s", "org.freedesktop.systemd.ValueTest2");
416 assert_se(sd_bus_error_has_name(&error, SD_BUS_ERROR_UNKNOWN_INTERFACE));
417 sd_bus_error_free(&error);
419 r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.DBus.ObjectManager", "GetManagedObjects", &error, &reply, "");
421 assert_se(sd_bus_error_has_name(&error, SD_BUS_ERROR_UNKNOWN_METHOD));
422 sd_bus_error_free(&error);
424 r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/value", "org.freedesktop.DBus.ObjectManager", "GetManagedObjects", &error, &reply, "");
427 bus_message_dump(reply, stdout, BUS_MESSAGE_DUMP_WITH_HEADER);
429 sd_bus_message_unref(reply);
432 r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/value/a", "org.freedesktop.systemd.ValueTest", "NotifyTest", &error, NULL, "");
435 r = sd_bus_process(bus, &reply);
438 assert_se(sd_bus_message_is_signal(reply, "org.freedesktop.DBus.Properties", "PropertiesChanged"));
439 bus_message_dump(reply, stdout, BUS_MESSAGE_DUMP_WITH_HEADER);
441 sd_bus_message_unref(reply);
444 r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/value/a", "org.freedesktop.systemd.ValueTest", "NotifyTest2", &error, NULL, "");
447 r = sd_bus_process(bus, &reply);
450 assert_se(sd_bus_message_is_signal(reply, "org.freedesktop.DBus.Properties", "PropertiesChanged"));
451 bus_message_dump(reply, stdout, BUS_MESSAGE_DUMP_WITH_HEADER);
453 sd_bus_message_unref(reply);
456 r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.systemd.test", "EmitInterfacesAdded", &error, NULL, "");
459 r = sd_bus_process(bus, &reply);
462 assert_se(sd_bus_message_is_signal(reply, "org.freedesktop.DBus.ObjectManager", "InterfacesAdded"));
463 bus_message_dump(reply, stdout, BUS_MESSAGE_DUMP_WITH_HEADER);
465 sd_bus_message_unref(reply);
468 r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.systemd.test", "EmitInterfacesRemoved", &error, NULL, "");
471 r = sd_bus_process(bus, &reply);
474 assert_se(sd_bus_message_is_signal(reply, "org.freedesktop.DBus.ObjectManager", "InterfacesRemoved"));
475 bus_message_dump(reply, stdout, BUS_MESSAGE_DUMP_WITH_HEADER);
477 sd_bus_message_unref(reply);
480 r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.systemd.test", "EmitObjectAdded", &error, NULL, "");
483 r = sd_bus_process(bus, &reply);
486 assert_se(sd_bus_message_is_signal(reply, "org.freedesktop.DBus.ObjectManager", "InterfacesAdded"));
487 bus_message_dump(reply, stdout, BUS_MESSAGE_DUMP_WITH_HEADER);
489 sd_bus_message_unref(reply);
492 r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.systemd.test", "EmitObjectRemoved", &error, NULL, "");
495 r = sd_bus_process(bus, &reply);
498 assert_se(sd_bus_message_is_signal(reply, "org.freedesktop.DBus.ObjectManager", "InterfacesRemoved"));
499 bus_message_dump(reply, stdout, BUS_MESSAGE_DUMP_WITH_HEADER);
501 sd_bus_message_unref(reply);
504 r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.systemd.test", "Exit", &error, NULL, "");
512 int main(int argc, char *argv[]) {
513 struct context c = {};
520 c.automatic_integer_property = 4711;
521 assert_se(c.automatic_string_property = strdup("dudeldu"));
523 assert_se(socketpair(AF_UNIX, SOCK_STREAM, 0, c.fds) >= 0);
525 r = pthread_create(&s, NULL, server, &c);
531 q = pthread_join(s, &p);
538 if (PTR_TO_INT(p) < 0)
539 return PTR_TO_INT(p);
542 free(c.automatic_string_property);