]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/libsystemd-bus/test-bus-objects.c
timedated: use libsystemd-bus instead of libdbus for bus communication
[thirdparty/systemd.git] / src / libsystemd-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
38 struct context {
39 int fds[2];
40 bool quit;
41 char *something;
42 char *automatic_string_property;
43 uint32_t automatic_integer_property;
44 };
45
46 static int something_handler(sd_bus *bus, sd_bus_message *m, void *userdata) {
47 struct context *c = userdata;
48 const char *s;
49 char *n = NULL;
50 int r;
51
52 r = sd_bus_message_read(m, "s", &s);
53 assert_se(r > 0);
54
55 n = strjoin("<<<", s, ">>>", NULL);
56 assert_se(n);
57
58 free(c->something);
59 c->something = n;
60
61 log_info("AlterSomething() called, got %s, returning %s", s, n);
62
63 r = sd_bus_reply_method_return(bus, m, "s", n);
64 assert_se(r >= 0);
65
66 return 1;
67 }
68
69 static int exit_handler(sd_bus *bus, sd_bus_message *m, void *userdata) {
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(bus, 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, sd_bus_error *error, void *userdata) {
84 struct context *c = userdata;
85 int r;
86
87 log_info("property get for %s called", property);
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, sd_bus_error *error, void *userdata) {
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, sd_bus_error *error, void *userdata) {
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 *bus, sd_bus_message *m, void *userdata) {
132 int r;
133
134 assert_se(sd_bus_emit_properties_changed(bus, m->path, "org.freedesktop.systemd.ValueTest", "Value", NULL) >= 0);
135
136 r = sd_bus_reply_method_return(bus, m, NULL);
137 assert_se(r >= 0);
138
139 return 1;
140 }
141
142 static int emit_interfaces_added(sd_bus *bus, sd_bus_message *m, void *userdata) {
143 int r;
144
145 assert_se(sd_bus_emit_interfaces_added(bus, m->path, "org.freedesktop.systemd.test", NULL) >= 0);
146
147 r = sd_bus_reply_method_return(bus, m, NULL);
148 assert_se(r >= 0);
149
150 return 1;
151 }
152
153 static int emit_interfaces_removed(sd_bus *bus, sd_bus_message *m, void *userdata) {
154 int r;
155
156 assert_se(sd_bus_emit_interfaces_removed(bus, m->path, "org.freedesktop.systemd.test", NULL) >= 0);
157
158 r = sd_bus_reply_method_return(bus, m, NULL);
159 assert_se(r >= 0);
160
161 return 1;
162 }
163
164 static const sd_bus_vtable vtable[] = {
165 SD_BUS_VTABLE_START(0),
166 SD_BUS_METHOD("AlterSomething", "s", "s", something_handler, 0),
167 SD_BUS_METHOD("Exit", "", "", exit_handler, 0),
168 SD_BUS_WRITABLE_PROPERTY("Something", "s", get_handler, set_handler, 0, 0),
169 SD_BUS_WRITABLE_PROPERTY("AutomaticStringProperty", "s", NULL, NULL, offsetof(struct context, automatic_string_property), 0),
170 SD_BUS_WRITABLE_PROPERTY("AutomaticIntegerProperty", "u", NULL, NULL, offsetof(struct context, automatic_integer_property), 0),
171 SD_BUS_METHOD("NoOperation", NULL, NULL, NULL, 0),
172 SD_BUS_METHOD("EmitInterfacesAdded", NULL, NULL, emit_interfaces_added, 0),
173 SD_BUS_METHOD("EmitInterfacesRemoved", NULL, NULL, emit_interfaces_removed, 0),
174 SD_BUS_VTABLE_END
175 };
176
177 static const sd_bus_vtable vtable2[] = {
178 SD_BUS_VTABLE_START(0),
179 SD_BUS_METHOD("NotifyTest", "", "", notify_test, 0),
180 SD_BUS_PROPERTY("Value", "s", value_handler, 10, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
181 SD_BUS_VTABLE_END
182 };
183
184 static int enumerator_callback(sd_bus *b, const char *path, char ***nodes, void *userdata) {
185
186 if (object_path_startswith("/value", path))
187 assert_se(*nodes = strv_new("/value/a", "/value/b", "/value/c", NULL));
188
189 return 1;
190 }
191
192 static void *server(void *p) {
193 struct context *c = p;
194 sd_bus *bus = NULL;
195 sd_id128_t id;
196 int r;
197
198 c->quit = false;
199
200 assert_se(sd_id128_randomize(&id) >= 0);
201
202 assert_se(sd_bus_new(&bus) >= 0);
203 assert_se(sd_bus_set_fd(bus, c->fds[0], c->fds[0]) >= 0);
204 assert_se(sd_bus_set_server(bus, 1, id) >= 0);
205
206 assert_se(sd_bus_add_object_vtable(bus, "/foo", "org.freedesktop.systemd.test", vtable, c) >= 0);
207 assert_se(sd_bus_add_object_vtable(bus, "/foo", "org.freedesktop.systemd.test2", vtable, c) >= 0);
208 assert_se(sd_bus_add_fallback_vtable(bus, "/value", "org.freedesktop.systemd.ValueTest", vtable2, NULL, UINT_TO_PTR(20)) >= 0);
209 assert_se(sd_bus_add_node_enumerator(bus, "/value", enumerator_callback, NULL) >= 0);
210 assert_se(sd_bus_add_object_manager(bus, "/value") >= 0);
211
212 assert_se(sd_bus_start(bus) >= 0);
213
214 log_error("Entering event loop on server");
215
216 while (!c->quit) {
217 log_error("Loop!");
218
219 r = sd_bus_process(bus, NULL);
220 if (r < 0) {
221 log_error("Failed to process requests: %s", strerror(-r));
222 goto fail;
223 }
224
225 if (r == 0) {
226 r = sd_bus_wait(bus, (uint64_t) -1);
227 if (r < 0) {
228 log_error("Failed to wait: %s", strerror(-r));
229 goto fail;
230 }
231
232 continue;
233 }
234 }
235
236 r = 0;
237
238 fail:
239 if (bus) {
240 sd_bus_flush(bus);
241 sd_bus_unref(bus);
242 }
243
244 return INT_TO_PTR(r);
245 }
246
247 static int client(struct context *c) {
248 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
249 _cleanup_bus_unref_ sd_bus *bus = NULL;
250 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
251 const char *s;
252 int r;
253
254 assert_se(sd_bus_new(&bus) >= 0);
255 assert_se(sd_bus_set_fd(bus, c->fds[1], c->fds[1]) >= 0);
256 assert_se(sd_bus_start(bus) >= 0);
257
258 r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.systemd.test", "NoOperation", &error, NULL, NULL);
259 assert_se(r >= 0);
260
261 r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.systemd.test", "AlterSomething", &error, &reply, "s", "hallo");
262 assert_se(r >= 0);
263
264 r = sd_bus_message_read(reply, "s", &s);
265 assert_se(r >= 0);
266 assert_se(streq(s, "<<<hallo>>>"));
267
268 sd_bus_message_unref(reply);
269 reply = NULL;
270
271 r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.systemd.test", "Doesntexist", &error, &reply, "");
272 assert_se(r < 0);
273 assert_se(sd_bus_error_has_name(&error, SD_BUS_ERROR_UNKNOWN_METHOD));
274
275 sd_bus_error_free(&error);
276
277 r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.systemd.test", "AlterSomething", &error, &reply, "as", 1, "hallo");
278 assert_se(r < 0);
279 assert_se(sd_bus_error_has_name(&error, SD_BUS_ERROR_INVALID_ARGS));
280
281 sd_bus_error_free(&error);
282
283 r = sd_bus_get_property(bus, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.systemd.test", "Something", &error, &reply, "s");
284 assert_se(r >= 0);
285
286 r = sd_bus_message_read(reply, "s", &s);
287 assert_se(r >= 0);
288 assert_se(streq(s, "<<<hallo>>>"));
289
290 sd_bus_message_unref(reply);
291 reply = NULL;
292
293 r = sd_bus_set_property(bus, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.systemd.test", "Something", &error, "s", "test");
294 assert_se(r >= 0);
295
296 r = sd_bus_get_property(bus, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.systemd.test", "Something", &error, &reply, "s");
297 assert_se(r >= 0);
298
299 r = sd_bus_message_read(reply, "s", &s);
300 assert_se(r >= 0);
301 assert_se(streq(s, "test"));
302
303 sd_bus_message_unref(reply);
304 reply = NULL;
305
306 r = sd_bus_set_property(bus, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.systemd.test", "AutomaticIntegerProperty", &error, "u", 815);
307 assert_se(r >= 0);
308
309 assert_se(c->automatic_integer_property == 815);
310
311 r = sd_bus_set_property(bus, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.systemd.test", "AutomaticStringProperty", &error, "s", "Du Dödel, Du!");
312 assert_se(r >= 0);
313
314 assert_se(streq(c->automatic_string_property, "Du Dödel, Du!"));
315
316 r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.DBus.Introspectable", "Introspect", &error, &reply, "");
317 assert_se(r >= 0);
318
319 r = sd_bus_message_read(reply, "s", &s);
320 assert_se(r >= 0);
321 fputs(s, stdout);
322
323 sd_bus_message_unref(reply);
324 reply = NULL;
325
326 r = sd_bus_get_property(bus, "org.freedesktop.systemd.test", "/value/xuzz", "org.freedesktop.systemd.ValueTest", "Value", &error, &reply, "s");
327 assert_se(r >= 0);
328
329 r = sd_bus_message_read(reply, "s", &s);
330 assert_se(r >= 0);
331 log_info("read %s", s);
332
333 sd_bus_message_unref(reply);
334 reply = NULL;
335
336 r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/", "org.freedesktop.DBus.Introspectable", "Introspect", &error, &reply, "");
337 assert_se(r >= 0);
338
339 r = sd_bus_message_read(reply, "s", &s);
340 assert_se(r >= 0);
341 fputs(s, stdout);
342
343 sd_bus_message_unref(reply);
344 reply = NULL;
345
346 r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/value", "org.freedesktop.DBus.Introspectable", "Introspect", &error, &reply, "");
347 assert_se(r >= 0);
348
349 r = sd_bus_message_read(reply, "s", &s);
350 assert_se(r >= 0);
351 fputs(s, stdout);
352
353 sd_bus_message_unref(reply);
354 reply = NULL;
355
356 r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/value/a", "org.freedesktop.DBus.Introspectable", "Introspect", &error, &reply, "");
357 assert_se(r >= 0);
358
359 r = sd_bus_message_read(reply, "s", &s);
360 assert_se(r >= 0);
361 fputs(s, stdout);
362
363 sd_bus_message_unref(reply);
364 reply = NULL;
365
366 r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.DBus.Properties", "GetAll", &error, &reply, "s", "");
367 assert_se(r >= 0);
368
369 bus_message_dump(reply);
370
371 sd_bus_message_unref(reply);
372 reply = NULL;
373
374 r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/value/a", "org.freedesktop.DBus.Properties", "GetAll", &error, &reply, "s", "org.freedesktop.systemd.ValueTest2");
375 assert_se(r < 0);
376 assert_se(sd_bus_error_has_name(&error, SD_BUS_ERROR_UNKNOWN_INTERFACE));
377 sd_bus_error_free(&error);
378
379 r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.DBus.ObjectManager", "GetManagedObjects", &error, &reply, "");
380 assert_se(r < 0);
381 assert_se(sd_bus_error_has_name(&error, SD_BUS_ERROR_UNKNOWN_METHOD));
382 sd_bus_error_free(&error);
383
384 r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/value", "org.freedesktop.DBus.ObjectManager", "GetManagedObjects", &error, &reply, "");
385 assert_se(r >= 0);
386
387 bus_message_dump(reply);
388
389 sd_bus_message_unref(reply);
390 reply = NULL;
391
392 r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/value/a", "org.freedesktop.systemd.ValueTest", "NotifyTest", &error, NULL, "");
393 assert_se(r >= 0);
394
395 r = sd_bus_process(bus, &reply);
396 assert_se(r > 0);
397
398 assert_se(sd_bus_message_is_signal(reply, "org.freedesktop.DBus.Properties", "PropertiesChanged"));
399 bus_message_dump(reply);
400
401 sd_bus_message_unref(reply);
402 reply = NULL;
403
404 r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.systemd.test", "EmitInterfacesAdded", &error, NULL, "");
405 assert_se(r >= 0);
406
407 r = sd_bus_process(bus, &reply);
408 assert_se(r > 0);
409
410 assert_se(sd_bus_message_is_signal(reply, "org.freedesktop.DBus.ObjectManager", "InterfacesAdded"));
411 bus_message_dump(reply);
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.systemd.test", "EmitInterfacesRemoved", &error, NULL, "");
417 assert_se(r >= 0);
418
419 r = sd_bus_process(bus, &reply);
420 assert_se(r > 0);
421
422 assert_se(sd_bus_message_is_signal(reply, "org.freedesktop.DBus.ObjectManager", "InterfacesRemoved"));
423 bus_message_dump(reply);
424
425 sd_bus_message_unref(reply);
426 reply = NULL;
427
428 r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.systemd.test", "Exit", &error, NULL, "");
429 assert_se(r >= 0);
430
431 sd_bus_flush(bus);
432
433 return 0;
434 }
435
436 int main(int argc, char *argv[]) {
437 struct context c;
438 pthread_t s;
439 void *p;
440 int r, q;
441
442 zero(c);
443
444 c.automatic_integer_property = 4711;
445 assert_se(c.automatic_string_property = strdup("dudeldu"));
446
447 assert_se(socketpair(AF_UNIX, SOCK_STREAM, 0, c.fds) >= 0);
448
449 r = pthread_create(&s, NULL, server, &c);
450 if (r != 0)
451 return -r;
452
453 r = client(&c);
454
455 q = pthread_join(s, &p);
456 if (q != 0)
457 return -q;
458
459 if (r < 0)
460 return r;
461
462 if (PTR_TO_INT(p) < 0)
463 return PTR_TO_INT(p);
464
465 free(c.something);
466 free(c.automatic_string_property);
467
468 return EXIT_SUCCESS;
469 }