]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/libsystemd/sd-bus/test-bus-objects.c
Merge pull request #1036 from poettering/sd-bus-arg0has
[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 "log.h"
26 #include "util.h"
27 #include "macro.h"
28 #include "strv.h"
29
30 #include "sd-bus.h"
31 #include "bus-internal.h"
32 #include "bus-message.h"
33 #include "bus-dump.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_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;
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 }