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