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