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