15 #include <sys/eventfd.h>
17 #include "kdbus-api.h"
18 #include "kdbus-test.h"
19 #include "kdbus-util.h"
20 #include "kdbus-enum.h"
22 static struct kdbus_conn *conn_a, *conn_b;
23 static unsigned int cookie = 0xdeadbeef;
25 static void nop_handler(int sig) {}
27 static int interrupt_sync(struct kdbus_conn *conn_src,
28 struct kdbus_conn *conn_dst)
32 struct kdbus_msg *msg = NULL;
33 struct sigaction sa = {
34 .sa_handler = nop_handler,
35 .sa_flags = SA_NOCLDSTOP|SA_RESTART,
40 ASSERT_RETURN_VAL(pid >= 0, pid);
43 ret = sigaction(SIGINT, &sa, NULL);
44 ASSERT_EXIT(ret == 0);
46 ret = kdbus_msg_send_sync(conn_dst, NULL, cookie,
47 KDBUS_MSG_EXPECT_REPLY,
48 100000000ULL, 0, conn_src->id, -1);
49 ASSERT_EXIT(ret == -ETIMEDOUT);
54 ret = kdbus_msg_recv_poll(conn_src, 100, &msg, NULL);
55 ASSERT_RETURN(ret == 0 && msg->cookie == cookie);
59 ret = kill(pid, SIGINT);
60 ASSERT_RETURN_VAL(ret == 0, ret);
62 ret = waitpid(pid, &status, 0);
63 ASSERT_RETURN_VAL(ret >= 0, ret);
65 if (WIFSIGNALED(status))
68 ret = kdbus_msg_recv_poll(conn_src, 100, NULL, NULL);
69 ASSERT_RETURN(ret == -ETIMEDOUT);
71 return (status == EXIT_SUCCESS) ? TEST_OK : TEST_ERR;
74 static int close_epipe_sync(const char *bus)
78 struct kdbus_conn *conn_src;
79 struct kdbus_conn *conn_dst;
80 struct kdbus_msg *msg = NULL;
82 conn_src = kdbus_hello(bus, 0, NULL, 0);
83 ASSERT_RETURN(conn_src);
85 ret = kdbus_add_match_empty(conn_src);
86 ASSERT_RETURN(ret == 0);
88 conn_dst = kdbus_hello(bus, 0, NULL, 0);
89 ASSERT_RETURN(conn_dst);
93 ASSERT_RETURN_VAL(pid >= 0, pid);
98 /* close our reference */
99 dst_id = conn_dst->id;
100 kdbus_conn_free(conn_dst);
102 ret = kdbus_msg_recv_poll(conn_src, 100, &msg, NULL);
103 ASSERT_EXIT(ret == 0 && msg->cookie == cookie);
104 ASSERT_EXIT(msg->src_id == dst_id);
107 ret = kdbus_msg_send_sync(conn_src, NULL, cookie,
108 KDBUS_MSG_EXPECT_REPLY,
109 100000000ULL, 0, dst_id, -1);
110 ASSERT_EXIT(ret == -EPIPE);
115 ret = kdbus_msg_send(conn_dst, NULL, cookie, 0, 0, 0,
116 KDBUS_DST_ID_BROADCAST, 0, NULL);
117 ASSERT_RETURN(ret == 0);
120 ret = kdbus_msg_recv_poll(conn_dst, 100, &msg, NULL);
121 ASSERT_RETURN(ret == 0 && msg->cookie == cookie);
125 /* destroy connection */
126 kdbus_conn_free(conn_dst);
127 kdbus_conn_free(conn_src);
129 ret = waitpid(pid, &status, 0);
130 ASSERT_RETURN_VAL(ret >= 0, ret);
132 if (!WIFEXITED(status))
135 return (status == EXIT_SUCCESS) ? TEST_OK : TEST_ERR;
138 static int cancel_fd_sync(struct kdbus_conn *conn_src,
139 struct kdbus_conn *conn_dst)
144 uint64_t counter = 1;
145 struct kdbus_msg *msg = NULL;
147 cancel_fd = eventfd(0, 0);
148 ASSERT_RETURN_VAL(cancel_fd >= 0, cancel_fd);
152 ASSERT_RETURN_VAL(pid >= 0, pid);
155 ret = kdbus_msg_send_sync(conn_dst, NULL, cookie,
156 KDBUS_MSG_EXPECT_REPLY,
157 100000000ULL, 0, conn_src->id,
159 ASSERT_EXIT(ret == -ECANCELED);
164 ret = kdbus_msg_recv_poll(conn_src, 100, &msg, NULL);
165 ASSERT_RETURN(ret == 0 && msg->cookie == cookie);
169 ret = write(cancel_fd, &counter, sizeof(counter));
170 ASSERT_RETURN(ret == sizeof(counter));
172 ret = waitpid(pid, &status, 0);
173 ASSERT_RETURN_VAL(ret >= 0, ret);
175 if (WIFSIGNALED(status))
178 return (status == EXIT_SUCCESS) ? TEST_OK : TEST_ERR;
181 static int no_cancel_sync(struct kdbus_conn *conn_src,
182 struct kdbus_conn *conn_dst)
187 struct kdbus_msg *msg = NULL;
189 /* pass eventfd, but never signal it so it shouldn't have any effect */
191 cancel_fd = eventfd(0, 0);
192 ASSERT_RETURN_VAL(cancel_fd >= 0, cancel_fd);
196 ASSERT_RETURN_VAL(pid >= 0, pid);
199 ret = kdbus_msg_send_sync(conn_dst, NULL, cookie,
200 KDBUS_MSG_EXPECT_REPLY,
201 100000000ULL, 0, conn_src->id,
203 ASSERT_EXIT(ret == 0);
208 ret = kdbus_msg_recv_poll(conn_src, 100, &msg, NULL);
209 ASSERT_RETURN_VAL(ret == 0 && msg->cookie == cookie, -1);
213 ret = kdbus_msg_send_reply(conn_src, cookie, conn_dst->id);
214 ASSERT_RETURN_VAL(ret >= 0, ret);
216 ret = waitpid(pid, &status, 0);
217 ASSERT_RETURN_VAL(ret >= 0, ret);
219 if (WIFSIGNALED(status))
222 return (status == EXIT_SUCCESS) ? 0 : -1;
225 static void *run_thread_reply(void *data)
228 unsigned long status = TEST_OK;
230 ret = kdbus_msg_recv_poll(conn_a, 3000, NULL, NULL);
234 kdbus_printf("Thread received message, sending reply ...\n");
236 /* using an unknown cookie must fail */
237 ret = kdbus_msg_send_reply(conn_a, ~cookie, conn_b->id);
243 ret = kdbus_msg_send_reply(conn_a, cookie, conn_b->id);
251 return (void *) status;
254 int kdbus_test_sync_reply(struct kdbus_test_env *env)
256 unsigned long status;
260 conn_a = kdbus_hello(env->buspath, 0, NULL, 0);
261 conn_b = kdbus_hello(env->buspath, 0, NULL, 0);
262 ASSERT_RETURN(conn_a && conn_b);
264 pthread_create(&thread, NULL, run_thread_reply, NULL);
266 ret = kdbus_msg_send_sync(conn_b, NULL, cookie,
267 KDBUS_MSG_EXPECT_REPLY,
268 5000000000ULL, 0, conn_a->id, -1);
270 pthread_join(thread, (void *) &status);
271 ASSERT_RETURN(status == 0);
272 ASSERT_RETURN(ret == 0);
274 ret = interrupt_sync(conn_a, conn_b);
275 ASSERT_RETURN(ret == 0);
277 ret = close_epipe_sync(env->buspath);
278 ASSERT_RETURN(ret == 0);
280 ret = cancel_fd_sync(conn_a, conn_b);
281 ASSERT_RETURN(ret == 0);
283 ret = no_cancel_sync(conn_a, conn_b);
284 ASSERT_RETURN(ret == 0);
286 kdbus_printf("-- closing bus connections\n");
288 kdbus_conn_free(conn_a);
289 kdbus_conn_free(conn_b);
294 #define BYEBYE_ME ((void*)0L)
295 #define BYEBYE_THEM ((void*)1L)
297 static void *run_thread_byebye(void *data)
299 struct kdbus_cmd cmd_byebye = { .size = sizeof(cmd_byebye) };
302 ret = kdbus_msg_recv_poll(conn_a, 3000, NULL, NULL);
304 kdbus_printf("Thread received message, invoking BYEBYE ...\n");
305 kdbus_msg_recv(conn_a, NULL, NULL);
306 if (data == BYEBYE_ME)
307 kdbus_cmd_byebye(conn_b->fd, &cmd_byebye);
308 else if (data == BYEBYE_THEM)
309 kdbus_cmd_byebye(conn_a->fd, &cmd_byebye);
316 int kdbus_test_sync_byebye(struct kdbus_test_env *env)
322 * This sends a synchronous message to a thread, which waits until it
323 * received the message and then invokes BYEBYE on the *ORIGINAL*
324 * connection. That is, on the same connection that synchronously waits
326 * This should properly wake the connection up and cause ECONNRESET as
327 * the connection is disconnected now.
329 * The second time, we do the same but invoke BYEBYE on the *TARGET*
330 * connection. This should also wake up the synchronous sender as the
331 * reply cannot be sent by a disconnected target.
334 conn_a = kdbus_hello(env->buspath, 0, NULL, 0);
335 conn_b = kdbus_hello(env->buspath, 0, NULL, 0);
336 ASSERT_RETURN(conn_a && conn_b);
338 pthread_create(&thread, NULL, run_thread_byebye, BYEBYE_ME);
340 ret = kdbus_msg_send_sync(conn_b, NULL, cookie,
341 KDBUS_MSG_EXPECT_REPLY,
342 5000000000ULL, 0, conn_a->id, -1);
344 ASSERT_RETURN(ret == -ECONNRESET);
346 pthread_join(thread, NULL);
348 kdbus_conn_free(conn_a);
349 kdbus_conn_free(conn_b);
351 conn_a = kdbus_hello(env->buspath, 0, NULL, 0);
352 conn_b = kdbus_hello(env->buspath, 0, NULL, 0);
353 ASSERT_RETURN(conn_a && conn_b);
355 pthread_create(&thread, NULL, run_thread_byebye, BYEBYE_THEM);
357 ret = kdbus_msg_send_sync(conn_b, NULL, cookie,
358 KDBUS_MSG_EXPECT_REPLY,
359 5000000000ULL, 0, conn_a->id, -1);
361 ASSERT_RETURN(ret == -EPIPE);
363 pthread_join(thread, NULL);
365 kdbus_conn_free(conn_a);
366 kdbus_conn_free(conn_b);