chiark / gitweb /
bus: implicitly collect ucred/label information
[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
27 #include "log.h"
28 #include "util.h"
29
30 #include "sd-bus.h"
31 #include "bus-message.h"
32 #include "bus-error.h"
33
34 static int server_init(sd_bus **_bus) {
35         sd_bus *bus = NULL;
36         sd_id128_t id;
37         int r;
38         const char *unique;
39
40         assert(_bus);
41
42         r = sd_bus_open_user(&bus);
43         if (r < 0) {
44                 log_error("Failed to connect to user bus: %s", strerror(-r));
45                 goto fail;
46         }
47
48         r = sd_bus_get_peer(bus, &id);
49         if (r < 0) {
50                 log_error("Failed to get peer ID: %s", strerror(-r));
51                 goto fail;
52         }
53
54         r = sd_bus_get_unique_name(bus, &unique);
55         if (r < 0) {
56                 log_error("Failed to get unique name: %s", strerror(-r));
57                 goto fail;
58         }
59
60         log_info("Peer ID is " SD_ID128_FORMAT_STR ".", SD_ID128_FORMAT_VAL(id));
61         log_info("Unique ID: %s", unique);
62         log_info("Can send file handles: %i", sd_bus_can_send(bus, 'h'));
63
64         r = sd_bus_request_name(bus, "org.freedesktop.systemd.test", 0);
65         if (r < 0) {
66                 log_error("Failed to acquire name: %s", strerror(-r));
67                 goto fail;
68         }
69
70         *_bus = bus;
71         return 0;
72
73 fail:
74         if (bus)
75                 sd_bus_unref(bus);
76
77         return r;
78 }
79
80 static int server(sd_bus *bus) {
81         int r;
82         bool client1_gone = false, client2_gone = false;
83
84         while (!client1_gone || !client2_gone) {
85                 _cleanup_bus_message_unref_ sd_bus_message *m = NULL, *reply = NULL;
86                 pid_t pid = 0;
87
88                 r = sd_bus_process(bus, &m);
89                 if (r < 0) {
90                         log_error("Failed to process requests: %s", strerror(-r));
91                         goto fail;
92                 }
93
94                 if (r == 0) {
95                         r = sd_bus_wait(bus, (uint64_t) -1);
96                         if (r < 0) {
97                                 log_error("Failed to wait: %s", strerror(-r));
98                                 goto fail;
99                         }
100
101                         continue;
102                 }
103
104                 if (!m)
105                         continue;
106
107                 sd_bus_message_get_pid(m, &pid);
108                 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_label(m)));
109                 /* bus_message_dump(m); */
110                 /* sd_bus_message_rewind(m, true); */
111
112                 if (sd_bus_message_is_method_call(m, "org.freedesktop.systemd.test", "LowerCase")) {
113                         const char *hello;
114                         _cleanup_free_ char *lowercase = NULL;
115
116                         r = sd_bus_message_read(m, "s", &hello);
117                         if (r < 0) {
118                                 log_error("Failed to get parameter: %s", strerror(-r));
119                                 goto fail;
120                         }
121
122                         r = sd_bus_message_new_method_return(bus, m, &reply);
123                         if (r < 0) {
124                                 log_error("Failed to allocate return: %s", strerror(-r));
125                                 goto fail;
126                         }
127
128                         lowercase = strdup(hello);
129                         if (!lowercase) {
130                                 r = log_oom();
131                                 goto fail;
132                         }
133
134                         ascii_strlower(lowercase);
135
136                         r = sd_bus_message_append(reply, "s", lowercase);
137                         if (r < 0) {
138                                 log_error("Failed to append message: %s", strerror(-r));
139                                 goto fail;
140                         }
141                 } else if (sd_bus_message_is_method_call(m, "org.freedesktop.systemd.test", "ExitClient1")) {
142
143                         r = sd_bus_message_new_method_return(bus, m, &reply);
144                         if (r < 0) {
145                                 log_error("Failed to allocate return: %s", strerror(-r));
146                                 goto fail;
147                         }
148
149                         client1_gone = true;
150                 } else if (sd_bus_message_is_method_call(m, "org.freedesktop.systemd.test", "ExitClient2")) {
151
152                         r = sd_bus_message_new_method_return(bus, m, &reply);
153                         if (r < 0) {
154                                 log_error("Failed to allocate return: %s", strerror(-r));
155                                 goto fail;
156                         }
157
158                         client2_gone = true;
159                 } else if (sd_bus_message_is_method_call(m, "org.freedesktop.systemd.test", "Slow")) {
160
161                         r = sd_bus_message_new_method_return(bus, m, &reply);
162                         if (r < 0) {
163                                 log_error("Failed to allocate return: %s", strerror(-r));
164                                 goto fail;
165                         }
166
167                         sleep(1);
168                 } else if (sd_bus_message_is_method_call(m, NULL, NULL)) {
169                         const sd_bus_error e = SD_BUS_ERROR_INIT_CONST("org.freedesktop.DBus.Error.UnknownMethod", "Unknown method.");
170
171                         r = sd_bus_message_new_method_error(bus, m, &e, &reply);
172                         if (r < 0) {
173                                 log_error("Failed to allocate return: %s", strerror(-r));
174                                 goto fail;
175                         }
176                 }
177
178                 if (reply) {
179                         r = sd_bus_send(bus, reply, NULL);
180                         if (r < 0) {
181                                 log_error("Failed to send reply: %s", strerror(-r));
182                                 goto fail;
183                         }
184
185                         /* log_info("Sent"); */
186                         /* bus_message_dump(reply); */
187                         /* sd_bus_message_rewind(reply, true); */
188                 }
189         }
190
191         r = 0;
192
193 fail:
194         if (bus) {
195                 sd_bus_flush(bus);
196                 sd_bus_unref(bus);
197         }
198
199         return r;
200 }
201
202 static void* client1(void*p) {
203         _cleanup_bus_message_unref_ sd_bus_message *m = NULL, *reply = NULL;
204         sd_bus *bus = NULL;
205         sd_bus_error error = SD_BUS_ERROR_INIT;
206         const char *hello;
207         int r;
208
209         r = sd_bus_open_user(&bus);
210         if (r < 0) {
211                 log_error("Failed to connect to user bus: %s", strerror(-r));
212                 goto finish;
213         }
214
215         r = sd_bus_message_new_method_call(
216                         bus,
217                         "org.freedesktop.systemd.test",
218                         "/",
219                         "org.freedesktop.systemd.test",
220                         "LowerCase",
221                         &m);
222         if (r < 0) {
223                 log_error("Failed to allocate method call: %s", strerror(-r));
224                 goto finish;
225         }
226
227         r = sd_bus_message_append(m, "s", "HELLO");
228         if (r < 0) {
229                 log_error("Failed to append string: %s", strerror(-r));
230                 goto finish;
231         }
232
233         r = sd_bus_send_with_reply_and_block(bus, m, 0, &error, &reply);
234         if (r < 0) {
235                 log_error("Failed to issue method call: %s", bus_error_message(&error, -r));
236                 goto finish;
237         }
238
239         r = sd_bus_message_read(reply, "s", &hello);
240         if (r < 0) {
241                 log_error("Failed to get string: %s", strerror(-r));
242                 goto finish;
243         }
244
245         assert(streq(hello, "hello"));
246
247         r = 0;
248
249 finish:
250         if (bus) {
251                 _cleanup_bus_message_unref_ sd_bus_message *q;
252
253                 r = sd_bus_message_new_method_call(
254                                 bus,
255                                 "org.freedesktop.systemd.test",
256                                 "/",
257                                 "org.freedesktop.systemd.test",
258                                 "ExitClient1",
259                                 &q);
260                 if (r < 0) {
261                         log_error("Failed to allocate method call: %s", strerror(-r));
262                         goto finish;
263                 }
264
265                 sd_bus_send(bus, q, NULL);
266                 sd_bus_flush(bus);
267                 sd_bus_unref(bus);
268         }
269
270         sd_bus_error_free(&error);
271         return INT_TO_PTR(r);
272 }
273
274 static int quit_callback(sd_bus *b, int ret, sd_bus_message *m, void *userdata) {
275         bool *x = userdata;
276
277         log_error("Quit callback: %s", strerror(ret));
278
279         *x = 1;
280         return 1;
281 }
282
283 static void* client2(void*p) {
284         _cleanup_bus_message_unref_ sd_bus_message *m = NULL, *reply = NULL;
285         sd_bus *bus = NULL;
286         sd_bus_error error = SD_BUS_ERROR_INIT;
287         bool quit = false;
288         const char *mid;
289         int r;
290
291         r = sd_bus_open_user(&bus);
292         if (r < 0) {
293                 log_error("Failed to connect to user bus: %s", strerror(-r));
294                 goto finish;
295         }
296
297         r = sd_bus_message_new_method_call(
298                         bus,
299                         "org.freedesktop.systemd.test",
300                         "/",
301                         "org.freedesktop.DBus.Peer",
302                         "GetMachineId",
303                         &m);
304         if (r < 0) {
305                 log_error("Failed to allocate method call: %s", strerror(-r));
306                 goto finish;
307         }
308
309         r = sd_bus_send_with_reply_and_block(bus, m, 0, &error, &reply);
310         if (r < 0) {
311                 log_error("Failed to issue method call: %s", bus_error_message(&error, -r));
312                 goto finish;
313         }
314
315         r = sd_bus_message_read(reply, "s", &mid);
316         if (r < 0) {
317                 log_error("Failed to parse machine ID: %s", strerror(-r));
318                 goto finish;
319         }
320
321         log_info("Machine ID is %s.", mid);
322
323         sd_bus_message_unref(m);
324         m = NULL;
325
326         r = sd_bus_message_new_method_call(
327                         bus,
328                         "org.freedesktop.systemd.test",
329                         "/",
330                         "org.freedesktop.systemd.test",
331                         "Slow",
332                         &m);
333         if (r < 0) {
334                 log_error("Failed to allocate method call: %s", strerror(-r));
335                 goto finish;
336         }
337
338         sd_bus_message_unref(reply);
339         reply = NULL;
340
341         r = sd_bus_send_with_reply_and_block(bus, m, 200 * USEC_PER_MSEC, &error, &reply);
342         if (r < 0)
343                 log_info("Failed to issue method call: %s", bus_error_message(&error, -r));
344         else
345                 log_info("Slow call succeed.");
346
347         sd_bus_message_unref(m);
348         m = NULL;
349
350         r = sd_bus_message_new_method_call(
351                         bus,
352                         "org.freedesktop.systemd.test",
353                         "/",
354                         "org.freedesktop.systemd.test",
355                         "Slow",
356                         &m);
357         if (r < 0) {
358                 log_error("Failed to allocate method call: %s", strerror(-r));
359                 goto finish;
360         }
361
362         r = sd_bus_send_with_reply(bus, m, quit_callback, &quit, 200 * USEC_PER_MSEC, NULL);
363         if (r < 0) {
364                 log_info("Failed to issue method call: %s", bus_error_message(&error, -r));
365                 goto finish;
366         }
367
368         while (!quit) {
369                 r = sd_bus_process(bus, NULL);
370                 if (r < 0) {
371                         log_error("Failed to process requests: %s", strerror(-r));
372                         goto finish;
373                 }
374                 if (r == 0) {
375                         r = sd_bus_wait(bus, (uint64_t) -1);
376                         if (r < 0) {
377                                 log_error("Failed to wait: %s", strerror(-r));
378                                 goto finish;
379                         }
380                 }
381         }
382
383         r = 0;
384
385 finish:
386         if (bus) {
387                 _cleanup_bus_message_unref_ sd_bus_message *q;
388
389                 r = sd_bus_message_new_method_call(
390                                 bus,
391                                 "org.freedesktop.systemd.test",
392                                 "/",
393                                 "org.freedesktop.systemd.test",
394                                 "ExitClient2",
395                                 &q);
396                 if (r < 0) {
397                         log_error("Failed to allocate method call: %s", strerror(-r));
398                         goto finish;
399                 }
400
401                 sd_bus_send(bus, q, NULL);
402                 sd_bus_flush(bus);
403                 sd_bus_unref(bus);
404         }
405
406         sd_bus_error_free(&error);
407         return INT_TO_PTR(r);
408 }
409
410 int main(int argc, char *argv[]) {
411         pthread_t c1, c2;
412         sd_bus *bus;
413         void *p;
414         int q, r;
415
416         r = server_init(&bus);
417         if (r < 0)
418                 return EXIT_FAILURE;
419
420         log_info("Initialized...");
421
422         r = pthread_create(&c1, NULL, client1, bus);
423         if (r != 0)
424                 return EXIT_FAILURE;
425
426         r = pthread_create(&c2, NULL, client2, bus);
427         if (r != 0)
428                 return EXIT_FAILURE;
429
430         r = server(bus);
431
432         q = pthread_join(c1, &p);
433         if (q != 0)
434                 return EXIT_FAILURE;
435         q = pthread_join(c2, &p);
436         if (q != 0)
437                 return EXIT_FAILURE;
438         if (r < 0)
439                 return EXIT_FAILURE;
440
441         return EXIT_SUCCESS;
442 }