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