sd-varlink: do not call disconnect callback for incomplete connection

The connect callback is called after sd_varlink_server_add_connection()
succeeds. Do not call the disconnect callback for connections that have
not been established yet.
This commit is contained in:
Yu Watanabe
2026-08-14 23:56:19 +09:00
parent db08fdbc33
commit 63da977f64
2 changed files with 21 additions and 5 deletions
+7 -5
View File
@@ -1773,7 +1773,7 @@ _public_ int sd_varlink_flush(sd_varlink *v) {
return json_stream_flush(&v->stream);
}
static void varlink_detach_server(sd_varlink *v) {
static void varlink_detach_server(sd_varlink *v, bool connected) {
sd_varlink_server *saved_server;
assert(v);
@@ -1808,7 +1808,7 @@ static void varlink_detach_server(sd_varlink *v) {
saved_server = TAKE_PTR(v->server);
if (saved_server->disconnect_callback)
if (saved_server->disconnect_callback && connected)
saved_server->disconnect_callback(saved_server, v, saved_server->userdata);
varlink_server_test_exit_on_idle(saved_server);
@@ -1822,12 +1822,14 @@ _public_ int sd_varlink_close(sd_varlink *v) {
if (v->state == VARLINK_DISCONNECTED)
return 0;
bool connected = v->state >= 0;
varlink_set_state(v, VARLINK_DISCONNECTED);
/* Let's take a reference first, since varlink_detach_server() might drop the final (dangling) ref
* which would destroy us before we can call varlink_clear() */
sd_varlink_ref(v);
varlink_detach_server(v);
varlink_detach_server(v, connected);
varlink_clear(v);
sd_varlink_unref(v);
@@ -3462,8 +3464,6 @@ _public_ int sd_varlink_server_add_connection_pair(
(void) sd_varlink_set_allow_fd_passing_input(v, FLAGS_SET(server->flags, SD_VARLINK_SERVER_ALLOW_FD_PASSING_INPUT));
(void) sd_varlink_set_allow_fd_passing_output(v, FLAGS_SET(server->flags, SD_VARLINK_SERVER_ALLOW_FD_PASSING_OUTPUT));
varlink_set_state(v, VARLINK_IDLE_SERVER);
if (server->event) {
r = sd_varlink_attach_event(v, server->event, server->event_priority);
if (r < 0) {
@@ -3479,6 +3479,8 @@ _public_ int sd_varlink_server_add_connection_pair(
}
}
varlink_set_state(v, VARLINK_IDLE_SERVER);
(void) mark_varlink_socket(input_fd, /* path= */ NULL, "server");
if (ret)
+14
View File
@@ -1504,6 +1504,12 @@ TEST(ctrunc) {
ASSERT_OK(r);
}
static void disconnect_callback(sd_varlink_server *server, sd_varlink *link, void *userdata) {
unsigned *counter = ASSERT_PTR(userdata);
(*counter)++;
}
TEST(add_connection_failure_cleanup) {
_cleanup_(sd_varlink_server_unrefp) sd_varlink_server *s = NULL;
_cleanup_close_pair_ int fds[2] = EBADF_PAIR;
@@ -1514,6 +1520,11 @@ TEST(add_connection_failure_cleanup) {
};
ASSERT_OK(sd_varlink_server_new(&s, SD_VARLINK_SERVER_ACCOUNT_UID));
unsigned c = 0;
ASSERT_OK(sd_varlink_server_bind_disconnect(s, disconnect_callback));
ASSERT_NULL(sd_varlink_server_set_userdata(s, &c));
ASSERT_OK(sd_varlink_server_set_connections_per_uid_max(s, 1));
ASSERT_OK_ERRNO(socketpair(AF_UNIX, SOCK_STREAM|SOCK_CLOEXEC, 0, fds));
@@ -1522,15 +1533,18 @@ TEST(add_connection_failure_cleanup) {
ASSERT_ERROR(sd_varlink_server_add_connection_pair(s, fds[0], bad_fd, &ucred, /* ret= */ NULL), EBADF);
ASSERT_EQ(sd_varlink_server_current_connections(s), 0U);
ASSERT_EQ(c, 0U); /* The disconnect callback is not called. */
sd_varlink *v = NULL;
ASSERT_OK(sd_varlink_server_add_connection(s, fds[0], &v));
TAKE_FD(fds[0]);
ASSERT_NOT_NULL(v);
ASSERT_EQ(sd_varlink_server_current_connections(s), 1U);
ASSERT_EQ(c, 0U); /* The disconnect callback is not called yet. */
ASSERT_OK_POSITIVE(sd_varlink_close(v));
ASSERT_EQ(sd_varlink_server_current_connections(s), 0U);
ASSERT_EQ(c, 1U); /* The disconnect callback is called when the connection is closed. */
}
DEFINE_TEST_MAIN(LOG_DEBUG);