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/>.
34 #include "bus-internal.h"
35 #include "bus-message.h"
43 char *automatic_string_property;
44 uint32_t automatic_integer_property;
47 static int something_handler(sd_bus *bus, sd_bus_message *m, void *userdata, sd_bus_error *error) {
48 struct context *c = userdata;
53 r = sd_bus_message_read(m, "s", &s);
56 n = strjoin("<<<", s, ">>>", NULL);
62 log_info("AlterSomething() called, got %s, returning %s", s, n);
64 /* This should fail, since the return type doesn't match */
65 assert_se(sd_bus_reply_method_return(m, "u", 4711) == -ENOMSG);
67 r = sd_bus_reply_method_return(m, "s", n);
73 static int exit_handler(sd_bus *bus, sd_bus_message *m, void *userdata, sd_bus_error *error) {
74 struct context *c = userdata;
79 log_info("Exit called");
81 r = sd_bus_reply_method_return(m, "");
87 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) {
88 struct context *c = userdata;
91 log_info("property get for %s called, returning \"%s\".", property, c->something);
93 r = sd_bus_message_append(reply, "s", c->something);
99 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) {
100 struct context *c = userdata;
105 log_info("property set for %s called", property);
107 r = sd_bus_message_read(value, "s", &s);
119 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) {
120 _cleanup_free_ char *s = NULL;
124 assert_se(asprintf(&s, "object %p, path %s", userdata, path) >= 0);
125 r = sd_bus_message_append(reply, "s", s);
128 assert_se(x = startswith(path, "/value/"));
130 assert_se(PTR_TO_UINT(userdata) == 30);
135 static int notify_test(sd_bus *bus, sd_bus_message *m, void *userdata, sd_bus_error *error) {
138 assert_se(sd_bus_emit_properties_changed(bus, m->path, "org.freedesktop.systemd.ValueTest", "Value", NULL) >= 0);
140 r = sd_bus_reply_method_return(m, NULL);
146 static int notify_test2(sd_bus *bus, sd_bus_message *m, void *userdata, sd_bus_error *error) {
149 assert_se(sd_bus_emit_properties_changed_strv(bus, m->path, "org.freedesktop.systemd.ValueTest", NULL) >= 0);
151 r = sd_bus_reply_method_return(m, NULL);
157 static int emit_interfaces_added(sd_bus *bus, sd_bus_message *m, void *userdata, sd_bus_error *error) {
160 assert_se(sd_bus_emit_interfaces_added(bus, m->path, "org.freedesktop.systemd.test", NULL) >= 0);
162 r = sd_bus_reply_method_return(m, NULL);
168 static int emit_interfaces_removed(sd_bus *bus, sd_bus_message *m, void *userdata, sd_bus_error *error) {
171 assert_se(sd_bus_emit_interfaces_removed(bus, m->path, "org.freedesktop.systemd.test", NULL) >= 0);
173 r = sd_bus_reply_method_return(m, NULL);
179 static int emit_object_added(sd_bus *bus, sd_bus_message *m, void *userdata, sd_bus_error *error) {
182 assert_se(sd_bus_emit_object_added(bus, m->path) >= 0);
184 r = sd_bus_reply_method_return(m, NULL);
190 static int emit_object_removed(sd_bus *bus, sd_bus_message *m, void *userdata, sd_bus_error *error) {
193 assert_se(sd_bus_emit_object_removed(bus, m->path) >= 0);
195 r = sd_bus_reply_method_return(m, NULL);
201 static const sd_bus_vtable vtable[] = {
202 SD_BUS_VTABLE_START(0),
203 SD_BUS_METHOD("AlterSomething", "s", "s", something_handler, 0),
204 SD_BUS_METHOD("Exit", "", "", exit_handler, 0),
205 SD_BUS_WRITABLE_PROPERTY("Something", "s", get_handler, set_handler, 0, 0),
206 SD_BUS_WRITABLE_PROPERTY("AutomaticStringProperty", "s", NULL, NULL, offsetof(struct context, automatic_string_property), 0),
207 SD_BUS_WRITABLE_PROPERTY("AutomaticIntegerProperty", "u", NULL, NULL, offsetof(struct context, automatic_integer_property), 0),
208 SD_BUS_METHOD("NoOperation", NULL, NULL, NULL, 0),
209 SD_BUS_METHOD("EmitInterfacesAdded", NULL, NULL, emit_interfaces_added, 0),
210 SD_BUS_METHOD("EmitInterfacesRemoved", NULL, NULL, emit_interfaces_removed, 0),
211 SD_BUS_METHOD("EmitObjectAdded", NULL, NULL, emit_object_added, 0),
212 SD_BUS_METHOD("EmitObjectRemoved", NULL, NULL, emit_object_removed, 0),
216 static const sd_bus_vtable vtable2[] = {
217 SD_BUS_VTABLE_START(0),
218 SD_BUS_METHOD("NotifyTest", "", "", notify_test, 0),
219 SD_BUS_METHOD("NotifyTest2", "", "", notify_test2, 0),
220 SD_BUS_PROPERTY("Value", "s", value_handler, 10, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
221 SD_BUS_PROPERTY("Value2", "s", value_handler, 10, SD_BUS_VTABLE_PROPERTY_EMITS_INVALIDATION),
222 SD_BUS_PROPERTY("Value3", "s", value_handler, 10, SD_BUS_VTABLE_PROPERTY_CONST),
223 SD_BUS_PROPERTY("Value4", "s", value_handler, 10, 0),
227 static int enumerator_callback(sd_bus *bus, const char *path, void *userdata, char ***nodes, sd_bus_error *error) {
229 if (object_path_startswith("/value", path))
230 assert_se(*nodes = strv_new("/value/a", "/value/b", "/value/c", NULL));
235 static void *server(void *p) {
236 struct context *c = p;
243 assert_se(sd_id128_randomize(&id) >= 0);
245 assert_se(sd_bus_new(&bus) >= 0);
246 assert_se(sd_bus_set_fd(bus, c->fds[0], c->fds[0]) >= 0);
247 assert_se(sd_bus_set_server(bus, 1, id) >= 0);
249 assert_se(sd_bus_add_object_vtable(bus, NULL, "/foo", "org.freedesktop.systemd.test", vtable, c) >= 0);
250 assert_se(sd_bus_add_object_vtable(bus, NULL, "/foo", "org.freedesktop.systemd.test2", vtable, c) >= 0);
251 assert_se(sd_bus_add_fallback_vtable(bus, NULL, "/value", "org.freedesktop.systemd.ValueTest", vtable2, NULL, UINT_TO_PTR(20)) >= 0);
252 assert_se(sd_bus_add_node_enumerator(bus, NULL, "/value", enumerator_callback, NULL) >= 0);
253 assert_se(sd_bus_add_object_manager(bus, NULL, "/value") >= 0);
255 assert_se(sd_bus_start(bus) >= 0);
257 log_error("Entering event loop on server");
262 r = sd_bus_process(bus, NULL);
264 log_error_errno(r, "Failed to process requests: %m");
269 r = sd_bus_wait(bus, (uint64_t) -1);
271 log_error_errno(r, "Failed to wait: %m");
287 return INT_TO_PTR(r);
290 static int client(struct context *c) {
291 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
292 _cleanup_bus_unref_ sd_bus *bus = NULL;
293 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
297 assert_se(sd_bus_new(&bus) >= 0);
298 assert_se(sd_bus_set_fd(bus, c->fds[1], c->fds[1]) >= 0);
299 assert_se(sd_bus_start(bus) >= 0);
301 r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.systemd.test", "NoOperation", &error, NULL, NULL);
304 r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.systemd.test", "AlterSomething", &error, &reply, "s", "hallo");
307 r = sd_bus_message_read(reply, "s", &s);
309 assert_se(streq(s, "<<<hallo>>>"));
311 sd_bus_message_unref(reply);
314 r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.systemd.test", "Doesntexist", &error, &reply, "");
316 assert_se(sd_bus_error_has_name(&error, SD_BUS_ERROR_UNKNOWN_METHOD));
318 sd_bus_error_free(&error);
320 r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.systemd.test", "AlterSomething", &error, &reply, "as", 1, "hallo");
322 assert_se(sd_bus_error_has_name(&error, SD_BUS_ERROR_INVALID_ARGS));
324 sd_bus_error_free(&error);
326 r = sd_bus_get_property(bus, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.systemd.test", "Something", &error, &reply, "s");
329 r = sd_bus_message_read(reply, "s", &s);
331 assert_se(streq(s, "<<<hallo>>>"));
333 sd_bus_message_unref(reply);
336 r = sd_bus_set_property(bus, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.systemd.test", "Something", &error, "s", "test");
339 r = sd_bus_get_property(bus, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.systemd.test", "Something", &error, &reply, "s");
342 r = sd_bus_message_read(reply, "s", &s);
344 assert_se(streq(s, "test"));
346 sd_bus_message_unref(reply);
349 r = sd_bus_set_property(bus, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.systemd.test", "AutomaticIntegerProperty", &error, "u", 815);
352 assert_se(c->automatic_integer_property == 815);
354 r = sd_bus_set_property(bus, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.systemd.test", "AutomaticStringProperty", &error, "s", "Du Dödel, Du!");
357 assert_se(streq(c->automatic_string_property, "Du Dödel, Du!"));
359 r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.DBus.Introspectable", "Introspect", &error, &reply, "");
362 r = sd_bus_message_read(reply, "s", &s);
366 sd_bus_message_unref(reply);
369 r = sd_bus_get_property(bus, "org.freedesktop.systemd.test", "/value/xuzz", "org.freedesktop.systemd.ValueTest", "Value", &error, &reply, "s");
372 r = sd_bus_message_read(reply, "s", &s);
374 log_info("read %s", s);
376 sd_bus_message_unref(reply);
379 r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/", "org.freedesktop.DBus.Introspectable", "Introspect", &error, &reply, "");
382 r = sd_bus_message_read(reply, "s", &s);
386 sd_bus_message_unref(reply);
389 r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/value", "org.freedesktop.DBus.Introspectable", "Introspect", &error, &reply, "");
392 r = sd_bus_message_read(reply, "s", &s);
396 sd_bus_message_unref(reply);
399 r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/value/a", "org.freedesktop.DBus.Introspectable", "Introspect", &error, &reply, "");
402 r = sd_bus_message_read(reply, "s", &s);
406 sd_bus_message_unref(reply);
409 r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.DBus.Properties", "GetAll", &error, &reply, "s", "");
412 bus_message_dump(reply, stdout, BUS_MESSAGE_DUMP_WITH_HEADER);
414 sd_bus_message_unref(reply);
417 r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/value/a", "org.freedesktop.DBus.Properties", "GetAll", &error, &reply, "s", "org.freedesktop.systemd.ValueTest2");
419 assert_se(sd_bus_error_has_name(&error, SD_BUS_ERROR_UNKNOWN_INTERFACE));
420 sd_bus_error_free(&error);
422 r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.DBus.ObjectManager", "GetManagedObjects", &error, &reply, "");
424 assert_se(sd_bus_error_has_name(&error, SD_BUS_ERROR_UNKNOWN_METHOD));
425 sd_bus_error_free(&error);
427 r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/value", "org.freedesktop.DBus.ObjectManager", "GetManagedObjects", &error, &reply, "");
430 bus_message_dump(reply, stdout, BUS_MESSAGE_DUMP_WITH_HEADER);
432 sd_bus_message_unref(reply);
435 r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/value/a", "org.freedesktop.systemd.ValueTest", "NotifyTest", &error, NULL, "");
438 r = sd_bus_process(bus, &reply);
441 assert_se(sd_bus_message_is_signal(reply, "org.freedesktop.DBus.Properties", "PropertiesChanged"));
442 bus_message_dump(reply, stdout, BUS_MESSAGE_DUMP_WITH_HEADER);
444 sd_bus_message_unref(reply);
447 r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/value/a", "org.freedesktop.systemd.ValueTest", "NotifyTest2", &error, NULL, "");
450 r = sd_bus_process(bus, &reply);
453 assert_se(sd_bus_message_is_signal(reply, "org.freedesktop.DBus.Properties", "PropertiesChanged"));
454 bus_message_dump(reply, stdout, BUS_MESSAGE_DUMP_WITH_HEADER);
456 sd_bus_message_unref(reply);
459 r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.systemd.test", "EmitInterfacesAdded", &error, NULL, "");
462 r = sd_bus_process(bus, &reply);
465 assert_se(sd_bus_message_is_signal(reply, "org.freedesktop.DBus.ObjectManager", "InterfacesAdded"));
466 bus_message_dump(reply, stdout, BUS_MESSAGE_DUMP_WITH_HEADER);
468 sd_bus_message_unref(reply);
471 r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.systemd.test", "EmitInterfacesRemoved", &error, NULL, "");
474 r = sd_bus_process(bus, &reply);
477 assert_se(sd_bus_message_is_signal(reply, "org.freedesktop.DBus.ObjectManager", "InterfacesRemoved"));
478 bus_message_dump(reply, stdout, BUS_MESSAGE_DUMP_WITH_HEADER);
480 sd_bus_message_unref(reply);
483 r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.systemd.test", "EmitObjectAdded", &error, NULL, "");
486 r = sd_bus_process(bus, &reply);
489 assert_se(sd_bus_message_is_signal(reply, "org.freedesktop.DBus.ObjectManager", "InterfacesAdded"));
490 bus_message_dump(reply, stdout, BUS_MESSAGE_DUMP_WITH_HEADER);
492 sd_bus_message_unref(reply);
495 r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.systemd.test", "EmitObjectRemoved", &error, NULL, "");
498 r = sd_bus_process(bus, &reply);
501 assert_se(sd_bus_message_is_signal(reply, "org.freedesktop.DBus.ObjectManager", "InterfacesRemoved"));
502 bus_message_dump(reply, stdout, BUS_MESSAGE_DUMP_WITH_HEADER);
504 sd_bus_message_unref(reply);
507 r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.systemd.test", "Exit", &error, NULL, "");
515 int main(int argc, char *argv[]) {
516 struct context c = {};
523 c.automatic_integer_property = 4711;
524 assert_se(c.automatic_string_property = strdup("dudeldu"));
526 assert_se(socketpair(AF_UNIX, SOCK_STREAM, 0, c.fds) >= 0);
528 r = pthread_create(&s, NULL, server, &c);
534 q = pthread_join(s, &p);
541 if (PTR_TO_INT(p) < 0)
542 return PTR_TO_INT(p);
545 free(c.automatic_string_property);