diff --git a/NEWS b/NEWS index 2595e055ddfe..40209f92bf99 100644 --- a/NEWS +++ b/NEWS @@ -85,6 +85,8 @@ PHP NEWS - Streams: . Applied the so_linger, so_rcvbuf and so_sndbuf context options to unix sockets. (David Carlier) + . stream_socket_accept() no longer reports an error on a zero timeout with no + pending connection (GH-23879). (Lazizbek Ergashev) - Standard: . Fixed bug #60110 (fclose(), file_put_contents(), copy() do not return false diff --git a/UPGRADING b/UPGRADING index a6cdf9829ab1..67a462c4c964 100644 --- a/UPGRADING +++ b/UPGRADING @@ -28,6 +28,8 @@ PHP 8.7 UPGRADE NOTES . The number of filters that can be chained in a php://filter URL is limited to 16 by default. Set the stream context option max_filter_count to change this. + . stream_socket_accept() no longer reports an error when the timeout is 0 + and no connection is pending. It still returns false. ======================================== 2. New Features diff --git a/ext/standard/streamsfuncs.c b/ext/standard/streamsfuncs.c index 6502ac279e26..e9d7345a1bf4 100644 --- a/ext/standard/streamsfuncs.c +++ b/ext/standard/streamsfuncs.c @@ -314,7 +314,12 @@ PHP_FUNCTION(stream_socket_accept) php_stream_error_operation_begin(); - if (0 == php_stream_xport_accept(stream, &clistream, + php_socket_t fd; + if (tv_pointer && tv.tv_sec == 0 && tv.tv_usec == 0 + && SUCCESS == php_stream_cast(stream, PHP_STREAM_AS_FD_FOR_SELECT | PHP_STREAM_CAST_INTERNAL, (void*)&fd, 0) + && fd != SOCK_ERR && php_pollfd_for_ms(fd, PHP_POLLREADABLE, 0) == 0) { + RETVAL_FALSE; + } else if (0 == php_stream_xport_accept(stream, &clistream, zpeername ? &peername : NULL, NULL, NULL, tv_pointer, &errstr diff --git a/ext/standard/tests/streams/gh23879.phpt b/ext/standard/tests/streams/gh23879.phpt new file mode 100644 index 000000000000..fe6fe0dddc12 --- /dev/null +++ b/ext/standard/tests/streams/gh23879.phpt @@ -0,0 +1,41 @@ +--TEST-- +GH-23879 (stream_socket_accept() reports AcceptFailed when no connection is pending) +--FILE-- + [ + 'error_mode' => StreamErrorMode::Exception, + 'error_store' => StreamErrorStore::All, + ], + ]), +); +stream_set_blocking($server, false); + +var_dump(stream_socket_accept($server, 0)); +var_dump(stream_last_errors()); + +$client = stream_socket_client('tcp://' . stream_socket_get_name($server, false)); +var_dump(is_resource(stream_socket_accept($server, 1))); +var_dump(stream_socket_accept($server, 0)); + +stream_set_blocking($server, true); +var_dump(stream_socket_accept($server, 0)); + +try { + stream_socket_accept($server, 0.1); +} catch (StreamException $e) { + echo $e->getMessage(), "\n"; + echo $e->getErrors()[0]->code->name, "\n"; +} +?> +--EXPECTF-- +bool(false) +array(0) { +} +bool(true) +bool(false) +bool(false) +Accept failed: %s +AcceptFailed