chiark / gitweb /
bus: implement full method call timeout logic
[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         int r;
37
38         assert(_bus);
39
40         r = sd_bus_open_user(&bus);
41         if (r < 0) {
42                 log_error("Failed to connect to user bus: %s", strerror(-r));
43                 goto fail;
44         }
45
46         r = sd_bus_request_name(bus, "org.freedesktop.systemd.test", 0);
47         if (r < 0) {
48                 log_error("Failed to acquire name: %s", strerror(-r));
49                 goto fail;
50         }
51
52         *_bus = bus;
53         return 0;
54
55 fail:
56         if (bus)
57                 sd_bus_unref(bus);
58
59         return r;
60 }
61
62 static int server(sd_bus *bus) {
63         int r;
64         bool client1_gone = false, client2_gone = false;
65
66         while (!client1_gone || !client2_gone) {
67                 _cleanup_bus_message_unref_ sd_bus_message *m = NULL, *reply = NULL;
68
69                 r = sd_bus_process(bus, &m);
70                 if (r < 0) {
71                         log_error("Failed to process requests: %s", strerror(-r));
72                         goto fail;
73                 }
74
75                 if (r == 0) {
76                         r = sd_bus_wait(bus, (uint64_t) -1);
77                         if (r < 0) {
78                                 log_error("Failed to wait: %s", strerror(-r));
79                                 goto fail;
80                         }
81
82                         continue;
83                 }
84
85                 if (!m)
86                         continue;
87
88                 log_info("Got message! %s", strna(sd_bus_message_get_member(m)));
89                 /* bus_message_dump(m); */
90                 /* sd_bus_message_rewind(m, true); */
91
92                 if (sd_bus_message_is_method_call(m, "org.freedesktop.systemd.test", "LowerCase")) {
93                         const char *hello;
94                         _cleanup_free_ char *lowercase = NULL;
95
96                         r = sd_bus_message_read(m, "s", &hello);
97                         if (r < 0) {
98                                 log_error("Failed to get parameter: %s", strerror(-r));
99                                 goto fail;
100                         }
101
102                         r = sd_bus_message_new_method_return(bus, m, &reply);
103                         if (r < 0) {
104                                 log_error("Failed to allocate return: %s", strerror(-r));
105                                 goto fail;
106                         }
107
108                         lowercase = strdup(hello);
109                         if (!lowercase) {
110                                 r = log_oom();
111                                 goto fail;
112                         }
113
114                         ascii_strlower(lowercase);
115
116                         r = sd_bus_message_append(reply, "s", lowercase);
117                         if (r < 0) {
118                                 log_error("Failed to append message: %s", strerror(-r));
119                                 goto fail;
120                         }
121                 } else if (sd_bus_message_is_method_call(m, "org.freedesktop.systemd.test", "ExitClient1")) {
122
123                         r = sd_bus_message_new_method_return(bus, m, &reply);
124                         if (r < 0) {
125                                 log_error("Failed to allocate return: %s", strerror(-r));
126                                 goto fail;
127                         }
128
129                         client1_gone = true;
130                 } else if (sd_bus_message_is_method_call(m, "org.freedesktop.systemd.test", "ExitClient2")) {
131
132                         r = sd_bus_message_new_method_return(bus, m, &reply);
133                         if (r < 0) {
134                                 log_error("Failed to allocate return: %s", strerror(-r));
135                                 goto fail;
136                         }
137
138                         client2_gone = true;
139                 } else if (sd_bus_message_is_method_call(m, "org.freedesktop.systemd.test", "Slow")) {
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                         sleep(1);
148                 } else if (sd_bus_message_is_method_call(m, NULL, NULL)) {
149                         const sd_bus_error e = SD_BUS_ERROR_INIT_CONST("org.freedesktop.DBus.Error.UnknownMethod", "Unknown method.");
150
151                         r = sd_bus_message_new_method_error(bus, m, &e, &reply);
152                         if (r < 0) {
153                                 log_error("Failed to allocate return: %s", strerror(-r));
154                                 goto fail;
155                         }
156                 }
157
158                 if (reply) {
159                         r = sd_bus_send(bus, reply, NULL);
160                         if (r < 0) {
161                                 log_error("Failed to send reply: %s", strerror(-r));
162                                 goto fail;
163                         }
164
165                         /* log_info("Sent"); */
166                         /* bus_message_dump(reply); */
167                         /* sd_bus_message_rewind(reply, true); */
168                 }
169         }
170
171         r = 0;
172
173 fail:
174         if (bus) {
175                 sd_bus_flush(bus);
176                 sd_bus_unref(bus);
177         }
178
179         return r;
180 }
181
182 static void* client1(void*p) {
183         _cleanup_bus_message_unref_ sd_bus_message *m = NULL, *reply = NULL;
184         sd_bus *bus = NULL;
185         sd_bus_error error = SD_BUS_ERROR_INIT;
186         const char *hello;
187         int r;
188
189         r = sd_bus_open_user(&bus);
190         if (r < 0) {
191                 log_error("Failed to connect to user bus: %s", strerror(-r));
192                 goto finish;
193         }
194
195         r = sd_bus_message_new_method_call(
196                         bus,
197                         "org.freedesktop.systemd.test",
198                         "/",
199                         "org.freedesktop.systemd.test",
200                         "LowerCase",
201                         &m);
202         if (r < 0) {
203                 log_error("Failed to allocate method call: %s", strerror(-r));
204                 goto finish;
205         }
206
207         r = sd_bus_message_append(m, "s", "HELLO");
208         if (r < 0) {
209                 log_error("Failed to append string: %s", strerror(-r));
210                 goto finish;
211         }
212
213         r = sd_bus_send_with_reply_and_block(bus, m, 0, &error, &reply);
214         if (r < 0) {
215                 log_error("Failed to issue method call: %s", bus_error_message(&error, -r));
216                 goto finish;
217         }
218
219         r = sd_bus_message_read(reply, "s", &hello);
220         if (r < 0) {
221                 log_error("Failed to get string: %s", strerror(-r));
222                 goto finish;
223         }
224
225         assert(streq(hello, "hello"));
226
227         r = 0;
228
229 finish:
230         if (bus) {
231                 _cleanup_bus_message_unref_ sd_bus_message *q;
232
233                 r = sd_bus_message_new_method_call(
234                                 bus,
235                                 "org.freedesktop.systemd.test",
236                                 "/",
237                                 "org.freedesktop.systemd.test",
238                                 "ExitClient1",
239                                 &q);
240                 if (r < 0) {
241                         log_error("Failed to allocate method call: %s", strerror(-r));
242                         goto finish;
243                 }
244
245                 sd_bus_send(bus, q, NULL);
246                 sd_bus_flush(bus);
247                 sd_bus_unref(bus);
248         }
249
250         sd_bus_error_free(&error);
251         return INT_TO_PTR(r);
252 }
253
254 static int quit_callback(sd_bus *b, int ret, sd_bus_message *m, void *userdata) {
255         bool *x = userdata;
256
257         log_error("Quit callback: %s", strerror(ret));
258
259         *x = 1;
260         return 1;
261 }
262
263 static void* client2(void*p) {
264         _cleanup_bus_message_unref_ sd_bus_message *m = NULL, *reply = NULL;
265         sd_bus *bus = NULL;
266         sd_bus_error error = SD_BUS_ERROR_INIT;
267         int r;
268         bool quit = false;
269
270         r = sd_bus_open_user(&bus);
271         if (r < 0) {
272                 log_error("Failed to connect to user bus: %s", strerror(-r));
273                 goto finish;
274         }
275
276         r = sd_bus_message_new_method_call(
277                         bus,
278                         "org.freedesktop.systemd.test",
279                         "/",
280                         "org.freedesktop.systemd.test",
281                         "Slow",
282                         &m);
283         if (r < 0) {
284                 log_error("Failed to allocate method call: %s", strerror(-r));
285                 goto finish;
286         }
287
288         r = sd_bus_send_with_reply_and_block(bus, m, 200 * USEC_PER_MSEC, &error, &reply);
289         if (r < 0)
290                 log_info("Failed to issue method call: %s", bus_error_message(&error, -r));
291         else
292                 log_info("Slow call succeed.");
293
294         sd_bus_message_unref(m);
295         m = NULL;
296
297         r = sd_bus_message_new_method_call(
298                         bus,
299                         "org.freedesktop.systemd.test",
300                         "/",
301                         "org.freedesktop.systemd.test",
302                         "Slow",
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(bus, m, quit_callback, &quit, 200 * USEC_PER_MSEC, NULL);
310         if (r < 0) {
311                 log_info("Failed to issue method call: %s", bus_error_message(&error, -r));
312                 goto finish;
313         }
314
315         while (!quit) {
316                 r = sd_bus_process(bus, NULL);
317                 if (r < 0) {
318                         log_error("Failed to process requests: %s", strerror(-r));
319                         goto finish;
320                 }
321                 if (r == 0) {
322                         r = sd_bus_wait(bus, (uint64_t) -1);
323                         if (r < 0) {
324                                 log_error("Failed to wait: %s", strerror(-r));
325                                 goto finish;
326                         }
327                 }
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                                 "org.freedesktop.systemd.test",
339                                 "/",
340                                 "org.freedesktop.systemd.test",
341                                 "ExitClient2",
342                                 &q);
343                 if (r < 0) {
344                         log_error("Failed to allocate method call: %s", strerror(-r));
345                         goto finish;
346                 }
347
348                 sd_bus_send(bus, q, NULL);
349                 sd_bus_flush(bus);
350                 sd_bus_unref(bus);
351         }
352
353         sd_bus_error_free(&error);
354         return INT_TO_PTR(r);
355 }
356
357 int main(int argc, char *argv[]) {
358         pthread_t c1, c2;
359         sd_bus *bus;
360         void *p;
361         int q, r;
362
363         r = server_init(&bus);
364         if (r < 0)
365                 return EXIT_FAILURE;
366
367         log_info("Initialized...");
368
369         r = pthread_create(&c1, NULL, client1, bus);
370         if (r != 0)
371                 return EXIT_FAILURE;
372
373         r = pthread_create(&c2, NULL, client2, bus);
374         if (r != 0)
375                 return EXIT_FAILURE;
376
377         r = server(bus);
378
379         q = pthread_join(c1, &p);
380         if (q != 0)
381                 return EXIT_FAILURE;
382         q = pthread_join(c2, &p);
383         if (q != 0)
384                 return EXIT_FAILURE;
385         if (r < 0)
386                 return EXIT_FAILURE;
387
388         return EXIT_SUCCESS;
389 }