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