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