From b901cbc4d84bd4eb5dbb27dabc329ba03457274a Mon Sep 17 00:00:00 2001 From: Kartik Naik Date: Wed, 15 Jul 2026 15:48:00 +0530 Subject: poll_win: restore fd_sets before each select() retry select() strips not-ready descriptors from the fd_sets, so a timed-out pass leaves them empty and the next pass calls select() with three empty sets, which Windows rejects with WSAEINVAL. Keep a pristine copy and restore it before each retry so an idle socket waits out the timeout. --- apps/openssl/compat/poll_win.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/apps/openssl/compat/poll_win.c b/apps/openssl/compat/poll_win.c index c518962..0d15522 100644 --- a/apps/openssl/compat/poll_win.c +++ b/apps/openssl/compat/poll_win.c @@ -166,6 +166,7 @@ poll(struct pollfd *pfds, nfds_t nfds, int timeout_ms) * select machinery */ fd_set rfds, wfds, efds; + fd_set rfds_in, wfds_in, efds_in; int rc; int num_sockets; @@ -250,12 +251,27 @@ poll(struct pollfd *pfds, nfds_t nfds, int timeout_ms) looptime_ms = (timeout_ms > 100 || timeout_ms == -1) ? 100 : timeout_ms; + /* + * select() clears every descriptor that is not ready from the + * fd_sets, so a pass that times out leaves them empty. Keep a + * pristine copy and restore it before each select(), otherwise the + * next pass hands select() three empty sets and Windows fails it with + * WSAEINVAL instead of waiting out the remaining timeout. + */ + rfds_in = rfds; + wfds_in = wfds; + efds_in = efds; + do { TIMEVAL tv; tv.tv_sec = 0; tv.tv_usec = looptime_ms * 1000; int handle_signaled = 0; + rfds = rfds_in; + wfds = wfds_in; + efds = efds_in; + /* * Check if any file handles have signaled */ -- cgit v1.2.3-55-g6feb