chiark / gitweb /
hwdb: Update database of Bluetooth company identifiers
[elogind.git] / src / libsystemd / 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 *b, 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, "/foo", "org.freedesktop.systemd.test", vtable, c) >= 0);
226         assert_se(sd_bus_add_object_vtable(bus, "/foo", "org.freedesktop.systemd.test2", vtable, c) >= 0);
227         assert_se(sd_bus_add_fallback_vtable(bus, "/value", "org.freedesktop.systemd.ValueTest", vtable2, NULL, UINT_TO_PTR(20)) >= 0);
228         assert_se(sd_bus_add_node_enumerator(bus, "/value", enumerator_callback, NULL) >= 0);
229         assert_se(sd_bus_add_object_manager(bus, "/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("Failed to process requests: %s", strerror(-r));
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("Failed to wait: %s", strerror(-r));
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, true);
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, true);
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, true);
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, true);
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, true);
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, true);
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 }