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 notify_test2(sd_bus *bus, sd_bus_message *m, void *userdata, sd_bus_error *error) {
149 assert_se(sd_bus_emit_properties_changed_strv(bus, m->path, "org.freedesktop.systemd.ValueTest", NULL) >= 0);
151 r = sd_bus_reply_method_return(m, NULL);
157 static int emit_interfaces_added(sd_bus *bus, sd_bus_message *m, void *userdata, sd_bus_error *error) {
160 assert_se(sd_bus_emit_interfaces_added(bus, m->path, "org.freedesktop.systemd.test", NULL) >= 0);
162 r = sd_bus_reply_method_return(m, NULL);
168 static int emit_interfaces_removed(sd_bus *bus, sd_bus_message *m, void *userdata, sd_bus_error *error) {
171 assert_se(sd_bus_emit_interfaces_removed(bus, m->path, "org.freedesktop.systemd.test", NULL) >= 0);
173 r = sd_bus_reply_method_return(m, NULL);
179 static const sd_bus_vtable vtable[] = {
180 SD_BUS_VTABLE_START(0),
181 SD_BUS_METHOD("AlterSomething", "s", "s", something_handler, 0),
182 SD_BUS_METHOD("Exit", "", "", exit_handler, 0),
183 SD_BUS_WRITABLE_PROPERTY("Something", "s", get_handler, set_handler, 0, 0),
184 SD_BUS_WRITABLE_PROPERTY("AutomaticStringProperty", "s", NULL, NULL, offsetof(struct context, automatic_string_property), 0),
185 SD_BUS_WRITABLE_PROPERTY("AutomaticIntegerProperty", "u", NULL, NULL, offsetof(struct context, automatic_integer_property), 0),
186 SD_BUS_METHOD("NoOperation", NULL, NULL, NULL, 0),
187 SD_BUS_METHOD("EmitInterfacesAdded", NULL, NULL, emit_interfaces_added, 0),
188 SD_BUS_METHOD("EmitInterfacesRemoved", NULL, NULL, emit_interfaces_removed, 0),
192 static const sd_bus_vtable vtable2[] = {
193 SD_BUS_VTABLE_START(0),
194 SD_BUS_METHOD("NotifyTest", "", "", notify_test, 0),
195 SD_BUS_METHOD("NotifyTest2", "", "", notify_test2, 0),
196 SD_BUS_PROPERTY("Value", "s", value_handler, 10, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
197 SD_BUS_PROPERTY("Value2", "s", value_handler, 10, SD_BUS_VTABLE_PROPERTY_EMITS_INVALIDATION),
198 SD_BUS_PROPERTY("Value3", "s", value_handler, 10, SD_BUS_VTABLE_PROPERTY_CONST),
199 SD_BUS_PROPERTY("Value4", "s", value_handler, 10, 0),
203 static int enumerator_callback(sd_bus *bus, const char *path, void *userdata, char ***nodes, sd_bus_error *error) {
205 if (object_path_startswith("/value", path))
206 assert_se(*nodes = strv_new("/value/a", "/value/b", "/value/c", NULL));
211 static void *server(void *p) {
212 struct context *c = p;
219 assert_se(sd_id128_randomize(&id) >= 0);
221 assert_se(sd_bus_new(&bus) >= 0);
222 assert_se(sd_bus_set_fd(bus, c->fds[0], c->fds[0]) >= 0);
223 assert_se(sd_bus_set_server(bus, 1, id) >= 0);
225 assert_se(sd_bus_add_object_vtable(bus, NULL, "/foo", "org.freedesktop.systemd.test", vtable, c) >= 0);
226 assert_se(sd_bus_add_object_vtable(bus, NULL, "/foo", "org.freedesktop.systemd.test2", vtable, c) >= 0);
227 assert_se(sd_bus_add_fallback_vtable(bus, NULL, "/value", "org.freedesktop.systemd.ValueTest", vtable2, NULL, UINT_TO_PTR(20)) >= 0);
228 assert_se(sd_bus_add_node_enumerator(bus, NULL, "/value", enumerator_callback, NULL) >= 0);
229 assert_se(sd_bus_add_object_manager(bus, NULL, "/value") >= 0);
231 assert_se(sd_bus_start(bus) >= 0);
233 log_error("Entering event loop on server");
238 r = sd_bus_process(bus, NULL);
240 log_error("Failed to process requests: %s", strerror(-r));
245 r = sd_bus_wait(bus, (uint64_t) -1);
247 log_error("Failed to wait: %s", strerror(-r));
263 return INT_TO_PTR(r);
266 static int client(struct context *c) {
267 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
268 _cleanup_bus_unref_ sd_bus *bus = NULL;
269 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
273 assert_se(sd_bus_new(&bus) >= 0);
274 assert_se(sd_bus_set_fd(bus, c->fds[1], c->fds[1]) >= 0);
275 assert_se(sd_bus_start(bus) >= 0);
277 r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.systemd.test", "NoOperation", &error, NULL, NULL);
280 r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.systemd.test", "AlterSomething", &error, &reply, "s", "hallo");
283 r = sd_bus_message_read(reply, "s", &s);
285 assert_se(streq(s, "<<<hallo>>>"));
287 sd_bus_message_unref(reply);
290 r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.systemd.test", "Doesntexist", &error, &reply, "");
292 assert_se(sd_bus_error_has_name(&error, SD_BUS_ERROR_UNKNOWN_METHOD));
294 sd_bus_error_free(&error);
296 r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.systemd.test", "AlterSomething", &error, &reply, "as", 1, "hallo");
298 assert_se(sd_bus_error_has_name(&error, SD_BUS_ERROR_INVALID_ARGS));
300 sd_bus_error_free(&error);
302 r = sd_bus_get_property(bus, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.systemd.test", "Something", &error, &reply, "s");
305 r = sd_bus_message_read(reply, "s", &s);
307 assert_se(streq(s, "<<<hallo>>>"));
309 sd_bus_message_unref(reply);
312 r = sd_bus_set_property(bus, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.systemd.test", "Something", &error, "s", "test");
315 r = sd_bus_get_property(bus, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.systemd.test", "Something", &error, &reply, "s");
318 r = sd_bus_message_read(reply, "s", &s);
320 assert_se(streq(s, "test"));
322 sd_bus_message_unref(reply);
325 r = sd_bus_set_property(bus, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.systemd.test", "AutomaticIntegerProperty", &error, "u", 815);
328 assert_se(c->automatic_integer_property == 815);
330 r = sd_bus_set_property(bus, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.systemd.test", "AutomaticStringProperty", &error, "s", "Du Dödel, Du!");
333 assert_se(streq(c->automatic_string_property, "Du Dödel, Du!"));
335 r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.DBus.Introspectable", "Introspect", &error, &reply, "");
338 r = sd_bus_message_read(reply, "s", &s);
342 sd_bus_message_unref(reply);
345 r = sd_bus_get_property(bus, "org.freedesktop.systemd.test", "/value/xuzz", "org.freedesktop.systemd.ValueTest", "Value", &error, &reply, "s");
348 r = sd_bus_message_read(reply, "s", &s);
350 log_info("read %s", s);
352 sd_bus_message_unref(reply);
355 r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/", "org.freedesktop.DBus.Introspectable", "Introspect", &error, &reply, "");
358 r = sd_bus_message_read(reply, "s", &s);
362 sd_bus_message_unref(reply);
365 r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/value", "org.freedesktop.DBus.Introspectable", "Introspect", &error, &reply, "");
368 r = sd_bus_message_read(reply, "s", &s);
372 sd_bus_message_unref(reply);
375 r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/value/a", "org.freedesktop.DBus.Introspectable", "Introspect", &error, &reply, "");
378 r = sd_bus_message_read(reply, "s", &s);
382 sd_bus_message_unref(reply);
385 r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.DBus.Properties", "GetAll", &error, &reply, "s", "");
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.DBus.Properties", "GetAll", &error, &reply, "s", "org.freedesktop.systemd.ValueTest2");
395 assert_se(sd_bus_error_has_name(&error, SD_BUS_ERROR_UNKNOWN_INTERFACE));
396 sd_bus_error_free(&error);
398 r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.DBus.ObjectManager", "GetManagedObjects", &error, &reply, "");
400 assert_se(sd_bus_error_has_name(&error, SD_BUS_ERROR_UNKNOWN_METHOD));
401 sd_bus_error_free(&error);
403 r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/value", "org.freedesktop.DBus.ObjectManager", "GetManagedObjects", &error, &reply, "");
406 bus_message_dump(reply, stdout, true);
408 sd_bus_message_unref(reply);
411 r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/value/a", "org.freedesktop.systemd.ValueTest", "NotifyTest", &error, NULL, "");
414 r = sd_bus_process(bus, &reply);
417 assert_se(sd_bus_message_is_signal(reply, "org.freedesktop.DBus.Properties", "PropertiesChanged"));
418 bus_message_dump(reply, stdout, true);
420 sd_bus_message_unref(reply);
423 r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/value/a", "org.freedesktop.systemd.ValueTest", "NotifyTest2", &error, NULL, "");
426 r = sd_bus_process(bus, &reply);
429 assert_se(sd_bus_message_is_signal(reply, "org.freedesktop.DBus.Properties", "PropertiesChanged"));
430 bus_message_dump(reply, stdout, true);
432 sd_bus_message_unref(reply);
435 r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.systemd.test", "EmitInterfacesAdded", &error, NULL, "");
438 r = sd_bus_process(bus, &reply);
441 assert_se(sd_bus_message_is_signal(reply, "org.freedesktop.DBus.ObjectManager", "InterfacesAdded"));
442 bus_message_dump(reply, stdout, true);
444 sd_bus_message_unref(reply);
447 r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.systemd.test", "EmitInterfacesRemoved", &error, NULL, "");
450 r = sd_bus_process(bus, &reply);
453 assert_se(sd_bus_message_is_signal(reply, "org.freedesktop.DBus.ObjectManager", "InterfacesRemoved"));
454 bus_message_dump(reply, stdout, true);
456 sd_bus_message_unref(reply);
459 r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.systemd.test", "Exit", &error, NULL, "");
467 int main(int argc, char *argv[]) {
468 struct context c = {};
475 c.automatic_integer_property = 4711;
476 assert_se(c.automatic_string_property = strdup("dudeldu"));
478 assert_se(socketpair(AF_UNIX, SOCK_STREAM, 0, c.fds) >= 0);
480 r = pthread_create(&s, NULL, server, &c);
486 q = pthread_join(s, &p);
493 if (PTR_TO_INT(p) < 0)
494 return PTR_TO_INT(p);
497 free(c.automatic_string_property);