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