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 * automatic properties for Set()
42 * automatic NULL method
43 * allow NULL as signatures in vtable
44 * node hierarchy updates during dispatching
45 * emit_interfaces_added/emit_interfaces_removed
53 const char *automatic_string_property;
54 uint32_t automatic_integer_property;
57 static int something_handler(sd_bus *bus, sd_bus_message *m, void *userdata) {
58 struct context *c = userdata;
63 r = sd_bus_message_read(m, "s", &s);
66 n = strjoin("<<<", s, ">>>", NULL);
72 log_info("AlterSomething() called, got %s, returning %s", s, n);
74 r = sd_bus_reply_method_return(bus, m, "s", n);
80 static int exit_handler(sd_bus *bus, sd_bus_message *m, void *userdata) {
81 struct context *c = userdata;
86 log_info("Exit called");
88 r = sd_bus_reply_method_return(bus, m, "");
94 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) {
95 struct context *c = userdata;
98 log_info("property get for %s called", property);
100 r = sd_bus_message_append(reply, "s", c->something);
106 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) {
107 struct context *c = userdata;
112 log_info("property set for %s called", property);
114 r = sd_bus_message_read(value, "s", &s);
126 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) {
127 _cleanup_free_ char *s = NULL;
131 assert_se(asprintf(&s, "object %p, path %s", userdata, path) >= 0);
132 r = sd_bus_message_append(reply, "s", s);
135 assert_se(x = startswith(path, "/value/"));
137 assert_se(PTR_TO_UINT(userdata) == 30);
142 static int notify_test(sd_bus *bus, sd_bus_message *m, void *userdata) {
145 assert_se(sd_bus_emit_properties_changed(bus, m->path, "org.freedesktop.systemd.ValueTest", "Value", NULL) >= 0);
147 r = sd_bus_reply_method_return(bus, m, NULL);
153 static const sd_bus_vtable vtable[] = {
154 SD_BUS_VTABLE_START(0),
155 SD_BUS_METHOD("AlterSomething", "s", "s", something_handler, 0),
156 SD_BUS_METHOD("Exit", "", "", exit_handler, 0),
157 SD_BUS_WRITABLE_PROPERTY("Something", "s", get_handler, set_handler, 0, 0),
158 SD_BUS_PROPERTY("AutomaticStringProperty", "s", NULL, offsetof(struct context, automatic_string_property), 0),
159 SD_BUS_PROPERTY("AutomaticIntegerProperty", "u", NULL, offsetof(struct context, automatic_integer_property), 0),
163 static const sd_bus_vtable vtable2[] = {
164 SD_BUS_VTABLE_START(0),
165 SD_BUS_METHOD("NotifyTest", "", "", notify_test, 0),
166 SD_BUS_PROPERTY("Value", "s", value_handler, 10, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
170 static int enumerator_callback(sd_bus *b, const char *path, char ***nodes, void *userdata) {
172 if (object_path_startswith("/value", path))
173 assert_se(*nodes = strv_new("/value/a", "/value/b", "/value/c", NULL));
178 static void *server(void *p) {
179 struct context *c = p;
186 assert_se(sd_id128_randomize(&id) >= 0);
188 assert_se(sd_bus_new(&bus) >= 0);
189 assert_se(sd_bus_set_fd(bus, c->fds[0], c->fds[0]) >= 0);
190 assert_se(sd_bus_set_server(bus, 1, id) >= 0);
192 assert_se(sd_bus_add_object_vtable(bus, "/foo", "org.freedesktop.systemd.test", vtable, c) >= 0);
193 assert_se(sd_bus_add_object_vtable(bus, "/foo", "org.freedesktop.systemd.test2", vtable, c) >= 0);
194 assert_se(sd_bus_add_fallback_vtable(bus, "/value", "org.freedesktop.systemd.ValueTest", vtable2, NULL, UINT_TO_PTR(20)) >= 0);
195 assert_se(sd_bus_add_node_enumerator(bus, "/value", enumerator_callback, NULL) >= 0);
196 assert_se(sd_bus_add_object_manager(bus, "/value") >= 0);
198 assert_se(sd_bus_start(bus) >= 0);
200 log_error("Entering event loop on server");
205 r = sd_bus_process(bus, NULL);
207 log_error("Failed to process requests: %s", strerror(-r));
212 r = sd_bus_wait(bus, (uint64_t) -1);
214 log_error("Failed to wait: %s", strerror(-r));
230 return INT_TO_PTR(r);
233 static int client(struct context *c) {
234 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
235 _cleanup_bus_unref_ sd_bus *bus = NULL;
236 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
240 assert_se(sd_bus_new(&bus) >= 0);
241 assert_se(sd_bus_set_fd(bus, c->fds[1], c->fds[1]) >= 0);
242 assert_se(sd_bus_start(bus) >= 0);
244 r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.systemd.test", "AlterSomething", &error, &reply, "s", "hallo");
247 r = sd_bus_message_read(reply, "s", &s);
249 assert_se(streq(s, "<<<hallo>>>"));
251 sd_bus_message_unref(reply);
254 r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.systemd.test", "Doesntexist", &error, &reply, "");
256 assert_se(sd_bus_error_has_name(&error, "org.freedesktop.DBus.Error.UnknownMethod"));
258 sd_bus_error_free(&error);
260 r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.systemd.test", "AlterSomething", &error, &reply, "as", 1, "hallo");
262 assert_se(sd_bus_error_has_name(&error, "org.freedesktop.DBus.Error.InvalidArgs"));
264 sd_bus_error_free(&error);
266 r = sd_bus_get_property(bus, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.systemd.test", "Something", &error, &reply, "s");
269 r = sd_bus_message_read(reply, "s", &s);
271 assert_se(streq(s, "<<<hallo>>>"));
273 sd_bus_message_unref(reply);
276 r = sd_bus_set_property(bus, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.systemd.test", "Something", &error, "s", "test");
279 r = sd_bus_get_property(bus, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.systemd.test", "Something", &error, &reply, "s");
282 r = sd_bus_message_read(reply, "s", &s);
284 assert_se(streq(s, "test"));
286 sd_bus_message_unref(reply);
289 r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.DBus.Introspectable", "Introspect", &error, &reply, "");
292 r = sd_bus_message_read(reply, "s", &s);
296 sd_bus_message_unref(reply);
299 r = sd_bus_get_property(bus, "org.freedesktop.systemd.test", "/value/xuzz", "org.freedesktop.systemd.ValueTest", "Value", &error, &reply, "s");
302 r = sd_bus_message_read(reply, "s", &s);
304 log_info("read %s", s);
306 sd_bus_message_unref(reply);
309 r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/", "org.freedesktop.DBus.Introspectable", "Introspect", &error, &reply, "");
312 r = sd_bus_message_read(reply, "s", &s);
316 sd_bus_message_unref(reply);
319 r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/value", "org.freedesktop.DBus.Introspectable", "Introspect", &error, &reply, "");
322 r = sd_bus_message_read(reply, "s", &s);
326 sd_bus_message_unref(reply);
329 r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/value/a", "org.freedesktop.DBus.Introspectable", "Introspect", &error, &reply, "");
332 r = sd_bus_message_read(reply, "s", &s);
336 sd_bus_message_unref(reply);
339 r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.DBus.Properties", "GetAll", &error, &reply, "s", "");
342 bus_message_dump(reply);
344 sd_bus_message_unref(reply);
347 r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/value/a", "org.freedesktop.DBus.Properties", "GetAll", &error, &reply, "s", "org.freedesktop.systemd.ValueTest2");
349 assert_se(sd_bus_error_has_name(&error, "org.freedesktop.DBus.Error.UnknownInterface"));
350 sd_bus_error_free(&error);
352 r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.DBus.ObjectManager", "GetManagedObjects", &error, &reply, "");
354 assert_se(sd_bus_error_has_name(&error, "org.freedesktop.DBus.Error.UnknownMethod"));
355 sd_bus_error_free(&error);
357 r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/value", "org.freedesktop.DBus.ObjectManager", "GetManagedObjects", &error, &reply, "");
360 bus_message_dump(reply);
362 sd_bus_message_unref(reply);
365 r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/value/a", "org.freedesktop.systemd.ValueTest", "NotifyTest", &error, NULL, "");
368 r = sd_bus_process(bus, &reply);
371 assert_se(sd_bus_message_is_signal(reply, "org.freedesktop.DBus.Properties", "PropertiesChanged"));
372 bus_message_dump(reply);
374 sd_bus_message_unref(reply);
377 r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.systemd.test", "Exit", &error, NULL, "");
385 int main(int argc, char *argv[]) {
393 c.automatic_integer_property = 4711;
394 c.automatic_string_property = "dudeldu";
396 assert_se(socketpair(AF_UNIX, SOCK_STREAM, 0, c.fds) >= 0);
398 r = pthread_create(&s, NULL, server, &c);
404 q = pthread_join(s, &p);
411 if (PTR_TO_INT(p) < 0)
412 return PTR_TO_INT(p);