chiark / gitweb /
bus: use C99 struct construction for error initializers
[elogind.git] / src / libsystemd-bus / test-bus-server.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 #include <fcntl.h>
27
28 #include "log.h"
29 #include "util.h"
30 #include "macro.h"
31
32 #include "sd-bus.h"
33 #include "bus-internal.h"
34 #include "bus-message.h"
35
36 struct context {
37         int fds[2];
38
39         bool client_negotiate_unix_fds;
40         bool server_negotiate_unix_fds;
41
42         bool client_anonymous_auth;
43         bool server_anonymous_auth;
44 };
45
46 static void *server(void *p) {
47         struct context *c = p;
48         sd_bus *bus = NULL;
49         sd_id128_t id;
50         bool quit = false;
51         int r;
52
53         assert_se(sd_id128_randomize(&id) >= 0);
54
55         assert_se(sd_bus_new(&bus) >= 0);
56         assert_se(sd_bus_set_fd(bus, c->fds[0], c->fds[0]) >= 0);
57         assert_se(sd_bus_set_server(bus, 1, id) >= 0);
58         assert_se(sd_bus_set_negotiate_fds(bus, c->server_negotiate_unix_fds) >= 0);
59         assert_se(sd_bus_set_anonymous(bus, c->server_anonymous_auth) >= 0);
60         assert_se(sd_bus_start(bus) >= 0);
61
62         while (!quit) {
63                 _cleanup_bus_message_unref_ sd_bus_message *m = NULL, *reply = NULL;
64
65                 r = sd_bus_process(bus, &m);
66                 if (r < 0) {
67                         log_error("Failed to process requests: %s", strerror(-r));
68                         goto fail;
69                 }
70
71                 if (r == 0) {
72                         r = sd_bus_wait(bus, (uint64_t) -1);
73                         if (r < 0) {
74                                 log_error("Failed to wait: %s", strerror(-r));
75                                 goto fail;
76                         }
77
78                         continue;
79                 }
80
81                 if (!m)
82                         continue;
83
84                 log_info("Got message! member=%s", strna(sd_bus_message_get_member(m)));
85
86                 if (sd_bus_message_is_method_call(m, "org.freedesktop.systemd.test", "Exit")) {
87
88                         assert_se((sd_bus_can_send(bus, 'h') >= 1) == (c->server_negotiate_unix_fds && c->client_negotiate_unix_fds));
89
90                         r = sd_bus_message_new_method_return(bus, m, &reply);
91                         if (r < 0) {
92                                 log_error("Failed to allocate return: %s", strerror(-r));
93                                 goto fail;
94                         }
95
96                         quit = true;
97
98                 } else if (sd_bus_message_is_method_call(m, NULL, NULL)) {
99                         r = sd_bus_message_new_method_error(
100                                         bus, m,
101                                         &SD_BUS_ERROR_MAKE("org.freedesktop.DBus.Error.UnknownMethod", "Unknown method."),
102                                         &reply);
103                         if (r < 0) {
104                                 log_error("Failed to allocate return: %s", strerror(-r));
105                                 goto fail;
106                         }
107                 }
108
109                 if (reply) {
110                         r = sd_bus_send(bus, reply, NULL);
111                         if (r < 0) {
112                                 log_error("Failed to send reply: %s", strerror(-r));
113                                 goto fail;
114                         }
115                 }
116         }
117
118         r = 0;
119
120 fail:
121         if (bus) {
122                 sd_bus_flush(bus);
123                 sd_bus_unref(bus);
124         }
125
126         return INT_TO_PTR(r);
127 }
128
129 static int client(struct context *c) {
130         _cleanup_bus_message_unref_ sd_bus_message *m = NULL, *reply = NULL;
131         _cleanup_bus_unref_ sd_bus *bus = NULL;
132         sd_bus_error error = SD_BUS_ERROR_NULL;
133         int r;
134
135         assert_se(sd_bus_new(&bus) >= 0);
136         assert_se(sd_bus_set_fd(bus, c->fds[1], c->fds[1]) >= 0);
137         assert_se(sd_bus_set_negotiate_fds(bus, c->client_negotiate_unix_fds) >= 0);
138         assert_se(sd_bus_set_anonymous(bus, c->client_anonymous_auth) >= 0);
139         assert_se(sd_bus_start(bus) >= 0);
140
141         r = sd_bus_message_new_method_call(
142                         bus,
143                         "org.freedesktop.systemd.test",
144                         "/",
145                         "org.freedesktop.systemd.test",
146                         "Exit",
147                         &m);
148         if (r < 0) {
149                 log_error("Failed to allocate method call: %s", strerror(-r));
150                 return r;
151         }
152
153         r = sd_bus_send_with_reply_and_block(bus, m, 0, &error, &reply);
154         if (r < 0) {
155                 log_error("Failed to issue method call: %s", bus_error_message(&error, -r));
156                 return r;
157         }
158
159         return 0;
160 }
161
162 static int test_one(bool client_negotiate_unix_fds, bool server_negotiate_unix_fds,
163                     bool client_anonymous_auth, bool server_anonymous_auth) {
164
165         struct context c;
166         pthread_t s;
167         void *p;
168         int r, q;
169
170         zero(c);
171
172         assert_se(socketpair(AF_UNIX, SOCK_STREAM, 0, c.fds) >= 0);
173
174         c.client_negotiate_unix_fds = client_negotiate_unix_fds;
175         c.server_negotiate_unix_fds = server_negotiate_unix_fds;
176         c.client_anonymous_auth = client_anonymous_auth;
177         c.server_anonymous_auth = server_anonymous_auth;
178
179         r = pthread_create(&s, NULL, server, &c);
180         if (r != 0)
181                 return -r;
182
183         r = client(&c);
184
185         q = pthread_join(s, &p);
186         if (q != 0)
187                 return -q;
188
189         if (r < 0)
190                 return r;
191
192         if (PTR_TO_INT(p) < 0)
193                 return PTR_TO_INT(p);
194
195         return 0;
196 }
197
198 int main(int argc, char *argv[]) {
199         int r;
200
201         r = test_one(true, true, false, false);
202         assert_se(r >= 0);
203
204         r = test_one(true, false, false, false);
205         assert_se(r >= 0);
206
207         r = test_one(false, true, false, false);
208         assert_se(r >= 0);
209
210         r = test_one(false, false, false, false);
211         assert_se(r >= 0);
212
213         r = test_one(true, true, true, true);
214         assert_se(r >= 0);
215
216         r = test_one(true, true, false, true);
217         assert_se(r >= 0);
218
219         r = test_one(true, true, true, false);
220         assert_se(r == -EPERM);
221
222         return EXIT_SUCCESS;
223 }