1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
8 #include "alloc-util.h"
10 #include "bus-internal.h"
11 #include "bus-message.h"
21 char *automatic_string_property
;
22 uint32_t automatic_integer_property
;
25 static int something_handler(sd_bus_message
*m
, void *userdata
, sd_bus_error
*error
) {
26 struct context
*c
= userdata
;
31 r
= sd_bus_message_read(m
, "s", &s
);
34 n
= strjoin("<<<", s
, ">>>");
40 log_info("AlterSomething() called, got %s, returning %s", s
, n
);
42 /* This should fail, since the return type doesn't match */
43 assert_se(sd_bus_reply_method_return(m
, "u", 4711) == -ENOMSG
);
45 r
= sd_bus_reply_method_return(m
, "s", n
);
51 static int exit_handler(sd_bus_message
*m
, void *userdata
, sd_bus_error
*error
) {
52 struct context
*c
= userdata
;
57 log_info("Exit called");
59 r
= sd_bus_reply_method_return(m
, "");
65 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
) {
66 struct context
*c
= userdata
;
69 log_info("property get for %s called, returning \"%s\".", property
, c
->something
);
71 r
= sd_bus_message_append(reply
, "s", c
->something
);
77 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
) {
78 struct context
*c
= userdata
;
83 log_info("property set for %s called", property
);
85 r
= sd_bus_message_read(value
, "s", &s
);
97 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
) {
98 _cleanup_free_
char *s
= NULL
;
102 assert_se(asprintf(&s
, "object %p, path %s", userdata
, path
) >= 0);
103 r
= sd_bus_message_append(reply
, "s", s
);
106 assert_se(x
= startswith(path
, "/value/"));
108 assert_se(PTR_TO_UINT(userdata
) == 30);
113 static int notify_test(sd_bus_message
*m
, void *userdata
, sd_bus_error
*error
) {
116 assert_se(sd_bus_emit_properties_changed(sd_bus_message_get_bus(m
), m
->path
, "org.freedesktop.systemd.ValueTest", "Value", NULL
) >= 0);
118 r
= sd_bus_reply_method_return(m
, NULL
);
124 static int notify_test2(sd_bus_message
*m
, void *userdata
, sd_bus_error
*error
) {
127 assert_se(sd_bus_emit_properties_changed_strv(sd_bus_message_get_bus(m
), m
->path
, "org.freedesktop.systemd.ValueTest", NULL
) >= 0);
129 r
= sd_bus_reply_method_return(m
, NULL
);
135 static int emit_interfaces_added(sd_bus_message
*m
, void *userdata
, sd_bus_error
*error
) {
138 assert_se(sd_bus_emit_interfaces_added(sd_bus_message_get_bus(m
), "/value/a/x", "org.freedesktop.systemd.ValueTest", NULL
) >= 0);
140 r
= sd_bus_reply_method_return(m
, NULL
);
146 static int emit_interfaces_removed(sd_bus_message
*m
, void *userdata
, sd_bus_error
*error
) {
149 assert_se(sd_bus_emit_interfaces_removed(sd_bus_message_get_bus(m
), "/value/a/x", "org.freedesktop.systemd.ValueTest", NULL
) >= 0);
151 r
= sd_bus_reply_method_return(m
, NULL
);
157 static int emit_object_added(sd_bus_message
*m
, void *userdata
, sd_bus_error
*error
) {
160 assert_se(sd_bus_emit_object_added(sd_bus_message_get_bus(m
), "/value/a/x") >= 0);
162 r
= sd_bus_reply_method_return(m
, NULL
);
168 static int emit_object_removed(sd_bus_message
*m
, void *userdata
, sd_bus_error
*error
) {
171 assert_se(sd_bus_emit_object_removed(sd_bus_message_get_bus(m
), "/value/a/x") >= 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),
189 SD_BUS_METHOD("EmitObjectAdded", NULL
, NULL
, emit_object_added
, 0),
190 SD_BUS_METHOD("EmitObjectRemoved", NULL
, NULL
, emit_object_removed
, 0),
194 static const sd_bus_vtable vtable2
[] = {
195 SD_BUS_VTABLE_START(0),
196 SD_BUS_METHOD("NotifyTest", "", "", notify_test
, 0),
197 SD_BUS_METHOD("NotifyTest2", "", "", notify_test2
, 0),
198 SD_BUS_PROPERTY("Value", "s", value_handler
, 10, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE
),
199 SD_BUS_PROPERTY("Value2", "s", value_handler
, 10, SD_BUS_VTABLE_PROPERTY_EMITS_INVALIDATION
),
200 SD_BUS_PROPERTY("Value3", "s", value_handler
, 10, SD_BUS_VTABLE_PROPERTY_CONST
),
201 SD_BUS_PROPERTY("Value4", "s", value_handler
, 10, 0),
202 SD_BUS_PROPERTY("AnExplicitProperty", "s", NULL
, offsetof(struct context
, something
), SD_BUS_VTABLE_PROPERTY_EXPLICIT
|SD_BUS_VTABLE_PROPERTY_EMITS_INVALIDATION
),
206 static int enumerator_callback(sd_bus
*bus
, const char *path
, void *userdata
, char ***nodes
, sd_bus_error
*error
) {
208 if (object_path_startswith("/value", path
))
209 assert_se(*nodes
= strv_new("/value/a", "/value/b", "/value/c"));
214 static int enumerator2_callback(sd_bus
*bus
, const char *path
, void *userdata
, char ***nodes
, sd_bus_error
*error
) {
216 if (object_path_startswith("/value/a", path
))
217 assert_se(*nodes
= strv_new("/value/a/x", "/value/a/y", "/value/a/z"));
222 static void *server(void *p
) {
223 struct context
*c
= p
;
230 assert_se(sd_id128_randomize(&id
) >= 0);
232 assert_se(sd_bus_new(&bus
) >= 0);
233 assert_se(sd_bus_set_fd(bus
, c
->fds
[0], c
->fds
[0]) >= 0);
234 assert_se(sd_bus_set_server(bus
, 1, id
) >= 0);
236 assert_se(sd_bus_add_object_vtable(bus
, NULL
, "/foo", "org.freedesktop.systemd.test", vtable
, c
) >= 0);
237 assert_se(sd_bus_add_object_vtable(bus
, NULL
, "/foo", "org.freedesktop.systemd.test2", vtable
, c
) >= 0);
238 assert_se(sd_bus_add_fallback_vtable(bus
, NULL
, "/value", "org.freedesktop.systemd.ValueTest", vtable2
, NULL
, UINT_TO_PTR(20)) >= 0);
239 assert_se(sd_bus_add_node_enumerator(bus
, NULL
, "/value", enumerator_callback
, NULL
) >= 0);
240 assert_se(sd_bus_add_node_enumerator(bus
, NULL
, "/value/a", enumerator2_callback
, NULL
) >= 0);
241 assert_se(sd_bus_add_object_manager(bus
, NULL
, "/value") >= 0);
242 assert_se(sd_bus_add_object_manager(bus
, NULL
, "/value/a") >= 0);
244 assert_se(sd_bus_start(bus
) >= 0);
246 log_error("Entering event loop on server");
251 r
= sd_bus_process(bus
, NULL
);
253 log_error_errno(r
, "Failed to process requests: %m");
258 r
= sd_bus_wait(bus
, UINT64_MAX
);
260 log_error_errno(r
, "Failed to wait: %m");
276 return INT_TO_PTR(r
);
279 static int client(struct context
*c
) {
280 _cleanup_(sd_bus_message_unrefp
) sd_bus_message
*reply
= NULL
;
281 _cleanup_(sd_bus_unrefp
) sd_bus
*bus
= NULL
;
282 _cleanup_(sd_bus_error_free
) sd_bus_error error
= SD_BUS_ERROR_NULL
;
286 assert_se(sd_bus_new(&bus
) >= 0);
287 assert_se(sd_bus_set_fd(bus
, c
->fds
[1], c
->fds
[1]) >= 0);
288 assert_se(sd_bus_start(bus
) >= 0);
290 r
= sd_bus_call_method(bus
, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.systemd.test", "NoOperation", &error
, NULL
, NULL
);
293 r
= sd_bus_call_method(bus
, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.systemd.test", "AlterSomething", &error
, &reply
, "s", "hallo");
296 r
= sd_bus_message_read(reply
, "s", &s
);
298 assert_se(streq(s
, "<<<hallo>>>"));
300 reply
= sd_bus_message_unref(reply
);
302 r
= sd_bus_call_method(bus
, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.systemd.test", "Doesntexist", &error
, &reply
, "");
304 assert_se(sd_bus_error_has_name(&error
, SD_BUS_ERROR_UNKNOWN_METHOD
));
306 sd_bus_error_free(&error
);
308 r
= sd_bus_call_method(bus
, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.systemd.test", "Doesntexist", &error
, &reply
, NULL
); /* NULL and "" are equivalent */
310 assert_se(sd_bus_error_has_name(&error
, SD_BUS_ERROR_UNKNOWN_METHOD
));
312 sd_bus_error_free(&error
);
314 r
= sd_bus_call_method(bus
, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.systemd.test", "AlterSomething", &error
, &reply
, "as", 1, "hallo");
316 assert_se(sd_bus_error_has_name(&error
, SD_BUS_ERROR_INVALID_ARGS
));
318 sd_bus_error_free(&error
);
320 r
= sd_bus_get_property(bus
, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.systemd.test", "Something", &error
, &reply
, "s");
323 r
= sd_bus_message_read(reply
, "s", &s
);
325 assert_se(streq(s
, "<<<hallo>>>"));
327 reply
= sd_bus_message_unref(reply
);
329 r
= sd_bus_set_property(bus
, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.systemd.test", "Something", &error
, "s", "test");
332 r
= sd_bus_get_property(bus
, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.systemd.test", "Something", &error
, &reply
, "s");
335 r
= sd_bus_message_read(reply
, "s", &s
);
337 assert_se(streq(s
, "test"));
339 reply
= sd_bus_message_unref(reply
);
341 r
= sd_bus_set_property(bus
, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.systemd.test", "AutomaticIntegerProperty", &error
, "u", 815);
344 assert_se(c
->automatic_integer_property
== 815);
346 r
= sd_bus_set_property(bus
, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.systemd.test", "AutomaticStringProperty", &error
, "s", "Du Dödel, Du!");
349 assert_se(streq(c
->automatic_string_property
, "Du Dödel, Du!"));
351 r
= sd_bus_call_method(bus
, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.DBus.Introspectable", "Introspect", &error
, &reply
, "");
354 r
= sd_bus_message_read(reply
, "s", &s
);
358 reply
= sd_bus_message_unref(reply
);
360 r
= sd_bus_call_method(bus
, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.DBus.Introspectable", "Introspect", &error
, &reply
, NULL
); /* NULL and "" are equivalent */
363 r
= sd_bus_message_read(reply
, "s", &s
);
367 reply
= sd_bus_message_unref(reply
);
369 r
= sd_bus_get_property(bus
, "org.freedesktop.systemd.test", "/value/xuzz", "org.freedesktop.systemd.ValueTest", "Value", &error
, &reply
, "s");
372 r
= sd_bus_message_read(reply
, "s", &s
);
374 log_info("read %s", s
);
376 reply
= sd_bus_message_unref(reply
);
378 r
= sd_bus_call_method(bus
, "org.freedesktop.systemd.test", "/", "org.freedesktop.DBus.Introspectable", "Introspect", &error
, &reply
, NULL
);
381 r
= sd_bus_message_read(reply
, "s", &s
);
385 reply
= sd_bus_message_unref(reply
);
387 r
= sd_bus_call_method(bus
, "org.freedesktop.systemd.test", "/value", "org.freedesktop.DBus.Introspectable", "Introspect", &error
, &reply
, NULL
);
390 r
= sd_bus_message_read(reply
, "s", &s
);
394 reply
= sd_bus_message_unref(reply
);
396 r
= sd_bus_call_method(bus
, "org.freedesktop.systemd.test", "/value/a", "org.freedesktop.DBus.Introspectable", "Introspect", &error
, &reply
, NULL
);
399 r
= sd_bus_message_read(reply
, "s", &s
);
403 reply
= sd_bus_message_unref(reply
);
405 r
= sd_bus_call_method(bus
, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.DBus.Properties", "GetAll", &error
, &reply
, "s", NULL
);
408 sd_bus_message_dump(reply
, stdout
, SD_BUS_MESSAGE_DUMP_WITH_HEADER
);
410 reply
= sd_bus_message_unref(reply
);
412 r
= sd_bus_call_method(bus
, "org.freedesktop.systemd.test", "/value/a", "org.freedesktop.DBus.Properties", "GetAll", &error
, &reply
, "s", "org.freedesktop.systemd.ValueTest2");
414 assert_se(sd_bus_error_has_name(&error
, SD_BUS_ERROR_UNKNOWN_INTERFACE
));
415 sd_bus_error_free(&error
);
417 r
= sd_bus_call_method(bus
, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.DBus.ObjectManager", "GetManagedObjects", &error
, &reply
, NULL
);
419 assert_se(sd_bus_error_has_name(&error
, SD_BUS_ERROR_UNKNOWN_METHOD
));
420 sd_bus_error_free(&error
);
422 r
= sd_bus_call_method(bus
, "org.freedesktop.systemd.test", "/value", "org.freedesktop.DBus.ObjectManager", "GetManagedObjects", &error
, &reply
, NULL
);
425 sd_bus_message_dump(reply
, stdout
, SD_BUS_MESSAGE_DUMP_WITH_HEADER
);
427 reply
= sd_bus_message_unref(reply
);
429 r
= sd_bus_call_method(bus
, "org.freedesktop.systemd.test", "/value/a", "org.freedesktop.systemd.ValueTest", "NotifyTest", &error
, NULL
, NULL
);
432 r
= sd_bus_process(bus
, &reply
);
435 assert_se(sd_bus_message_is_signal(reply
, "org.freedesktop.DBus.Properties", "PropertiesChanged"));
436 sd_bus_message_dump(reply
, stdout
, SD_BUS_MESSAGE_DUMP_WITH_HEADER
);
438 reply
= sd_bus_message_unref(reply
);
440 r
= sd_bus_call_method(bus
, "org.freedesktop.systemd.test", "/value/a", "org.freedesktop.systemd.ValueTest", "NotifyTest2", &error
, NULL
, NULL
);
443 r
= sd_bus_process(bus
, &reply
);
446 assert_se(sd_bus_message_is_signal(reply
, "org.freedesktop.DBus.Properties", "PropertiesChanged"));
447 sd_bus_message_dump(reply
, stdout
, SD_BUS_MESSAGE_DUMP_WITH_HEADER
);
449 reply
= sd_bus_message_unref(reply
);
451 r
= sd_bus_call_method(bus
, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.systemd.test", "EmitInterfacesAdded", &error
, NULL
, NULL
);
454 r
= sd_bus_process(bus
, &reply
);
457 assert_se(sd_bus_message_is_signal(reply
, "org.freedesktop.DBus.ObjectManager", "InterfacesAdded"));
458 sd_bus_message_dump(reply
, stdout
, SD_BUS_MESSAGE_DUMP_WITH_HEADER
);
460 reply
= sd_bus_message_unref(reply
);
462 r
= sd_bus_call_method(bus
, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.systemd.test", "EmitInterfacesRemoved", &error
, NULL
, NULL
);
465 r
= sd_bus_process(bus
, &reply
);
468 assert_se(sd_bus_message_is_signal(reply
, "org.freedesktop.DBus.ObjectManager", "InterfacesRemoved"));
469 sd_bus_message_dump(reply
, stdout
, SD_BUS_MESSAGE_DUMP_WITH_HEADER
);
471 reply
= sd_bus_message_unref(reply
);
473 r
= sd_bus_call_method(bus
, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.systemd.test", "EmitObjectAdded", &error
, NULL
, 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 reply
= sd_bus_message_unref(reply
);
484 r
= sd_bus_call_method(bus
, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.systemd.test", "EmitObjectRemoved", &error
, NULL
, NULL
);
487 r
= sd_bus_process(bus
, &reply
);
490 assert_se(sd_bus_message_is_signal(reply
, "org.freedesktop.DBus.ObjectManager", "InterfacesRemoved"));
491 sd_bus_message_dump(reply
, stdout
, SD_BUS_MESSAGE_DUMP_WITH_HEADER
);
493 reply
= sd_bus_message_unref(reply
);
495 r
= sd_bus_call_method(bus
, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.systemd.test", "Exit", &error
, NULL
, NULL
);
503 int main(int argc
, char *argv
[]) {
504 struct context c
= {};
509 c
.automatic_integer_property
= 4711;
510 assert_se(c
.automatic_string_property
= strdup("dudeldu"));
512 assert_se(socketpair(AF_UNIX
, SOCK_STREAM
, 0, c
.fds
) >= 0);
514 r
= pthread_create(&s
, NULL
, server
, &c
);
520 q
= pthread_join(s
, &p
);
527 if (PTR_TO_INT(p
) < 0)
528 return PTR_TO_INT(p
);
531 free(c
.automatic_string_property
);