]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/libsystemd/sd-bus/test-bus-server.c
bd8978034604fe16307da36db7b3aeecc4ae2d8f
[thirdparty/systemd.git] / src / libsystemd / 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 <pthread.h>
23 #include <stdlib.h>
24
25 #include "sd-bus.h"
26
27 #include "bus-internal.h"
28 #include "bus-util.h"
29 #include "log.h"
30 #include "macro.h"
31 #include "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_(sd_bus_message_unrefp) 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_(sd_bus_message_unrefp) sd_bus_message *m = NULL, *reply = NULL;
128 _cleanup_(sd_bus_unrefp) 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 }