From 63da977f6413af7e5969da71f1fd89c5cc6680ec Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Thu, 13 Aug 2026 07:46:33 +0900 Subject: [PATCH] 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. --- src/libsystemd/sd-varlink/sd-varlink.c | 12 +++++++----- src/libsystemd/sd-varlink/test-varlink.c | 14 ++++++++++++++ 2 files changed, 21 insertions(+), 5 deletions(-) diff --git a/src/libsystemd/sd-varlink/sd-varlink.c b/src/libsystemd/sd-varlink/sd-varlink.c index f7de8b8f43..15c250fec3 100644 --- a/src/libsystemd/sd-varlink/sd-varlink.c +++ b/src/libsystemd/sd-varlink/sd-varlink.c @@ -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) diff --git a/src/libsystemd/sd-varlink/test-varlink.c b/src/libsystemd/sd-varlink/test-varlink.c index 41d5f53deb..ca43bcde90 100644 --- a/src/libsystemd/sd-varlink/test-varlink.c +++ b/src/libsystemd/sd-varlink/test-varlink.c @@ -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);