]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/libsystemd/sd-bus/test-bus-watch-bind.c
tree-wide: remove Lennart's copyright lines
[thirdparty/systemd.git] / src / libsystemd / sd-bus / test-bus-watch-bind.c
CommitLineData
8a5cd31e
LP
1/* SPDX-License-Identifier: LGPL-2.1+ */
2/***
8a5cd31e
LP
3***/
4
5#include <pthread.h>
6
7#include "sd-bus.h"
8#include "sd-event.h"
9#include "sd-id128.h"
10
11#include "alloc-util.h"
12#include "fd-util.h"
13#include "fileio.h"
14#include "fs-util.h"
15#include "mkdir.h"
16#include "path-util.h"
17#include "random-util.h"
18#include "rm-rf.h"
19#include "socket-util.h"
20#include "string-util.h"
21
22static int method_foobar(sd_bus_message *m, void *userdata, sd_bus_error *ret_error) {
23 log_info("Got Foobar() call.");
24
25 assert_se(sd_event_exit(sd_bus_get_event(sd_bus_message_get_bus(m)), 0) >= 0);
26 return sd_bus_reply_method_return(m, NULL);
27}
28
29static int method_exit(sd_bus_message *m, void *userdata, sd_bus_error *ret_error) {
30 log_info("Got Exit() call");
31 assert_se(sd_event_exit(sd_bus_get_event(sd_bus_message_get_bus(m)), 1) >= 0);
32 return sd_bus_reply_method_return(m, NULL);
33}
34
35static const sd_bus_vtable vtable[] = {
36 SD_BUS_VTABLE_START(0),
37 SD_BUS_METHOD("Foobar", NULL, NULL, method_foobar, SD_BUS_VTABLE_UNPRIVILEGED),
38 SD_BUS_METHOD("Exit", NULL, NULL, method_exit, SD_BUS_VTABLE_UNPRIVILEGED),
39 SD_BUS_VTABLE_END,
40};
41
42static void* thread_server(void *p) {
43 _cleanup_free_ char *suffixed = NULL, *suffixed2 = NULL, *d = NULL;
44 _cleanup_close_ int fd = -1;
45 union sockaddr_union u = {
46 .un.sun_family = AF_UNIX,
47 };
48 const char *path = p;
49
50 log_debug("Initializing server");
51
52 /* Let's play some games, by slowly creating the socket directory, and renaming it in the middle */
53 (void) usleep(100 * USEC_PER_MSEC);
54
55 assert_se(mkdir_parents(path, 0755) >= 0);
56 (void) usleep(100 * USEC_PER_MSEC);
57
58 d = dirname_malloc(path);
59 assert_se(d);
60 assert_se(asprintf(&suffixed, "%s.%" PRIx64, d, random_u64()) >= 0);
61 assert_se(rename(d, suffixed) >= 0);
62 (void) usleep(100 * USEC_PER_MSEC);
63
64 assert_se(asprintf(&suffixed2, "%s.%" PRIx64, d, random_u64()) >= 0);
65 assert_se(symlink(suffixed2, d) >= 0);
66 (void) usleep(100 * USEC_PER_MSEC);
67
68 assert_se(symlink(basename(suffixed), suffixed2) >= 0);
69 (void) usleep(100 * USEC_PER_MSEC);
70
71 strncpy(u.un.sun_path, path, sizeof(u.un.sun_path));
72
73 fd = socket(AF_UNIX, SOCK_STREAM|SOCK_CLOEXEC, 0);
74 assert_se(fd >= 0);
75
76 assert_se(bind(fd, &u.sa, SOCKADDR_UN_LEN(u.un)) >= 0);
77 usleep(100 * USEC_PER_MSEC);
78
79 assert_se(listen(fd, SOMAXCONN) >= 0);
80 usleep(100 * USEC_PER_MSEC);
81
82 assert_se(touch(path) >= 0);
83 usleep(100 * USEC_PER_MSEC);
84
85 log_debug("Initialized server");
86
87 for (;;) {
88 _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL;
89 _cleanup_(sd_event_unrefp) sd_event *event = NULL;
90 sd_id128_t id;
91 int bus_fd, code;
92
93 assert_se(sd_id128_randomize(&id) >= 0);
94
95 assert_se(sd_event_new(&event) >= 0);
96
97 bus_fd = accept4(fd, NULL, NULL, SOCK_NONBLOCK|SOCK_CLOEXEC);
98 assert_se(bus_fd >= 0);
99
100 log_debug("Accepted server connection");
101
102 assert_se(sd_bus_new(&bus) >= 0);
103 assert_se(sd_bus_set_description(bus, "server") >= 0);
104 assert_se(sd_bus_set_fd(bus, bus_fd, bus_fd) >= 0);
105 assert_se(sd_bus_set_server(bus, true, id) >= 0);
106 /* assert_se(sd_bus_set_anonymous(bus, true) >= 0); */
107
108 assert_se(sd_bus_attach_event(bus, event, 0) >= 0);
109
110 assert_se(sd_bus_add_object_vtable(bus, NULL, "/foo", "foo.TestInterface", vtable, NULL) >= 0);
111
112 assert_se(sd_bus_start(bus) >= 0);
113
114 assert_se(sd_event_loop(event) >= 0);
115
116 assert_se(sd_event_get_exit_code(event, &code) >= 0);
117
118 if (code > 0)
119 break;
120 }
121
122 log_debug("Server done");
123
124 return NULL;
125}
126
127static void* thread_client1(void *p) {
128 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
129 _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL;
130 const char *path = p, *t;
131 int r;
132
133 log_debug("Initializing client1");
134
135 assert_se(sd_bus_new(&bus) >= 0);
136 assert_se(sd_bus_set_description(bus, "client1") >= 0);
137
138 t = strjoina("unix:path=", path);
139 assert_se(sd_bus_set_address(bus, t) >= 0);
140 assert_se(sd_bus_set_watch_bind(bus, true) >= 0);
141 assert_se(sd_bus_start(bus) >= 0);
142
143 r = sd_bus_call_method(bus, "foo.bar", "/foo", "foo.TestInterface", "Foobar", &error, NULL, NULL);
144 assert_se(r >= 0);
145
146 log_debug("Client1 done");
147
148 return NULL;
149}
150
151static int client2_callback(sd_bus_message *m, void *userdata, sd_bus_error *ret_error) {
152 assert_se(sd_bus_message_is_method_error(m, NULL) == 0);
153 assert_se(sd_event_exit(sd_bus_get_event(sd_bus_message_get_bus(m)), 0) >= 0);
154 return 0;
155}
156
157static void* thread_client2(void *p) {
158 _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL;
159 _cleanup_(sd_event_unrefp) sd_event *event = NULL;
160 const char *path = p, *t;
161
162 log_debug("Initializing client2");
163
164 assert_se(sd_event_new(&event) >= 0);
165 assert_se(sd_bus_new(&bus) >= 0);
166 assert_se(sd_bus_set_description(bus, "client2") >= 0);
167
168 t = strjoina("unix:path=", path);
169 assert_se(sd_bus_set_address(bus, t) >= 0);
170 assert_se(sd_bus_set_watch_bind(bus, true) >= 0);
171 assert_se(sd_bus_attach_event(bus, event, 0) >= 0);
172 assert_se(sd_bus_start(bus) >= 0);
173
174 assert_se(sd_bus_call_method_async(bus, NULL, "foo.bar", "/foo", "foo.TestInterface", "Foobar", client2_callback, NULL, NULL) >= 0);
175
176 assert_se(sd_event_loop(event) >= 0);
177
178 log_debug("Client2 done");
179
180 return NULL;
181}
182
183static void request_exit(const char *path) {
184 _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL;
185 const char *t;
186
187 assert_se(sd_bus_new(&bus) >= 0);
188
189 t = strjoina("unix:path=", path);
190 assert_se(sd_bus_set_address(bus, t) >= 0);
191 assert_se(sd_bus_set_watch_bind(bus, true) >= 0);
192 assert_se(sd_bus_set_description(bus, "request-exit") >= 0);
193 assert_se(sd_bus_start(bus) >= 0);
194
195 assert_se(sd_bus_call_method(bus, "foo.bar", "/foo", "foo.TestInterface", "Exit", NULL, NULL, NULL) >= 0);
196}
197
198int main(int argc, char *argv[]) {
199 _cleanup_(rm_rf_physical_and_freep) char *d = NULL;
200 pthread_t server, client1, client2;
201 char *path;
202
203 log_set_max_level(LOG_DEBUG);
204
205 /* We use /dev/shm here rather than /tmp, since some weird distros might set up /tmp as some weird fs that
206 * doesn't support inotify properly. */
207 assert_se(mkdtemp_malloc("/dev/shm/systemd-watch-bind-XXXXXX", &d) >= 0);
208
209 path = strjoina(d, "/this/is/a/socket");
210
211 assert_se(pthread_create(&server, NULL, thread_server, path) == 0);
212 assert_se(pthread_create(&client1, NULL, thread_client1, path) == 0);
213 assert_se(pthread_create(&client2, NULL, thread_client2, path) == 0);
214
215 assert_se(pthread_join(client1, NULL) == 0);
216 assert_se(pthread_join(client2, NULL) == 0);
217
218 request_exit(path);
219
220 assert_se(pthread_join(server, NULL) == 0);
221
222 return 0;
223}