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 * node hierarchy updates during dispatching
43 * emit_interfaces_added/emit_interfaces_removed
51 const char *automatic_string_property;
52 uint32_t automatic_integer_property;
55 static int something_handler(sd_bus *bus, sd_bus_message *m, void *userdata) {
56 struct context *c = userdata;
61 r = sd_bus_message_read(m, "s", &s);
64 n = strjoin("<<<", s, ">>>", NULL);
70 log_info("AlterSomething() called, got %s, returning %s", s, n);
72 r = sd_bus_reply_method_return(bus, m, "s", n);
78 static int exit_handler(sd_bus *bus, sd_bus_message *m, void *userdata) {
79 struct context *c = userdata;
84 log_info("Exit called");
86 r = sd_bus_reply_method_return(bus, m, "");
92 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) {
93 struct context *c = userdata;
96 log_info("property get for %s called", property);
98 r = sd_bus_message_append(reply, "s", c->something);
104 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) {
105 struct context *c = userdata;
110 log_info("property set for %s called", property);
112 r = sd_bus_message_read(value, "s", &s);
124 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) {
125 _cleanup_free_ char *s = NULL;
129 assert_se(asprintf(&s, "object %p, path %s", userdata, path) >= 0);
130 r = sd_bus_message_append(reply, "s", s);
133 assert_se(x = startswith(path, "/value/"));
135 assert_se(PTR_TO_UINT(userdata) == 30);
140 static int notify_test(sd_bus *bus, sd_bus_message *m, void *userdata) {
143 assert_se(sd_bus_emit_properties_changed(bus, m->path, "org.freedesktop.systemd.ValueTest", "Value", NULL) >= 0);
145 r = sd_bus_reply_method_return(bus, m, NULL);
151 static const sd_bus_vtable vtable[] = {
152 SD_BUS_VTABLE_START(0),
153 SD_BUS_METHOD("AlterSomething", "s", "s", something_handler, 0),
154 SD_BUS_METHOD("Exit", "", "", exit_handler, 0),
155 SD_BUS_WRITABLE_PROPERTY("Something", "s", get_handler, set_handler, 0, 0),
156 SD_BUS_PROPERTY("AutomaticStringProperty", "s", NULL, offsetof(struct context, automatic_string_property), 0),
157 SD_BUS_PROPERTY("AutomaticIntegerProperty", "u", NULL, offsetof(struct context, automatic_integer_property), 0),
158 SD_BUS_METHOD("NoOperation", "", "", NULL, 0),
162 static const sd_bus_vtable vtable2[] = {
163 SD_BUS_VTABLE_START(0),
164 SD_BUS_METHOD("NotifyTest", "", "", notify_test, 0),
165 SD_BUS_PROPERTY("Value", "s", value_handler, 10, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
169 static int enumerator_callback(sd_bus *b, const char *path, char ***nodes, void *userdata) {
171 if (object_path_startswith("/value", path))
172 assert_se(*nodes = strv_new("/value/a", "/value/b", "/value/c", NULL));
177 static void *server(void *p) {
178 struct context *c = p;
185 assert_se(sd_id128_randomize(&id) >= 0);
187 assert_se(sd_bus_new(&bus) >= 0);
188 assert_se(sd_bus_set_fd(bus, c->fds[0], c->fds[0]) >= 0);
189 assert_se(sd_bus_set_server(bus, 1, id) >= 0);
191 assert_se(sd_bus_add_object_vtable(bus, "/foo", "org.freedesktop.systemd.test", vtable, c) >= 0);
192 assert_se(sd_bus_add_object_vtable(bus, "/foo", "org.freedesktop.systemd.test2", vtable, c) >= 0);
193 assert_se(sd_bus_add_fallback_vtable(bus, "/value", "org.freedesktop.systemd.ValueTest", vtable2, NULL, UINT_TO_PTR(20)) >= 0);
194 assert_se(sd_bus_add_node_enumerator(bus, "/value", enumerator_callback, NULL) >= 0);
195 assert_se(sd_bus_add_object_manager(bus, "/value") >= 0);
197 assert_se(sd_bus_start(bus) >= 0);
199 log_error("Entering event loop on server");
204 r = sd_bus_process(bus, NULL);
206 log_error("Failed to process requests: %s", strerror(-r));
211 r = sd_bus_wait(bus, (uint64_t) -1);
213 log_error("Failed to wait: %s", strerror(-r));
229 return INT_TO_PTR(r);
232 static int client(struct context *c) {
233 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
234 _cleanup_bus_unref_ sd_bus *bus = NULL;
235 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
239 assert_se(sd_bus_new(&bus) >= 0);
240 assert_se(sd_bus_set_fd(bus, c->fds[1], c->fds[1]) >= 0);
241 assert_se(sd_bus_start(bus) >= 0);
243 r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.systemd.test", "NoOperation", &error, NULL, NULL);
246 r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.systemd.test", "AlterSomething", &error, &reply, "s", "hallo");
249 r = sd_bus_message_read(reply, "s", &s);
251 assert_se(streq(s, "<<<hallo>>>"));
253 sd_bus_message_unref(reply);
256 r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.systemd.test", "Doesntexist", &error, &reply, "");
258 assert_se(sd_bus_error_has_name(&error, "org.freedesktop.DBus.Error.UnknownMethod"));
260 sd_bus_error_free(&error);
262 r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.systemd.test", "AlterSomething", &error, &reply, "as", 1, "hallo");
264 assert_se(sd_bus_error_has_name(&error, "org.freedesktop.DBus.Error.InvalidArgs"));
266 sd_bus_error_free(&error);
268 r = sd_bus_get_property(bus, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.systemd.test", "Something", &error, &reply, "s");
271 r = sd_bus_message_read(reply, "s", &s);
273 assert_se(streq(s, "<<<hallo>>>"));
275 sd_bus_message_unref(reply);
278 r = sd_bus_set_property(bus, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.systemd.test", "Something", &error, "s", "test");
281 r = sd_bus_get_property(bus, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.systemd.test", "Something", &error, &reply, "s");
284 r = sd_bus_message_read(reply, "s", &s);
286 assert_se(streq(s, "test"));
288 sd_bus_message_unref(reply);
291 r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.DBus.Introspectable", "Introspect", &error, &reply, "");
294 r = sd_bus_message_read(reply, "s", &s);
298 sd_bus_message_unref(reply);
301 r = sd_bus_get_property(bus, "org.freedesktop.systemd.test", "/value/xuzz", "org.freedesktop.systemd.ValueTest", "Value", &error, &reply, "s");
304 r = sd_bus_message_read(reply, "s", &s);
306 log_info("read %s", s);
308 sd_bus_message_unref(reply);
311 r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/", "org.freedesktop.DBus.Introspectable", "Introspect", &error, &reply, "");
314 r = sd_bus_message_read(reply, "s", &s);
318 sd_bus_message_unref(reply);
321 r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/value", "org.freedesktop.DBus.Introspectable", "Introspect", &error, &reply, "");
324 r = sd_bus_message_read(reply, "s", &s);
328 sd_bus_message_unref(reply);
331 r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/value/a", "org.freedesktop.DBus.Introspectable", "Introspect", &error, &reply, "");
334 r = sd_bus_message_read(reply, "s", &s);
338 sd_bus_message_unref(reply);
341 r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.DBus.Properties", "GetAll", &error, &reply, "s", "");
344 bus_message_dump(reply);
346 sd_bus_message_unref(reply);
349 r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/value/a", "org.freedesktop.DBus.Properties", "GetAll", &error, &reply, "s", "org.freedesktop.systemd.ValueTest2");
351 assert_se(sd_bus_error_has_name(&error, "org.freedesktop.DBus.Error.UnknownInterface"));
352 sd_bus_error_free(&error);
354 r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.DBus.ObjectManager", "GetManagedObjects", &error, &reply, "");
356 assert_se(sd_bus_error_has_name(&error, "org.freedesktop.DBus.Error.UnknownMethod"));
357 sd_bus_error_free(&error);
359 r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/value", "org.freedesktop.DBus.ObjectManager", "GetManagedObjects", &error, &reply, "");
362 bus_message_dump(reply);
364 sd_bus_message_unref(reply);
367 r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/value/a", "org.freedesktop.systemd.ValueTest", "NotifyTest", &error, NULL, "");
370 r = sd_bus_process(bus, &reply);
373 assert_se(sd_bus_message_is_signal(reply, "org.freedesktop.DBus.Properties", "PropertiesChanged"));
374 bus_message_dump(reply);
376 sd_bus_message_unref(reply);
379 r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.systemd.test", "Exit", &error, NULL, "");
387 int main(int argc, char *argv[]) {
395 c.automatic_integer_property = 4711;
396 c.automatic_string_property = "dudeldu";
398 assert_se(socketpair(AF_UNIX, SOCK_STREAM, 0, c.fds) >= 0);
400 r = pthread_create(&s, NULL, server, &c);
406 q = pthread_join(s, &p);
413 if (PTR_TO_INT(p) < 0)
414 return PTR_TO_INT(p);