Hello everyone,
I identified an issue related to the way the events FD_CONNECT and
FD_CLOSE returned by WSAEnumNetworkEvents are currently handled in
winsup/cygwin/fhandler_socket_inet.cc.
It seems like the code does not handle the fact that those events are
returned only once for a socket and if not acted upon by the calling
program may not be received again. This means poll and select are
currently not consistend about the socket still being writable after a
connect failure. The first call to poll or select would signal the
socket as writable, but not any following call. The first call consumes
the FD_CONNECT and FD_CLOSE events, regardless of the event mask
supplied by the calling program. So even if the calling program does not
care about writability in the first call, the events are consumed and
following calls checking for writability will not be able to detect a
connection failure.
A very simple test to reproduce can be made with the Cygwin provided
curl package. After installing with current Cygwin, issue the following
command to make it try connecting to a local non-listening port (eg. 47):
curl -v 127.0.0.1:47
With current Cygwin this will never timeout. An explanation of the curl
internals can be found here [1], but the short version is: curl waits on
sockets without checking/handling writability in a first poll call and
then after waiting, the writability (connection failure) is checked in a
second poll call per wait-loop iteration. Therefore curl can never
detect the connection failure in the second call, because the first call
already consumed the relevant events.
As far as I understand calling poll and/or select should not
change/reset the socket readyness state, therefore I created a simple
fix which could be used to solve this issue. Attached you will find a
suggested patch to make sure poll and select always signal writability
of a connection failed socket. With this patch applied the above example
command failed with a "Connection refused" as expected.
This patch only fixes the behaviour regarding connection failure (during
FD_CONNECT), I am not sure if connection closure (during FD_CLOSE) is
also affected, but I was not able to find code handling the fact that
FD_CLOSE is only signalled once.
Please take a look and thanks in advance!
Best regards,
Marc Hörsken
[1] https://github.com/curl/curl/pull/5509#issuecomment-658357933
From 7cd9d597a2a314c3aeb5b7c8aaa970ded6d56d7a Mon Sep 17 00:00:00 2001
From: Marc Hoersken <i...@marc-hoersken.de>
Date: Wed, 15 Jul 2020 20:53:21 +0200
Subject: [PATCH] Cygwin: make sure failed sockets always signal writability
Since FD_CONNECT is only given once, we manually need to set
FD_WRITE for connection failed sockets to have consistent
behaviour in programs calling poll/select multiple times.
Example test to non-listening port: curl -v 127.0.0.1:47
---
winsup/cygwin/fhandler_socket_inet.cc | 6 ++++++
1 file changed, 6 insertions(+)
diff --git a/winsup/cygwin/fhandler_socket_inet.cc
b/winsup/cygwin/fhandler_socket_inet.cc
index 74c415d..e5b0d2d 100644
--- a/winsup/cygwin/fhandler_socket_inet.cc
+++ b/winsup/cygwin/fhandler_socket_inet.cc
@@ -376,6 +376,12 @@ fhandler_socket_wsock::evaluate_events (const long
event_mask, long &events,
if (erase)
wsock_events->events &= ~(events & ~(FD_WRITE | FD_CLOSE));
}
+ /* Since FD_CONNECT is only given once, we manually need to set
+ FD_WRITE for connection failed sockets to have consistent
+ behaviour in programs calling poll/select multiple times.
+ Example test to non-listening port: curl -v 127.0.0.1:47 */
+ if ((connect_state () == connect_failed) && (event_mask & FD_WRITE))
+ wsock_events->events |= FD_WRITE;
UNLOCK_EVENTS;
return ret;
--
2.7.4
--
Problem reports: https://cygwin.com/problems.html
FAQ: https://cygwin.com/faq/
Documentation: https://cygwin.com/docs.html
Unsubscribe info: https://cygwin.com/ml/#unsubscribe-simple