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