]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/libsystemd-bus/test-bus-chat.c
bus: add convenience calls for method replies, too
[thirdparty/systemd.git] / src / libsystemd-bus / test-bus-chat.c
CommitLineData
89ffcd2a
LP
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>
e3017af9 25#include <unistd.h>
2c93b4ef 26#include <fcntl.h>
89ffcd2a
LP
27
28#include "log.h"
29#include "util.h"
49e5de64 30#include "macro.h"
89ffcd2a
LP
31
32#include "sd-bus.h"
33#include "bus-message.h"
e3017af9 34#include "bus-error.h"
392d5b37
LP
35#include "bus-match.h"
36#include "bus-internal.h"
37
38static int match_callback(sd_bus *bus, int error, sd_bus_message *m, void *userdata) {
39 log_info("Match triggered! interface=%s member=%s", strna(sd_bus_message_get_interface(m)), strna(sd_bus_message_get_member(m)));
40 return 0;
41}
89ffcd2a 42
a652755d
LP
43static int object_callback(sd_bus *bus, int error, sd_bus_message *m, void *userdata) {
44 int r;
45
46 assert(bus);
47
48 if (error != 0)
49 return 0;
50
51 if (sd_bus_message_is_method_call(m, "org.object.test", "Foobar")) {
52 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
53
54 log_info("Invoked Foobar() on %s", sd_bus_message_get_path(m));
55
56 r = sd_bus_message_new_method_return(bus, m, &reply);
57 if (r < 0) {
58 log_error("Failed to allocate return: %s", strerror(-r));
59 return r;
60 }
61
62 r = sd_bus_send(bus, reply, NULL);
63 if (r < 0) {
64 log_error("Failed to send reply: %s", strerror(-r));
65 return r;
66 }
67
68 return 1;
69 }
70
71 return 0;
72}
73
89ffcd2a
LP
74static int server_init(sd_bus **_bus) {
75 sd_bus *bus = NULL;
d728d708 76 sd_id128_t id;
89ffcd2a 77 int r;
20902f3e 78 const char *unique;
89ffcd2a
LP
79
80 assert(_bus);
81
82 r = sd_bus_open_user(&bus);
83 if (r < 0) {
84 log_error("Failed to connect to user bus: %s", strerror(-r));
85 goto fail;
86 }
87
98178d39 88 r = sd_bus_get_server_id(bus, &id);
d728d708 89 if (r < 0) {
98178d39 90 log_error("Failed to get server ID: %s", strerror(-r));
d728d708
LP
91 goto fail;
92 }
93
20902f3e
LP
94 r = sd_bus_get_unique_name(bus, &unique);
95 if (r < 0) {
96 log_error("Failed to get unique name: %s", strerror(-r));
97 goto fail;
98 }
99
d728d708 100 log_info("Peer ID is " SD_ID128_FORMAT_STR ".", SD_ID128_FORMAT_VAL(id));
20902f3e 101 log_info("Unique ID: %s", unique);
d728d708 102 log_info("Can send file handles: %i", sd_bus_can_send(bus, 'h'));
d728d708 103
89ffcd2a
LP
104 r = sd_bus_request_name(bus, "org.freedesktop.systemd.test", 0);
105 if (r < 0) {
106 log_error("Failed to acquire name: %s", strerror(-r));
107 goto fail;
108 }
109
a652755d
LP
110 r = sd_bus_add_fallback(bus, "/foo/bar", object_callback, NULL);
111 if (r < 0) {
112 log_error("Failed to add object: %s", strerror(-r));
113 goto fail;
114 }
115
392d5b37
LP
116 r = sd_bus_add_match(bus, "type='signal',interface='foo.bar',member='Notify'", match_callback, NULL);
117 if (r < 0) {
118 log_error("Failed to add match: %s", strerror(-r));
119 goto fail;
120 }
121
122 r = sd_bus_add_match(bus, "type='signal',interface='org.freedesktop.DBus',member='NameOwnerChanged'", match_callback, NULL);
123 if (r < 0) {
124 log_error("Failed to add match: %s", strerror(-r));
125 goto fail;
126 }
127
128 bus_match_dump(&bus->match_callbacks, 0);
129
89ffcd2a
LP
130 *_bus = bus;
131 return 0;
132
133fail:
134 if (bus)
135 sd_bus_unref(bus);
136
137 return r;
138}
139
e3017af9 140static int server(sd_bus *bus) {
89ffcd2a 141 int r;
e3017af9 142 bool client1_gone = false, client2_gone = false;
89ffcd2a 143
e3017af9 144 while (!client1_gone || !client2_gone) {
89ffcd2a 145 _cleanup_bus_message_unref_ sd_bus_message *m = NULL, *reply = NULL;
2571ead1 146 pid_t pid = 0;
89ffcd2a
LP
147
148 r = sd_bus_process(bus, &m);
149 if (r < 0) {
150 log_error("Failed to process requests: %s", strerror(-r));
151 goto fail;
152 }
e3017af9 153
89ffcd2a
LP
154 if (r == 0) {
155 r = sd_bus_wait(bus, (uint64_t) -1);
156 if (r < 0) {
157 log_error("Failed to wait: %s", strerror(-r));
158 goto fail;
159 }
160
161 continue;
162 }
163
e3017af9
LP
164 if (!m)
165 continue;
166
2571ead1
LP
167 sd_bus_message_get_pid(m, &pid);
168 log_info("Got message! member=%s pid=%lu label=%s", strna(sd_bus_message_get_member(m)), (unsigned long) pid, strna(sd_bus_message_get_label(m)));
89ffcd2a
LP
169 /* bus_message_dump(m); */
170 /* sd_bus_message_rewind(m, true); */
171
172 if (sd_bus_message_is_method_call(m, "org.freedesktop.systemd.test", "LowerCase")) {
173 const char *hello;
174 _cleanup_free_ char *lowercase = NULL;
175
176 r = sd_bus_message_read(m, "s", &hello);
177 if (r < 0) {
178 log_error("Failed to get parameter: %s", strerror(-r));
179 goto fail;
180 }
181
182 r = sd_bus_message_new_method_return(bus, m, &reply);
183 if (r < 0) {
184 log_error("Failed to allocate return: %s", strerror(-r));
185 goto fail;
186 }
187
188 lowercase = strdup(hello);
189 if (!lowercase) {
190 r = log_oom();
191 goto fail;
192 }
193
194 ascii_strlower(lowercase);
195
196 r = sd_bus_message_append(reply, "s", lowercase);
197 if (r < 0) {
198 log_error("Failed to append message: %s", strerror(-r));
199 goto fail;
200 }
e3017af9
LP
201 } else if (sd_bus_message_is_method_call(m, "org.freedesktop.systemd.test", "ExitClient1")) {
202
203 r = sd_bus_message_new_method_return(bus, m, &reply);
204 if (r < 0) {
205 log_error("Failed to allocate return: %s", strerror(-r));
206 goto fail;
207 }
208
209 client1_gone = true;
210 } else if (sd_bus_message_is_method_call(m, "org.freedesktop.systemd.test", "ExitClient2")) {
211
212 r = sd_bus_message_new_method_return(bus, m, &reply);
213 if (r < 0) {
214 log_error("Failed to allocate return: %s", strerror(-r));
215 goto fail;
216 }
217
218 client2_gone = true;
219 } else if (sd_bus_message_is_method_call(m, "org.freedesktop.systemd.test", "Slow")) {
220
221 r = sd_bus_message_new_method_return(bus, m, &reply);
222 if (r < 0) {
223 log_error("Failed to allocate return: %s", strerror(-r));
224 goto fail;
225 }
226
227 sleep(1);
2c93b4ef
LP
228
229 } else if (sd_bus_message_is_method_call(m, "org.freedesktop.systemd.test", "FileDescriptor")) {
230 int fd;
231 static const char x = 'X';
232
233 r = sd_bus_message_read(m, "h", &fd);
234 if (r < 0) {
235 log_error("Failed to get parameter: %s", strerror(-r));
236 goto fail;
237 }
238
239 if (write(fd, &x, 1) < 0) {
240 log_error("Failed to write to fd: %m");
241 close_nointr_nofail(fd);
242 goto fail;
243 }
244
245 close_nointr_nofail(fd);
246
247 r = sd_bus_message_new_method_return(bus, m, &reply);
248 if (r < 0) {
249 log_error("Failed to allocate return: %s", strerror(-r));
250 goto fail;
251 }
252
e3017af9 253 } else if (sd_bus_message_is_method_call(m, NULL, NULL)) {
89ffcd2a 254
c784c5ce
LP
255 r = sd_bus_message_new_method_error(
256 bus, m,
257 &SD_BUS_ERROR_MAKE("org.freedesktop.DBus.Error.UnknownMethod", "Unknown method."),
258 &reply);
89ffcd2a
LP
259 if (r < 0) {
260 log_error("Failed to allocate return: %s", strerror(-r));
261 goto fail;
262 }
263 }
264
265 if (reply) {
266 r = sd_bus_send(bus, reply, NULL);
267 if (r < 0) {
268 log_error("Failed to send reply: %s", strerror(-r));
269 goto fail;
270 }
e3017af9
LP
271
272 /* log_info("Sent"); */
273 /* bus_message_dump(reply); */
274 /* sd_bus_message_rewind(reply, true); */
89ffcd2a
LP
275 }
276 }
277
278 r = 0;
279
280fail:
e3017af9
LP
281 if (bus) {
282 sd_bus_flush(bus);
89ffcd2a 283 sd_bus_unref(bus);
e3017af9 284 }
89ffcd2a 285
e3017af9 286 return r;
89ffcd2a
LP
287}
288
e3017af9 289static void* client1(void*p) {
89ffcd2a
LP
290 _cleanup_bus_message_unref_ sd_bus_message *m = NULL, *reply = NULL;
291 sd_bus *bus = NULL;
c784c5ce 292 sd_bus_error error = SD_BUS_ERROR_NULL;
89ffcd2a
LP
293 const char *hello;
294 int r;
2c93b4ef
LP
295 int pp[2] = { -1, -1 };
296 char x;
89ffcd2a
LP
297
298 r = sd_bus_open_user(&bus);
299 if (r < 0) {
300 log_error("Failed to connect to user bus: %s", strerror(-r));
301 goto finish;
302 }
303
304 r = sd_bus_message_new_method_call(
305 bus,
306 "org.freedesktop.systemd.test",
307 "/",
308 "org.freedesktop.systemd.test",
309 "LowerCase",
310 &m);
311 if (r < 0) {
312 log_error("Failed to allocate method call: %s", strerror(-r));
313 goto finish;
314 }
315
316 r = sd_bus_message_append(m, "s", "HELLO");
317 if (r < 0) {
318 log_error("Failed to append string: %s", strerror(-r));
319 goto finish;
320 }
321
e3017af9 322 r = sd_bus_send_with_reply_and_block(bus, m, 0, &error, &reply);
89ffcd2a 323 if (r < 0) {
e3017af9 324 log_error("Failed to issue method call: %s", bus_error_message(&error, -r));
89ffcd2a
LP
325 goto finish;
326 }
327
328 r = sd_bus_message_read(reply, "s", &hello);
329 if (r < 0) {
330 log_error("Failed to get string: %s", strerror(-r));
331 goto finish;
332 }
333
334 assert(streq(hello, "hello"));
335
2c93b4ef
LP
336 if (pipe2(pp, O_CLOEXEC|O_NONBLOCK) < 0) {
337 log_error("Failed to allocate pipe: %m");
338 r = -errno;
339 goto finish;
340 }
341
342 sd_bus_message_unref(m);
343 m = NULL;
344 r = sd_bus_message_new_method_call(
345 bus,
346 "org.freedesktop.systemd.test",
347 "/",
348 "org.freedesktop.systemd.test",
349 "FileDescriptor",
350 &m);
351 if (r < 0) {
352 log_error("Failed to allocate method call: %s", strerror(-r));
353 goto finish;
354 }
355
356 r = sd_bus_message_append(m, "h", pp[1]);
357 if (r < 0) {
358 log_error("Failed to append string: %s", strerror(-r));
359 goto finish;
360 }
361
362 sd_bus_message_unref(reply);
363 reply = NULL;
364 r = sd_bus_send_with_reply_and_block(bus, m, 0, &error, &reply);
365 if (r < 0) {
366 log_error("Failed to issue method call: %s", bus_error_message(&error, -r));
367 goto finish;
368 }
369
370 errno = 0;
371 if (read(pp[0], &x, 1) <= 0) {
372 log_error("Failed to read from pipe: %s", errno ? strerror(errno) : "early read");
373 goto finish;
374 }
375
89ffcd2a
LP
376 r = 0;
377
378finish:
379 if (bus) {
380 _cleanup_bus_message_unref_ sd_bus_message *q;
381
382 r = sd_bus_message_new_method_call(
383 bus,
384 "org.freedesktop.systemd.test",
385 "/",
386 "org.freedesktop.systemd.test",
e3017af9 387 "ExitClient1",
89ffcd2a
LP
388 &q);
389 if (r < 0) {
390 log_error("Failed to allocate method call: %s", strerror(-r));
391 goto finish;
392 }
393
394 sd_bus_send(bus, q, NULL);
395 sd_bus_flush(bus);
396 sd_bus_unref(bus);
397 }
398
399 sd_bus_error_free(&error);
2c93b4ef
LP
400
401 close_pipe(pp);
402
e3017af9
LP
403 return INT_TO_PTR(r);
404}
405
406static int quit_callback(sd_bus *b, int ret, sd_bus_message *m, void *userdata) {
407 bool *x = userdata;
408
409 log_error("Quit callback: %s", strerror(ret));
410
411 *x = 1;
412 return 1;
413}
414
415static void* client2(void*p) {
416 _cleanup_bus_message_unref_ sd_bus_message *m = NULL, *reply = NULL;
417 sd_bus *bus = NULL;
c784c5ce 418 sd_bus_error error = SD_BUS_ERROR_NULL;
e3017af9 419 bool quit = false;
b9bf7e2b
LP
420 const char *mid;
421 int r;
e3017af9
LP
422
423 r = sd_bus_open_user(&bus);
424 if (r < 0) {
425 log_error("Failed to connect to user bus: %s", strerror(-r));
426 goto finish;
427 }
428
a652755d
LP
429 r = sd_bus_message_new_method_call(
430 bus,
431 "org.freedesktop.systemd.test",
432 "/foo/bar/waldo/piep",
433 "org.object.test",
434 "Foobar",
435 &m);
436 if (r < 0) {
437 log_error("Failed to allocate method call: %s", strerror(-r));
438 goto finish;
439 }
440
441 r = sd_bus_send(bus, m, NULL);
442 if (r < 0) {
443 log_error("Failed to issue method call: %s", bus_error_message(&error, -r));
444 goto finish;
445 }
446
447 sd_bus_message_unref(m);
448 m = NULL;
449
392d5b37
LP
450 r = sd_bus_message_new_signal(
451 bus,
452 "/foobar",
453 "foo.bar",
454 "Notify",
455 &m);
456 if (r < 0) {
457 log_error("Failed to allocate signal: %s", strerror(-r));
458 goto finish;
459 }
460
461 r = sd_bus_send(bus, m, NULL);
462 if (r < 0) {
463 log_error("Failed to issue signal: %s", bus_error_message(&error, -r));
464 goto finish;
465 }
466
467 sd_bus_message_unref(m);
468 m = NULL;
469
b9bf7e2b
LP
470 r = sd_bus_message_new_method_call(
471 bus,
472 "org.freedesktop.systemd.test",
473 "/",
474 "org.freedesktop.DBus.Peer",
475 "GetMachineId",
476 &m);
477 if (r < 0) {
478 log_error("Failed to allocate method call: %s", strerror(-r));
479 goto finish;
480 }
481
482 r = sd_bus_send_with_reply_and_block(bus, m, 0, &error, &reply);
483 if (r < 0) {
484 log_error("Failed to issue method call: %s", bus_error_message(&error, -r));
485 goto finish;
486 }
487
488 r = sd_bus_message_read(reply, "s", &mid);
489 if (r < 0) {
490 log_error("Failed to parse machine ID: %s", strerror(-r));
491 goto finish;
492 }
493
494 log_info("Machine ID is %s.", mid);
495
496 sd_bus_message_unref(m);
497 m = NULL;
498
e3017af9
LP
499 r = sd_bus_message_new_method_call(
500 bus,
501 "org.freedesktop.systemd.test",
502 "/",
503 "org.freedesktop.systemd.test",
504 "Slow",
505 &m);
506 if (r < 0) {
507 log_error("Failed to allocate method call: %s", strerror(-r));
508 goto finish;
509 }
510
b9bf7e2b
LP
511 sd_bus_message_unref(reply);
512 reply = NULL;
513
e3017af9
LP
514 r = sd_bus_send_with_reply_and_block(bus, m, 200 * USEC_PER_MSEC, &error, &reply);
515 if (r < 0)
516 log_info("Failed to issue method call: %s", bus_error_message(&error, -r));
517 else
518 log_info("Slow call succeed.");
519
520 sd_bus_message_unref(m);
521 m = NULL;
522
523 r = sd_bus_message_new_method_call(
524 bus,
525 "org.freedesktop.systemd.test",
526 "/",
527 "org.freedesktop.systemd.test",
528 "Slow",
529 &m);
530 if (r < 0) {
531 log_error("Failed to allocate method call: %s", strerror(-r));
532 goto finish;
533 }
534
535 r = sd_bus_send_with_reply(bus, m, quit_callback, &quit, 200 * USEC_PER_MSEC, NULL);
536 if (r < 0) {
537 log_info("Failed to issue method call: %s", bus_error_message(&error, -r));
538 goto finish;
539 }
540
541 while (!quit) {
542 r = sd_bus_process(bus, NULL);
543 if (r < 0) {
544 log_error("Failed to process requests: %s", strerror(-r));
545 goto finish;
546 }
547 if (r == 0) {
548 r = sd_bus_wait(bus, (uint64_t) -1);
549 if (r < 0) {
550 log_error("Failed to wait: %s", strerror(-r));
551 goto finish;
552 }
553 }
554 }
555
556 r = 0;
557
558finish:
559 if (bus) {
560 _cleanup_bus_message_unref_ sd_bus_message *q;
561
562 r = sd_bus_message_new_method_call(
563 bus,
564 "org.freedesktop.systemd.test",
565 "/",
566 "org.freedesktop.systemd.test",
567 "ExitClient2",
568 &q);
569 if (r < 0) {
570 log_error("Failed to allocate method call: %s", strerror(-r));
571 goto finish;
572 }
573
574 sd_bus_send(bus, q, NULL);
575 sd_bus_flush(bus);
576 sd_bus_unref(bus);
577 }
578
579 sd_bus_error_free(&error);
580 return INT_TO_PTR(r);
89ffcd2a
LP
581}
582
583int main(int argc, char *argv[]) {
e3017af9 584 pthread_t c1, c2;
89ffcd2a
LP
585 sd_bus *bus;
586 void *p;
587 int q, r;
588
589 r = server_init(&bus);
49e5de64
ZJS
590 if (r < 0) {
591 log_info("Failed to connect to bus, skipping tests.");
592 return EXIT_TEST_SKIP;
593 }
89ffcd2a 594
e3017af9
LP
595 log_info("Initialized...");
596
597 r = pthread_create(&c1, NULL, client1, bus);
598 if (r != 0)
89ffcd2a 599 return EXIT_FAILURE;
89ffcd2a 600
e3017af9
LP
601 r = pthread_create(&c2, NULL, client2, bus);
602 if (r != 0)
603 return EXIT_FAILURE;
89ffcd2a 604
e3017af9
LP
605 r = server(bus);
606
607 q = pthread_join(c1, &p);
608 if (q != 0)
609 return EXIT_FAILURE;
2181a7f5
LP
610 if (PTR_TO_INT(p) < 0)
611 return EXIT_FAILURE;
612
e3017af9 613 q = pthread_join(c2, &p);
89ffcd2a
LP
614 if (q != 0)
615 return EXIT_FAILURE;
2181a7f5
LP
616 if (PTR_TO_INT(p) < 0)
617 return EXIT_FAILURE;
618
89ffcd2a
LP
619 if (r < 0)
620 return EXIT_FAILURE;
621
622 return EXIT_SUCCESS;
623}