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, sd_bus_error *error) {
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 /* This should fail, since the return type doesn't match */
65 assert_se(sd_bus_reply_method_return(m, "u", 4711) == -ENOMSG);
67 r = sd_bus_reply_method_return(m, "s", n);
73 static int exit_handler(sd_bus *bus, sd_bus_message *m, void *userdata, sd_bus_error *error) {
74 struct context *c = userdata;
79 log_info("Exit called");
81 r = sd_bus_reply_method_return(m, "");
87 static int get_handler(sd_bus *bus, const char *path, const char *interface, const char *property, sd_bus_message *reply, void *userdata, sd_bus_error *error) {
88 struct context *c = userdata;
91 log_info("property get for %s called, returning \"%s\".", property, c->something);
93 r = sd_bus_message_append(reply, "s", c->something);
99 static int set_handler(sd_bus *bus, const char *path, const char *interface, const char *property, sd_bus_message *value, void *userdata, sd_bus_error *error) {
100 struct context *c = userdata;
105 log_info("property set for %s called", property);
107 r = sd_bus_message_read(value, "s", &s);
119 static int value_handler(sd_bus *bus, const char *path, const char *interface, const char *property, sd_bus_message *reply, void *userdata, sd_bus_error *error) {
120 _cleanup_free_ char *s = NULL;
124 assert_se(asprintf(&s, "object %p, path %s", userdata, path) >= 0);
125 r = sd_bus_message_append(reply, "s", s);
128 assert_se(x = startswith(path, "/value/"));
130 assert_se(PTR_TO_UINT(userdata) == 30);
135 static int notify_test(sd_bus *bus, sd_bus_message *m, void *userdata, sd_bus_error *error) {
138 assert_se(sd_bus_emit_properties_changed(bus, m->path, "org.freedesktop.systemd.ValueTest", "Value", NULL) >= 0);
140 r = sd_bus_reply_method_return(m, NULL);
146 static int emit_interfaces_added(sd_bus *bus, sd_bus_message *m, void *userdata, sd_bus_error *error) {
149 assert_se(sd_bus_emit_interfaces_added(bus, m->path, "org.freedesktop.systemd.test", NULL) >= 0);
151 r = sd_bus_reply_method_return(m, NULL);
157 static int emit_interfaces_removed(sd_bus *bus, sd_bus_message *m, void *userdata, sd_bus_error *error) {
160 assert_se(sd_bus_emit_interfaces_removed(bus, m->path, "org.freedesktop.systemd.test", NULL) >= 0);
162 r = sd_bus_reply_method_return(m, NULL);
168 static const sd_bus_vtable vtable[] = {
169 SD_BUS_VTABLE_START(0),
170 SD_BUS_METHOD("AlterSomething", "s", "s", something_handler, 0),
171 SD_BUS_METHOD("Exit", "", "", exit_handler, 0),
172 SD_BUS_WRITABLE_PROPERTY("Something", "s", get_handler, set_handler, 0, 0),
173 SD_BUS_WRITABLE_PROPERTY("AutomaticStringProperty", "s", NULL, NULL, offsetof(struct context, automatic_string_property), 0),
174 SD_BUS_WRITABLE_PROPERTY("AutomaticIntegerProperty", "u", NULL, NULL, offsetof(struct context, automatic_integer_property), 0),
175 SD_BUS_METHOD("NoOperation", NULL, NULL, NULL, 0),
176 SD_BUS_METHOD("EmitInterfacesAdded", NULL, NULL, emit_interfaces_added, 0),
177 SD_BUS_METHOD("EmitInterfacesRemoved", NULL, NULL, emit_interfaces_removed, 0),
181 static const sd_bus_vtable vtable2[] = {
182 SD_BUS_VTABLE_START(0),
183 SD_BUS_METHOD("NotifyTest", "", "", notify_test, 0),
184 SD_BUS_PROPERTY("Value", "s", value_handler, 10, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
188 static int enumerator_callback(sd_bus *b, const char *path, void *userdata, char ***nodes, sd_bus_error *error) {
190 if (object_path_startswith("/value", path))
191 assert_se(*nodes = strv_new("/value/a", "/value/b", "/value/c", NULL));
196 static void *server(void *p) {
197 struct context *c = p;
204 assert_se(sd_id128_randomize(&id) >= 0);
206 assert_se(sd_bus_new(&bus) >= 0);
207 assert_se(sd_bus_set_fd(bus, c->fds[0], c->fds[0]) >= 0);
208 assert_se(sd_bus_set_server(bus, 1, id) >= 0);
210 assert_se(sd_bus_add_object_vtable(bus, "/foo", "org.freedesktop.systemd.test", vtable, c) >= 0);
211 assert_se(sd_bus_add_object_vtable(bus, "/foo", "org.freedesktop.systemd.test2", vtable, c) >= 0);
212 assert_se(sd_bus_add_fallback_vtable(bus, "/value", "org.freedesktop.systemd.ValueTest", vtable2, NULL, UINT_TO_PTR(20)) >= 0);
213 assert_se(sd_bus_add_node_enumerator(bus, "/value", enumerator_callback, NULL) >= 0);
214 assert_se(sd_bus_add_object_manager(bus, "/value") >= 0);
216 assert_se(sd_bus_start(bus) >= 0);
218 log_error("Entering event loop on server");
223 r = sd_bus_process(bus, NULL);
225 log_error("Failed to process requests: %s", strerror(-r));
230 r = sd_bus_wait(bus, (uint64_t) -1);
232 log_error("Failed to wait: %s", strerror(-r));
248 return INT_TO_PTR(r);
251 static int client(struct context *c) {
252 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
253 _cleanup_bus_unref_ sd_bus *bus = NULL;
254 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
258 assert_se(sd_bus_new(&bus) >= 0);
259 assert_se(sd_bus_set_fd(bus, c->fds[1], c->fds[1]) >= 0);
260 assert_se(sd_bus_start(bus) >= 0);
262 r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.systemd.test", "NoOperation", &error, NULL, NULL);
265 r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.systemd.test", "AlterSomething", &error, &reply, "s", "hallo");
268 r = sd_bus_message_read(reply, "s", &s);
270 assert_se(streq(s, "<<<hallo>>>"));
272 sd_bus_message_unref(reply);
275 r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.systemd.test", "Doesntexist", &error, &reply, "");
277 assert_se(sd_bus_error_has_name(&error, SD_BUS_ERROR_UNKNOWN_METHOD));
279 sd_bus_error_free(&error);
281 r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.systemd.test", "AlterSomething", &error, &reply, "as", 1, "hallo");
283 assert_se(sd_bus_error_has_name(&error, SD_BUS_ERROR_INVALID_ARGS));
285 sd_bus_error_free(&error);
287 r = sd_bus_get_property(bus, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.systemd.test", "Something", &error, &reply, "s");
290 r = sd_bus_message_read(reply, "s", &s);
292 assert_se(streq(s, "<<<hallo>>>"));
294 sd_bus_message_unref(reply);
297 r = sd_bus_set_property(bus, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.systemd.test", "Something", &error, "s", "test");
300 r = sd_bus_get_property(bus, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.systemd.test", "Something", &error, &reply, "s");
303 r = sd_bus_message_read(reply, "s", &s);
305 assert_se(streq(s, "test"));
307 sd_bus_message_unref(reply);
310 r = sd_bus_set_property(bus, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.systemd.test", "AutomaticIntegerProperty", &error, "u", 815);
313 assert_se(c->automatic_integer_property == 815);
315 r = sd_bus_set_property(bus, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.systemd.test", "AutomaticStringProperty", &error, "s", "Du Dödel, Du!");
318 assert_se(streq(c->automatic_string_property, "Du Dödel, Du!"));
320 r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/foo", "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_get_property(bus, "org.freedesktop.systemd.test", "/value/xuzz", "org.freedesktop.systemd.ValueTest", "Value", &error, &reply, "s");
333 r = sd_bus_message_read(reply, "s", &s);
335 log_info("read %s", s);
337 sd_bus_message_unref(reply);
340 r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/", "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", "/value", "org.freedesktop.DBus.Introspectable", "Introspect", &error, &reply, "");
353 r = sd_bus_message_read(reply, "s", &s);
357 sd_bus_message_unref(reply);
360 r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/value/a", "org.freedesktop.DBus.Introspectable", "Introspect", &error, &reply, "");
363 r = sd_bus_message_read(reply, "s", &s);
367 sd_bus_message_unref(reply);
370 r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.DBus.Properties", "GetAll", &error, &reply, "s", "");
373 bus_message_dump(reply, stdout, true);
375 sd_bus_message_unref(reply);
378 r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/value/a", "org.freedesktop.DBus.Properties", "GetAll", &error, &reply, "s", "org.freedesktop.systemd.ValueTest2");
380 assert_se(sd_bus_error_has_name(&error, SD_BUS_ERROR_UNKNOWN_INTERFACE));
381 sd_bus_error_free(&error);
383 r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.DBus.ObjectManager", "GetManagedObjects", &error, &reply, "");
385 assert_se(sd_bus_error_has_name(&error, SD_BUS_ERROR_UNKNOWN_METHOD));
386 sd_bus_error_free(&error);
388 r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/value", "org.freedesktop.DBus.ObjectManager", "GetManagedObjects", &error, &reply, "");
391 bus_message_dump(reply, stdout, true);
393 sd_bus_message_unref(reply);
396 r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/value/a", "org.freedesktop.systemd.ValueTest", "NotifyTest", &error, NULL, "");
399 r = sd_bus_process(bus, &reply);
402 assert_se(sd_bus_message_is_signal(reply, "org.freedesktop.DBus.Properties", "PropertiesChanged"));
403 bus_message_dump(reply, stdout, true);
405 sd_bus_message_unref(reply);
408 r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.systemd.test", "EmitInterfacesAdded", &error, NULL, "");
411 r = sd_bus_process(bus, &reply);
414 assert_se(sd_bus_message_is_signal(reply, "org.freedesktop.DBus.ObjectManager", "InterfacesAdded"));
415 bus_message_dump(reply, stdout, true);
417 sd_bus_message_unref(reply);
420 r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.systemd.test", "EmitInterfacesRemoved", &error, NULL, "");
423 r = sd_bus_process(bus, &reply);
426 assert_se(sd_bus_message_is_signal(reply, "org.freedesktop.DBus.ObjectManager", "InterfacesRemoved"));
427 bus_message_dump(reply, stdout, true);
429 sd_bus_message_unref(reply);
432 r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.systemd.test", "Exit", &error, NULL, "");
440 int main(int argc, char *argv[]) {
441 struct context c = {};
448 c.automatic_integer_property = 4711;
449 assert_se(c.automatic_string_property = strdup("dudeldu"));
451 assert_se(socketpair(AF_UNIX, SOCK_STREAM, 0, c.fds) >= 0);
453 r = pthread_create(&s, NULL, server, &c);
459 q = pthread_join(s, &p);
466 if (PTR_TO_INT(p) < 0)
467 return PTR_TO_INT(p);
470 free(c.automatic_string_property);