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/>.
31 #include "bus-internal.h"
32 #include "bus-message.h"
40 char *automatic_string_property
;
41 uint32_t automatic_integer_property
;
44 static int something_handler(sd_bus_message
*m
, void *userdata
, sd_bus_error
*error
) {
45 struct context
*c
= userdata
;
50 r
= sd_bus_message_read(m
, "s", &s
);
53 n
= strjoin("<<<", s
, ">>>", NULL
);
59 log_info("AlterSomething() called, got %s, returning %s", s
, n
);
61 /* This should fail, since the return type doesn't match */
62 assert_se(sd_bus_reply_method_return(m
, "u", 4711) == -ENOMSG
);
64 r
= sd_bus_reply_method_return(m
, "s", n
);
70 static int exit_handler(sd_bus_message
*m
, void *userdata
, sd_bus_error
*error
) {
71 struct context
*c
= userdata
;
76 log_info("Exit called");
78 r
= sd_bus_reply_method_return(m
, "");
84 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
) {
85 struct context
*c
= userdata
;
88 log_info("property get for %s called, returning \"%s\".", property
, c
->something
);
90 r
= sd_bus_message_append(reply
, "s", c
->something
);
96 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
) {
97 struct context
*c
= userdata
;
102 log_info("property set for %s called", property
);
104 r
= sd_bus_message_read(value
, "s", &s
);
116 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
) {
117 _cleanup_free_
char *s
= NULL
;
121 assert_se(asprintf(&s
, "object %p, path %s", userdata
, path
) >= 0);
122 r
= sd_bus_message_append(reply
, "s", s
);
125 assert_se(x
= startswith(path
, "/value/"));
127 assert_se(PTR_TO_UINT(userdata
) == 30);
132 static int notify_test(sd_bus_message
*m
, void *userdata
, sd_bus_error
*error
) {
135 assert_se(sd_bus_emit_properties_changed(sd_bus_message_get_bus(m
), m
->path
, "org.freedesktop.systemd.ValueTest", "Value", NULL
) >= 0);
137 r
= sd_bus_reply_method_return(m
, NULL
);
143 static int notify_test2(sd_bus_message
*m
, void *userdata
, sd_bus_error
*error
) {
146 assert_se(sd_bus_emit_properties_changed_strv(sd_bus_message_get_bus(m
), m
->path
, "org.freedesktop.systemd.ValueTest", NULL
) >= 0);
148 r
= sd_bus_reply_method_return(m
, NULL
);
154 static int emit_interfaces_added(sd_bus_message
*m
, void *userdata
, sd_bus_error
*error
) {
157 assert_se(sd_bus_emit_interfaces_added(sd_bus_message_get_bus(m
), "/value/a/x", "org.freedesktop.systemd.ValueTest", NULL
) >= 0);
159 r
= sd_bus_reply_method_return(m
, NULL
);
165 static int emit_interfaces_removed(sd_bus_message
*m
, void *userdata
, sd_bus_error
*error
) {
168 assert_se(sd_bus_emit_interfaces_removed(sd_bus_message_get_bus(m
), "/value/a/x", "org.freedesktop.systemd.ValueTest", NULL
) >= 0);
170 r
= sd_bus_reply_method_return(m
, NULL
);
176 static int emit_object_added(sd_bus_message
*m
, void *userdata
, sd_bus_error
*error
) {
179 assert_se(sd_bus_emit_object_added(sd_bus_message_get_bus(m
), "/value/a/x") >= 0);
181 r
= sd_bus_reply_method_return(m
, NULL
);
187 static int emit_object_removed(sd_bus_message
*m
, void *userdata
, sd_bus_error
*error
) {
190 assert_se(sd_bus_emit_object_removed(sd_bus_message_get_bus(m
), "/value/a/x") >= 0);
192 r
= sd_bus_reply_method_return(m
, NULL
);
198 static const sd_bus_vtable vtable
[] = {
199 SD_BUS_VTABLE_START(0),
200 SD_BUS_METHOD("AlterSomething", "s", "s", something_handler
, 0),
201 SD_BUS_METHOD("Exit", "", "", exit_handler
, 0),
202 SD_BUS_WRITABLE_PROPERTY("Something", "s", get_handler
, set_handler
, 0, 0),
203 SD_BUS_WRITABLE_PROPERTY("AutomaticStringProperty", "s", NULL
, NULL
, offsetof(struct context
, automatic_string_property
), 0),
204 SD_BUS_WRITABLE_PROPERTY("AutomaticIntegerProperty", "u", NULL
, NULL
, offsetof(struct context
, automatic_integer_property
), 0),
205 SD_BUS_METHOD("NoOperation", NULL
, NULL
, NULL
, 0),
206 SD_BUS_METHOD("EmitInterfacesAdded", NULL
, NULL
, emit_interfaces_added
, 0),
207 SD_BUS_METHOD("EmitInterfacesRemoved", NULL
, NULL
, emit_interfaces_removed
, 0),
208 SD_BUS_METHOD("EmitObjectAdded", NULL
, NULL
, emit_object_added
, 0),
209 SD_BUS_METHOD("EmitObjectRemoved", NULL
, NULL
, emit_object_removed
, 0),
213 static const sd_bus_vtable vtable2
[] = {
214 SD_BUS_VTABLE_START(0),
215 SD_BUS_METHOD("NotifyTest", "", "", notify_test
, 0),
216 SD_BUS_METHOD("NotifyTest2", "", "", notify_test2
, 0),
217 SD_BUS_PROPERTY("Value", "s", value_handler
, 10, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE
),
218 SD_BUS_PROPERTY("Value2", "s", value_handler
, 10, SD_BUS_VTABLE_PROPERTY_EMITS_INVALIDATION
),
219 SD_BUS_PROPERTY("Value3", "s", value_handler
, 10, SD_BUS_VTABLE_PROPERTY_CONST
),
220 SD_BUS_PROPERTY("Value4", "s", value_handler
, 10, 0),
221 SD_BUS_PROPERTY("AnExplicitProperty", "s", NULL
, offsetof(struct context
, something
), SD_BUS_VTABLE_PROPERTY_EXPLICIT
|SD_BUS_VTABLE_PROPERTY_EMITS_INVALIDATION
),
225 static int enumerator_callback(sd_bus
*bus
, const char *path
, void *userdata
, char ***nodes
, sd_bus_error
*error
) {
227 if (object_path_startswith("/value", path
))
228 assert_se(*nodes
= strv_new("/value/a", "/value/b", "/value/c", NULL
));
233 static int enumerator2_callback(sd_bus
*bus
, const char *path
, void *userdata
, char ***nodes
, sd_bus_error
*error
) {
235 if (object_path_startswith("/value/a", path
))
236 assert_se(*nodes
= strv_new("/value/a/x", "/value/a/y", "/value/a/z", NULL
));
241 static void *server(void *p
) {
242 struct context
*c
= p
;
249 assert_se(sd_id128_randomize(&id
) >= 0);
251 assert_se(sd_bus_new(&bus
) >= 0);
252 assert_se(sd_bus_set_fd(bus
, c
->fds
[0], c
->fds
[0]) >= 0);
253 assert_se(sd_bus_set_server(bus
, 1, id
) >= 0);
255 assert_se(sd_bus_add_object_vtable(bus
, NULL
, "/foo", "org.freedesktop.systemd.test", vtable
, c
) >= 0);
256 assert_se(sd_bus_add_object_vtable(bus
, NULL
, "/foo", "org.freedesktop.systemd.test2", vtable
, c
) >= 0);
257 assert_se(sd_bus_add_fallback_vtable(bus
, NULL
, "/value", "org.freedesktop.systemd.ValueTest", vtable2
, NULL
, UINT_TO_PTR(20)) >= 0);
258 assert_se(sd_bus_add_node_enumerator(bus
, NULL
, "/value", enumerator_callback
, NULL
) >= 0);
259 assert_se(sd_bus_add_node_enumerator(bus
, NULL
, "/value/a", enumerator2_callback
, NULL
) >= 0);
260 assert_se(sd_bus_add_object_manager(bus
, NULL
, "/value") >= 0);
261 assert_se(sd_bus_add_object_manager(bus
, NULL
, "/value/a") >= 0);
263 assert_se(sd_bus_start(bus
) >= 0);
265 log_error("Entering event loop on server");
270 r
= sd_bus_process(bus
, NULL
);
272 log_error_errno(r
, "Failed to process requests: %m");
277 r
= sd_bus_wait(bus
, (uint64_t) -1);
279 log_error_errno(r
, "Failed to wait: %m");
295 return INT_TO_PTR(r
);
298 static int client(struct context
*c
) {
299 _cleanup_bus_message_unref_ sd_bus_message
*reply
= NULL
;
300 _cleanup_bus_unref_ sd_bus
*bus
= NULL
;
301 _cleanup_bus_error_free_ sd_bus_error error
= SD_BUS_ERROR_NULL
;
305 assert_se(sd_bus_new(&bus
) >= 0);
306 assert_se(sd_bus_set_fd(bus
, c
->fds
[1], c
->fds
[1]) >= 0);
307 assert_se(sd_bus_start(bus
) >= 0);
309 r
= sd_bus_call_method(bus
, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.systemd.test", "NoOperation", &error
, NULL
, NULL
);
312 r
= sd_bus_call_method(bus
, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.systemd.test", "AlterSomething", &error
, &reply
, "s", "hallo");
315 r
= sd_bus_message_read(reply
, "s", &s
);
317 assert_se(streq(s
, "<<<hallo>>>"));
319 sd_bus_message_unref(reply
);
322 r
= sd_bus_call_method(bus
, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.systemd.test", "Doesntexist", &error
, &reply
, "");
324 assert_se(sd_bus_error_has_name(&error
, SD_BUS_ERROR_UNKNOWN_METHOD
));
326 sd_bus_error_free(&error
);
328 r
= sd_bus_call_method(bus
, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.systemd.test", "AlterSomething", &error
, &reply
, "as", 1, "hallo");
330 assert_se(sd_bus_error_has_name(&error
, SD_BUS_ERROR_INVALID_ARGS
));
332 sd_bus_error_free(&error
);
334 r
= sd_bus_get_property(bus
, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.systemd.test", "Something", &error
, &reply
, "s");
337 r
= sd_bus_message_read(reply
, "s", &s
);
339 assert_se(streq(s
, "<<<hallo>>>"));
341 sd_bus_message_unref(reply
);
344 r
= sd_bus_set_property(bus
, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.systemd.test", "Something", &error
, "s", "test");
347 r
= sd_bus_get_property(bus
, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.systemd.test", "Something", &error
, &reply
, "s");
350 r
= sd_bus_message_read(reply
, "s", &s
);
352 assert_se(streq(s
, "test"));
354 sd_bus_message_unref(reply
);
357 r
= sd_bus_set_property(bus
, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.systemd.test", "AutomaticIntegerProperty", &error
, "u", 815);
360 assert_se(c
->automatic_integer_property
== 815);
362 r
= sd_bus_set_property(bus
, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.systemd.test", "AutomaticStringProperty", &error
, "s", "Du Dödel, Du!");
365 assert_se(streq(c
->automatic_string_property
, "Du Dödel, Du!"));
367 r
= sd_bus_call_method(bus
, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.DBus.Introspectable", "Introspect", &error
, &reply
, "");
370 r
= sd_bus_message_read(reply
, "s", &s
);
374 sd_bus_message_unref(reply
);
377 r
= sd_bus_get_property(bus
, "org.freedesktop.systemd.test", "/value/xuzz", "org.freedesktop.systemd.ValueTest", "Value", &error
, &reply
, "s");
380 r
= sd_bus_message_read(reply
, "s", &s
);
382 log_info("read %s", s
);
384 sd_bus_message_unref(reply
);
387 r
= sd_bus_call_method(bus
, "org.freedesktop.systemd.test", "/", "org.freedesktop.DBus.Introspectable", "Introspect", &error
, &reply
, "");
390 r
= sd_bus_message_read(reply
, "s", &s
);
394 sd_bus_message_unref(reply
);
397 r
= sd_bus_call_method(bus
, "org.freedesktop.systemd.test", "/value", "org.freedesktop.DBus.Introspectable", "Introspect", &error
, &reply
, "");
400 r
= sd_bus_message_read(reply
, "s", &s
);
404 sd_bus_message_unref(reply
);
407 r
= sd_bus_call_method(bus
, "org.freedesktop.systemd.test", "/value/a", "org.freedesktop.DBus.Introspectable", "Introspect", &error
, &reply
, "");
410 r
= sd_bus_message_read(reply
, "s", &s
);
414 sd_bus_message_unref(reply
);
417 r
= sd_bus_call_method(bus
, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.DBus.Properties", "GetAll", &error
, &reply
, "s", "");
420 bus_message_dump(reply
, stdout
, BUS_MESSAGE_DUMP_WITH_HEADER
);
422 sd_bus_message_unref(reply
);
425 r
= sd_bus_call_method(bus
, "org.freedesktop.systemd.test", "/value/a", "org.freedesktop.DBus.Properties", "GetAll", &error
, &reply
, "s", "org.freedesktop.systemd.ValueTest2");
427 assert_se(sd_bus_error_has_name(&error
, SD_BUS_ERROR_UNKNOWN_INTERFACE
));
428 sd_bus_error_free(&error
);
430 r
= sd_bus_call_method(bus
, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.DBus.ObjectManager", "GetManagedObjects", &error
, &reply
, "");
432 assert_se(sd_bus_error_has_name(&error
, SD_BUS_ERROR_UNKNOWN_METHOD
));
433 sd_bus_error_free(&error
);
435 r
= sd_bus_call_method(bus
, "org.freedesktop.systemd.test", "/value", "org.freedesktop.DBus.ObjectManager", "GetManagedObjects", &error
, &reply
, "");
438 bus_message_dump(reply
, stdout
, BUS_MESSAGE_DUMP_WITH_HEADER
);
440 sd_bus_message_unref(reply
);
443 r
= sd_bus_call_method(bus
, "org.freedesktop.systemd.test", "/value/a", "org.freedesktop.systemd.ValueTest", "NotifyTest", &error
, NULL
, "");
446 r
= sd_bus_process(bus
, &reply
);
449 assert_se(sd_bus_message_is_signal(reply
, "org.freedesktop.DBus.Properties", "PropertiesChanged"));
450 bus_message_dump(reply
, stdout
, BUS_MESSAGE_DUMP_WITH_HEADER
);
452 sd_bus_message_unref(reply
);
455 r
= sd_bus_call_method(bus
, "org.freedesktop.systemd.test", "/value/a", "org.freedesktop.systemd.ValueTest", "NotifyTest2", &error
, NULL
, "");
458 r
= sd_bus_process(bus
, &reply
);
461 assert_se(sd_bus_message_is_signal(reply
, "org.freedesktop.DBus.Properties", "PropertiesChanged"));
462 bus_message_dump(reply
, stdout
, BUS_MESSAGE_DUMP_WITH_HEADER
);
464 sd_bus_message_unref(reply
);
467 r
= sd_bus_call_method(bus
, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.systemd.test", "EmitInterfacesAdded", &error
, NULL
, "");
470 r
= sd_bus_process(bus
, &reply
);
473 assert_se(sd_bus_message_is_signal(reply
, "org.freedesktop.DBus.ObjectManager", "InterfacesAdded"));
474 bus_message_dump(reply
, stdout
, BUS_MESSAGE_DUMP_WITH_HEADER
);
476 sd_bus_message_unref(reply
);
479 r
= sd_bus_call_method(bus
, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.systemd.test", "EmitInterfacesRemoved", &error
, NULL
, "");
482 r
= sd_bus_process(bus
, &reply
);
485 assert_se(sd_bus_message_is_signal(reply
, "org.freedesktop.DBus.ObjectManager", "InterfacesRemoved"));
486 bus_message_dump(reply
, stdout
, BUS_MESSAGE_DUMP_WITH_HEADER
);
488 sd_bus_message_unref(reply
);
491 r
= sd_bus_call_method(bus
, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.systemd.test", "EmitObjectAdded", &error
, NULL
, "");
494 r
= sd_bus_process(bus
, &reply
);
497 assert_se(sd_bus_message_is_signal(reply
, "org.freedesktop.DBus.ObjectManager", "InterfacesAdded"));
498 bus_message_dump(reply
, stdout
, BUS_MESSAGE_DUMP_WITH_HEADER
);
500 sd_bus_message_unref(reply
);
503 r
= sd_bus_call_method(bus
, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.systemd.test", "EmitObjectRemoved", &error
, NULL
, "");
506 r
= sd_bus_process(bus
, &reply
);
509 assert_se(sd_bus_message_is_signal(reply
, "org.freedesktop.DBus.ObjectManager", "InterfacesRemoved"));
510 bus_message_dump(reply
, stdout
, BUS_MESSAGE_DUMP_WITH_HEADER
);
512 sd_bus_message_unref(reply
);
515 r
= sd_bus_call_method(bus
, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.systemd.test", "Exit", &error
, NULL
, "");
523 int main(int argc
, char *argv
[]) {
524 struct context c
= {};
531 c
.automatic_integer_property
= 4711;
532 assert_se(c
.automatic_string_property
= strdup("dudeldu"));
534 assert_se(socketpair(AF_UNIX
, SOCK_STREAM
, 0, c
.fds
) >= 0);
536 r
= pthread_create(&s
, NULL
, server
, &c
);
542 q
= pthread_join(s
, &p
);
549 if (PTR_TO_INT(p
) < 0)
550 return PTR_TO_INT(p
);
553 free(c
.automatic_string_property
);