1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
8 #include "alloc-util.h"
10 #include "bus-internal.h"
11 #include "bus-message.h"
22 char *automatic_string_property
;
23 uint32_t automatic_integer_property
;
26 static int something_handler(sd_bus_message
*m
, void *userdata
, sd_bus_error
*error
) {
27 struct context
*c
= userdata
;
32 r
= sd_bus_message_read(m
, "s", &s
);
35 n
= strjoin("<<<", s
, ">>>");
41 log_info("AlterSomething() called, got %s, returning %s", s
, n
);
43 /* This should fail, since the return type doesn't match */
44 assert_se(sd_bus_reply_method_return(m
, "u", 4711) == -ENOMSG
);
46 r
= sd_bus_reply_method_return(m
, "s", n
);
52 static int exit_handler(sd_bus_message
*m
, void *userdata
, sd_bus_error
*error
) {
53 struct context
*c
= userdata
;
58 log_info("Exit called");
60 r
= sd_bus_reply_method_return(m
, "");
66 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
) {
67 struct context
*c
= userdata
;
70 log_info("property get for %s called, returning \"%s\".", property
, c
->something
);
72 r
= sd_bus_message_append(reply
, "s", c
->something
);
78 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
) {
79 struct context
*c
= userdata
;
84 log_info("property set for %s called", property
);
86 r
= sd_bus_message_read(value
, "s", &s
);
98 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
) {
99 _cleanup_free_
char *s
= NULL
;
103 assert_se(asprintf(&s
, "object %p, path %s", userdata
, path
) >= 0);
104 r
= sd_bus_message_append(reply
, "s", s
);
107 assert_se(x
= startswith(path
, "/value/"));
109 assert_se(PTR_TO_UINT(userdata
) == 30);
114 static int notify_test(sd_bus_message
*m
, void *userdata
, sd_bus_error
*error
) {
117 assert_se(sd_bus_emit_properties_changed(sd_bus_message_get_bus(m
), m
->path
, "org.freedesktop.systemd.ValueTest", "Value", NULL
) >= 0);
119 r
= sd_bus_reply_method_return(m
, NULL
);
125 static int notify_test2(sd_bus_message
*m
, void *userdata
, sd_bus_error
*error
) {
128 assert_se(sd_bus_emit_properties_changed_strv(sd_bus_message_get_bus(m
), m
->path
, "org.freedesktop.systemd.ValueTest", NULL
) >= 0);
130 r
= sd_bus_reply_method_return(m
, NULL
);
136 static int emit_interfaces_added(sd_bus_message
*m
, void *userdata
, sd_bus_error
*error
) {
139 assert_se(sd_bus_emit_interfaces_added(sd_bus_message_get_bus(m
), "/value/a/x", "org.freedesktop.systemd.ValueTest", NULL
) >= 0);
141 r
= sd_bus_reply_method_return(m
, NULL
);
147 static int emit_interfaces_removed(sd_bus_message
*m
, void *userdata
, sd_bus_error
*error
) {
150 assert_se(sd_bus_emit_interfaces_removed(sd_bus_message_get_bus(m
), "/value/a/x", "org.freedesktop.systemd.ValueTest", NULL
) >= 0);
152 r
= sd_bus_reply_method_return(m
, NULL
);
158 static int emit_object_added(sd_bus_message
*m
, void *userdata
, sd_bus_error
*error
) {
161 assert_se(sd_bus_emit_object_added(sd_bus_message_get_bus(m
), "/value/a/x") >= 0);
163 r
= sd_bus_reply_method_return(m
, NULL
);
169 static int emit_object_removed(sd_bus_message
*m
, void *userdata
, sd_bus_error
*error
) {
172 assert_se(sd_bus_emit_object_removed(sd_bus_message_get_bus(m
), "/value/a/x") >= 0);
174 r
= sd_bus_reply_method_return(m
, NULL
);
180 static const sd_bus_vtable vtable
[] = {
181 SD_BUS_VTABLE_START(0),
182 SD_BUS_METHOD("AlterSomething", "s", "s", something_handler
, 0),
183 SD_BUS_METHOD("Exit", "", "", exit_handler
, 0),
184 SD_BUS_WRITABLE_PROPERTY("Something", "s", get_handler
, set_handler
, 0, 0),
185 SD_BUS_WRITABLE_PROPERTY("AutomaticStringProperty", "s", NULL
, NULL
, offsetof(struct context
, automatic_string_property
), 0),
186 SD_BUS_WRITABLE_PROPERTY("AutomaticIntegerProperty", "u", NULL
, NULL
, offsetof(struct context
, automatic_integer_property
), 0),
187 SD_BUS_METHOD("NoOperation", NULL
, NULL
, NULL
, 0),
188 SD_BUS_METHOD("EmitInterfacesAdded", NULL
, NULL
, emit_interfaces_added
, 0),
189 SD_BUS_METHOD("EmitInterfacesRemoved", NULL
, NULL
, emit_interfaces_removed
, 0),
190 SD_BUS_METHOD("EmitObjectAdded", NULL
, NULL
, emit_object_added
, 0),
191 SD_BUS_METHOD("EmitObjectRemoved", NULL
, NULL
, emit_object_removed
, 0),
195 static const sd_bus_vtable vtable2
[] = {
196 SD_BUS_VTABLE_START(0),
197 SD_BUS_METHOD("NotifyTest", "", "", notify_test
, 0),
198 SD_BUS_METHOD("NotifyTest2", "", "", notify_test2
, 0),
199 SD_BUS_PROPERTY("Value", "s", value_handler
, 10, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE
),
200 SD_BUS_PROPERTY("Value2", "s", value_handler
, 10, SD_BUS_VTABLE_PROPERTY_EMITS_INVALIDATION
),
201 SD_BUS_PROPERTY("Value3", "s", value_handler
, 10, SD_BUS_VTABLE_PROPERTY_CONST
),
202 SD_BUS_PROPERTY("Value4", "s", value_handler
, 10, 0),
203 SD_BUS_PROPERTY("AnExplicitProperty", "s", NULL
, offsetof(struct context
, something
), SD_BUS_VTABLE_PROPERTY_EXPLICIT
|SD_BUS_VTABLE_PROPERTY_EMITS_INVALIDATION
),
207 static int enumerator_callback(sd_bus
*bus
, const char *path
, void *userdata
, char ***nodes
, sd_bus_error
*error
) {
209 if (object_path_startswith("/value", path
))
210 assert_se(*nodes
= strv_new("/value/a", "/value/b", "/value/c"));
215 static int enumerator2_callback(sd_bus
*bus
, const char *path
, void *userdata
, char ***nodes
, sd_bus_error
*error
) {
217 if (object_path_startswith("/value/a", path
))
218 assert_se(*nodes
= strv_new("/value/a/x", "/value/a/y", "/value/a/z"));
223 static void *server(void *p
) {
224 struct context
*c
= p
;
231 assert_se(sd_id128_randomize(&id
) >= 0);
233 assert_se(sd_bus_new(&bus
) >= 0);
234 assert_se(sd_bus_set_fd(bus
, c
->fds
[0], c
->fds
[0]) >= 0);
235 assert_se(sd_bus_set_server(bus
, 1, id
) >= 0);
237 assert_se(sd_bus_add_object_vtable(bus
, NULL
, "/foo", "org.freedesktop.systemd.test", vtable
, c
) >= 0);
238 assert_se(sd_bus_add_object_vtable(bus
, NULL
, "/foo", "org.freedesktop.systemd.test2", vtable
, c
) >= 0);
239 assert_se(sd_bus_add_fallback_vtable(bus
, NULL
, "/value", "org.freedesktop.systemd.ValueTest", vtable2
, NULL
, UINT_TO_PTR(20)) >= 0);
240 assert_se(sd_bus_add_node_enumerator(bus
, NULL
, "/value", enumerator_callback
, NULL
) >= 0);
241 assert_se(sd_bus_add_node_enumerator(bus
, NULL
, "/value/a", enumerator2_callback
, NULL
) >= 0);
242 assert_se(sd_bus_add_object_manager(bus
, NULL
, "/value") >= 0);
243 assert_se(sd_bus_add_object_manager(bus
, NULL
, "/value/a") >= 0);
245 assert_se(sd_bus_start(bus
) >= 0);
247 log_error("Entering event loop on server");
252 r
= sd_bus_process(bus
, NULL
);
254 log_error_errno(r
, "Failed to process requests: %m");
259 r
= sd_bus_wait(bus
, (uint64_t) -1);
261 log_error_errno(r
, "Failed to wait: %m");
277 return INT_TO_PTR(r
);
280 static int client(struct context
*c
) {
281 _cleanup_(sd_bus_message_unrefp
) sd_bus_message
*reply
= NULL
;
282 _cleanup_(sd_bus_unrefp
) sd_bus
*bus
= NULL
;
283 _cleanup_(sd_bus_error_free
) sd_bus_error error
= SD_BUS_ERROR_NULL
;
287 assert_se(sd_bus_new(&bus
) >= 0);
288 assert_se(sd_bus_set_fd(bus
, c
->fds
[1], c
->fds
[1]) >= 0);
289 assert_se(sd_bus_start(bus
) >= 0);
291 r
= sd_bus_call_method(bus
, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.systemd.test", "NoOperation", &error
, NULL
, NULL
);
294 r
= sd_bus_call_method(bus
, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.systemd.test", "AlterSomething", &error
, &reply
, "s", "hallo");
297 r
= sd_bus_message_read(reply
, "s", &s
);
299 assert_se(streq(s
, "<<<hallo>>>"));
301 sd_bus_message_unref(reply
);
304 r
= sd_bus_call_method(bus
, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.systemd.test", "Doesntexist", &error
, &reply
, "");
306 assert_se(sd_bus_error_has_name(&error
, SD_BUS_ERROR_UNKNOWN_METHOD
));
308 sd_bus_error_free(&error
);
310 r
= sd_bus_call_method(bus
, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.systemd.test", "AlterSomething", &error
, &reply
, "as", 1, "hallo");
312 assert_se(sd_bus_error_has_name(&error
, SD_BUS_ERROR_INVALID_ARGS
));
314 sd_bus_error_free(&error
);
316 r
= sd_bus_get_property(bus
, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.systemd.test", "Something", &error
, &reply
, "s");
319 r
= sd_bus_message_read(reply
, "s", &s
);
321 assert_se(streq(s
, "<<<hallo>>>"));
323 sd_bus_message_unref(reply
);
326 r
= sd_bus_set_property(bus
, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.systemd.test", "Something", &error
, "s", "test");
329 r
= sd_bus_get_property(bus
, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.systemd.test", "Something", &error
, &reply
, "s");
332 r
= sd_bus_message_read(reply
, "s", &s
);
334 assert_se(streq(s
, "test"));
336 sd_bus_message_unref(reply
);
339 r
= sd_bus_set_property(bus
, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.systemd.test", "AutomaticIntegerProperty", &error
, "u", 815);
342 assert_se(c
->automatic_integer_property
== 815);
344 r
= sd_bus_set_property(bus
, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.systemd.test", "AutomaticStringProperty", &error
, "s", "Du Dödel, Du!");
347 assert_se(streq(c
->automatic_string_property
, "Du Dödel, Du!"));
349 r
= sd_bus_call_method(bus
, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.DBus.Introspectable", "Introspect", &error
, &reply
, "");
352 r
= sd_bus_message_read(reply
, "s", &s
);
356 sd_bus_message_unref(reply
);
359 r
= sd_bus_get_property(bus
, "org.freedesktop.systemd.test", "/value/xuzz", "org.freedesktop.systemd.ValueTest", "Value", &error
, &reply
, "s");
362 r
= sd_bus_message_read(reply
, "s", &s
);
364 log_info("read %s", s
);
366 sd_bus_message_unref(reply
);
369 r
= sd_bus_call_method(bus
, "org.freedesktop.systemd.test", "/", "org.freedesktop.DBus.Introspectable", "Introspect", &error
, &reply
, "");
372 r
= sd_bus_message_read(reply
, "s", &s
);
376 sd_bus_message_unref(reply
);
379 r
= sd_bus_call_method(bus
, "org.freedesktop.systemd.test", "/value", "org.freedesktop.DBus.Introspectable", "Introspect", &error
, &reply
, "");
382 r
= sd_bus_message_read(reply
, "s", &s
);
386 sd_bus_message_unref(reply
);
389 r
= sd_bus_call_method(bus
, "org.freedesktop.systemd.test", "/value/a", "org.freedesktop.DBus.Introspectable", "Introspect", &error
, &reply
, "");
392 r
= sd_bus_message_read(reply
, "s", &s
);
396 sd_bus_message_unref(reply
);
399 r
= sd_bus_call_method(bus
, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.DBus.Properties", "GetAll", &error
, &reply
, "s", "");
402 sd_bus_message_dump(reply
, stdout
, SD_BUS_MESSAGE_DUMP_WITH_HEADER
);
404 sd_bus_message_unref(reply
);
407 r
= sd_bus_call_method(bus
, "org.freedesktop.systemd.test", "/value/a", "org.freedesktop.DBus.Properties", "GetAll", &error
, &reply
, "s", "org.freedesktop.systemd.ValueTest2");
409 assert_se(sd_bus_error_has_name(&error
, SD_BUS_ERROR_UNKNOWN_INTERFACE
));
410 sd_bus_error_free(&error
);
412 r
= sd_bus_call_method(bus
, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.DBus.ObjectManager", "GetManagedObjects", &error
, &reply
, "");
414 assert_se(sd_bus_error_has_name(&error
, SD_BUS_ERROR_UNKNOWN_METHOD
));
415 sd_bus_error_free(&error
);
417 r
= sd_bus_call_method(bus
, "org.freedesktop.systemd.test", "/value", "org.freedesktop.DBus.ObjectManager", "GetManagedObjects", &error
, &reply
, "");
420 sd_bus_message_dump(reply
, stdout
, SD_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.systemd.ValueTest", "NotifyTest", &error
, NULL
, "");
428 r
= sd_bus_process(bus
, &reply
);
431 assert_se(sd_bus_message_is_signal(reply
, "org.freedesktop.DBus.Properties", "PropertiesChanged"));
432 sd_bus_message_dump(reply
, stdout
, SD_BUS_MESSAGE_DUMP_WITH_HEADER
);
434 sd_bus_message_unref(reply
);
437 r
= sd_bus_call_method(bus
, "org.freedesktop.systemd.test", "/value/a", "org.freedesktop.systemd.ValueTest", "NotifyTest2", &error
, NULL
, "");
440 r
= sd_bus_process(bus
, &reply
);
443 assert_se(sd_bus_message_is_signal(reply
, "org.freedesktop.DBus.Properties", "PropertiesChanged"));
444 sd_bus_message_dump(reply
, stdout
, SD_BUS_MESSAGE_DUMP_WITH_HEADER
);
446 sd_bus_message_unref(reply
);
449 r
= sd_bus_call_method(bus
, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.systemd.test", "EmitInterfacesAdded", &error
, NULL
, "");
452 r
= sd_bus_process(bus
, &reply
);
455 assert_se(sd_bus_message_is_signal(reply
, "org.freedesktop.DBus.ObjectManager", "InterfacesAdded"));
456 sd_bus_message_dump(reply
, stdout
, SD_BUS_MESSAGE_DUMP_WITH_HEADER
);
458 sd_bus_message_unref(reply
);
461 r
= sd_bus_call_method(bus
, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.systemd.test", "EmitInterfacesRemoved", &error
, NULL
, "");
464 r
= sd_bus_process(bus
, &reply
);
467 assert_se(sd_bus_message_is_signal(reply
, "org.freedesktop.DBus.ObjectManager", "InterfacesRemoved"));
468 sd_bus_message_dump(reply
, stdout
, SD_BUS_MESSAGE_DUMP_WITH_HEADER
);
470 sd_bus_message_unref(reply
);
473 r
= sd_bus_call_method(bus
, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.systemd.test", "EmitObjectAdded", &error
, NULL
, "");
476 r
= sd_bus_process(bus
, &reply
);
479 assert_se(sd_bus_message_is_signal(reply
, "org.freedesktop.DBus.ObjectManager", "InterfacesAdded"));
480 sd_bus_message_dump(reply
, stdout
, SD_BUS_MESSAGE_DUMP_WITH_HEADER
);
482 sd_bus_message_unref(reply
);
485 r
= sd_bus_call_method(bus
, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.systemd.test", "EmitObjectRemoved", &error
, NULL
, "");
488 r
= sd_bus_process(bus
, &reply
);
491 assert_se(sd_bus_message_is_signal(reply
, "org.freedesktop.DBus.ObjectManager", "InterfacesRemoved"));
492 sd_bus_message_dump(reply
, stdout
, SD_BUS_MESSAGE_DUMP_WITH_HEADER
);
494 sd_bus_message_unref(reply
);
497 r
= sd_bus_call_method(bus
, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.systemd.test", "Exit", &error
, NULL
, "");
505 int main(int argc
, char *argv
[]) {
506 struct context c
= {};
511 c
.automatic_integer_property
= 4711;
512 assert_se(c
.automatic_string_property
= strdup("dudeldu"));
514 assert_se(socketpair(AF_UNIX
, SOCK_STREAM
, 0, c
.fds
) >= 0);
516 r
= pthread_create(&s
, NULL
, server
, &c
);
522 q
= pthread_join(s
, &p
);
529 if (PTR_TO_INT(p
) < 0)
530 return PTR_TO_INT(p
);
533 free(c
.automatic_string_property
);