2 This file is part of systemd.
4 Copyright 2013 Lennart Poettering
6 systemd is free software; you can redistribute it and/or modify it
7 under the terms of the GNU Lesser General Public License as published by
8 the Free Software Foundation; either version 2.1 of the License, or
9 (at your option) any later version.
11 systemd is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 Lesser General Public License for more details.
16 You should have received a copy of the GNU Lesser General Public License
17 along with systemd; If not, see <http://www.gnu.org/licenses/>.
25 #include "alloc-util.h"
27 #include "bus-internal.h"
28 #include "bus-message.h"
39 char *automatic_string_property
;
40 uint32_t automatic_integer_property
;
43 static int something_handler(sd_bus_message
*m
, void *userdata
, sd_bus_error
*error
) {
44 struct context
*c
= userdata
;
49 r
= sd_bus_message_read(m
, "s", &s
);
52 n
= strjoin("<<<", s
, ">>>", NULL
);
58 log_info("AlterSomething() called, got %s, returning %s", s
, n
);
60 /* This should fail, since the return type doesn't match */
61 assert_se(sd_bus_reply_method_return(m
, "u", 4711) == -ENOMSG
);
63 r
= sd_bus_reply_method_return(m
, "s", n
);
69 static int exit_handler(sd_bus_message
*m
, void *userdata
, sd_bus_error
*error
) {
70 struct context
*c
= userdata
;
75 log_info("Exit called");
77 r
= sd_bus_reply_method_return(m
, "");
83 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
) {
84 struct context
*c
= userdata
;
87 log_info("property get for %s called, returning \"%s\".", property
, c
->something
);
89 r
= sd_bus_message_append(reply
, "s", c
->something
);
95 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
) {
96 struct context
*c
= userdata
;
101 log_info("property set for %s called", property
);
103 r
= sd_bus_message_read(value
, "s", &s
);
115 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
) {
116 _cleanup_free_
char *s
= NULL
;
120 assert_se(asprintf(&s
, "object %p, path %s", userdata
, path
) >= 0);
121 r
= sd_bus_message_append(reply
, "s", s
);
124 assert_se(x
= startswith(path
, "/value/"));
126 assert_se(PTR_TO_UINT(userdata
) == 30);
131 static int notify_test(sd_bus_message
*m
, void *userdata
, sd_bus_error
*error
) {
134 assert_se(sd_bus_emit_properties_changed(sd_bus_message_get_bus(m
), m
->path
, "org.freedesktop.systemd.ValueTest", "Value", NULL
) >= 0);
136 r
= sd_bus_reply_method_return(m
, NULL
);
142 static int notify_test2(sd_bus_message
*m
, void *userdata
, sd_bus_error
*error
) {
145 assert_se(sd_bus_emit_properties_changed_strv(sd_bus_message_get_bus(m
), m
->path
, "org.freedesktop.systemd.ValueTest", NULL
) >= 0);
147 r
= sd_bus_reply_method_return(m
, NULL
);
153 static int emit_interfaces_added(sd_bus_message
*m
, void *userdata
, sd_bus_error
*error
) {
156 assert_se(sd_bus_emit_interfaces_added(sd_bus_message_get_bus(m
), "/value/a/x", "org.freedesktop.systemd.ValueTest", NULL
) >= 0);
158 r
= sd_bus_reply_method_return(m
, NULL
);
164 static int emit_interfaces_removed(sd_bus_message
*m
, void *userdata
, sd_bus_error
*error
) {
167 assert_se(sd_bus_emit_interfaces_removed(sd_bus_message_get_bus(m
), "/value/a/x", "org.freedesktop.systemd.ValueTest", NULL
) >= 0);
169 r
= sd_bus_reply_method_return(m
, NULL
);
175 static int emit_object_added(sd_bus_message
*m
, void *userdata
, sd_bus_error
*error
) {
178 assert_se(sd_bus_emit_object_added(sd_bus_message_get_bus(m
), "/value/a/x") >= 0);
180 r
= sd_bus_reply_method_return(m
, NULL
);
186 static int emit_object_removed(sd_bus_message
*m
, void *userdata
, sd_bus_error
*error
) {
189 assert_se(sd_bus_emit_object_removed(sd_bus_message_get_bus(m
), "/value/a/x") >= 0);
191 r
= sd_bus_reply_method_return(m
, NULL
);
197 static const sd_bus_vtable vtable
[] = {
198 SD_BUS_VTABLE_START(0),
199 SD_BUS_METHOD("AlterSomething", "s", "s", something_handler
, 0),
200 SD_BUS_METHOD("Exit", "", "", exit_handler
, 0),
201 SD_BUS_WRITABLE_PROPERTY("Something", "s", get_handler
, set_handler
, 0, 0),
202 SD_BUS_WRITABLE_PROPERTY("AutomaticStringProperty", "s", NULL
, NULL
, offsetof(struct context
, automatic_string_property
), 0),
203 SD_BUS_WRITABLE_PROPERTY("AutomaticIntegerProperty", "u", NULL
, NULL
, offsetof(struct context
, automatic_integer_property
), 0),
204 SD_BUS_METHOD("NoOperation", NULL
, NULL
, NULL
, 0),
205 SD_BUS_METHOD("EmitInterfacesAdded", NULL
, NULL
, emit_interfaces_added
, 0),
206 SD_BUS_METHOD("EmitInterfacesRemoved", NULL
, NULL
, emit_interfaces_removed
, 0),
207 SD_BUS_METHOD("EmitObjectAdded", NULL
, NULL
, emit_object_added
, 0),
208 SD_BUS_METHOD("EmitObjectRemoved", NULL
, NULL
, emit_object_removed
, 0),
212 static const sd_bus_vtable vtable2
[] = {
213 SD_BUS_VTABLE_START(0),
214 SD_BUS_METHOD("NotifyTest", "", "", notify_test
, 0),
215 SD_BUS_METHOD("NotifyTest2", "", "", notify_test2
, 0),
216 SD_BUS_PROPERTY("Value", "s", value_handler
, 10, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE
),
217 SD_BUS_PROPERTY("Value2", "s", value_handler
, 10, SD_BUS_VTABLE_PROPERTY_EMITS_INVALIDATION
),
218 SD_BUS_PROPERTY("Value3", "s", value_handler
, 10, SD_BUS_VTABLE_PROPERTY_CONST
),
219 SD_BUS_PROPERTY("Value4", "s", value_handler
, 10, 0),
220 SD_BUS_PROPERTY("AnExplicitProperty", "s", NULL
, offsetof(struct context
, something
), SD_BUS_VTABLE_PROPERTY_EXPLICIT
|SD_BUS_VTABLE_PROPERTY_EMITS_INVALIDATION
),
224 static int enumerator_callback(sd_bus
*bus
, const char *path
, void *userdata
, char ***nodes
, sd_bus_error
*error
) {
226 if (object_path_startswith("/value", path
))
227 assert_se(*nodes
= strv_new("/value/a", "/value/b", "/value/c", NULL
));
232 static int enumerator2_callback(sd_bus
*bus
, const char *path
, void *userdata
, char ***nodes
, sd_bus_error
*error
) {
234 if (object_path_startswith("/value/a", path
))
235 assert_se(*nodes
= strv_new("/value/a/x", "/value/a/y", "/value/a/z", NULL
));
240 static void *server(void *p
) {
241 struct context
*c
= p
;
248 assert_se(sd_id128_randomize(&id
) >= 0);
250 assert_se(sd_bus_new(&bus
) >= 0);
251 assert_se(sd_bus_set_fd(bus
, c
->fds
[0], c
->fds
[0]) >= 0);
252 assert_se(sd_bus_set_server(bus
, 1, id
) >= 0);
254 assert_se(sd_bus_add_object_vtable(bus
, NULL
, "/foo", "org.freedesktop.systemd.test", vtable
, c
) >= 0);
255 assert_se(sd_bus_add_object_vtable(bus
, NULL
, "/foo", "org.freedesktop.systemd.test2", vtable
, c
) >= 0);
256 assert_se(sd_bus_add_fallback_vtable(bus
, NULL
, "/value", "org.freedesktop.systemd.ValueTest", vtable2
, NULL
, UINT_TO_PTR(20)) >= 0);
257 assert_se(sd_bus_add_node_enumerator(bus
, NULL
, "/value", enumerator_callback
, NULL
) >= 0);
258 assert_se(sd_bus_add_node_enumerator(bus
, NULL
, "/value/a", enumerator2_callback
, NULL
) >= 0);
259 assert_se(sd_bus_add_object_manager(bus
, NULL
, "/value") >= 0);
260 assert_se(sd_bus_add_object_manager(bus
, NULL
, "/value/a") >= 0);
262 assert_se(sd_bus_start(bus
) >= 0);
264 log_error("Entering event loop on server");
269 r
= sd_bus_process(bus
, NULL
);
271 log_error_errno(r
, "Failed to process requests: %m");
276 r
= sd_bus_wait(bus
, (uint64_t) -1);
278 log_error_errno(r
, "Failed to wait: %m");
294 return INT_TO_PTR(r
);
297 static int client(struct context
*c
) {
298 _cleanup_(sd_bus_message_unrefp
) sd_bus_message
*reply
= NULL
;
299 _cleanup_(sd_bus_unrefp
) sd_bus
*bus
= NULL
;
300 _cleanup_(sd_bus_error_free
) sd_bus_error error
= SD_BUS_ERROR_NULL
;
304 assert_se(sd_bus_new(&bus
) >= 0);
305 assert_se(sd_bus_set_fd(bus
, c
->fds
[1], c
->fds
[1]) >= 0);
306 assert_se(sd_bus_start(bus
) >= 0);
308 r
= sd_bus_call_method(bus
, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.systemd.test", "NoOperation", &error
, NULL
, NULL
);
311 r
= sd_bus_call_method(bus
, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.systemd.test", "AlterSomething", &error
, &reply
, "s", "hallo");
314 r
= sd_bus_message_read(reply
, "s", &s
);
316 assert_se(streq(s
, "<<<hallo>>>"));
318 sd_bus_message_unref(reply
);
321 r
= sd_bus_call_method(bus
, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.systemd.test", "Doesntexist", &error
, &reply
, "");
323 assert_se(sd_bus_error_has_name(&error
, SD_BUS_ERROR_UNKNOWN_METHOD
));
325 sd_bus_error_free(&error
);
327 r
= sd_bus_call_method(bus
, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.systemd.test", "AlterSomething", &error
, &reply
, "as", 1, "hallo");
329 assert_se(sd_bus_error_has_name(&error
, SD_BUS_ERROR_INVALID_ARGS
));
331 sd_bus_error_free(&error
);
333 r
= sd_bus_get_property(bus
, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.systemd.test", "Something", &error
, &reply
, "s");
336 r
= sd_bus_message_read(reply
, "s", &s
);
338 assert_se(streq(s
, "<<<hallo>>>"));
340 sd_bus_message_unref(reply
);
343 r
= sd_bus_set_property(bus
, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.systemd.test", "Something", &error
, "s", "test");
346 r
= sd_bus_get_property(bus
, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.systemd.test", "Something", &error
, &reply
, "s");
349 r
= sd_bus_message_read(reply
, "s", &s
);
351 assert_se(streq(s
, "test"));
353 sd_bus_message_unref(reply
);
356 r
= sd_bus_set_property(bus
, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.systemd.test", "AutomaticIntegerProperty", &error
, "u", 815);
359 assert_se(c
->automatic_integer_property
== 815);
361 r
= sd_bus_set_property(bus
, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.systemd.test", "AutomaticStringProperty", &error
, "s", "Du Dödel, Du!");
364 assert_se(streq(c
->automatic_string_property
, "Du Dödel, Du!"));
366 r
= sd_bus_call_method(bus
, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.DBus.Introspectable", "Introspect", &error
, &reply
, "");
369 r
= sd_bus_message_read(reply
, "s", &s
);
373 sd_bus_message_unref(reply
);
376 r
= sd_bus_get_property(bus
, "org.freedesktop.systemd.test", "/value/xuzz", "org.freedesktop.systemd.ValueTest", "Value", &error
, &reply
, "s");
379 r
= sd_bus_message_read(reply
, "s", &s
);
381 log_info("read %s", s
);
383 sd_bus_message_unref(reply
);
386 r
= sd_bus_call_method(bus
, "org.freedesktop.systemd.test", "/", "org.freedesktop.DBus.Introspectable", "Introspect", &error
, &reply
, "");
389 r
= sd_bus_message_read(reply
, "s", &s
);
393 sd_bus_message_unref(reply
);
396 r
= sd_bus_call_method(bus
, "org.freedesktop.systemd.test", "/value", "org.freedesktop.DBus.Introspectable", "Introspect", &error
, &reply
, "");
399 r
= sd_bus_message_read(reply
, "s", &s
);
403 sd_bus_message_unref(reply
);
406 r
= sd_bus_call_method(bus
, "org.freedesktop.systemd.test", "/value/a", "org.freedesktop.DBus.Introspectable", "Introspect", &error
, &reply
, "");
409 r
= sd_bus_message_read(reply
, "s", &s
);
413 sd_bus_message_unref(reply
);
416 r
= sd_bus_call_method(bus
, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.DBus.Properties", "GetAll", &error
, &reply
, "s", "");
419 bus_message_dump(reply
, stdout
, BUS_MESSAGE_DUMP_WITH_HEADER
);
421 sd_bus_message_unref(reply
);
424 r
= sd_bus_call_method(bus
, "org.freedesktop.systemd.test", "/value/a", "org.freedesktop.DBus.Properties", "GetAll", &error
, &reply
, "s", "org.freedesktop.systemd.ValueTest2");
426 assert_se(sd_bus_error_has_name(&error
, SD_BUS_ERROR_UNKNOWN_INTERFACE
));
427 sd_bus_error_free(&error
);
429 r
= sd_bus_call_method(bus
, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.DBus.ObjectManager", "GetManagedObjects", &error
, &reply
, "");
431 assert_se(sd_bus_error_has_name(&error
, SD_BUS_ERROR_UNKNOWN_METHOD
));
432 sd_bus_error_free(&error
);
434 r
= sd_bus_call_method(bus
, "org.freedesktop.systemd.test", "/value", "org.freedesktop.DBus.ObjectManager", "GetManagedObjects", &error
, &reply
, "");
437 bus_message_dump(reply
, stdout
, BUS_MESSAGE_DUMP_WITH_HEADER
);
439 sd_bus_message_unref(reply
);
442 r
= sd_bus_call_method(bus
, "org.freedesktop.systemd.test", "/value/a", "org.freedesktop.systemd.ValueTest", "NotifyTest", &error
, NULL
, "");
445 r
= sd_bus_process(bus
, &reply
);
448 assert_se(sd_bus_message_is_signal(reply
, "org.freedesktop.DBus.Properties", "PropertiesChanged"));
449 bus_message_dump(reply
, stdout
, BUS_MESSAGE_DUMP_WITH_HEADER
);
451 sd_bus_message_unref(reply
);
454 r
= sd_bus_call_method(bus
, "org.freedesktop.systemd.test", "/value/a", "org.freedesktop.systemd.ValueTest", "NotifyTest2", &error
, NULL
, "");
457 r
= sd_bus_process(bus
, &reply
);
460 assert_se(sd_bus_message_is_signal(reply
, "org.freedesktop.DBus.Properties", "PropertiesChanged"));
461 bus_message_dump(reply
, stdout
, BUS_MESSAGE_DUMP_WITH_HEADER
);
463 sd_bus_message_unref(reply
);
466 r
= sd_bus_call_method(bus
, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.systemd.test", "EmitInterfacesAdded", &error
, NULL
, "");
469 r
= sd_bus_process(bus
, &reply
);
472 assert_se(sd_bus_message_is_signal(reply
, "org.freedesktop.DBus.ObjectManager", "InterfacesAdded"));
473 bus_message_dump(reply
, stdout
, BUS_MESSAGE_DUMP_WITH_HEADER
);
475 sd_bus_message_unref(reply
);
478 r
= sd_bus_call_method(bus
, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.systemd.test", "EmitInterfacesRemoved", &error
, NULL
, "");
481 r
= sd_bus_process(bus
, &reply
);
484 assert_se(sd_bus_message_is_signal(reply
, "org.freedesktop.DBus.ObjectManager", "InterfacesRemoved"));
485 bus_message_dump(reply
, stdout
, BUS_MESSAGE_DUMP_WITH_HEADER
);
487 sd_bus_message_unref(reply
);
490 r
= sd_bus_call_method(bus
, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.systemd.test", "EmitObjectAdded", &error
, NULL
, "");
493 r
= sd_bus_process(bus
, &reply
);
496 assert_se(sd_bus_message_is_signal(reply
, "org.freedesktop.DBus.ObjectManager", "InterfacesAdded"));
497 bus_message_dump(reply
, stdout
, BUS_MESSAGE_DUMP_WITH_HEADER
);
499 sd_bus_message_unref(reply
);
502 r
= sd_bus_call_method(bus
, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.systemd.test", "EmitObjectRemoved", &error
, NULL
, "");
505 r
= sd_bus_process(bus
, &reply
);
508 assert_se(sd_bus_message_is_signal(reply
, "org.freedesktop.DBus.ObjectManager", "InterfacesRemoved"));
509 bus_message_dump(reply
, stdout
, BUS_MESSAGE_DUMP_WITH_HEADER
);
511 sd_bus_message_unref(reply
);
514 r
= sd_bus_call_method(bus
, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.systemd.test", "Exit", &error
, NULL
, "");
522 int main(int argc
, char *argv
[]) {
523 struct context c
= {};
530 c
.automatic_integer_property
= 4711;
531 assert_se(c
.automatic_string_property
= strdup("dudeldu"));
533 assert_se(socketpair(AF_UNIX
, SOCK_STREAM
, 0, c
.fds
) >= 0);
535 r
= pthread_create(&s
, NULL
, server
, &c
);
541 q
= pthread_join(s
, &p
);
548 if (PTR_TO_INT(p
) < 0)
549 return PTR_TO_INT(p
);
552 free(c
.automatic_string_property
);