From b5ac78b5fdef9c288f32f6d8aa29a833c799e888 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20Svensson?= Date: Tue, 31 Mar 2026 13:26:01 +0200 Subject: [PATCH 1/2] Apply connect_timeout to TLS handshake MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit SSL_connect() blocks indefinitely when connecting with TLS to a non-TLS server. Apply the connect_timeout as a socket timeout around the SSL_connect() call for blocking connections. Signed-off-by: Björn Svensson --- src/tls.c | 15 +++++++++++++++ tests/client_test.c | 31 +++++++++++++++++++++++++++++++ 2 files changed, 46 insertions(+) diff --git a/src/tls.c b/src/tls.c index 83b34e9f..82f505a2 100644 --- a/src/tls.c +++ b/src/tls.c @@ -376,7 +376,22 @@ static int valkeyTLSConnect(valkeyContext *c, SSL *ssl) { ERR_clear_error(); + /* Apply connect_timeout to the TLS handshake. */ + if ((c->flags & VALKEY_BLOCK) && c->connect_timeout != NULL) + c->funcs->set_timeout(c, *c->connect_timeout); + int rv = SSL_connect(rssl->ssl); + + /* Restore the command_timeout. */ + if ((c->flags & VALKEY_BLOCK) && c->connect_timeout != NULL) { + if (c->command_timeout != NULL) { + c->funcs->set_timeout(c, *c->command_timeout); + } else { + struct timeval tv_zero = {0, 0}; + c->funcs->set_timeout(c, tv_zero); + } + } + if (rv == 1) { c->funcs = &valkeyContextTLSFuncs; c->privctx = rssl; diff --git a/tests/client_test.c b/tests/client_test.c index 4d2f477a..adb3d58d 100644 --- a/tests/client_test.c +++ b/tests/client_test.c @@ -2676,6 +2676,36 @@ static void sharded_pubsub_test(struct config cfg) { } #endif /* VALKEY_TEST_ASYNC */ +#ifdef VALKEY_TEST_TLS +/* Test that a TLS handshake to a non-TLS server times out using + * connect_timeout rather than hanging indefinitely. */ +static void test_tls_handshake_timeout(struct config config) { + test("TLS handshake to non-TLS port times out with connect_timeout: "); + +#ifndef _WIN32 + /* Abort the test after 5 seconds. */ + unsigned int old_alarm = alarm(5); +#endif + + struct timeval tv = {0, 100000}; /* 100ms */ + valkeyOptions opt = {0}; + VALKEY_OPTIONS_SET_TCP(&opt, config.tcp.host, config.tcp.port); /* TCP */ + opt.connect_timeout = &tv; + /* No command timeout set. */ + + valkeyContext *c = valkeyConnectWithOptions(&opt); + assert(c != NULL && c->err == 0); + + int rc = valkeyInitiateTLSWithContext(c, _tls_ctx); + test_cond(rc == VALKEY_ERR && c->err != 0); + valkeyFree(c); + +#ifndef _WIN32 + alarm(old_alarm); /* Reset any alarm. */ +#endif +} +#endif /* VALKEY_TEST_TLS */ + int main(int argc, char **argv) { struct config cfg = { .tcp = { @@ -2840,6 +2870,7 @@ int main(int argc, char **argv) { test_blocking_io_errors(cfg); test_invalid_timeout_errors(cfg); test_append_formatted_commands(cfg); + test_tls_handshake_timeout(cfg); if (throughput) test_throughput(cfg); From 861a715984fdcf71a55adde4b9a4922d3a6d958e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20Svensson?= Date: Tue, 31 Mar 2026 14:31:19 +0200 Subject: [PATCH 2/2] fixup: check c->funcs && c->funcs->set_timeout MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Björn Svensson --- src/tls.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/tls.c b/src/tls.c index 82f505a2..b95150ea 100644 --- a/src/tls.c +++ b/src/tls.c @@ -377,13 +377,16 @@ static int valkeyTLSConnect(valkeyContext *c, SSL *ssl) { ERR_clear_error(); /* Apply connect_timeout to the TLS handshake. */ - if ((c->flags & VALKEY_BLOCK) && c->connect_timeout != NULL) + if ((c->flags & VALKEY_BLOCK) && c->connect_timeout != NULL && + c->funcs && c->funcs->set_timeout) { c->funcs->set_timeout(c, *c->connect_timeout); + } int rv = SSL_connect(rssl->ssl); /* Restore the command_timeout. */ - if ((c->flags & VALKEY_BLOCK) && c->connect_timeout != NULL) { + if ((c->flags & VALKEY_BLOCK) && c->connect_timeout != NULL && + c->funcs && c->funcs->set_timeout) { if (c->command_timeout != NULL) { c->funcs->set_timeout(c, *c->command_timeout); } else {