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/>.
27 #include "alloc-util.h"
29 #include "bus-internal.h"
30 #include "bus-message.h"
41 char *automatic_string_property
;
42 uint32_t automatic_integer_property
;
45 static int something_handler(sd_bus_message
*m
, void *userdata
, sd_bus_error
*error
) {
46 struct context
*c
= userdata
;
51 r
= sd_bus_message_read(m
, "s", &s
);
54 n
= strjoin("<<<", s
, ">>>", NULL
);
60 log_info("AlterSomething() called, got %s, returning %s", s
, n
);
62 /* This should fail, since the return type doesn't match */
63 assert_se(sd_bus_reply_method_return(m
, "u", 4711) == -ENOMSG
);
65 r
= sd_bus_reply_method_return(m
, "s", n
);
71 static int exit_handler(sd_bus_message
*m
, void *userdata
, sd_bus_error
*error
) {
72 struct context
*c
= userdata
;
77 log_info("Exit called");
79 r
= sd_bus_reply_method_return(m
, "");
85 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
) {
86 struct context
*c
= userdata
;
89 log_info("property get for %s called, returning \"%s\".", property
, c
->something
);
91 r
= sd_bus_message_append(reply
, "s", c
->something
);
97 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
) {
98 struct context
*c
= userdata
;
103 log_info("property set for %s called", property
);
105 r
= sd_bus_message_read(value
, "s", &s
);
117 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
) {
118 _cleanup_free_
char *s
= NULL
;
122 assert_se(asprintf(&s
, "object %p, path %s", userdata
, path
) >= 0);
123 r
= sd_bus_message_append(reply
, "s", s
);
126 assert_se(x
= startswith(path
, "/value/"));
128 assert_se(PTR_TO_UINT(userdata
) == 30);
133 static int notify_test(sd_bus_message
*m
, void *userdata
, sd_bus_error
*error
) {
136 assert_se(sd_bus_emit_properties_changed(sd_bus_message_get_bus(m
), m
->path
, "org.freedesktop.systemd.ValueTest", "Value", NULL
) >= 0);
138 r
= sd_bus_reply_method_return(m
, NULL
);
144 static int notify_test2(sd_bus_message
*m
, void *userdata
, sd_bus_error
*error
) {
147 assert_se(sd_bus_emit_properties_changed_strv(sd_bus_message_get_bus(m
), m
->path
, "org.freedesktop.systemd.ValueTest", NULL
) >= 0);
149 r
= sd_bus_reply_method_return(m
, NULL
);
155 static int emit_interfaces_added(sd_bus_message
*m
, void *userdata
, sd_bus_error
*error
) {
158 assert_se(sd_bus_emit_interfaces_added(sd_bus_message_get_bus(m
), "/value/a/x", "org.freedesktop.systemd.ValueTest", NULL
) >= 0);
160 r
= sd_bus_reply_method_return(m
, NULL
);
166 static int emit_interfaces_removed(sd_bus_message
*m
, void *userdata
, sd_bus_error
*error
) {
169 assert_se(sd_bus_emit_interfaces_removed(sd_bus_message_get_bus(m
), "/value/a/x", "org.freedesktop.systemd.ValueTest", NULL
) >= 0);
171 r
= sd_bus_reply_method_return(m
, NULL
);
177 static int emit_object_added(sd_bus_message
*m
, void *userdata
, sd_bus_error
*error
) {
180 assert_se(sd_bus_emit_object_added(sd_bus_message_get_bus(m
), "/value/a/x") >= 0);
182 r
= sd_bus_reply_method_return(m
, NULL
);
188 static int emit_object_removed(sd_bus_message
*m
, void *userdata
, sd_bus_error
*error
) {
191 assert_se(sd_bus_emit_object_removed(sd_bus_message_get_bus(m
), "/value/a/x") >= 0);
193 r
= sd_bus_reply_method_return(m
, NULL
);
199 static const sd_bus_vtable vtable
[] = {
200 SD_BUS_VTABLE_START(0),
201 SD_BUS_METHOD("AlterSomething", "s", "s", something_handler
, 0),
202 SD_BUS_METHOD("Exit", "", "", exit_handler
, 0),
203 SD_BUS_WRITABLE_PROPERTY("Something", "s", get_handler
, set_handler
, 0, 0),
204 SD_BUS_WRITABLE_PROPERTY("AutomaticStringProperty", "s", NULL
, NULL
, offsetof(struct context
, automatic_string_property
), 0),
205 SD_BUS_WRITABLE_PROPERTY("AutomaticIntegerProperty", "u", NULL
, NULL
, offsetof(struct context
, automatic_integer_property
), 0),
206 SD_BUS_METHOD("NoOperation", NULL
, NULL
, NULL
, 0),
207 SD_BUS_METHOD("EmitInterfacesAdded", NULL
, NULL
, emit_interfaces_added
, 0),
208 SD_BUS_METHOD("EmitInterfacesRemoved", NULL
, NULL
, emit_interfaces_removed
, 0),
209 SD_BUS_METHOD("EmitObjectAdded", NULL
, NULL
, emit_object_added
, 0),
210 SD_BUS_METHOD("EmitObjectRemoved", NULL
, NULL
, emit_object_removed
, 0),
214 static const sd_bus_vtable vtable2
[] = {
215 SD_BUS_VTABLE_START(0),
216 SD_BUS_METHOD("NotifyTest", "", "", notify_test
, 0),
217 SD_BUS_METHOD("NotifyTest2", "", "", notify_test2
, 0),
218 SD_BUS_PROPERTY("Value", "s", value_handler
, 10, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE
),
219 SD_BUS_PROPERTY("Value2", "s", value_handler
, 10, SD_BUS_VTABLE_PROPERTY_EMITS_INVALIDATION
),
220 SD_BUS_PROPERTY("Value3", "s", value_handler
, 10, SD_BUS_VTABLE_PROPERTY_CONST
),
221 SD_BUS_PROPERTY("Value4", "s", value_handler
, 10, 0),
222 SD_BUS_PROPERTY("AnExplicitProperty", "s", NULL
, offsetof(struct context
, something
), SD_BUS_VTABLE_PROPERTY_EXPLICIT
|SD_BUS_VTABLE_PROPERTY_EMITS_INVALIDATION
),
226 static int enumerator_callback(sd_bus
*bus
, const char *path
, void *userdata
, char ***nodes
, sd_bus_error
*error
) {
228 if (object_path_startswith("/value", path
))
229 assert_se(*nodes
= strv_new("/value/a", "/value/b", "/value/c", NULL
));
234 static int enumerator2_callback(sd_bus
*bus
, const char *path
, void *userdata
, char ***nodes
, sd_bus_error
*error
) {
236 if (object_path_startswith("/value/a", path
))
237 assert_se(*nodes
= strv_new("/value/a/x", "/value/a/y", "/value/a/z", NULL
));
242 static void *server(void *p
) {
243 struct context
*c
= p
;
250 assert_se(sd_id128_randomize(&id
) >= 0);
252 assert_se(sd_bus_new(&bus
) >= 0);
253 assert_se(sd_bus_set_fd(bus
, c
->fds
[0], c
->fds
[0]) >= 0);
254 assert_se(sd_bus_set_server(bus
, 1, id
) >= 0);
256 assert_se(sd_bus_add_object_vtable(bus
, NULL
, "/foo", "org.freedesktop.systemd.test", vtable
, c
) >= 0);
257 assert_se(sd_bus_add_object_vtable(bus
, NULL
, "/foo", "org.freedesktop.systemd.test2", vtable
, c
) >= 0);
258 assert_se(sd_bus_add_fallback_vtable(bus
, NULL
, "/value", "org.freedesktop.systemd.ValueTest", vtable2
, NULL
, UINT_TO_PTR(20)) >= 0);
259 assert_se(sd_bus_add_node_enumerator(bus
, NULL
, "/value", enumerator_callback
, NULL
) >= 0);
260 assert_se(sd_bus_add_node_enumerator(bus
, NULL
, "/value/a", enumerator2_callback
, NULL
) >= 0);
261 assert_se(sd_bus_add_object_manager(bus
, NULL
, "/value") >= 0);
262 assert_se(sd_bus_add_object_manager(bus
, NULL
, "/value/a") >= 0);
264 assert_se(sd_bus_start(bus
) >= 0);
266 log_error("Entering event loop on server");
271 r
= sd_bus_process(bus
, NULL
);
273 log_error_errno(r
, "Failed to process requests: %m");
278 r
= sd_bus_wait(bus
, (uint64_t) -1);
280 log_error_errno(r
, "Failed to wait: %m");
296 return INT_TO_PTR(r
);
299 static int client(struct context
*c
) {
300 _cleanup_bus_message_unref_ sd_bus_message
*reply
= NULL
;
301 _cleanup_bus_unref_ sd_bus
*bus
= NULL
;
302 _cleanup_bus_error_free_ sd_bus_error error
= SD_BUS_ERROR_NULL
;
306 assert_se(sd_bus_new(&bus
) >= 0);
307 assert_se(sd_bus_set_fd(bus
, c
->fds
[1], c
->fds
[1]) >= 0);
308 assert_se(sd_bus_start(bus
) >= 0);
310 r
= sd_bus_call_method(bus
, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.systemd.test", "NoOperation", &error
, NULL
, NULL
);
313 r
= sd_bus_call_method(bus
, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.systemd.test", "AlterSomething", &error
, &reply
, "s", "hallo");
316 r
= sd_bus_message_read(reply
, "s", &s
);
318 assert_se(streq(s
, "<<<hallo>>>"));
320 sd_bus_message_unref(reply
);
323 r
= sd_bus_call_method(bus
, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.systemd.test", "Doesntexist", &error
, &reply
, "");
325 assert_se(sd_bus_error_has_name(&error
, SD_BUS_ERROR_UNKNOWN_METHOD
));
327 sd_bus_error_free(&error
);
329 r
= sd_bus_call_method(bus
, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.systemd.test", "AlterSomething", &error
, &reply
, "as", 1, "hallo");
331 assert_se(sd_bus_error_has_name(&error
, SD_BUS_ERROR_INVALID_ARGS
));
333 sd_bus_error_free(&error
);
335 r
= sd_bus_get_property(bus
, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.systemd.test", "Something", &error
, &reply
, "s");
338 r
= sd_bus_message_read(reply
, "s", &s
);
340 assert_se(streq(s
, "<<<hallo>>>"));
342 sd_bus_message_unref(reply
);
345 r
= sd_bus_set_property(bus
, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.systemd.test", "Something", &error
, "s", "test");
348 r
= sd_bus_get_property(bus
, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.systemd.test", "Something", &error
, &reply
, "s");
351 r
= sd_bus_message_read(reply
, "s", &s
);
353 assert_se(streq(s
, "test"));
355 sd_bus_message_unref(reply
);
358 r
= sd_bus_set_property(bus
, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.systemd.test", "AutomaticIntegerProperty", &error
, "u", 815);
361 assert_se(c
->automatic_integer_property
== 815);
363 r
= sd_bus_set_property(bus
, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.systemd.test", "AutomaticStringProperty", &error
, "s", "Du Dödel, Du!");
366 assert_se(streq(c
->automatic_string_property
, "Du Dödel, Du!"));
368 r
= sd_bus_call_method(bus
, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.DBus.Introspectable", "Introspect", &error
, &reply
, "");
371 r
= sd_bus_message_read(reply
, "s", &s
);
375 sd_bus_message_unref(reply
);
378 r
= sd_bus_get_property(bus
, "org.freedesktop.systemd.test", "/value/xuzz", "org.freedesktop.systemd.ValueTest", "Value", &error
, &reply
, "s");
381 r
= sd_bus_message_read(reply
, "s", &s
);
383 log_info("read %s", s
);
385 sd_bus_message_unref(reply
);
388 r
= sd_bus_call_method(bus
, "org.freedesktop.systemd.test", "/", "org.freedesktop.DBus.Introspectable", "Introspect", &error
, &reply
, "");
391 r
= sd_bus_message_read(reply
, "s", &s
);
395 sd_bus_message_unref(reply
);
398 r
= sd_bus_call_method(bus
, "org.freedesktop.systemd.test", "/value", "org.freedesktop.DBus.Introspectable", "Introspect", &error
, &reply
, "");
401 r
= sd_bus_message_read(reply
, "s", &s
);
405 sd_bus_message_unref(reply
);
408 r
= sd_bus_call_method(bus
, "org.freedesktop.systemd.test", "/value/a", "org.freedesktop.DBus.Introspectable", "Introspect", &error
, &reply
, "");
411 r
= sd_bus_message_read(reply
, "s", &s
);
415 sd_bus_message_unref(reply
);
418 r
= sd_bus_call_method(bus
, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.DBus.Properties", "GetAll", &error
, &reply
, "s", "");
421 bus_message_dump(reply
, stdout
, BUS_MESSAGE_DUMP_WITH_HEADER
);
423 sd_bus_message_unref(reply
);
426 r
= sd_bus_call_method(bus
, "org.freedesktop.systemd.test", "/value/a", "org.freedesktop.DBus.Properties", "GetAll", &error
, &reply
, "s", "org.freedesktop.systemd.ValueTest2");
428 assert_se(sd_bus_error_has_name(&error
, SD_BUS_ERROR_UNKNOWN_INTERFACE
));
429 sd_bus_error_free(&error
);
431 r
= sd_bus_call_method(bus
, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.DBus.ObjectManager", "GetManagedObjects", &error
, &reply
, "");
433 assert_se(sd_bus_error_has_name(&error
, SD_BUS_ERROR_UNKNOWN_METHOD
));
434 sd_bus_error_free(&error
);
436 r
= sd_bus_call_method(bus
, "org.freedesktop.systemd.test", "/value", "org.freedesktop.DBus.ObjectManager", "GetManagedObjects", &error
, &reply
, "");
439 bus_message_dump(reply
, stdout
, BUS_MESSAGE_DUMP_WITH_HEADER
);
441 sd_bus_message_unref(reply
);
444 r
= sd_bus_call_method(bus
, "org.freedesktop.systemd.test", "/value/a", "org.freedesktop.systemd.ValueTest", "NotifyTest", &error
, NULL
, "");
447 r
= sd_bus_process(bus
, &reply
);
450 assert_se(sd_bus_message_is_signal(reply
, "org.freedesktop.DBus.Properties", "PropertiesChanged"));
451 bus_message_dump(reply
, stdout
, BUS_MESSAGE_DUMP_WITH_HEADER
);
453 sd_bus_message_unref(reply
);
456 r
= sd_bus_call_method(bus
, "org.freedesktop.systemd.test", "/value/a", "org.freedesktop.systemd.ValueTest", "NotifyTest2", &error
, NULL
, "");
459 r
= sd_bus_process(bus
, &reply
);
462 assert_se(sd_bus_message_is_signal(reply
, "org.freedesktop.DBus.Properties", "PropertiesChanged"));
463 bus_message_dump(reply
, stdout
, BUS_MESSAGE_DUMP_WITH_HEADER
);
465 sd_bus_message_unref(reply
);
468 r
= sd_bus_call_method(bus
, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.systemd.test", "EmitInterfacesAdded", &error
, NULL
, "");
471 r
= sd_bus_process(bus
, &reply
);
474 assert_se(sd_bus_message_is_signal(reply
, "org.freedesktop.DBus.ObjectManager", "InterfacesAdded"));
475 bus_message_dump(reply
, stdout
, BUS_MESSAGE_DUMP_WITH_HEADER
);
477 sd_bus_message_unref(reply
);
480 r
= sd_bus_call_method(bus
, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.systemd.test", "EmitInterfacesRemoved", &error
, NULL
, "");
483 r
= sd_bus_process(bus
, &reply
);
486 assert_se(sd_bus_message_is_signal(reply
, "org.freedesktop.DBus.ObjectManager", "InterfacesRemoved"));
487 bus_message_dump(reply
, stdout
, BUS_MESSAGE_DUMP_WITH_HEADER
);
489 sd_bus_message_unref(reply
);
492 r
= sd_bus_call_method(bus
, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.systemd.test", "EmitObjectAdded", &error
, NULL
, "");
495 r
= sd_bus_process(bus
, &reply
);
498 assert_se(sd_bus_message_is_signal(reply
, "org.freedesktop.DBus.ObjectManager", "InterfacesAdded"));
499 bus_message_dump(reply
, stdout
, BUS_MESSAGE_DUMP_WITH_HEADER
);
501 sd_bus_message_unref(reply
);
504 r
= sd_bus_call_method(bus
, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.systemd.test", "EmitObjectRemoved", &error
, NULL
, "");
507 r
= sd_bus_process(bus
, &reply
);
510 assert_se(sd_bus_message_is_signal(reply
, "org.freedesktop.DBus.ObjectManager", "InterfacesRemoved"));
511 bus_message_dump(reply
, stdout
, BUS_MESSAGE_DUMP_WITH_HEADER
);
513 sd_bus_message_unref(reply
);
516 r
= sd_bus_call_method(bus
, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.systemd.test", "Exit", &error
, NULL
, "");
524 int main(int argc
, char *argv
[]) {
525 struct context c
= {};
532 c
.automatic_integer_property
= 4711;
533 assert_se(c
.automatic_string_property
= strdup("dudeldu"));
535 assert_se(socketpair(AF_UNIX
, SOCK_STREAM
, 0, c
.fds
) >= 0);
537 r
= pthread_create(&s
, NULL
, server
, &c
);
543 q
= pthread_join(s
, &p
);
550 if (PTR_TO_INT(p
) < 0)
551 return PTR_TO_INT(p
);
554 free(c
.automatic_string_property
);