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