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