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"
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_bus_message_unref_ sd_bus_message
*reply
= NULL
;
299 _cleanup_bus_unref_ sd_bus
*bus
= NULL
;
300 _cleanup_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
);