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