1 /* SPDX-License-Identifier: LGPL-2.1+ */
10 #include "alloc-util.h"
12 #include "bus-internal.h"
13 #include "bus-message.h"
24 char *automatic_string_property
;
25 uint32_t automatic_integer_property
;
28 static int something_handler(sd_bus_message
*m
, void *userdata
, sd_bus_error
*error
) {
29 struct context
*c
= userdata
;
34 r
= sd_bus_message_read(m
, "s", &s
);
37 n
= strjoin("<<<", s
, ">>>");
43 log_info("AlterSomething() called, got %s, returning %s", s
, n
);
45 /* This should fail, since the return type doesn't match */
46 assert_se(sd_bus_reply_method_return(m
, "u", 4711) == -ENOMSG
);
48 r
= sd_bus_reply_method_return(m
, "s", n
);
54 static int exit_handler(sd_bus_message
*m
, void *userdata
, sd_bus_error
*error
) {
55 struct context
*c
= userdata
;
60 log_info("Exit called");
62 r
= sd_bus_reply_method_return(m
, "");
68 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
) {
69 struct context
*c
= userdata
;
72 log_info("property get for %s called, returning \"%s\".", property
, c
->something
);
74 r
= sd_bus_message_append(reply
, "s", c
->something
);
80 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
) {
81 struct context
*c
= userdata
;
86 log_info("property set for %s called", property
);
88 r
= sd_bus_message_read(value
, "s", &s
);
100 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
) {
101 _cleanup_free_
char *s
= NULL
;
105 assert_se(asprintf(&s
, "object %p, path %s", userdata
, path
) >= 0);
106 r
= sd_bus_message_append(reply
, "s", s
);
109 assert_se(x
= startswith(path
, "/value/"));
111 assert_se(PTR_TO_UINT(userdata
) == 30);
116 static int notify_test(sd_bus_message
*m
, void *userdata
, sd_bus_error
*error
) {
119 assert_se(sd_bus_emit_properties_changed(sd_bus_message_get_bus(m
), m
->path
, "org.freedesktop.systemd.ValueTest", "Value", NULL
) >= 0);
121 r
= sd_bus_reply_method_return(m
, NULL
);
127 static int notify_test2(sd_bus_message
*m
, void *userdata
, sd_bus_error
*error
) {
130 assert_se(sd_bus_emit_properties_changed_strv(sd_bus_message_get_bus(m
), m
->path
, "org.freedesktop.systemd.ValueTest", NULL
) >= 0);
132 r
= sd_bus_reply_method_return(m
, NULL
);
138 static int emit_interfaces_added(sd_bus_message
*m
, void *userdata
, sd_bus_error
*error
) {
141 assert_se(sd_bus_emit_interfaces_added(sd_bus_message_get_bus(m
), "/value/a/x", "org.freedesktop.systemd.ValueTest", NULL
) >= 0);
143 r
= sd_bus_reply_method_return(m
, NULL
);
149 static int emit_interfaces_removed(sd_bus_message
*m
, void *userdata
, sd_bus_error
*error
) {
152 assert_se(sd_bus_emit_interfaces_removed(sd_bus_message_get_bus(m
), "/value/a/x", "org.freedesktop.systemd.ValueTest", NULL
) >= 0);
154 r
= sd_bus_reply_method_return(m
, NULL
);
160 static int emit_object_added(sd_bus_message
*m
, void *userdata
, sd_bus_error
*error
) {
163 assert_se(sd_bus_emit_object_added(sd_bus_message_get_bus(m
), "/value/a/x") >= 0);
165 r
= sd_bus_reply_method_return(m
, NULL
);
171 static int emit_object_removed(sd_bus_message
*m
, void *userdata
, sd_bus_error
*error
) {
174 assert_se(sd_bus_emit_object_removed(sd_bus_message_get_bus(m
), "/value/a/x") >= 0);
176 r
= sd_bus_reply_method_return(m
, NULL
);
182 static const sd_bus_vtable vtable
[] = {
183 SD_BUS_VTABLE_START(0),
184 SD_BUS_METHOD("AlterSomething", "s", "s", something_handler
, 0),
185 SD_BUS_METHOD("Exit", "", "", exit_handler
, 0),
186 SD_BUS_WRITABLE_PROPERTY("Something", "s", get_handler
, set_handler
, 0, 0),
187 SD_BUS_WRITABLE_PROPERTY("AutomaticStringProperty", "s", NULL
, NULL
, offsetof(struct context
, automatic_string_property
), 0),
188 SD_BUS_WRITABLE_PROPERTY("AutomaticIntegerProperty", "u", NULL
, NULL
, offsetof(struct context
, automatic_integer_property
), 0),
189 SD_BUS_METHOD("NoOperation", NULL
, NULL
, NULL
, 0),
190 SD_BUS_METHOD("EmitInterfacesAdded", NULL
, NULL
, emit_interfaces_added
, 0),
191 SD_BUS_METHOD("EmitInterfacesRemoved", NULL
, NULL
, emit_interfaces_removed
, 0),
192 SD_BUS_METHOD("EmitObjectAdded", NULL
, NULL
, emit_object_added
, 0),
193 SD_BUS_METHOD("EmitObjectRemoved", NULL
, NULL
, emit_object_removed
, 0),
197 static const sd_bus_vtable vtable2
[] = {
198 SD_BUS_VTABLE_START(0),
199 SD_BUS_METHOD("NotifyTest", "", "", notify_test
, 0),
200 SD_BUS_METHOD("NotifyTest2", "", "", notify_test2
, 0),
201 SD_BUS_PROPERTY("Value", "s", value_handler
, 10, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE
),
202 SD_BUS_PROPERTY("Value2", "s", value_handler
, 10, SD_BUS_VTABLE_PROPERTY_EMITS_INVALIDATION
),
203 SD_BUS_PROPERTY("Value3", "s", value_handler
, 10, SD_BUS_VTABLE_PROPERTY_CONST
),
204 SD_BUS_PROPERTY("Value4", "s", value_handler
, 10, 0),
205 SD_BUS_PROPERTY("AnExplicitProperty", "s", NULL
, offsetof(struct context
, something
), SD_BUS_VTABLE_PROPERTY_EXPLICIT
|SD_BUS_VTABLE_PROPERTY_EMITS_INVALIDATION
),
209 static int enumerator_callback(sd_bus
*bus
, const char *path
, void *userdata
, char ***nodes
, sd_bus_error
*error
) {
211 if (object_path_startswith("/value", path
))
212 assert_se(*nodes
= strv_new("/value/a", "/value/b", "/value/c", NULL
));
217 static int enumerator2_callback(sd_bus
*bus
, const char *path
, void *userdata
, char ***nodes
, sd_bus_error
*error
) {
219 if (object_path_startswith("/value/a", path
))
220 assert_se(*nodes
= strv_new("/value/a/x", "/value/a/y", "/value/a/z", NULL
));
225 static void *server(void *p
) {
226 struct context
*c
= p
;
233 assert_se(sd_id128_randomize(&id
) >= 0);
235 assert_se(sd_bus_new(&bus
) >= 0);
236 assert_se(sd_bus_set_fd(bus
, c
->fds
[0], c
->fds
[0]) >= 0);
237 assert_se(sd_bus_set_server(bus
, 1, id
) >= 0);
239 assert_se(sd_bus_add_object_vtable(bus
, NULL
, "/foo", "org.freedesktop.systemd.test", vtable
, c
) >= 0);
240 assert_se(sd_bus_add_object_vtable(bus
, NULL
, "/foo", "org.freedesktop.systemd.test2", vtable
, c
) >= 0);
241 assert_se(sd_bus_add_fallback_vtable(bus
, NULL
, "/value", "org.freedesktop.systemd.ValueTest", vtable2
, NULL
, UINT_TO_PTR(20)) >= 0);
242 assert_se(sd_bus_add_node_enumerator(bus
, NULL
, "/value", enumerator_callback
, NULL
) >= 0);
243 assert_se(sd_bus_add_node_enumerator(bus
, NULL
, "/value/a", enumerator2_callback
, NULL
) >= 0);
244 assert_se(sd_bus_add_object_manager(bus
, NULL
, "/value") >= 0);
245 assert_se(sd_bus_add_object_manager(bus
, NULL
, "/value/a") >= 0);
247 assert_se(sd_bus_start(bus
) >= 0);
249 log_error("Entering event loop on server");
254 r
= sd_bus_process(bus
, NULL
);
256 log_error_errno(r
, "Failed to process requests: %m");
261 r
= sd_bus_wait(bus
, (uint64_t) -1);
263 log_error_errno(r
, "Failed to wait: %m");
279 return INT_TO_PTR(r
);
282 static int client(struct context
*c
) {
283 _cleanup_(sd_bus_message_unrefp
) sd_bus_message
*reply
= NULL
;
284 _cleanup_(sd_bus_unrefp
) sd_bus
*bus
= NULL
;
285 _cleanup_(sd_bus_error_free
) sd_bus_error error
= SD_BUS_ERROR_NULL
;
289 assert_se(sd_bus_new(&bus
) >= 0);
290 assert_se(sd_bus_set_fd(bus
, c
->fds
[1], c
->fds
[1]) >= 0);
291 assert_se(sd_bus_start(bus
) >= 0);
293 r
= sd_bus_call_method(bus
, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.systemd.test", "NoOperation", &error
, NULL
, NULL
);
296 r
= sd_bus_call_method(bus
, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.systemd.test", "AlterSomething", &error
, &reply
, "s", "hallo");
299 r
= sd_bus_message_read(reply
, "s", &s
);
301 assert_se(streq(s
, "<<<hallo>>>"));
303 sd_bus_message_unref(reply
);
306 r
= sd_bus_call_method(bus
, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.systemd.test", "Doesntexist", &error
, &reply
, "");
308 assert_se(sd_bus_error_has_name(&error
, SD_BUS_ERROR_UNKNOWN_METHOD
));
310 sd_bus_error_free(&error
);
312 r
= sd_bus_call_method(bus
, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.systemd.test", "AlterSomething", &error
, &reply
, "as", 1, "hallo");
314 assert_se(sd_bus_error_has_name(&error
, SD_BUS_ERROR_INVALID_ARGS
));
316 sd_bus_error_free(&error
);
318 r
= sd_bus_get_property(bus
, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.systemd.test", "Something", &error
, &reply
, "s");
321 r
= sd_bus_message_read(reply
, "s", &s
);
323 assert_se(streq(s
, "<<<hallo>>>"));
325 sd_bus_message_unref(reply
);
328 r
= sd_bus_set_property(bus
, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.systemd.test", "Something", &error
, "s", "test");
331 r
= sd_bus_get_property(bus
, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.systemd.test", "Something", &error
, &reply
, "s");
334 r
= sd_bus_message_read(reply
, "s", &s
);
336 assert_se(streq(s
, "test"));
338 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 sd_bus_message_unref(reply
);
361 r
= sd_bus_get_property(bus
, "org.freedesktop.systemd.test", "/value/xuzz", "org.freedesktop.systemd.ValueTest", "Value", &error
, &reply
, "s");
364 r
= sd_bus_message_read(reply
, "s", &s
);
366 log_info("read %s", s
);
368 sd_bus_message_unref(reply
);
371 r
= sd_bus_call_method(bus
, "org.freedesktop.systemd.test", "/", "org.freedesktop.DBus.Introspectable", "Introspect", &error
, &reply
, "");
374 r
= sd_bus_message_read(reply
, "s", &s
);
378 sd_bus_message_unref(reply
);
381 r
= sd_bus_call_method(bus
, "org.freedesktop.systemd.test", "/value", "org.freedesktop.DBus.Introspectable", "Introspect", &error
, &reply
, "");
384 r
= sd_bus_message_read(reply
, "s", &s
);
388 sd_bus_message_unref(reply
);
391 r
= sd_bus_call_method(bus
, "org.freedesktop.systemd.test", "/value/a", "org.freedesktop.DBus.Introspectable", "Introspect", &error
, &reply
, "");
394 r
= sd_bus_message_read(reply
, "s", &s
);
398 sd_bus_message_unref(reply
);
401 r
= sd_bus_call_method(bus
, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.DBus.Properties", "GetAll", &error
, &reply
, "s", "");
404 bus_message_dump(reply
, stdout
, BUS_MESSAGE_DUMP_WITH_HEADER
);
406 sd_bus_message_unref(reply
);
409 r
= sd_bus_call_method(bus
, "org.freedesktop.systemd.test", "/value/a", "org.freedesktop.DBus.Properties", "GetAll", &error
, &reply
, "s", "org.freedesktop.systemd.ValueTest2");
411 assert_se(sd_bus_error_has_name(&error
, SD_BUS_ERROR_UNKNOWN_INTERFACE
));
412 sd_bus_error_free(&error
);
414 r
= sd_bus_call_method(bus
, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.DBus.ObjectManager", "GetManagedObjects", &error
, &reply
, "");
416 assert_se(sd_bus_error_has_name(&error
, SD_BUS_ERROR_UNKNOWN_METHOD
));
417 sd_bus_error_free(&error
);
419 r
= sd_bus_call_method(bus
, "org.freedesktop.systemd.test", "/value", "org.freedesktop.DBus.ObjectManager", "GetManagedObjects", &error
, &reply
, "");
422 bus_message_dump(reply
, stdout
, BUS_MESSAGE_DUMP_WITH_HEADER
);
424 sd_bus_message_unref(reply
);
427 r
= sd_bus_call_method(bus
, "org.freedesktop.systemd.test", "/value/a", "org.freedesktop.systemd.ValueTest", "NotifyTest", &error
, NULL
, "");
430 r
= sd_bus_process(bus
, &reply
);
433 assert_se(sd_bus_message_is_signal(reply
, "org.freedesktop.DBus.Properties", "PropertiesChanged"));
434 bus_message_dump(reply
, stdout
, BUS_MESSAGE_DUMP_WITH_HEADER
);
436 sd_bus_message_unref(reply
);
439 r
= sd_bus_call_method(bus
, "org.freedesktop.systemd.test", "/value/a", "org.freedesktop.systemd.ValueTest", "NotifyTest2", &error
, NULL
, "");
442 r
= sd_bus_process(bus
, &reply
);
445 assert_se(sd_bus_message_is_signal(reply
, "org.freedesktop.DBus.Properties", "PropertiesChanged"));
446 bus_message_dump(reply
, stdout
, BUS_MESSAGE_DUMP_WITH_HEADER
);
448 sd_bus_message_unref(reply
);
451 r
= sd_bus_call_method(bus
, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.systemd.test", "EmitInterfacesAdded", &error
, NULL
, "");
454 r
= sd_bus_process(bus
, &reply
);
457 assert_se(sd_bus_message_is_signal(reply
, "org.freedesktop.DBus.ObjectManager", "InterfacesAdded"));
458 bus_message_dump(reply
, stdout
, BUS_MESSAGE_DUMP_WITH_HEADER
);
460 sd_bus_message_unref(reply
);
463 r
= sd_bus_call_method(bus
, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.systemd.test", "EmitInterfacesRemoved", &error
, NULL
, "");
466 r
= sd_bus_process(bus
, &reply
);
469 assert_se(sd_bus_message_is_signal(reply
, "org.freedesktop.DBus.ObjectManager", "InterfacesRemoved"));
470 bus_message_dump(reply
, stdout
, BUS_MESSAGE_DUMP_WITH_HEADER
);
472 sd_bus_message_unref(reply
);
475 r
= sd_bus_call_method(bus
, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.systemd.test", "EmitObjectAdded", &error
, NULL
, "");
478 r
= sd_bus_process(bus
, &reply
);
481 assert_se(sd_bus_message_is_signal(reply
, "org.freedesktop.DBus.ObjectManager", "InterfacesAdded"));
482 bus_message_dump(reply
, stdout
, BUS_MESSAGE_DUMP_WITH_HEADER
);
484 sd_bus_message_unref(reply
);
487 r
= sd_bus_call_method(bus
, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.systemd.test", "EmitObjectRemoved", &error
, NULL
, "");
490 r
= sd_bus_process(bus
, &reply
);
493 assert_se(sd_bus_message_is_signal(reply
, "org.freedesktop.DBus.ObjectManager", "InterfacesRemoved"));
494 bus_message_dump(reply
, stdout
, BUS_MESSAGE_DUMP_WITH_HEADER
);
496 sd_bus_message_unref(reply
);
499 r
= sd_bus_call_method(bus
, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.systemd.test", "Exit", &error
, NULL
, "");
507 int main(int argc
, char *argv
[]) {
508 struct context c
= {};
513 c
.automatic_integer_property
= 4711;
514 assert_se(c
.automatic_string_property
= strdup("dudeldu"));
516 assert_se(socketpair(AF_UNIX
, SOCK_STREAM
, 0, c
.fds
) >= 0);
518 r
= pthread_create(&s
, NULL
, server
, &c
);
524 q
= pthread_join(s
, &p
);
531 if (PTR_TO_INT(p
) < 0)
532 return PTR_TO_INT(p
);
535 free(c
.automatic_string_property
);