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