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"
42 char *automatic_string_property;
43 uint32_t automatic_integer_property;
46 static int something_handler(sd_bus *bus, sd_bus_message *m, void *userdata) {
47 struct context *c = userdata;
52 r = sd_bus_message_read(m, "s", &s);
55 n = strjoin("<<<", s, ">>>", NULL);
61 log_info("AlterSomething() called, got %s, returning %s", s, n);
63 r = sd_bus_reply_method_return(bus, m, "s", n);
69 static int exit_handler(sd_bus *bus, sd_bus_message *m, void *userdata) {
70 struct context *c = userdata;
75 log_info("Exit called");
77 r = sd_bus_reply_method_return(bus, m, "");
83 static int get_handler(sd_bus *bus, const char *path, const char *interface, const char *property, sd_bus_message *reply, sd_bus_error *error, void *userdata) {
84 struct context *c = userdata;
87 log_info("property get for %s called", property);
89 r = sd_bus_message_append(reply, "s", c->something);
95 static int set_handler(sd_bus *bus, const char *path, const char *interface, const char *property, sd_bus_message *value, sd_bus_error *error, void *userdata) {
96 struct context *c = userdata;
101 log_info("property set for %s called", property);
103 r = sd_bus_message_read(value, "s", &s);
115 static int value_handler(sd_bus *bus, const char *path, const char *interface, const char *property, sd_bus_message *reply, sd_bus_error *error, void *userdata) {
116 _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(x = startswith(path, "/value/"));
126 assert_se(PTR_TO_UINT(userdata) == 30);
131 static int notify_test(sd_bus *bus, sd_bus_message *m, void *userdata) {
134 assert_se(sd_bus_emit_properties_changed(bus, m->path, "org.freedesktop.systemd.ValueTest", "Value", NULL) >= 0);
136 r = sd_bus_reply_method_return(bus, m, NULL);
142 static int emit_interfaces_added(sd_bus *bus, sd_bus_message *m, void *userdata) {
145 assert_se(sd_bus_emit_interfaces_added(bus, m->path, "org.freedesktop.systemd.test", NULL) >= 0);
147 r = sd_bus_reply_method_return(bus, m, NULL);
153 static int emit_interfaces_removed(sd_bus *bus, sd_bus_message *m, void *userdata) {
156 assert_se(sd_bus_emit_interfaces_removed(bus, m->path, "org.freedesktop.systemd.test", NULL) >= 0);
158 r = sd_bus_reply_method_return(bus, m, NULL);
164 static const sd_bus_vtable vtable[] = {
165 SD_BUS_VTABLE_START(0),
166 SD_BUS_METHOD("AlterSomething", "s", "s", something_handler, 0),
167 SD_BUS_METHOD("Exit", "", "", exit_handler, 0),
168 SD_BUS_WRITABLE_PROPERTY("Something", "s", get_handler, set_handler, 0, 0),
169 SD_BUS_WRITABLE_PROPERTY("AutomaticStringProperty", "s", NULL, NULL, offsetof(struct context, automatic_string_property), 0),
170 SD_BUS_WRITABLE_PROPERTY("AutomaticIntegerProperty", "u", NULL, NULL, offsetof(struct context, automatic_integer_property), 0),
171 SD_BUS_METHOD("NoOperation", NULL, NULL, NULL, 0),
172 SD_BUS_METHOD("EmitInterfacesAdded", NULL, NULL, emit_interfaces_added, 0),
173 SD_BUS_METHOD("EmitInterfacesRemoved", NULL, NULL, emit_interfaces_removed, 0),
177 static const sd_bus_vtable vtable2[] = {
178 SD_BUS_VTABLE_START(0),
179 SD_BUS_METHOD("NotifyTest", "", "", notify_test, 0),
180 SD_BUS_PROPERTY("Value", "s", value_handler, 10, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
184 static int enumerator_callback(sd_bus *b, const char *path, char ***nodes, void *userdata) {
186 if (object_path_startswith("/value", path))
187 assert_se(*nodes = strv_new("/value/a", "/value/b", "/value/c", NULL));
192 static void *server(void *p) {
193 struct context *c = p;
200 assert_se(sd_id128_randomize(&id) >= 0);
202 assert_se(sd_bus_new(&bus) >= 0);
203 assert_se(sd_bus_set_fd(bus, c->fds[0], c->fds[0]) >= 0);
204 assert_se(sd_bus_set_server(bus, 1, id) >= 0);
206 assert_se(sd_bus_add_object_vtable(bus, "/foo", "org.freedesktop.systemd.test", vtable, c) >= 0);
207 assert_se(sd_bus_add_object_vtable(bus, "/foo", "org.freedesktop.systemd.test2", vtable, c) >= 0);
208 assert_se(sd_bus_add_fallback_vtable(bus, "/value", "org.freedesktop.systemd.ValueTest", vtable2, NULL, UINT_TO_PTR(20)) >= 0);
209 assert_se(sd_bus_add_node_enumerator(bus, "/value", enumerator_callback, NULL) >= 0);
210 assert_se(sd_bus_add_object_manager(bus, "/value") >= 0);
212 assert_se(sd_bus_start(bus) >= 0);
214 log_error("Entering event loop on server");
219 r = sd_bus_process(bus, NULL);
221 log_error("Failed to process requests: %s", strerror(-r));
226 r = sd_bus_wait(bus, (uint64_t) -1);
228 log_error("Failed to wait: %s", strerror(-r));
244 return INT_TO_PTR(r);
247 static int client(struct context *c) {
248 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
249 _cleanup_bus_unref_ sd_bus *bus = NULL;
250 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
254 assert_se(sd_bus_new(&bus) >= 0);
255 assert_se(sd_bus_set_fd(bus, c->fds[1], c->fds[1]) >= 0);
256 assert_se(sd_bus_start(bus) >= 0);
258 r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.systemd.test", "NoOperation", &error, NULL, NULL);
261 r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.systemd.test", "AlterSomething", &error, &reply, "s", "hallo");
264 r = sd_bus_message_read(reply, "s", &s);
266 assert_se(streq(s, "<<<hallo>>>"));
268 sd_bus_message_unref(reply);
271 r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.systemd.test", "Doesntexist", &error, &reply, "");
273 assert_se(sd_bus_error_has_name(&error, SD_BUS_ERROR_UNKNOWN_METHOD));
275 sd_bus_error_free(&error);
277 r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.systemd.test", "AlterSomething", &error, &reply, "as", 1, "hallo");
279 assert_se(sd_bus_error_has_name(&error, SD_BUS_ERROR_INVALID_ARGS));
281 sd_bus_error_free(&error);
283 r = sd_bus_get_property(bus, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.systemd.test", "Something", &error, &reply, "s");
286 r = sd_bus_message_read(reply, "s", &s);
288 assert_se(streq(s, "<<<hallo>>>"));
290 sd_bus_message_unref(reply);
293 r = sd_bus_set_property(bus, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.systemd.test", "Something", &error, "s", "test");
296 r = sd_bus_get_property(bus, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.systemd.test", "Something", &error, &reply, "s");
299 r = sd_bus_message_read(reply, "s", &s);
301 assert_se(streq(s, "test"));
303 sd_bus_message_unref(reply);
306 r = sd_bus_set_property(bus, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.systemd.test", "AutomaticIntegerProperty", &error, "u", 815);
309 assert_se(c->automatic_integer_property == 815);
311 r = sd_bus_set_property(bus, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.systemd.test", "AutomaticStringProperty", &error, "s", "Du Dödel, Du!");
314 assert_se(streq(c->automatic_string_property, "Du Dödel, Du!"));
316 r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.DBus.Introspectable", "Introspect", &error, &reply, "");
319 r = sd_bus_message_read(reply, "s", &s);
323 sd_bus_message_unref(reply);
326 r = sd_bus_get_property(bus, "org.freedesktop.systemd.test", "/value/xuzz", "org.freedesktop.systemd.ValueTest", "Value", &error, &reply, "s");
329 r = sd_bus_message_read(reply, "s", &s);
331 log_info("read %s", s);
333 sd_bus_message_unref(reply);
336 r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/", "org.freedesktop.DBus.Introspectable", "Introspect", &error, &reply, "");
339 r = sd_bus_message_read(reply, "s", &s);
343 sd_bus_message_unref(reply);
346 r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/value", "org.freedesktop.DBus.Introspectable", "Introspect", &error, &reply, "");
349 r = sd_bus_message_read(reply, "s", &s);
353 sd_bus_message_unref(reply);
356 r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/value/a", "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_call_method(bus, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.DBus.Properties", "GetAll", &error, &reply, "s", "");
369 bus_message_dump(reply, stdout, true);
371 sd_bus_message_unref(reply);
374 r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/value/a", "org.freedesktop.DBus.Properties", "GetAll", &error, &reply, "s", "org.freedesktop.systemd.ValueTest2");
376 assert_se(sd_bus_error_has_name(&error, SD_BUS_ERROR_UNKNOWN_INTERFACE));
377 sd_bus_error_free(&error);
379 r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.DBus.ObjectManager", "GetManagedObjects", &error, &reply, "");
381 assert_se(sd_bus_error_has_name(&error, SD_BUS_ERROR_UNKNOWN_METHOD));
382 sd_bus_error_free(&error);
384 r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/value", "org.freedesktop.DBus.ObjectManager", "GetManagedObjects", &error, &reply, "");
387 bus_message_dump(reply, stdout, true);
389 sd_bus_message_unref(reply);
392 r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/value/a", "org.freedesktop.systemd.ValueTest", "NotifyTest", &error, NULL, "");
395 r = sd_bus_process(bus, &reply);
398 assert_se(sd_bus_message_is_signal(reply, "org.freedesktop.DBus.Properties", "PropertiesChanged"));
399 bus_message_dump(reply, stdout, true);
401 sd_bus_message_unref(reply);
404 r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.systemd.test", "EmitInterfacesAdded", &error, NULL, "");
407 r = sd_bus_process(bus, &reply);
410 assert_se(sd_bus_message_is_signal(reply, "org.freedesktop.DBus.ObjectManager", "InterfacesAdded"));
411 bus_message_dump(reply, stdout, true);
413 sd_bus_message_unref(reply);
416 r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.systemd.test", "EmitInterfacesRemoved", &error, NULL, "");
419 r = sd_bus_process(bus, &reply);
422 assert_se(sd_bus_message_is_signal(reply, "org.freedesktop.DBus.ObjectManager", "InterfacesRemoved"));
423 bus_message_dump(reply, stdout, true);
425 sd_bus_message_unref(reply);
428 r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.systemd.test", "Exit", &error, NULL, "");
436 int main(int argc, char *argv[]) {
444 c.automatic_integer_property = 4711;
445 assert_se(c.automatic_string_property = strdup("dudeldu"));
447 assert_se(socketpair(AF_UNIX, SOCK_STREAM, 0, c.fds) >= 0);
449 r = pthread_create(&s, NULL, server, &c);
455 q = pthread_join(s, &p);
462 if (PTR_TO_INT(p) < 0)
463 return PTR_TO_INT(p);
466 free(c.automatic_string_property);