]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/libsystemd-bus/test-bus-chat.c
bus: add API calls to escape string components of objects paths
[thirdparty/systemd.git] / src / libsystemd-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
eb01ba5d 39static int match_callback(sd_bus *bus, sd_bus_message *m, void *userdata) {
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
eb01ba5d 44static int object_callback(sd_bus *bus, sd_bus_message *m, void *userdata) {
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
d4100e24 55 r = sd_bus_reply_method_return(bus, m, NULL);
a652755d
LP
56 if (r < 0) {
57 log_error("Failed to send reply: %s", strerror(-r));
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) {
77 log_error("Failed to connect to user bus: %s", strerror(-r));
78 goto fail;
79 }
80
98178d39 81 r = sd_bus_get_server_id(bus, &id);
d728d708 82 if (r < 0) {
98178d39 83 log_error("Failed to get server ID: %s", strerror(-r));
d728d708
LP
84 goto fail;
85 }
86
20902f3e
LP
87 r = sd_bus_get_unique_name(bus, &unique);
88 if (r < 0) {
89 log_error("Failed to get unique name: %s", strerror(-r));
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) {
99 log_error("Failed to acquire name: %s", strerror(-r));
100 goto fail;
101 }
102
a652755d
LP
103 r = sd_bus_add_fallback(bus, "/foo/bar", object_callback, NULL);
104 if (r < 0) {
105 log_error("Failed to add object: %s", strerror(-r));
106 goto fail;
107 }
108
392d5b37
LP
109 r = sd_bus_add_match(bus, "type='signal',interface='foo.bar',member='Notify'", match_callback, NULL);
110 if (r < 0) {
111 log_error("Failed to add match: %s", strerror(-r));
112 goto fail;
113 }
114
115 r = sd_bus_add_match(bus, "type='signal',interface='org.freedesktop.DBus',member='NameOwnerChanged'", match_callback, NULL);
116 if (r < 0) {
117 log_error("Failed to add match: %s", strerror(-r));
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) {
144 log_error("Failed to process requests: %s", strerror(-r));
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) {
151 log_error("Failed to wait: %s", strerror(-r));
152 goto fail;
153 }
154
155 continue;
156 }
157
e3017af9
LP
158 if (!m)
159 continue;
160
2571ead1 161 sd_bus_message_get_pid(m, &pid);
4a875b61
LP
162 sd_bus_message_get_selinux_context(m, &label);
163 log_info("Got message! member=%s pid=%lu label=%s",
164 strna(sd_bus_message_get_member(m)),
165 (unsigned long) pid,
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) {
176 log_error("Failed to get parameter: %s", strerror(-r));
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
d4100e24 188 r = sd_bus_reply_method_return(bus, m, "s", lowercase);
89ffcd2a 189 if (r < 0) {
d4100e24 190 log_error("Failed to send reply: %s", strerror(-r));
89ffcd2a
LP
191 goto fail;
192 }
e3017af9
LP
193 } else if (sd_bus_message_is_method_call(m, "org.freedesktop.systemd.test", "ExitClient1")) {
194
d4100e24 195 r = sd_bus_reply_method_return(bus, m, NULL);
e3017af9 196 if (r < 0) {
d4100e24 197 log_error("Failed to send reply: %s", strerror(-r));
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
d4100e24 204 r = sd_bus_reply_method_return(bus, m, NULL);
e3017af9 205 if (r < 0) {
d4100e24 206 log_error("Failed to send reply: %s", strerror(-r));
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
d4100e24 215 r = sd_bus_reply_method_return(bus, m, NULL);
e3017af9 216 if (r < 0) {
d4100e24 217 log_error("Failed to send reply: %s", strerror(-r));
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) {
227 log_error("Failed to get parameter: %s", strerror(-r));
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");
235 close_nointr_nofail(fd);
236 goto fail;
237 }
238
d4100e24 239 r = sd_bus_reply_method_return(bus, m, NULL);
2c93b4ef 240 if (r < 0) {
d4100e24 241 log_error("Failed to send reply: %s", strerror(-r));
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(
c784c5ce 248 bus, m,
40ca29a1 249 &SD_BUS_ERROR_MAKE(SD_BUS_ERROR_UNKNOWN_METHOD, "Unknown method."));
89ffcd2a
LP
250 if (r < 0) {
251 log_error("Failed to send reply: %s", strerror(-r));
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) {
279 log_error("Failed to connect to user bus: %s", strerror(-r));
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) {
d4100e24 294 log_error("Failed to issue method call: %s", strerror(-r));
89ffcd2a
LP
295 goto finish;
296 }
297
298 r = sd_bus_message_read(reply, "s", &hello);
299 if (r < 0) {
300 log_error("Failed to get string: %s", strerror(-r));
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) {
b7f247e0 325 log_error("Failed to issue method call: %s", strerror(-r));
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,
343 "org.freedesktop.systemd.test",
344 "/",
345 "org.freedesktop.systemd.test",
e3017af9 346 "ExitClient1",
89ffcd2a 347 &q);
b7f247e0 348 if (r < 0)
89ffcd2a 349 log_error("Failed to allocate method call: %s", strerror(-r));
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
LP
358
359 close_pipe(pp);
360
e3017af9
LP
361 return INT_TO_PTR(r);
362}
363
eb01ba5d 364static int quit_callback(sd_bus *b, sd_bus_message *m, void *userdata) {
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) {
383 log_error("Failed to connect to user bus: %s", strerror(-r));
384 goto finish;
385 }
386
a652755d
LP
387 r = sd_bus_message_new_method_call(
388 bus,
389 "org.freedesktop.systemd.test",
390 "/foo/bar/waldo/piep",
391 "org.object.test",
392 "Foobar",
393 &m);
394 if (r < 0) {
395 log_error("Failed to allocate method call: %s", strerror(-r));
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,
410 "/foobar",
411 "foo.bar",
412 "Notify",
413 &m);
414 if (r < 0) {
415 log_error("Failed to allocate signal: %s", strerror(-r));
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,
430 "org.freedesktop.systemd.test",
431 "/",
432 "org.freedesktop.DBus.Peer",
433 "GetMachineId",
434 &m);
435 if (r < 0) {
436 log_error("Failed to allocate method call: %s", strerror(-r));
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) {
448 log_error("Failed to parse machine ID: %s", strerror(-r));
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,
459 "org.freedesktop.systemd.test",
460 "/",
461 "org.freedesktop.systemd.test",
462 "Slow",
463 &m);
464 if (r < 0) {
465 log_error("Failed to allocate method call: %s", strerror(-r));
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,
483 "org.freedesktop.systemd.test",
484 "/",
485 "org.freedesktop.systemd.test",
486 "Slow",
487 &m);
488 if (r < 0) {
489 log_error("Failed to allocate method call: %s", strerror(-r));
490 goto finish;
491 }
492
c49b30a2 493 r = sd_bus_call_async(bus, m, quit_callback, &quit, 200 * USEC_PER_MSEC, NULL);
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) {
502 log_error("Failed to process requests: %s", strerror(-r));
503 goto finish;
504 }
505 if (r == 0) {
506 r = sd_bus_wait(bus, (uint64_t) -1);
507 if (r < 0) {
508 log_error("Failed to wait: %s", strerror(-r));
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,
522 "org.freedesktop.systemd.test",
523 "/",
524 "org.freedesktop.systemd.test",
525 "ExitClient2",
526 &q);
527 if (r < 0) {
528 log_error("Failed to allocate method call: %s", strerror(-r));
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}