chiark / gitweb /
bus: implicitly handle peer commands Ping() and GetMachineId()
[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         bool quit = false;
268         const char *mid;
269         int r;
270
271         r = sd_bus_open_user(&bus);
272         if (r < 0) {
273                 log_error("Failed to connect to user bus: %s", strerror(-r));
274                 goto finish;
275         }
276
277         r = sd_bus_message_new_method_call(
278                         bus,
279                         "org.freedesktop.systemd.test",
280                         "/",
281                         "org.freedesktop.DBus.Peer",
282                         "GetMachineId",
283                         &m);
284         if (r < 0) {
285                 log_error("Failed to allocate method call: %s", strerror(-r));
286                 goto finish;
287         }
288
289         r = sd_bus_send_with_reply_and_block(bus, m, 0, &error, &reply);
290         if (r < 0) {
291                 log_error("Failed to issue method call: %s", bus_error_message(&error, -r));
292                 goto finish;
293         }
294
295         r = sd_bus_message_read(reply, "s", &mid);
296         if (r < 0) {
297                 log_error("Failed to parse machine ID: %s", strerror(-r));
298                 goto finish;
299         }
300
301         log_info("Machine ID is %s.", mid);
302
303         sd_bus_message_unref(m);
304         m = NULL;
305
306         r = sd_bus_message_new_method_call(
307                         bus,
308                         "org.freedesktop.systemd.test",
309                         "/",
310                         "org.freedesktop.systemd.test",
311                         "Slow",
312                         &m);
313         if (r < 0) {
314                 log_error("Failed to allocate method call: %s", strerror(-r));
315                 goto finish;
316         }
317
318         sd_bus_message_unref(reply);
319         reply = NULL;
320
321         r = sd_bus_send_with_reply_and_block(bus, m, 200 * USEC_PER_MSEC, &error, &reply);
322         if (r < 0)
323                 log_info("Failed to issue method call: %s", bus_error_message(&error, -r));
324         else
325                 log_info("Slow call succeed.");
326
327         sd_bus_message_unref(m);
328         m = NULL;
329
330         r = sd_bus_message_new_method_call(
331                         bus,
332                         "org.freedesktop.systemd.test",
333                         "/",
334                         "org.freedesktop.systemd.test",
335                         "Slow",
336                         &m);
337         if (r < 0) {
338                 log_error("Failed to allocate method call: %s", strerror(-r));
339                 goto finish;
340         }
341
342         r = sd_bus_send_with_reply(bus, m, quit_callback, &quit, 200 * USEC_PER_MSEC, NULL);
343         if (r < 0) {
344                 log_info("Failed to issue method call: %s", bus_error_message(&error, -r));
345                 goto finish;
346         }
347
348         while (!quit) {
349                 r = sd_bus_process(bus, NULL);
350                 if (r < 0) {
351                         log_error("Failed to process requests: %s", strerror(-r));
352                         goto finish;
353                 }
354                 if (r == 0) {
355                         r = sd_bus_wait(bus, (uint64_t) -1);
356                         if (r < 0) {
357                                 log_error("Failed to wait: %s", strerror(-r));
358                                 goto finish;
359                         }
360                 }
361         }
362
363         r = 0;
364
365 finish:
366         if (bus) {
367                 _cleanup_bus_message_unref_ sd_bus_message *q;
368
369                 r = sd_bus_message_new_method_call(
370                                 bus,
371                                 "org.freedesktop.systemd.test",
372                                 "/",
373                                 "org.freedesktop.systemd.test",
374                                 "ExitClient2",
375                                 &q);
376                 if (r < 0) {
377                         log_error("Failed to allocate method call: %s", strerror(-r));
378                         goto finish;
379                 }
380
381                 sd_bus_send(bus, q, NULL);
382                 sd_bus_flush(bus);
383                 sd_bus_unref(bus);
384         }
385
386         sd_bus_error_free(&error);
387         return INT_TO_PTR(r);
388 }
389
390 int main(int argc, char *argv[]) {
391         pthread_t c1, c2;
392         sd_bus *bus;
393         void *p;
394         int q, r;
395
396         r = server_init(&bus);
397         if (r < 0)
398                 return EXIT_FAILURE;
399
400         log_info("Initialized...");
401
402         r = pthread_create(&c1, NULL, client1, bus);
403         if (r != 0)
404                 return EXIT_FAILURE;
405
406         r = pthread_create(&c2, NULL, client2, bus);
407         if (r != 0)
408                 return EXIT_FAILURE;
409
410         r = server(bus);
411
412         q = pthread_join(c1, &p);
413         if (q != 0)
414                 return EXIT_FAILURE;
415         q = pthread_join(c2, &p);
416         if (q != 0)
417                 return EXIT_FAILURE;
418         if (r < 0)
419                 return EXIT_FAILURE;
420
421         return EXIT_SUCCESS;
422 }