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