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