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