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
42 * emit_interfaces_added/emit_interfaces_removed
50 char *automatic_string_property;
51 uint32_t automatic_integer_property;
54 static int something_handler(sd_bus *bus, sd_bus_message *m, void *userdata) {
55 struct context *c = userdata;
60 r = sd_bus_message_read(m, "s", &s);
63 n = strjoin("<<<", s, ">>>", NULL);
69 log_info("AlterSomething() called, got %s, returning %s", s, n);
71 r = sd_bus_reply_method_return(bus, m, "s", n);
77 static int exit_handler(sd_bus *bus, sd_bus_message *m, void *userdata) {
78 struct context *c = userdata;
83 log_info("Exit called");
85 r = sd_bus_reply_method_return(bus, m, "");
91 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) {
92 struct context *c = userdata;
95 log_info("property get for %s called", property);
97 r = sd_bus_message_append(reply, "s", c->something);
103 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) {
104 struct context *c = userdata;
109 log_info("property set for %s called", property);
111 r = sd_bus_message_read(value, "s", &s);
123 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) {
124 _cleanup_free_ char *s = NULL;
128 assert_se(asprintf(&s, "object %p, path %s", userdata, path) >= 0);
129 r = sd_bus_message_append(reply, "s", s);
132 assert_se(x = startswith(path, "/value/"));
134 assert_se(PTR_TO_UINT(userdata) == 30);
139 static int notify_test(sd_bus *bus, sd_bus_message *m, void *userdata) {
142 assert_se(sd_bus_emit_properties_changed(bus, m->path, "org.freedesktop.systemd.ValueTest", "Value", NULL) >= 0);
144 r = sd_bus_reply_method_return(bus, m, NULL);
150 static const sd_bus_vtable vtable[] = {
151 SD_BUS_VTABLE_START(0),
152 SD_BUS_METHOD("AlterSomething", "s", "s", something_handler, 0),
153 SD_BUS_METHOD("Exit", "", "", exit_handler, 0),
154 SD_BUS_WRITABLE_PROPERTY("Something", "s", get_handler, set_handler, 0, 0),
155 SD_BUS_WRITABLE_PROPERTY("AutomaticStringProperty", "s", NULL, NULL, offsetof(struct context, automatic_string_property), 0),
156 SD_BUS_WRITABLE_PROPERTY("AutomaticIntegerProperty", "u", NULL, NULL, offsetof(struct context, automatic_integer_property), 0),
157 SD_BUS_METHOD("NoOperation", "", "", NULL, 0),
161 static const sd_bus_vtable vtable2[] = {
162 SD_BUS_VTABLE_START(0),
163 SD_BUS_METHOD("NotifyTest", "", "", notify_test, 0),
164 SD_BUS_PROPERTY("Value", "s", value_handler, 10, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
168 static int enumerator_callback(sd_bus *b, const char *path, char ***nodes, void *userdata) {
170 if (object_path_startswith("/value", path))
171 assert_se(*nodes = strv_new("/value/a", "/value/b", "/value/c", NULL));
176 static void *server(void *p) {
177 struct context *c = p;
184 assert_se(sd_id128_randomize(&id) >= 0);
186 assert_se(sd_bus_new(&bus) >= 0);
187 assert_se(sd_bus_set_fd(bus, c->fds[0], c->fds[0]) >= 0);
188 assert_se(sd_bus_set_server(bus, 1, id) >= 0);
190 assert_se(sd_bus_add_object_vtable(bus, "/foo", "org.freedesktop.systemd.test", vtable, c) >= 0);
191 assert_se(sd_bus_add_object_vtable(bus, "/foo", "org.freedesktop.systemd.test2", vtable, c) >= 0);
192 assert_se(sd_bus_add_fallback_vtable(bus, "/value", "org.freedesktop.systemd.ValueTest", vtable2, NULL, UINT_TO_PTR(20)) >= 0);
193 assert_se(sd_bus_add_node_enumerator(bus, "/value", enumerator_callback, NULL) >= 0);
194 assert_se(sd_bus_add_object_manager(bus, "/value") >= 0);
196 assert_se(sd_bus_start(bus) >= 0);
198 log_error("Entering event loop on server");
203 r = sd_bus_process(bus, NULL);
205 log_error("Failed to process requests: %s", strerror(-r));
210 r = sd_bus_wait(bus, (uint64_t) -1);
212 log_error("Failed to wait: %s", strerror(-r));
228 return INT_TO_PTR(r);
231 static int client(struct context *c) {
232 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
233 _cleanup_bus_unref_ sd_bus *bus = NULL;
234 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
238 assert_se(sd_bus_new(&bus) >= 0);
239 assert_se(sd_bus_set_fd(bus, c->fds[1], c->fds[1]) >= 0);
240 assert_se(sd_bus_start(bus) >= 0);
242 r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.systemd.test", "NoOperation", &error, NULL, NULL);
245 r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.systemd.test", "AlterSomething", &error, &reply, "s", "hallo");
248 r = sd_bus_message_read(reply, "s", &s);
250 assert_se(streq(s, "<<<hallo>>>"));
252 sd_bus_message_unref(reply);
255 r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.systemd.test", "Doesntexist", &error, &reply, "");
257 assert_se(sd_bus_error_has_name(&error, "org.freedesktop.DBus.Error.UnknownMethod"));
259 sd_bus_error_free(&error);
261 r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.systemd.test", "AlterSomething", &error, &reply, "as", 1, "hallo");
263 assert_se(sd_bus_error_has_name(&error, "org.freedesktop.DBus.Error.InvalidArgs"));
265 sd_bus_error_free(&error);
267 r = sd_bus_get_property(bus, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.systemd.test", "Something", &error, &reply, "s");
270 r = sd_bus_message_read(reply, "s", &s);
272 assert_se(streq(s, "<<<hallo>>>"));
274 sd_bus_message_unref(reply);
277 r = sd_bus_set_property(bus, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.systemd.test", "Something", &error, "s", "test");
280 r = sd_bus_get_property(bus, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.systemd.test", "Something", &error, &reply, "s");
283 r = sd_bus_message_read(reply, "s", &s);
285 assert_se(streq(s, "test"));
287 sd_bus_message_unref(reply);
290 r = sd_bus_set_property(bus, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.systemd.test", "AutomaticIntegerProperty", &error, "u", 815);
293 assert_se(c->automatic_integer_property == 815);
295 r = sd_bus_set_property(bus, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.systemd.test", "AutomaticStringProperty", &error, "s", "Du Dödel, Du!");
298 assert_se(streq(c->automatic_string_property, "Du Dödel, Du!"));
300 r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.DBus.Introspectable", "Introspect", &error, &reply, "");
303 r = sd_bus_message_read(reply, "s", &s);
307 sd_bus_message_unref(reply);
310 r = sd_bus_get_property(bus, "org.freedesktop.systemd.test", "/value/xuzz", "org.freedesktop.systemd.ValueTest", "Value", &error, &reply, "s");
313 r = sd_bus_message_read(reply, "s", &s);
315 log_info("read %s", s);
317 sd_bus_message_unref(reply);
320 r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/", "org.freedesktop.DBus.Introspectable", "Introspect", &error, &reply, "");
323 r = sd_bus_message_read(reply, "s", &s);
327 sd_bus_message_unref(reply);
330 r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/value", "org.freedesktop.DBus.Introspectable", "Introspect", &error, &reply, "");
333 r = sd_bus_message_read(reply, "s", &s);
337 sd_bus_message_unref(reply);
340 r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/value/a", "org.freedesktop.DBus.Introspectable", "Introspect", &error, &reply, "");
343 r = sd_bus_message_read(reply, "s", &s);
347 sd_bus_message_unref(reply);
350 r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.DBus.Properties", "GetAll", &error, &reply, "s", "");
353 bus_message_dump(reply);
355 sd_bus_message_unref(reply);
358 r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/value/a", "org.freedesktop.DBus.Properties", "GetAll", &error, &reply, "s", "org.freedesktop.systemd.ValueTest2");
360 assert_se(sd_bus_error_has_name(&error, "org.freedesktop.DBus.Error.UnknownInterface"));
361 sd_bus_error_free(&error);
363 r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.DBus.ObjectManager", "GetManagedObjects", &error, &reply, "");
365 assert_se(sd_bus_error_has_name(&error, "org.freedesktop.DBus.Error.UnknownMethod"));
366 sd_bus_error_free(&error);
368 r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/value", "org.freedesktop.DBus.ObjectManager", "GetManagedObjects", &error, &reply, "");
371 bus_message_dump(reply);
373 sd_bus_message_unref(reply);
376 r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/value/a", "org.freedesktop.systemd.ValueTest", "NotifyTest", &error, NULL, "");
379 r = sd_bus_process(bus, &reply);
382 assert_se(sd_bus_message_is_signal(reply, "org.freedesktop.DBus.Properties", "PropertiesChanged"));
383 bus_message_dump(reply);
385 sd_bus_message_unref(reply);
388 r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.systemd.test", "Exit", &error, NULL, "");
396 int main(int argc, char *argv[]) {
404 c.automatic_integer_property = 4711;
405 assert_se(c.automatic_string_property = strdup("dudeldu"));
407 assert_se(socketpair(AF_UNIX, SOCK_STREAM, 0, c.fds) >= 0);
409 r = pthread_create(&s, NULL, server, &c);
415 q = pthread_join(s, &p);
422 if (PTR_TO_INT(p) < 0)
423 return PTR_TO_INT(p);
426 free(c.automatic_string_property);