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"
41 * node hierarchy updates during dispatching
49 char *automatic_string_property;
50 uint32_t automatic_integer_property;
53 static int something_handler(sd_bus *bus, sd_bus_message *m, void *userdata) {
54 struct context *c = userdata;
59 r = sd_bus_message_read(m, "s", &s);
62 n = strjoin("<<<", s, ">>>", NULL);
68 log_info("AlterSomething() called, got %s, returning %s", s, n);
70 r = sd_bus_reply_method_return(bus, m, "s", n);
76 static int exit_handler(sd_bus *bus, sd_bus_message *m, void *userdata) {
77 struct context *c = userdata;
82 log_info("Exit called");
84 r = sd_bus_reply_method_return(bus, m, "");
90 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) {
91 struct context *c = userdata;
94 log_info("property get for %s called", property);
96 r = sd_bus_message_append(reply, "s", c->something);
102 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) {
103 struct context *c = userdata;
108 log_info("property set for %s called", property);
110 r = sd_bus_message_read(value, "s", &s);
122 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) {
123 _cleanup_free_ char *s = NULL;
127 assert_se(asprintf(&s, "object %p, path %s", userdata, path) >= 0);
128 r = sd_bus_message_append(reply, "s", s);
131 assert_se(x = startswith(path, "/value/"));
133 assert_se(PTR_TO_UINT(userdata) == 30);
138 static int notify_test(sd_bus *bus, sd_bus_message *m, void *userdata) {
141 assert_se(sd_bus_emit_properties_changed(bus, m->path, "org.freedesktop.systemd.ValueTest", "Value", NULL) >= 0);
143 r = sd_bus_reply_method_return(bus, m, NULL);
149 static int emit_interfaces_added(sd_bus *bus, sd_bus_message *m, void *userdata) {
152 assert_se(sd_bus_emit_interfaces_added(bus, m->path, "org.freedesktop.systemd.test", NULL) >= 0);
154 r = sd_bus_reply_method_return(bus, m, NULL);
160 static int emit_interfaces_removed(sd_bus *bus, sd_bus_message *m, void *userdata) {
163 assert_se(sd_bus_emit_interfaces_removed(bus, m->path, "org.freedesktop.systemd.test", NULL) >= 0);
165 r = sd_bus_reply_method_return(bus, m, NULL);
171 static const sd_bus_vtable vtable[] = {
172 SD_BUS_VTABLE_START(0),
173 SD_BUS_METHOD("AlterSomething", "s", "s", something_handler, 0),
174 SD_BUS_METHOD("Exit", "", "", exit_handler, 0),
175 SD_BUS_WRITABLE_PROPERTY("Something", "s", get_handler, set_handler, 0, 0),
176 SD_BUS_WRITABLE_PROPERTY("AutomaticStringProperty", "s", NULL, NULL, offsetof(struct context, automatic_string_property), 0),
177 SD_BUS_WRITABLE_PROPERTY("AutomaticIntegerProperty", "u", NULL, NULL, offsetof(struct context, automatic_integer_property), 0),
178 SD_BUS_METHOD("NoOperation", NULL, NULL, NULL, 0),
179 SD_BUS_METHOD("EmitInterfacesAdded", NULL, NULL, emit_interfaces_added, 0),
180 SD_BUS_METHOD("EmitInterfacesRemoved", NULL, NULL, emit_interfaces_removed, 0),
184 static const sd_bus_vtable vtable2[] = {
185 SD_BUS_VTABLE_START(0),
186 SD_BUS_METHOD("NotifyTest", "", "", notify_test, 0),
187 SD_BUS_PROPERTY("Value", "s", value_handler, 10, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
191 static int enumerator_callback(sd_bus *b, const char *path, char ***nodes, void *userdata) {
193 if (object_path_startswith("/value", path))
194 assert_se(*nodes = strv_new("/value/a", "/value/b", "/value/c", NULL));
199 static void *server(void *p) {
200 struct context *c = p;
207 assert_se(sd_id128_randomize(&id) >= 0);
209 assert_se(sd_bus_new(&bus) >= 0);
210 assert_se(sd_bus_set_fd(bus, c->fds[0], c->fds[0]) >= 0);
211 assert_se(sd_bus_set_server(bus, 1, id) >= 0);
213 assert_se(sd_bus_add_object_vtable(bus, "/foo", "org.freedesktop.systemd.test", vtable, c) >= 0);
214 assert_se(sd_bus_add_object_vtable(bus, "/foo", "org.freedesktop.systemd.test2", vtable, c) >= 0);
215 assert_se(sd_bus_add_fallback_vtable(bus, "/value", "org.freedesktop.systemd.ValueTest", vtable2, NULL, UINT_TO_PTR(20)) >= 0);
216 assert_se(sd_bus_add_node_enumerator(bus, "/value", enumerator_callback, NULL) >= 0);
217 assert_se(sd_bus_add_object_manager(bus, "/value") >= 0);
219 assert_se(sd_bus_start(bus) >= 0);
221 log_error("Entering event loop on server");
226 r = sd_bus_process(bus, NULL);
228 log_error("Failed to process requests: %s", strerror(-r));
233 r = sd_bus_wait(bus, (uint64_t) -1);
235 log_error("Failed to wait: %s", strerror(-r));
251 return INT_TO_PTR(r);
254 static int client(struct context *c) {
255 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
256 _cleanup_bus_unref_ sd_bus *bus = NULL;
257 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
261 assert_se(sd_bus_new(&bus) >= 0);
262 assert_se(sd_bus_set_fd(bus, c->fds[1], c->fds[1]) >= 0);
263 assert_se(sd_bus_start(bus) >= 0);
265 r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.systemd.test", "NoOperation", &error, NULL, NULL);
268 r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.systemd.test", "AlterSomething", &error, &reply, "s", "hallo");
271 r = sd_bus_message_read(reply, "s", &s);
273 assert_se(streq(s, "<<<hallo>>>"));
275 sd_bus_message_unref(reply);
278 r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.systemd.test", "Doesntexist", &error, &reply, "");
280 assert_se(sd_bus_error_has_name(&error, "org.freedesktop.DBus.Error.UnknownMethod"));
282 sd_bus_error_free(&error);
284 r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.systemd.test", "AlterSomething", &error, &reply, "as", 1, "hallo");
286 assert_se(sd_bus_error_has_name(&error, "org.freedesktop.DBus.Error.InvalidArgs"));
288 sd_bus_error_free(&error);
290 r = sd_bus_get_property(bus, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.systemd.test", "Something", &error, &reply, "s");
293 r = sd_bus_message_read(reply, "s", &s);
295 assert_se(streq(s, "<<<hallo>>>"));
297 sd_bus_message_unref(reply);
300 r = sd_bus_set_property(bus, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.systemd.test", "Something", &error, "s", "test");
303 r = sd_bus_get_property(bus, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.systemd.test", "Something", &error, &reply, "s");
306 r = sd_bus_message_read(reply, "s", &s);
308 assert_se(streq(s, "test"));
310 sd_bus_message_unref(reply);
313 r = sd_bus_set_property(bus, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.systemd.test", "AutomaticIntegerProperty", &error, "u", 815);
316 assert_se(c->automatic_integer_property == 815);
318 r = sd_bus_set_property(bus, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.systemd.test", "AutomaticStringProperty", &error, "s", "Du Dödel, Du!");
321 assert_se(streq(c->automatic_string_property, "Du Dödel, Du!"));
323 r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.DBus.Introspectable", "Introspect", &error, &reply, "");
326 r = sd_bus_message_read(reply, "s", &s);
330 sd_bus_message_unref(reply);
333 r = sd_bus_get_property(bus, "org.freedesktop.systemd.test", "/value/xuzz", "org.freedesktop.systemd.ValueTest", "Value", &error, &reply, "s");
336 r = sd_bus_message_read(reply, "s", &s);
338 log_info("read %s", s);
340 sd_bus_message_unref(reply);
343 r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/", "org.freedesktop.DBus.Introspectable", "Introspect", &error, &reply, "");
346 r = sd_bus_message_read(reply, "s", &s);
350 sd_bus_message_unref(reply);
353 r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/value", "org.freedesktop.DBus.Introspectable", "Introspect", &error, &reply, "");
356 r = sd_bus_message_read(reply, "s", &s);
360 sd_bus_message_unref(reply);
363 r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/value/a", "org.freedesktop.DBus.Introspectable", "Introspect", &error, &reply, "");
366 r = sd_bus_message_read(reply, "s", &s);
370 sd_bus_message_unref(reply);
373 r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.DBus.Properties", "GetAll", &error, &reply, "s", "");
376 bus_message_dump(reply);
378 sd_bus_message_unref(reply);
381 r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/value/a", "org.freedesktop.DBus.Properties", "GetAll", &error, &reply, "s", "org.freedesktop.systemd.ValueTest2");
383 assert_se(sd_bus_error_has_name(&error, "org.freedesktop.DBus.Error.UnknownInterface"));
384 sd_bus_error_free(&error);
386 r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.DBus.ObjectManager", "GetManagedObjects", &error, &reply, "");
388 assert_se(sd_bus_error_has_name(&error, "org.freedesktop.DBus.Error.UnknownMethod"));
389 sd_bus_error_free(&error);
391 r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/value", "org.freedesktop.DBus.ObjectManager", "GetManagedObjects", &error, &reply, "");
394 bus_message_dump(reply);
396 sd_bus_message_unref(reply);
399 r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/value/a", "org.freedesktop.systemd.ValueTest", "NotifyTest", &error, NULL, "");
402 r = sd_bus_process(bus, &reply);
405 assert_se(sd_bus_message_is_signal(reply, "org.freedesktop.DBus.Properties", "PropertiesChanged"));
406 bus_message_dump(reply);
408 sd_bus_message_unref(reply);
411 r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.systemd.test", "EmitInterfacesAdded", &error, NULL, "");
414 r = sd_bus_process(bus, &reply);
417 assert_se(sd_bus_message_is_signal(reply, "org.freedesktop.DBus.ObjectManager", "InterfacesAdded"));
418 bus_message_dump(reply);
420 sd_bus_message_unref(reply);
423 r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.systemd.test", "EmitInterfacesRemoved", &error, NULL, "");
426 r = sd_bus_process(bus, &reply);
429 assert_se(sd_bus_message_is_signal(reply, "org.freedesktop.DBus.ObjectManager", "InterfacesRemoved"));
430 bus_message_dump(reply);
432 sd_bus_message_unref(reply);
435 r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.systemd.test", "Exit", &error, NULL, "");
443 int main(int argc, char *argv[]) {
451 c.automatic_integer_property = 4711;
452 assert_se(c.automatic_string_property = strdup("dudeldu"));
454 assert_se(socketpair(AF_UNIX, SOCK_STREAM, 0, c.fds) >= 0);
456 r = pthread_create(&s, NULL, server, &c);
462 q = pthread_join(s, &p);
469 if (PTR_TO_INT(p) < 0)
470 return PTR_TO_INT(p);
473 free(c.automatic_string_property);