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) {
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 r = sd_bus_reply_method_return(bus, m, "s", n);
70 static int exit_handler(sd_bus *bus, sd_bus_message *m, void *userdata) {
71 struct context *c = userdata;
76 log_info("Exit called");
78 r = sd_bus_reply_method_return(bus, m, "");
84 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) {
85 struct context *c = userdata;
88 log_info("property get for %s called", property);
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, sd_bus_error *error, void *userdata) {
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, sd_bus_error *error, void *userdata) {
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) {
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(bus, m, NULL);
143 static int emit_interfaces_added(sd_bus *bus, sd_bus_message *m, void *userdata) {
146 assert_se(sd_bus_emit_interfaces_added(bus, m->path, "org.freedesktop.systemd.test", NULL) >= 0);
148 r = sd_bus_reply_method_return(bus, m, NULL);
154 static int emit_interfaces_removed(sd_bus *bus, sd_bus_message *m, void *userdata) {
157 assert_se(sd_bus_emit_interfaces_removed(bus, m->path, "org.freedesktop.systemd.test", NULL) >= 0);
159 r = sd_bus_reply_method_return(bus, m, NULL);
165 static const sd_bus_vtable vtable[] = {
166 SD_BUS_VTABLE_START(0),
167 SD_BUS_METHOD("AlterSomething", "s", "s", something_handler, 0),
168 SD_BUS_METHOD("Exit", "", "", exit_handler, 0),
169 SD_BUS_WRITABLE_PROPERTY("Something", "s", get_handler, set_handler, 0, 0),
170 SD_BUS_WRITABLE_PROPERTY("AutomaticStringProperty", "s", NULL, NULL, offsetof(struct context, automatic_string_property), 0),
171 SD_BUS_WRITABLE_PROPERTY("AutomaticIntegerProperty", "u", NULL, NULL, offsetof(struct context, automatic_integer_property), 0),
172 SD_BUS_METHOD("NoOperation", NULL, NULL, NULL, 0),
173 SD_BUS_METHOD("EmitInterfacesAdded", NULL, NULL, emit_interfaces_added, 0),
174 SD_BUS_METHOD("EmitInterfacesRemoved", NULL, NULL, emit_interfaces_removed, 0),
178 static const sd_bus_vtable vtable2[] = {
179 SD_BUS_VTABLE_START(0),
180 SD_BUS_METHOD("NotifyTest", "", "", notify_test, 0),
181 SD_BUS_PROPERTY("Value", "s", value_handler, 10, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
185 static int enumerator_callback(sd_bus *b, const char *path, char ***nodes, void *userdata) {
187 if (object_path_startswith("/value", path))
188 assert_se(*nodes = strv_new("/value/a", "/value/b", "/value/c", NULL));
193 static void *server(void *p) {
194 struct context *c = p;
201 assert_se(sd_id128_randomize(&id) >= 0);
203 assert_se(sd_bus_new(&bus) >= 0);
204 assert_se(sd_bus_set_fd(bus, c->fds[0], c->fds[0]) >= 0);
205 assert_se(sd_bus_set_server(bus, 1, id) >= 0);
207 assert_se(sd_bus_add_object_vtable(bus, "/foo", "org.freedesktop.systemd.test", vtable, c) >= 0);
208 assert_se(sd_bus_add_object_vtable(bus, "/foo", "org.freedesktop.systemd.test2", vtable, c) >= 0);
209 assert_se(sd_bus_add_fallback_vtable(bus, "/value", "org.freedesktop.systemd.ValueTest", vtable2, NULL, UINT_TO_PTR(20)) >= 0);
210 assert_se(sd_bus_add_node_enumerator(bus, "/value", enumerator_callback, NULL) >= 0);
211 assert_se(sd_bus_add_object_manager(bus, "/value") >= 0);
213 assert_se(sd_bus_start(bus) >= 0);
215 log_error("Entering event loop on server");
220 r = sd_bus_process(bus, NULL);
222 log_error("Failed to process requests: %s", strerror(-r));
227 r = sd_bus_wait(bus, (uint64_t) -1);
229 log_error("Failed to wait: %s", strerror(-r));
245 return INT_TO_PTR(r);
248 static int client(struct context *c) {
249 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
250 _cleanup_bus_unref_ sd_bus *bus = NULL;
251 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
255 assert_se(sd_bus_new(&bus) >= 0);
256 assert_se(sd_bus_set_fd(bus, c->fds[1], c->fds[1]) >= 0);
257 assert_se(sd_bus_start(bus) >= 0);
259 r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.systemd.test", "NoOperation", &error, NULL, NULL);
262 r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.systemd.test", "AlterSomething", &error, &reply, "s", "hallo");
265 r = sd_bus_message_read(reply, "s", &s);
267 assert_se(streq(s, "<<<hallo>>>"));
269 sd_bus_message_unref(reply);
272 r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.systemd.test", "Doesntexist", &error, &reply, "");
274 assert_se(sd_bus_error_has_name(&error, SD_BUS_ERROR_UNKNOWN_METHOD));
276 sd_bus_error_free(&error);
278 r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.systemd.test", "AlterSomething", &error, &reply, "as", 1, "hallo");
280 assert_se(sd_bus_error_has_name(&error, SD_BUS_ERROR_INVALID_ARGS));
282 sd_bus_error_free(&error);
284 r = sd_bus_get_property(bus, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.systemd.test", "Something", &error, &reply, "s");
287 r = sd_bus_message_read(reply, "s", &s);
289 assert_se(streq(s, "<<<hallo>>>"));
291 sd_bus_message_unref(reply);
294 r = sd_bus_set_property(bus, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.systemd.test", "Something", &error, "s", "test");
297 r = sd_bus_get_property(bus, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.systemd.test", "Something", &error, &reply, "s");
300 r = sd_bus_message_read(reply, "s", &s);
302 assert_se(streq(s, "test"));
304 sd_bus_message_unref(reply);
307 r = sd_bus_set_property(bus, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.systemd.test", "AutomaticIntegerProperty", &error, "u", 815);
310 assert_se(c->automatic_integer_property == 815);
312 r = sd_bus_set_property(bus, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.systemd.test", "AutomaticStringProperty", &error, "s", "Du Dödel, Du!");
315 assert_se(streq(c->automatic_string_property, "Du Dödel, Du!"));
317 r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.DBus.Introspectable", "Introspect", &error, &reply, "");
320 r = sd_bus_message_read(reply, "s", &s);
324 sd_bus_message_unref(reply);
327 r = sd_bus_get_property(bus, "org.freedesktop.systemd.test", "/value/xuzz", "org.freedesktop.systemd.ValueTest", "Value", &error, &reply, "s");
330 r = sd_bus_message_read(reply, "s", &s);
332 log_info("read %s", s);
334 sd_bus_message_unref(reply);
337 r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/", "org.freedesktop.DBus.Introspectable", "Introspect", &error, &reply, "");
340 r = sd_bus_message_read(reply, "s", &s);
344 sd_bus_message_unref(reply);
347 r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/value", "org.freedesktop.DBus.Introspectable", "Introspect", &error, &reply, "");
350 r = sd_bus_message_read(reply, "s", &s);
354 sd_bus_message_unref(reply);
357 r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/value/a", "org.freedesktop.DBus.Introspectable", "Introspect", &error, &reply, "");
360 r = sd_bus_message_read(reply, "s", &s);
364 sd_bus_message_unref(reply);
367 r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.DBus.Properties", "GetAll", &error, &reply, "s", "");
370 bus_message_dump(reply, stdout, true);
372 sd_bus_message_unref(reply);
375 r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/value/a", "org.freedesktop.DBus.Properties", "GetAll", &error, &reply, "s", "org.freedesktop.systemd.ValueTest2");
377 assert_se(sd_bus_error_has_name(&error, SD_BUS_ERROR_UNKNOWN_INTERFACE));
378 sd_bus_error_free(&error);
380 r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.DBus.ObjectManager", "GetManagedObjects", &error, &reply, "");
382 assert_se(sd_bus_error_has_name(&error, SD_BUS_ERROR_UNKNOWN_METHOD));
383 sd_bus_error_free(&error);
385 r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/value", "org.freedesktop.DBus.ObjectManager", "GetManagedObjects", &error, &reply, "");
388 bus_message_dump(reply, stdout, true);
390 sd_bus_message_unref(reply);
393 r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/value/a", "org.freedesktop.systemd.ValueTest", "NotifyTest", &error, NULL, "");
396 r = sd_bus_process(bus, &reply);
399 assert_se(sd_bus_message_is_signal(reply, "org.freedesktop.DBus.Properties", "PropertiesChanged"));
400 bus_message_dump(reply, stdout, true);
402 sd_bus_message_unref(reply);
405 r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.systemd.test", "EmitInterfacesAdded", &error, NULL, "");
408 r = sd_bus_process(bus, &reply);
411 assert_se(sd_bus_message_is_signal(reply, "org.freedesktop.DBus.ObjectManager", "InterfacesAdded"));
412 bus_message_dump(reply, stdout, true);
414 sd_bus_message_unref(reply);
417 r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.systemd.test", "EmitInterfacesRemoved", &error, NULL, "");
420 r = sd_bus_process(bus, &reply);
423 assert_se(sd_bus_message_is_signal(reply, "org.freedesktop.DBus.ObjectManager", "InterfacesRemoved"));
424 bus_message_dump(reply, stdout, true);
426 sd_bus_message_unref(reply);
429 r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.systemd.test", "Exit", &error, NULL, "");
437 int main(int argc, char *argv[]) {
445 c.automatic_integer_property = 4711;
446 assert_se(c.automatic_string_property = strdup("dudeldu"));
448 assert_se(socketpair(AF_UNIX, SOCK_STREAM, 0, c.fds) >= 0);
450 r = pthread_create(&s, NULL, server, &c);
456 q = pthread_join(s, &p);
463 if (PTR_TO_INT(p) < 0)
464 return PTR_TO_INT(p);
467 free(c.automatic_string_property);