From 9f2e187e25e0c524e4047bb169bda9b1e9cfb5a4 Mon Sep 17 00:00:00 2001 From: Timo Sirainen Date: Tue, 9 Jun 2026 20:41:14 +0000 Subject: [PATCH] login-common: Fix connection hanging if ostream write fails If the ostream write failed, the istream was closed. This prevented its IO callback from being called, so the connection was just stuck. This happaned at least with haproxy health check connections. --- src/login-common/client-common.c | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/src/login-common/client-common.c b/src/login-common/client-common.c index 1cc1b2dcbb..ec954d63f7 100644 --- a/src/login-common/client-common.c +++ b/src/login-common/client-common.c @@ -1649,6 +1649,11 @@ void client_notify_status(struct client *client, bool bad, const char *text) client->v.notify_status(client, bad, text); } +static void client_send_raw_data_destroy(struct client *client) +{ + client_destroy(client, "Disconnected: Output error"); +} + void client_common_send_raw_data(struct client *client, const void *data, size_t size) { @@ -1659,8 +1664,18 @@ void client_common_send_raw_data(struct client *client, /* either disconnection or buffer full. in either case we want this connection destroyed. however destroying it here might break things if client is still tried to be accessed without - being referenced.. */ + being referenced, so do it lazily from a timeout. */ + io_remove(&client->io); i_stream_close(client->input); + /* If the client is already being destroyed, don't schedule + another destroy. Its to_disconnect was already removed and + wouldn't be cleaned up again, leaking the timeout. */ + if (!client->destroyed) { + timeout_remove(&client->to_disconnect); + client->to_disconnect = + timeout_add_short(0, + client_send_raw_data_destroy, client); + } } } -- 2.47.3