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