Repository navigation
Conversation
php_network_connect_socket() switches the socket to non-blocking mode for the connect and restores the original mode afterwards for synchronous connects. On Windows, SET_SOCKET_BLOCKING_MODE() sets `save = TRUE` and FIONBIO does not write back the previous mode, so RESTORE_SOCKET_BLOCKING_MODE() set the socket to non-blocking again. Winsock cannot query a socket's blocking mode, but all callers pass freshly created (blocking) sockets, so restore to blocking. This matches the POSIX behavior. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
I m pretty sure the fix is incorrect, part of it is MSG_DONTWAIT is 0 on windows. @shivammathur wdyt ? |
Yes, you are right. Do you want me to withdraw this PR, or let Claude give another try? I'm not really sure what happened inside. |
|
I believe the bug is real so it s worth fixing. AI or not however having a real windows expert looking into it is valuable. |
|
@vibbow |
Windows has no MSG_DONTWAIT, so now that the socket is restored to blocking mode after a synchronous connect, send() could block past the stream timeout. Switch to non-blocking mode for the duration of a timed write and restore blocking mode afterwards, as xp_ssl.c does. This also fixes timed writes on accepted sockets and after stream_set_blocking(true), which were already blocking on Windows. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
@devnexen @shivammathur Thanks. I've updated it as suggested: the socket is still restored to blocking after a synchronous connect, and On Windows, |
A write that times out may still have written part of the chunk, so fwrite() returns a non-zero length. On macOS this happened on many iterations, and the test hit the run-tests timeout. Stop at the first write that reports a timeout instead. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The test still hit the run-tests timeout on macOS, although the fix is Windows only, so timed writes to a stalled loopback peer don't time out reliably there either way. The bug and the fix are Windows specific, so limit the test to Windows like gh24173.phpt. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
|
Fixes #24173.
php_network_connect_socket()switches the socket to non-blocking mode for the connect, and for a synchronous connect it is supposed to restore the original mode afterwards. On Windows,SET_SOCKET_BLOCKING_MODE()setssave = TRUE, andFIONBIOdoesn't write back the previous mode. SoRESTORE_SOCKET_BLOCKING_MODE()passedTRUEagain, and the socket stayed non-blocking while the stream reportedblocked => true. Paths that callrecv()without polling first, such asstream_socket_recvfrom()andsocket_import_stream()+socket_read(), then failed immediately withWSAEWOULDBLOCK.Winsock can't query a socket's blocking mode, but all callers of
php_network_connect_socket()pass freshly created sockets, which are blocking. So this restores to blocking, which matches the POSIX behavior. Async connects don't callRESTORE, so they are unaffected.Since Windows has no
MSG_DONTWAIT, timed writes relied on the socket being left non-blocking: with a blocking socket,send()inphp_sockop_write()could block past the stream timeout. Sophp_sockop_write()now switches to non-blocking mode for the duration of a timed write on Windows and restores blocking mode afterwards, likexp_ssl.cdoes. This also fixes timed writes on accepted sockets and afterstream_set_blocking($s, true), which were already blocking and hung on Windows before this change.Tests:
gh24173.phpt(Windows only): a socket imported from a client stream is blocking.gh24173_write_timeout.phpt(Windows only): a timedfwrite()to a peer that doesn't read times out, for both a client socket and an accepted socket.Tested on Windows 11 with an 8.4 NTS x64 build (built with php-windows-builder):
fwrite()withstream_set_timeout()ordefault_socket_timeouttimes out on client sockets, accepted sockets, and afterstream_set_blocking(true).stream_socket_recvfrom()andsocket_import_stream()+socket_read()wait for data.fread()/fgets()timeouts,feof()and non-blocking writes are unchanged.ext/standard/tests/streams,ext/standard/tests/networkandext/sockets/testshave the same results as before the change.Also tested on Ubuntu 26.04: the same test directories pass, and behavior is unchanged (the code changes are Windows only).
This is independent of #24172 (GH-24171), which touches the same function.
🤖 Generated with Claude Code