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