]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/libsystemd/sd-bus/test-bus-chat.c
treewide: auto-convert the simple cases to log_*_errno()
[thirdparty/systemd.git] / src / libsystemd / sd-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
ebcf1f97 39static int match_callback(sd_bus *bus, sd_bus_message *m, void *userdata, sd_bus_error *ret_error) {
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
ebcf1f97 44static int object_callback(sd_bus *bus, sd_bus_message *m, void *userdata, sd_bus_error *ret_error) {
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
df2d202e 55 r = sd_bus_reply_method_return(m, NULL);
a652755d 56 if (r < 0) {
0a1beeb6 57 log_error_errno(-r, "Failed to send reply: %m");
a652755d
LP
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) {
0a1beeb6 77 log_error_errno(-r, "Failed to connect to user bus: %m");
89ffcd2a
LP
78 goto fail;
79 }
80
f7fce345 81 r = sd_bus_get_owner_id(bus, &id);
d728d708 82 if (r < 0) {
0a1beeb6 83 log_error_errno(-r, "Failed to get server ID: %m");
d728d708
LP
84 goto fail;
85 }
86
20902f3e
LP
87 r = sd_bus_get_unique_name(bus, &unique);
88 if (r < 0) {
0a1beeb6 89 log_error_errno(-r, "Failed to get unique name: %m");
20902f3e
LP
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) {
0a1beeb6 99 log_error_errno(-r, "Failed to acquire name: %m");
89ffcd2a
LP
100 goto fail;
101 }
102
19befb2d 103 r = sd_bus_add_fallback(bus, NULL, "/foo/bar", object_callback, NULL);
a652755d 104 if (r < 0) {
0a1beeb6 105 log_error_errno(-r, "Failed to add object: %m");
a652755d
LP
106 goto fail;
107 }
108
19befb2d 109 r = sd_bus_add_match(bus, NULL, "type='signal',interface='foo.bar',member='Notify'", match_callback, NULL);
392d5b37 110 if (r < 0) {
0a1beeb6 111 log_error_errno(-r, "Failed to add match: %m");
392d5b37
LP
112 goto fail;
113 }
114
19befb2d 115 r = sd_bus_add_match(bus, NULL, "type='signal',interface='org.freedesktop.DBus',member='NameOwnerChanged'", match_callback, NULL);
392d5b37 116 if (r < 0) {
0a1beeb6 117 log_error_errno(-r, "Failed to add match: %m");
392d5b37
LP
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) {
0a1beeb6 144 log_error_errno(-r, "Failed to process requests: %m");
89ffcd2a
LP
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) {
0a1beeb6 151 log_error_errno(-r, "Failed to wait: %m");
89ffcd2a
LP
152 goto fail;
153 }
154
155 continue;
156 }
157
e3017af9
LP
158 if (!m)
159 continue;
160
5b12334d
LP
161 sd_bus_creds_get_pid(sd_bus_message_get_creds(m), &pid);
162 sd_bus_creds_get_selinux_context(sd_bus_message_get_creds(m), &label);
de0671ee 163 log_info("Got message! member=%s pid="PID_FMT" label=%s",
4a875b61 164 strna(sd_bus_message_get_member(m)),
de0671ee 165 pid,
4a875b61 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) {
0a1beeb6 176 log_error_errno(-r, "Failed to get parameter: %m");
89ffcd2a
LP
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
df2d202e 188 r = sd_bus_reply_method_return(m, "s", lowercase);
89ffcd2a 189 if (r < 0) {
0a1beeb6 190 log_error_errno(-r, "Failed to send reply: %m");
89ffcd2a
LP
191 goto fail;
192 }
e3017af9
LP
193 } else if (sd_bus_message_is_method_call(m, "org.freedesktop.systemd.test", "ExitClient1")) {
194
df2d202e 195 r = sd_bus_reply_method_return(m, NULL);
e3017af9 196 if (r < 0) {
0a1beeb6 197 log_error_errno(-r, "Failed to send reply: %m");
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
df2d202e 204 r = sd_bus_reply_method_return(m, NULL);
e3017af9 205 if (r < 0) {
0a1beeb6 206 log_error_errno(-r, "Failed to send reply: %m");
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
df2d202e 215 r = sd_bus_reply_method_return(m, NULL);
e3017af9 216 if (r < 0) {
0a1beeb6 217 log_error_errno(-r, "Failed to send reply: %m");
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) {
0a1beeb6 227 log_error_errno(-r, "Failed to get parameter: %m");
2c93b4ef
LP
228 goto fail;
229 }
230
5a330cda
ZJS
231 log_info("Received fd=%d", fd);
232
2c93b4ef
LP
233 if (write(fd, &x, 1) < 0) {
234 log_error("Failed to write to fd: %m");
03e334a1 235 safe_close(fd);
2c93b4ef
LP
236 goto fail;
237 }
238
df2d202e 239 r = sd_bus_reply_method_return(m, NULL);
2c93b4ef 240 if (r < 0) {
0a1beeb6 241 log_error_errno(-r, "Failed to send reply: %m");
2c93b4ef
LP
242 goto fail;
243 }
244
e3017af9 245 } else if (sd_bus_message_is_method_call(m, NULL, NULL)) {
89ffcd2a 246
d4100e24 247 r = sd_bus_reply_method_error(
df2d202e 248 m,
14c24659 249 &SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_UNKNOWN_METHOD, "Unknown method."));
89ffcd2a 250 if (r < 0) {
0a1beeb6 251 log_error_errno(-r, "Failed to send reply: %m");
89ffcd2a
LP
252 goto fail;
253 }
254 }
255 }
256
257 r = 0;
258
259fail:
e3017af9
LP
260 if (bus) {
261 sd_bus_flush(bus);
89ffcd2a 262 sd_bus_unref(bus);
e3017af9 263 }
89ffcd2a 264
e3017af9 265 return r;
89ffcd2a
LP
266}
267
e3017af9 268static void* client1(void*p) {
e9b807c1 269 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
89ffcd2a 270 sd_bus *bus = NULL;
c784c5ce 271 sd_bus_error error = SD_BUS_ERROR_NULL;
89ffcd2a
LP
272 const char *hello;
273 int r;
2c93b4ef
LP
274 int pp[2] = { -1, -1 };
275 char x;
89ffcd2a
LP
276
277 r = sd_bus_open_user(&bus);
278 if (r < 0) {
0a1beeb6 279 log_error_errno(-r, "Failed to connect to user bus: %m");
89ffcd2a
LP
280 goto finish;
281 }
282
d4100e24 283 r = sd_bus_call_method(
89ffcd2a
LP
284 bus,
285 "org.freedesktop.systemd.test",
286 "/",
287 "org.freedesktop.systemd.test",
288 "LowerCase",
d4100e24
LP
289 &error,
290 &reply,
291 "s",
292 "HELLO");
89ffcd2a 293 if (r < 0) {
0a1beeb6 294 log_error_errno(-r, "Failed to issue method call: %m");
89ffcd2a
LP
295 goto finish;
296 }
297
298 r = sd_bus_message_read(reply, "s", &hello);
299 if (r < 0) {
0a1beeb6 300 log_error_errno(-r, "Failed to get string: %m");
89ffcd2a
LP
301 goto finish;
302 }
303
304 assert(streq(hello, "hello"));
305
2c93b4ef
LP
306 if (pipe2(pp, O_CLOEXEC|O_NONBLOCK) < 0) {
307 log_error("Failed to allocate pipe: %m");
308 r = -errno;
309 goto finish;
310 }
311
5a330cda
ZJS
312 log_info("Sending fd=%d", pp[1]);
313
b7f247e0 314 r = sd_bus_call_method(
2c93b4ef
LP
315 bus,
316 "org.freedesktop.systemd.test",
317 "/",
318 "org.freedesktop.systemd.test",
319 "FileDescriptor",
b7f247e0
LP
320 &error,
321 NULL,
322 "h",
323 pp[1]);
2c93b4ef 324 if (r < 0) {
0a1beeb6 325 log_error_errno(-r, "Failed to issue method call: %m");
2c93b4ef
LP
326 goto finish;
327 }
328
329 errno = 0;
330 if (read(pp[0], &x, 1) <= 0) {
331 log_error("Failed to read from pipe: %s", errno ? strerror(errno) : "early read");
332 goto finish;
333 }
334
89ffcd2a
LP
335 r = 0;
336
337finish:
338 if (bus) {
339 _cleanup_bus_message_unref_ sd_bus_message *q;
340
341 r = sd_bus_message_new_method_call(
342 bus,
151b9b96 343 &q,
89ffcd2a
LP
344 "org.freedesktop.systemd.test",
345 "/",
346 "org.freedesktop.systemd.test",
151b9b96 347 "ExitClient1");
b7f247e0 348 if (r < 0)
0a1beeb6 349 log_error_errno(-r, "Failed to allocate method call: %m");
b7f247e0
LP
350 else
351 sd_bus_send(bus, q, NULL);
89ffcd2a 352
89ffcd2a
LP
353 sd_bus_flush(bus);
354 sd_bus_unref(bus);
355 }
356
357 sd_bus_error_free(&error);
2c93b4ef 358
3d94f76c 359 safe_close_pair(pp);
2c93b4ef 360
e3017af9
LP
361 return INT_TO_PTR(r);
362}
363
ebcf1f97 364static int quit_callback(sd_bus *b, sd_bus_message *m, void *userdata, sd_bus_error *ret_error) {
e3017af9
LP
365 bool *x = userdata;
366
40ca29a1 367 log_error("Quit callback: %s", strerror(sd_bus_message_get_errno(m)));
e3017af9
LP
368
369 *x = 1;
370 return 1;
371}
372
373static void* client2(void*p) {
374 _cleanup_bus_message_unref_ sd_bus_message *m = NULL, *reply = NULL;
375 sd_bus *bus = NULL;
c784c5ce 376 sd_bus_error error = SD_BUS_ERROR_NULL;
e3017af9 377 bool quit = false;
b9bf7e2b
LP
378 const char *mid;
379 int r;
e3017af9
LP
380
381 r = sd_bus_open_user(&bus);
382 if (r < 0) {
0a1beeb6 383 log_error_errno(-r, "Failed to connect to user bus: %m");
e3017af9
LP
384 goto finish;
385 }
386
a652755d
LP
387 r = sd_bus_message_new_method_call(
388 bus,
151b9b96 389 &m,
a652755d
LP
390 "org.freedesktop.systemd.test",
391 "/foo/bar/waldo/piep",
392 "org.object.test",
151b9b96 393 "Foobar");
a652755d 394 if (r < 0) {
0a1beeb6 395 log_error_errno(-r, "Failed to allocate method call: %m");
a652755d
LP
396 goto finish;
397 }
398
399 r = sd_bus_send(bus, m, NULL);
400 if (r < 0) {
401 log_error("Failed to issue method call: %s", bus_error_message(&error, -r));
402 goto finish;
403 }
404
405 sd_bus_message_unref(m);
406 m = NULL;
407
392d5b37
LP
408 r = sd_bus_message_new_signal(
409 bus,
151b9b96 410 &m,
392d5b37
LP
411 "/foobar",
412 "foo.bar",
151b9b96 413 "Notify");
392d5b37 414 if (r < 0) {
0a1beeb6 415 log_error_errno(-r, "Failed to allocate signal: %m");
392d5b37
LP
416 goto finish;
417 }
418
419 r = sd_bus_send(bus, m, NULL);
420 if (r < 0) {
421 log_error("Failed to issue signal: %s", bus_error_message(&error, -r));
422 goto finish;
423 }
424
425 sd_bus_message_unref(m);
426 m = NULL;
427
b9bf7e2b
LP
428 r = sd_bus_message_new_method_call(
429 bus,
151b9b96 430 &m,
b9bf7e2b
LP
431 "org.freedesktop.systemd.test",
432 "/",
433 "org.freedesktop.DBus.Peer",
151b9b96 434 "GetMachineId");
b9bf7e2b 435 if (r < 0) {
0a1beeb6 436 log_error_errno(-r, "Failed to allocate method call: %m");
b9bf7e2b
LP
437 goto finish;
438 }
439
c49b30a2 440 r = sd_bus_call(bus, m, 0, &error, &reply);
b9bf7e2b
LP
441 if (r < 0) {
442 log_error("Failed to issue method call: %s", bus_error_message(&error, -r));
443 goto finish;
444 }
445
446 r = sd_bus_message_read(reply, "s", &mid);
447 if (r < 0) {
0a1beeb6 448 log_error_errno(-r, "Failed to parse machine ID: %m");
b9bf7e2b
LP
449 goto finish;
450 }
451
452 log_info("Machine ID is %s.", mid);
453
454 sd_bus_message_unref(m);
455 m = NULL;
456
e3017af9
LP
457 r = sd_bus_message_new_method_call(
458 bus,
151b9b96 459 &m,
e3017af9
LP
460 "org.freedesktop.systemd.test",
461 "/",
462 "org.freedesktop.systemd.test",
151b9b96 463 "Slow");
e3017af9 464 if (r < 0) {
0a1beeb6 465 log_error_errno(-r, "Failed to allocate method call: %m");
e3017af9
LP
466 goto finish;
467 }
468
b9bf7e2b
LP
469 sd_bus_message_unref(reply);
470 reply = NULL;
471
c49b30a2 472 r = sd_bus_call(bus, m, 200 * USEC_PER_MSEC, &error, &reply);
e3017af9
LP
473 if (r < 0)
474 log_info("Failed to issue method call: %s", bus_error_message(&error, -r));
475 else
476 log_info("Slow call succeed.");
477
478 sd_bus_message_unref(m);
479 m = NULL;
480
481 r = sd_bus_message_new_method_call(
482 bus,
151b9b96 483 &m,
e3017af9
LP
484 "org.freedesktop.systemd.test",
485 "/",
486 "org.freedesktop.systemd.test",
151b9b96 487 "Slow");
e3017af9 488 if (r < 0) {
0a1beeb6 489 log_error_errno(-r, "Failed to allocate method call: %m");
e3017af9
LP
490 goto finish;
491 }
492
19befb2d 493 r = sd_bus_call_async(bus, NULL, m, quit_callback, &quit, 200 * USEC_PER_MSEC);
e3017af9
LP
494 if (r < 0) {
495 log_info("Failed to issue method call: %s", bus_error_message(&error, -r));
496 goto finish;
497 }
498
499 while (!quit) {
500 r = sd_bus_process(bus, NULL);
501 if (r < 0) {
0a1beeb6 502 log_error_errno(-r, "Failed to process requests: %m");
e3017af9
LP
503 goto finish;
504 }
505 if (r == 0) {
506 r = sd_bus_wait(bus, (uint64_t) -1);
507 if (r < 0) {
0a1beeb6 508 log_error_errno(-r, "Failed to wait: %m");
e3017af9
LP
509 goto finish;
510 }
511 }
512 }
513
514 r = 0;
515
516finish:
517 if (bus) {
518 _cleanup_bus_message_unref_ sd_bus_message *q;
519
520 r = sd_bus_message_new_method_call(
521 bus,
151b9b96 522 &q,
e3017af9
LP
523 "org.freedesktop.systemd.test",
524 "/",
525 "org.freedesktop.systemd.test",
151b9b96 526 "ExitClient2");
e3017af9 527 if (r < 0) {
0a1beeb6 528 log_error_errno(-r, "Failed to allocate method call: %m");
e3017af9
LP
529 goto finish;
530 }
531
532 sd_bus_send(bus, q, NULL);
533 sd_bus_flush(bus);
534 sd_bus_unref(bus);
535 }
536
537 sd_bus_error_free(&error);
538 return INT_TO_PTR(r);
89ffcd2a
LP
539}
540
541int main(int argc, char *argv[]) {
e3017af9 542 pthread_t c1, c2;
89ffcd2a
LP
543 sd_bus *bus;
544 void *p;
545 int q, r;
546
547 r = server_init(&bus);
49e5de64
ZJS
548 if (r < 0) {
549 log_info("Failed to connect to bus, skipping tests.");
550 return EXIT_TEST_SKIP;
551 }
89ffcd2a 552
e3017af9
LP
553 log_info("Initialized...");
554
555 r = pthread_create(&c1, NULL, client1, bus);
556 if (r != 0)
89ffcd2a 557 return EXIT_FAILURE;
89ffcd2a 558
e3017af9
LP
559 r = pthread_create(&c2, NULL, client2, bus);
560 if (r != 0)
561 return EXIT_FAILURE;
89ffcd2a 562
e3017af9
LP
563 r = server(bus);
564
565 q = pthread_join(c1, &p);
566 if (q != 0)
567 return EXIT_FAILURE;
2181a7f5
LP
568 if (PTR_TO_INT(p) < 0)
569 return EXIT_FAILURE;
570
e3017af9 571 q = pthread_join(c2, &p);
89ffcd2a
LP
572 if (q != 0)
573 return EXIT_FAILURE;
2181a7f5
LP
574 if (PTR_TO_INT(p) < 0)
575 return EXIT_FAILURE;
576
89ffcd2a
LP
577 if (r < 0)
578 return EXIT_FAILURE;
579
580 return EXIT_SUCCESS;
581}