chiark / gitweb /
timedated: use libsystemd-bus instead of libdbus for bus communication
[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
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 }