]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/libsystemd/sd-bus/test-bus-objects.c
Merge pull request #548 from vcaputo/fix_path_state_debug_msg
[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-util.h"
34 #include "bus-dump.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 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(startswith(path, "/value/") != NULL || strcmp(path, "/value") == 0);
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), m->path, "org.freedesktop.systemd.test", 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), m->path, "org.freedesktop.systemd.test", 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), m->path) >= 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), m->path) >= 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_VTABLE_END
221 };
222
223 static int enumerator_callback(sd_bus *bus, const char *path, void *userdata, char ***nodes, sd_bus_error *error) {
224
225 if (object_path_startswith("/value", path))
226 assert_se(*nodes = strv_new("/value/a", "/value/b", "/value/c", NULL));
227
228 return 1;
229 }
230
231 static void *server(void *p) {
232 struct context *c = p;
233 sd_bus *bus = NULL;
234 sd_id128_t id;
235 int r;
236
237 c->quit = false;
238
239 assert_se(sd_id128_randomize(&id) >= 0);
240
241 assert_se(sd_bus_new(&bus) >= 0);
242 assert_se(sd_bus_set_fd(bus, c->fds[0], c->fds[0]) >= 0);
243 assert_se(sd_bus_set_server(bus, 1, id) >= 0);
244
245 assert_se(sd_bus_add_object_vtable(bus, NULL, "/foo", "org.freedesktop.systemd.test", vtable, c) >= 0);
246 assert_se(sd_bus_add_object_vtable(bus, NULL, "/foo", "org.freedesktop.systemd.test2", vtable, c) >= 0);
247 assert_se(sd_bus_add_fallback_vtable(bus, NULL, "/value", "org.freedesktop.systemd.ValueTest", vtable2, NULL, UINT_TO_PTR(20)) >= 0);
248 assert_se(sd_bus_add_node_enumerator(bus, NULL, "/value", enumerator_callback, NULL) >= 0);
249 assert_se(sd_bus_add_object_manager(bus, NULL, "/value") >= 0);
250
251 assert_se(sd_bus_start(bus) >= 0);
252
253 log_error("Entering event loop on server");
254
255 while (!c->quit) {
256 log_error("Loop!");
257
258 r = sd_bus_process(bus, NULL);
259 if (r < 0) {
260 log_error_errno(r, "Failed to process requests: %m");
261 goto fail;
262 }
263
264 if (r == 0) {
265 r = sd_bus_wait(bus, (uint64_t) -1);
266 if (r < 0) {
267 log_error_errno(r, "Failed to wait: %m");
268 goto fail;
269 }
270
271 continue;
272 }
273 }
274
275 r = 0;
276
277 fail:
278 if (bus) {
279 sd_bus_flush(bus);
280 sd_bus_unref(bus);
281 }
282
283 return INT_TO_PTR(r);
284 }
285
286 static int client(struct context *c) {
287 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
288 _cleanup_bus_unref_ sd_bus *bus = NULL;
289 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
290 const char *s;
291 int r;
292
293 assert_se(sd_bus_new(&bus) >= 0);
294 assert_se(sd_bus_set_fd(bus, c->fds[1], c->fds[1]) >= 0);
295 assert_se(sd_bus_start(bus) >= 0);
296
297 r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.systemd.test", "NoOperation", &error, NULL, NULL);
298 assert_se(r >= 0);
299
300 r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.systemd.test", "AlterSomething", &error, &reply, "s", "hallo");
301 assert_se(r >= 0);
302
303 r = sd_bus_message_read(reply, "s", &s);
304 assert_se(r >= 0);
305 assert_se(streq(s, "<<<hallo>>>"));
306
307 sd_bus_message_unref(reply);
308 reply = NULL;
309
310 r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.systemd.test", "Doesntexist", &error, &reply, "");
311 assert_se(r < 0);
312 assert_se(sd_bus_error_has_name(&error, SD_BUS_ERROR_UNKNOWN_METHOD));
313
314 sd_bus_error_free(&error);
315
316 r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.systemd.test", "AlterSomething", &error, &reply, "as", 1, "hallo");
317 assert_se(r < 0);
318 assert_se(sd_bus_error_has_name(&error, SD_BUS_ERROR_INVALID_ARGS));
319
320 sd_bus_error_free(&error);
321
322 r = sd_bus_get_property(bus, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.systemd.test", "Something", &error, &reply, "s");
323 assert_se(r >= 0);
324
325 r = sd_bus_message_read(reply, "s", &s);
326 assert_se(r >= 0);
327 assert_se(streq(s, "<<<hallo>>>"));
328
329 sd_bus_message_unref(reply);
330 reply = NULL;
331
332 r = sd_bus_set_property(bus, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.systemd.test", "Something", &error, "s", "test");
333 assert_se(r >= 0);
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, "test"));
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", "AutomaticIntegerProperty", &error, "u", 815);
346 assert_se(r >= 0);
347
348 assert_se(c->automatic_integer_property == 815);
349
350 r = sd_bus_set_property(bus, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.systemd.test", "AutomaticStringProperty", &error, "s", "Du Dödel, Du!");
351 assert_se(r >= 0);
352
353 assert_se(streq(c->automatic_string_property, "Du Dödel, Du!"));
354
355 r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.DBus.Introspectable", "Introspect", &error, &reply, "");
356 assert_se(r >= 0);
357
358 r = sd_bus_message_read(reply, "s", &s);
359 assert_se(r >= 0);
360 fputs(s, stdout);
361
362 sd_bus_message_unref(reply);
363 reply = NULL;
364
365 r = sd_bus_get_property(bus, "org.freedesktop.systemd.test", "/value/xuzz", "org.freedesktop.systemd.ValueTest", "Value", &error, &reply, "s");
366 assert_se(r >= 0);
367
368 r = sd_bus_message_read(reply, "s", &s);
369 assert_se(r >= 0);
370 log_info("read %s", s);
371
372 sd_bus_message_unref(reply);
373 reply = NULL;
374
375 r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/", "org.freedesktop.DBus.Introspectable", "Introspect", &error, &reply, "");
376 assert_se(r >= 0);
377
378 r = sd_bus_message_read(reply, "s", &s);
379 assert_se(r >= 0);
380 fputs(s, stdout);
381
382 sd_bus_message_unref(reply);
383 reply = NULL;
384
385 r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/value", "org.freedesktop.DBus.Introspectable", "Introspect", &error, &reply, "");
386 assert_se(r >= 0);
387
388 r = sd_bus_message_read(reply, "s", &s);
389 assert_se(r >= 0);
390 fputs(s, stdout);
391
392 sd_bus_message_unref(reply);
393 reply = NULL;
394
395 r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/value/a", "org.freedesktop.DBus.Introspectable", "Introspect", &error, &reply, "");
396 assert_se(r >= 0);
397
398 r = sd_bus_message_read(reply, "s", &s);
399 assert_se(r >= 0);
400 fputs(s, stdout);
401
402 sd_bus_message_unref(reply);
403 reply = NULL;
404
405 r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.DBus.Properties", "GetAll", &error, &reply, "s", "");
406 assert_se(r >= 0);
407
408 bus_message_dump(reply, stdout, BUS_MESSAGE_DUMP_WITH_HEADER);
409
410 sd_bus_message_unref(reply);
411 reply = NULL;
412
413 r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/value/a", "org.freedesktop.DBus.Properties", "GetAll", &error, &reply, "s", "org.freedesktop.systemd.ValueTest2");
414 assert_se(r < 0);
415 assert_se(sd_bus_error_has_name(&error, SD_BUS_ERROR_UNKNOWN_INTERFACE));
416 sd_bus_error_free(&error);
417
418 r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.DBus.ObjectManager", "GetManagedObjects", &error, &reply, "");
419 assert_se(r < 0);
420 assert_se(sd_bus_error_has_name(&error, SD_BUS_ERROR_UNKNOWN_METHOD));
421 sd_bus_error_free(&error);
422
423 r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/value", "org.freedesktop.DBus.ObjectManager", "GetManagedObjects", &error, &reply, "");
424 assert_se(r >= 0);
425
426 bus_message_dump(reply, stdout, BUS_MESSAGE_DUMP_WITH_HEADER);
427
428 sd_bus_message_unref(reply);
429 reply = NULL;
430
431 r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/value/a", "org.freedesktop.systemd.ValueTest", "NotifyTest", &error, NULL, "");
432 assert_se(r >= 0);
433
434 r = sd_bus_process(bus, &reply);
435 assert_se(r > 0);
436
437 assert_se(sd_bus_message_is_signal(reply, "org.freedesktop.DBus.Properties", "PropertiesChanged"));
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", "NotifyTest2", &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", "/foo", "org.freedesktop.systemd.test", "EmitInterfacesAdded", &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.ObjectManager", "InterfacesAdded"));
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", "EmitInterfacesRemoved", &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", "InterfacesRemoved"));
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", "EmitObjectAdded", &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", "InterfacesAdded"));
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", "EmitObjectRemoved", &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", "InterfacesRemoved"));
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", "Exit", &error, NULL, "");
504 assert_se(r >= 0);
505
506 sd_bus_flush(bus);
507
508 return 0;
509 }
510
511 int main(int argc, char *argv[]) {
512 struct context c = {};
513 pthread_t s;
514 void *p;
515 int r, q;
516
517 zero(c);
518
519 c.automatic_integer_property = 4711;
520 assert_se(c.automatic_string_property = strdup("dudeldu"));
521
522 assert_se(socketpair(AF_UNIX, SOCK_STREAM, 0, c.fds) >= 0);
523
524 r = pthread_create(&s, NULL, server, &c);
525 if (r != 0)
526 return -r;
527
528 r = client(&c);
529
530 q = pthread_join(s, &p);
531 if (q != 0)
532 return -q;
533
534 if (r < 0)
535 return r;
536
537 if (PTR_TO_INT(p) < 0)
538 return PTR_TO_INT(p);
539
540 free(c.something);
541 free(c.automatic_string_property);
542
543 return EXIT_SUCCESS;
544 }