Commit 0670df4cbb for openssl.org
commit 0670df4cbb543f5b23a4ecb6ff05fbbb5adb8e5f
Author: Matt Caswell <matt@openssl.foundation>
Date: Mon Aug 10 08:59:06 2026 +0100
Wait consistently across platforms when there is nothing to poll
poll_translate_ssl_dtls_conn() adds no file descriptor to the poll set when
the connection's BIO cannot supply one, which is the case for the memory and
datagram-pair BIOs the test suite is built on. Unlike the QUIC and DTLS
listener paths it does not report that as an error, and rightly so: a DTLS
connection with no pollable BIO has no readiness to wait for, but it still
has a retransmission deadline to wake for, so a wait with nothing to watch is
meaningful.
The resulting empty descriptor set was then handed to the operating system,
where the behaviour differs. poll() treats it as a plain sleep, so this
worked on Unix. Windows' select() rejects a call with no descriptors, so
ossl_rio_poll_builder_poll() returned failure and SSL_poll() failed with it.
Sleep out the deadline explicitly rather than relying on the platform. With
no descriptors and no deadline nothing could ever provide a wakeup, so that
combination is reported as a failure instead of sleeping for ever.
This has no test of its own: on any platform whose poll() already sleeps, the
behaviour before and after is identical, so only the Windows CI builds
distinguish them.
Assisted-by: Claude Code:claude-opus-5
Reviewed-by: Ryan Hooper <ryanh@openssl.foundation>
Reviewed-by: Tomas Mraz <tomas@openssl.foundation>
Merge-date: Fri Aug 14 15:45:41 2026
Merged-from: https://github.com/openssl/openssl/pull/32239
diff --git a/ssl/rio/poll_builder.c b/ssl/rio/poll_builder.c
index 8088b17ad7..61ded3f931 100644
--- a/ssl/rio/poll_builder.c
+++ b/ssl/rio/poll_builder.c
@@ -137,10 +137,40 @@ int ossl_rio_poll_builder_add_fd(RIO_POLL_BUILDER *rpb, int fd,
#endif
}
+/* Returns 1 if no file descriptors have been added to the poll builder. */
+static int rio_poll_builder_is_empty(const RIO_POLL_BUILDER *rpb)
+{
+#if RIO_POLL_METHOD == RIO_POLL_METHOD_SELECT
+ return rpb->hwm_fd < 0;
+#elif RIO_POLL_METHOD == RIO_POLL_METHOD_POLL
+ return rpb->pfd_num == 0;
+#else
+ return 1;
+#endif
+}
+
int ossl_rio_poll_builder_poll(RIO_POLL_BUILDER *rpb, OSSL_TIME deadline)
{
int rc;
+ /*
+ * Waiting with no file descriptors is legitimate: a DTLS connection whose
+ * BIO cannot provide a poll descriptor has no readiness to wait for, but
+ * still has a retransmission deadline to wake for. Handle that here rather
+ * than leaving it to the OS, because poll() treats an empty descriptor set
+ * as a plain sleep whereas Windows' select() rejects it outright.
+ *
+ * With no descriptors and no deadline nothing could ever wake us, so that
+ * is a caller error rather than an indefinite sleep.
+ */
+ if (rio_poll_builder_is_empty(rpb)) {
+ if (ossl_time_is_infinite(deadline))
+ return 0;
+
+ OSSL_sleep(ossl_time2ms(ossl_time_subtract(deadline, ossl_time_now())));
+ return 1;
+ }
+
#if RIO_POLL_METHOD == RIO_POLL_METHOD_SELECT
do {
struct timeval timeout, *p_timeout = &timeout;