Skip to content

Windows does not report Connection refused for default StreamSelectLoop (requires exceptfds instead of writefds) #206

Closed
@clue

Description

@clue

When creating an async TCP/IP connection, the pending client socket has to be monitored to detect a successful connection or a "Connection refused" error. Unix-like operating systems use a writable event for both events (which is what ReactPHP currently assumes), whereas Windows uses a writable event for successful connections, but an exceptional event for connection refused events (https://docs.microsoft.com/de-de/windows/win32/api/winsock2/nf-winsock2-select?redirectedfrom=MSDN).

We currently only provide interfaces to monitor readable and writable events, with no way to monitor "exceptional" events (i.e. the exceptfds for the select call). This means that we can not currently detect refused connections on Windows using the default StreamSelectLoop. Higher-level components (like react/socket) may detect this as a timeout condition, but the immediate events is not currently reported.

It's not too hard to expose the exceptfds through our interfaces, but this would introduce a BC break and given its limited use cases is probably not worth it. Additionally, poll/epoll expose a POLLPRI/EPOLLPRI flag, but the higher-level event loop implementations do not seem to expose this.

As an alternative, I've researched ways to automatically add a connecting socket to both the writefds and the exceptfds structures automatically on Windows. This matches with how ExtEventLoop reports a writable events on Windows for this situation and thus matches behavior on other platforms. The major problem with this approach is that there does not appear to be reliable way to detect whether a socket is in a "pending connection" state. If a socket that is not in a pending connection state is added to the exceptfds structure, the select call may also report out-of-band TCP/IP data ("urgent data"). While somewhat rarely used in practice, this may affect normal program execution with specially crafted network packages.

I've stumbled upon this while writing some test cases to solve #188. I'm still working on a work-around for this and appreciate any input 👍

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions