]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/libsystemd/sd-bus/test-bus-objects.c
f11cafd8881f891ed92ce9da459dea9a5d68742a
[thirdparty/systemd.git] / src / libsystemd / sd-bus / test-bus-objects.c
1 /***
2 This file is part of systemd.
3
4 Copyright 2013 Lennart Poettering
5
6 systemd is free software; you can redistribute it and/or modify it
7 under the terms of the GNU Lesser General Public License as published by
8 the Free Software Foundation; either version 2.1 of the License, or
9 (at your option) any later version.
10
11 systemd is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 Lesser General Public License for more details.
15
16 You should have received a copy of the GNU Lesser General Public License
17 along with systemd; If not, see <http://www.gnu.org/licenses/>.
18 ***/
19
20 #include <pthread.h>
21 #include <stdlib.h>
22
23 #include "sd-bus.h"
24
25 #include "alloc-util.h"
26 #include "bus-dump.h"
27 #include "bus-internal.h"
28 #include "bus-message.h"
29 #include "bus-util.h"
30 #include "log.h"
31 #include "macro.h"
32 #include "strv.h"
33 #include "util.h"
34
35 struct context {
36 int fds[2];
37 bool quit;
38 char *something;
39 char *automatic_string_property;
40 uint32_t automatic_integer_property;
41 };
42
43 static int something_handler(sd_bus_message *m, void *userdata, sd_bus_error *error) {
44 struct context *c = userdata;
45 const char *s;
46 char *n = NULL;
47 int r;
48
49 r = sd_bus_message_read(m, "s", &s);
50 assert_se(r > 0);
51
52 n = strjoin("<<<", s, ">>>", NULL);
53 assert_se(n);
54
55 free(c->something);
56 c->something = n;
57
58 log_info("AlterSomething() called, got %s, returning %s", s, n);
59
60 /* This should fail, since the return type doesn't match */
61 assert_se(sd_bus_reply_method_return(m, "u", 4711) == -ENOMSG);
62
63 r = sd_bus_reply_method_return(m, "s", n);
64 assert_se(r >= 0);
65
66 return 1;
67 }
68
69 static int exit_handler(sd_bus_message *m, void *userdata, sd_bus_error *error) {
70 struct context *c = userdata;
71 int r;
72
73 c->quit = true;
74
75 log_info("Exit called");
76
77 r = sd_bus_reply_method_return(m, "");
78 assert_se(r >= 0);
79
80 return 1;
81 }
82
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;
85 int r;
86
87 log_info("property get for %s called, returning \"%s\".", property, c->something);
88
89 r = sd_bus_message_append(reply, "s", c->something);
90 assert_se(r >= 0);
91
92 return 1;
93 }
94
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;
97 const char *s;
98 char *n;
99 int r;
100
101 log_info("property set for %s called", property);
102
103 r = sd_bus_message_read(value, "s", &s);
104 assert_se(r >= 0);
105
106 n = strdup(s);
107 assert_se(n);
108
109 free(c->something);
110 c->something = n;
111
112 return 1;
113 }
114
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;
117 const char *x;
118 int r;
119
120 assert_se(asprintf(&s, "object %p, path %s", userdata, path) >= 0);
121 r = sd_bus_message_append(reply, "s", s);
122 assert_se(r >= 0);
123
124 assert_se(x = startswith(path, "/value/"));
125
126 assert_se(PTR_TO_UINT(userdata) == 30);
127
128 return 1;
129 }
130
131 static int notify_test(sd_bus_message *m, void *userdata, sd_bus_error *error) {
132 int r;
133
134 assert_se(sd_bus_emit_properties_changed(sd_bus_message_get_bus(m), m->path, "org.freedesktop.systemd.ValueTest", "Value", NULL) >= 0);
135
136 r = sd_bus_reply_method_return(m, NULL);
137 assert_se(r >= 0);
138
139 return 1;
140 }
141
142 static int notify_test2(sd_bus_message *m, void *userdata, sd_bus_error *error) {
143 int r;
144
145 assert_se(sd_bus_emit_properties_changed_strv(sd_bus_message_get_bus(m), m->path, "org.freedesktop.systemd.ValueTest", NULL) >= 0);
146
147 r = sd_bus_reply_method_return(m, NULL);
148 assert_se(r >= 0);
149
150 return 1;
151 }
152
153 static int emit_interfaces_added(sd_bus_message *m, void *userdata, sd_bus_error *error) {
154 int r;
155
156 assert_se(sd_bus_emit_interfaces_added(sd_bus_message_get_bus(m), "/value/a/x", "org.freedesktop.systemd.ValueTest", NULL) >= 0);
157
158 r = sd_bus_reply_method_return(m, NULL);
159 assert_se(r >= 0);
160
161 return 1;
162 }
163
164 static int emit_interfaces_removed(sd_bus_message *m, void *userdata, sd_bus_error *error) {
165 int r;
166
167 assert_se(sd_bus_emit_interfaces_removed(sd_bus_message_get_bus(m), "/value/a/x", "org.freedesktop.systemd.ValueTest", NULL) >= 0);
168
169 r = sd_bus_reply_method_return(m, NULL);
170 assert_se(r >= 0);
171
172 return 1;
173 }
174
175 static int emit_object_added(sd_bus_message *m, void *userdata, sd_bus_error *error) {
176 int r;
177
178 assert_se(sd_bus_emit_object_added(sd_bus_message_get_bus(m), "/value/a/x") >= 0);
179
180 r = sd_bus_reply_method_return(m, NULL);
181 assert_se(r >= 0);
182
183 return 1;
184 }
185
186 static int emit_object_removed(sd_bus_message *m, void *userdata, sd_bus_error *error) {
187 int r;
188
189 assert_se(sd_bus_emit_object_removed(sd_bus_message_get_bus(m), "/value/a/x") >= 0);
190
191 r = sd_bus_reply_method_return(m, NULL);
192 assert_se(r >= 0);
193
194 return 1;
195 }
196
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),
209 SD_BUS_VTABLE_END
210 };
211
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),
221 SD_BUS_VTABLE_END
222 };
223
224 static int enumerator_callback(sd_bus *bus, const char *path, void *userdata, char ***nodes, sd_bus_error *error) {
225
226 if (object_path_startswith("/value", path))
227 assert_se(*nodes = strv_new("/value/a", "/value/b", "/value/c", NULL));
228
229 return 1;
230 }
231
232 static int enumerator2_callback(sd_bus *bus, const char *path, void *userdata, char ***nodes, sd_bus_error *error) {
233
234 if (object_path_startswith("/value/a", path))
235 assert_se(*nodes = strv_new("/value/a/x", "/value/a/y", "/value/a/z", NULL));
236
237 return 1;
238 }
239
240 static void *server(void *p) {
241 struct context *c = p;
242 sd_bus *bus = NULL;
243 sd_id128_t id;
244 int r;
245
246 c->quit = false;
247
248 assert_se(sd_id128_randomize(&id) >= 0);
249
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);
253
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);
261
262 assert_se(sd_bus_start(bus) >= 0);
263
264 log_error("Entering event loop on server");
265
266 while (!c->quit) {
267 log_error("Loop!");
268
269 r = sd_bus_process(bus, NULL);
270 if (r < 0) {
271 log_error_errno(r, "Failed to process requests: %m");
272 goto fail;
273 }
274
275 if (r == 0) {
276 r = sd_bus_wait(bus, (uint64_t) -1);
277 if (r < 0) {
278 log_error_errno(r, "Failed to wait: %m");
279 goto fail;
280 }
281
282 continue;
283 }
284 }
285
286 r = 0;
287
288 fail:
289 if (bus) {
290 sd_bus_flush(bus);
291 sd_bus_unref(bus);
292 }
293
294 return INT_TO_PTR(r);
295 }
296
297 static int client(struct context *c) {
298 _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
299 _cleanup_(sd_bus_unrefp) sd_bus *bus = NULL;
300 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
301 const char *s;
302 int r;
303
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);
307
308 r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.systemd.test", "NoOperation", &error, NULL, NULL);
309 assert_se(r >= 0);
310
311 r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.systemd.test", "AlterSomething", &error, &reply, "s", "hallo");
312 assert_se(r >= 0);
313
314 r = sd_bus_message_read(reply, "s", &s);
315 assert_se(r >= 0);
316 assert_se(streq(s, "<<<hallo>>>"));
317
318 sd_bus_message_unref(reply);
319 reply = NULL;
320
321 r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.systemd.test", "Doesntexist", &error, &reply, "");
322 assert_se(r < 0);
323 assert_se(sd_bus_error_has_name(&error, SD_BUS_ERROR_UNKNOWN_METHOD));
324
325 sd_bus_error_free(&error);
326
327 r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.systemd.test", "AlterSomething", &error, &reply, "as", 1, "hallo");
328 assert_se(r < 0);
329 assert_se(sd_bus_error_has_name(&error, SD_BUS_ERROR_INVALID_ARGS));
330
331 sd_bus_error_free(&error);
332
333 r = sd_bus_get_property(bus, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.systemd.test", "Something", &error, &reply, "s");
334 assert_se(r >= 0);
335
336 r = sd_bus_message_read(reply, "s", &s);
337 assert_se(r >= 0);
338 assert_se(streq(s, "<<<hallo>>>"));
339
340 sd_bus_message_unref(reply);
341 reply = NULL;
342
343 r = sd_bus_set_property(bus, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.systemd.test", "Something", &error, "s", "test");
344 assert_se(r >= 0);
345
346 r = sd_bus_get_property(bus, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.systemd.test", "Something", &error, &reply, "s");
347 assert_se(r >= 0);
348
349 r = sd_bus_message_read(reply, "s", &s);
350 assert_se(r >= 0);
351 assert_se(streq(s, "test"));
352
353 sd_bus_message_unref(reply);
354 reply = NULL;
355
356 r = sd_bus_set_property(bus, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.systemd.test", "AutomaticIntegerProperty", &error, "u", 815);
357 assert_se(r >= 0);
358
359 assert_se(c->automatic_integer_property == 815);
360
361 r = sd_bus_set_property(bus, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.systemd.test", "AutomaticStringProperty", &error, "s", "Du Dödel, Du!");
362 assert_se(r >= 0);
363
364 assert_se(streq(c->automatic_string_property, "Du Dödel, Du!"));
365
366 r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.DBus.Introspectable", "Introspect", &error, &reply, "");
367 assert_se(r >= 0);
368
369 r = sd_bus_message_read(reply, "s", &s);
370 assert_se(r >= 0);
371 fputs(s, stdout);
372
373 sd_bus_message_unref(reply);
374 reply = NULL;
375
376 r = sd_bus_get_property(bus, "org.freedesktop.systemd.test", "/value/xuzz", "org.freedesktop.systemd.ValueTest", "Value", &error, &reply, "s");
377 assert_se(r >= 0);
378
379 r = sd_bus_message_read(reply, "s", &s);
380 assert_se(r >= 0);
381 log_info("read %s", s);
382
383 sd_bus_message_unref(reply);
384 reply = NULL;
385
386 r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/", "org.freedesktop.DBus.Introspectable", "Introspect", &error, &reply, "");
387 assert_se(r >= 0);
388
389 r = sd_bus_message_read(reply, "s", &s);
390 assert_se(r >= 0);
391 fputs(s, stdout);
392
393 sd_bus_message_unref(reply);
394 reply = NULL;
395
396 r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/value", "org.freedesktop.DBus.Introspectable", "Introspect", &error, &reply, "");
397 assert_se(r >= 0);
398
399 r = sd_bus_message_read(reply, "s", &s);
400 assert_se(r >= 0);
401 fputs(s, stdout);
402
403 sd_bus_message_unref(reply);
404 reply = NULL;
405
406 r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/value/a", "org.freedesktop.DBus.Introspectable", "Introspect", &error, &reply, "");
407 assert_se(r >= 0);
408
409 r = sd_bus_message_read(reply, "s", &s);
410 assert_se(r >= 0);
411 fputs(s, stdout);
412
413 sd_bus_message_unref(reply);
414 reply = NULL;
415
416 r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.DBus.Properties", "GetAll", &error, &reply, "s", "");
417 assert_se(r >= 0);
418
419 bus_message_dump(reply, stdout, BUS_MESSAGE_DUMP_WITH_HEADER);
420
421 sd_bus_message_unref(reply);
422 reply = NULL;
423
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");
425 assert_se(r < 0);
426 assert_se(sd_bus_error_has_name(&error, SD_BUS_ERROR_UNKNOWN_INTERFACE));
427 sd_bus_error_free(&error);
428
429 r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.DBus.ObjectManager", "GetManagedObjects", &error, &reply, "");
430 assert_se(r < 0);
431 assert_se(sd_bus_error_has_name(&error, SD_BUS_ERROR_UNKNOWN_METHOD));
432 sd_bus_error_free(&error);
433
434 r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/value", "org.freedesktop.DBus.ObjectManager", "GetManagedObjects", &error, &reply, "");
435 assert_se(r >= 0);
436
437 bus_message_dump(reply, stdout, BUS_MESSAGE_DUMP_WITH_HEADER);
438
439 sd_bus_message_unref(reply);
440 reply = NULL;
441
442 r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/value/a", "org.freedesktop.systemd.ValueTest", "NotifyTest", &error, NULL, "");
443 assert_se(r >= 0);
444
445 r = sd_bus_process(bus, &reply);
446 assert_se(r > 0);
447
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);
450
451 sd_bus_message_unref(reply);
452 reply = NULL;
453
454 r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/value/a", "org.freedesktop.systemd.ValueTest", "NotifyTest2", &error, NULL, "");
455 assert_se(r >= 0);
456
457 r = sd_bus_process(bus, &reply);
458 assert_se(r > 0);
459
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);
462
463 sd_bus_message_unref(reply);
464 reply = NULL;
465
466 r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.systemd.test", "EmitInterfacesAdded", &error, NULL, "");
467 assert_se(r >= 0);
468
469 r = sd_bus_process(bus, &reply);
470 assert_se(r > 0);
471
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);
474
475 sd_bus_message_unref(reply);
476 reply = NULL;
477
478 r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.systemd.test", "EmitInterfacesRemoved", &error, NULL, "");
479 assert_se(r >= 0);
480
481 r = sd_bus_process(bus, &reply);
482 assert_se(r > 0);
483
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);
486
487 sd_bus_message_unref(reply);
488 reply = NULL;
489
490 r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.systemd.test", "EmitObjectAdded", &error, NULL, "");
491 assert_se(r >= 0);
492
493 r = sd_bus_process(bus, &reply);
494 assert_se(r > 0);
495
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);
498
499 sd_bus_message_unref(reply);
500 reply = NULL;
501
502 r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.systemd.test", "EmitObjectRemoved", &error, NULL, "");
503 assert_se(r >= 0);
504
505 r = sd_bus_process(bus, &reply);
506 assert_se(r > 0);
507
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);
510
511 sd_bus_message_unref(reply);
512 reply = NULL;
513
514 r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.systemd.test", "Exit", &error, NULL, "");
515 assert_se(r >= 0);
516
517 sd_bus_flush(bus);
518
519 return 0;
520 }
521
522 int main(int argc, char *argv[]) {
523 struct context c = {};
524 pthread_t s;
525 void *p;
526 int r, q;
527
528 zero(c);
529
530 c.automatic_integer_property = 4711;
531 assert_se(c.automatic_string_property = strdup("dudeldu"));
532
533 assert_se(socketpair(AF_UNIX, SOCK_STREAM, 0, c.fds) >= 0);
534
535 r = pthread_create(&s, NULL, server, &c);
536 if (r != 0)
537 return -r;
538
539 r = client(&c);
540
541 q = pthread_join(s, &p);
542 if (q != 0)
543 return -q;
544
545 if (r < 0)
546 return r;
547
548 if (PTR_TO_INT(p) < 0)
549 return PTR_TO_INT(p);
550
551 free(c.something);
552 free(c.automatic_string_property);
553
554 return EXIT_SUCCESS;
555 }