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