Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions NEWS
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,9 @@ 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 and reports TimeOut instead of AcceptFailed on other
timeouts (GH-23879). (Lazizbek Ergashev)

- Standard:
. Fixed bug #60110 (fclose(), file_put_contents(), copy() do not return false
Expand Down
3 changes: 3 additions & 0 deletions UPGRADING
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,9 @@ 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. When a non-zero
timeout expires, the error code is now TimeOut instead of AcceptFailed.

========================================
2. New Features
Expand Down
3 changes: 3 additions & 0 deletions UPGRADING.INTERNALS
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,9 @@ PHP 8.7 INTERNALS UPGRADE NOTES
- The INIT_CLASS_ENTRY_INIT_METHODS() macro, which was previously used as
part of handling disabled classes, was removed following the removal of
the `disable_classes` INI setting in PHP 8.5.
- php_stream_xport_accept() now returns 0 with a NULL client when no
connection is pending before the timeout. Callers must check the client,
not only the return value.

========================
2. Build system changes
Expand Down
4 changes: 4 additions & 0 deletions ext/openssl/xp_ssl.c
Original file line number Diff line number Diff line change
Expand Up @@ -3557,6 +3557,10 @@ static inline int php_openssl_tcp_sockop_accept(php_stream *stream, php_openssl_
}
}
}
} else if (xparam->outputs.error_code == PHP_TIMEOUT_ERROR_VALUE
|| PHP_IS_TRANSIENT_ERROR(xparam->outputs.error_code)) {
/* No pending connection, the caller decides how to report it. */
return 0;
}

return xparam->outputs.client == NULL ? -1 : 0;
Expand Down
12 changes: 9 additions & 3 deletions ext/standard/streamsfuncs.c
Original file line number Diff line number Diff line change
Expand Up @@ -314,11 +314,13 @@ PHP_FUNCTION(stream_socket_accept)

php_stream_error_operation_begin();

if (0 == php_stream_xport_accept(stream, &clistream,
int ret = php_stream_xport_accept(stream, &clistream,
zpeername ? &peername : NULL,
NULL, NULL,
tv_pointer, &errstr
) && clistream) {
);

if (0 == ret && clistream) {

if (peername) {
ZEND_TRY_ASSIGN_REF_STR(zpeername, peername);
Expand All @@ -328,7 +330,11 @@ PHP_FUNCTION(stream_socket_accept)
if (peername) {
zend_string_release(peername);
}
php_stream_warn(stream, AcceptFailed, "Accept failed: %s", errstr ? ZSTR_VAL(errstr) : "Unknown error");
if (0 != ret) {
php_stream_warn(stream, AcceptFailed, "Accept failed: %s", errstr ? ZSTR_VAL(errstr) : "Unknown error");
} else if (!tv_pointer || tv.tv_sec || tv.tv_usec) {
php_stream_warn(stream, TimeOut, "Accept failed: %s", errstr ? ZSTR_VAL(errstr) : "Unknown error");
}
RETVAL_FALSE;
}

Expand Down
41 changes: 41 additions & 0 deletions ext/standard/tests/streams/gh23879.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
--TEST--
GH-23879 (stream_socket_accept() reports AcceptFailed when no connection is pending)
--FILE--
<?php
$server = stream_socket_server(
'tcp://127.0.0.1:0',
context: stream_context_create([
'stream' => [
'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
TimeOut
2 changes: 0 additions & 2 deletions main/network.c
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,6 @@
# include "win32/time.h"
# define SOCK_ERR INVALID_SOCKET
# define SOCK_CONN_ERR SOCKET_ERROR
# define PHP_TIMEOUT_ERROR_VALUE WSAETIMEDOUT

#ifdef HAVE_IPV6
const struct in6_addr in6addr_any = {0}; /* IN6ADDR_ANY_INIT; */
Expand All @@ -78,7 +77,6 @@ const struct in6_addr in6addr_any = {0}; /* IN6ADDR_ANY_INIT; */
#else
# define SOCK_ERR -1
# define SOCK_CONN_ERR -1
# define PHP_TIMEOUT_ERROR_VALUE ETIMEDOUT
#endif

#ifdef HAVE_GETADDRINFO
Expand Down
2 changes: 2 additions & 0 deletions main/php_network.h
Original file line number Diff line number Diff line change
Expand Up @@ -109,10 +109,12 @@ typedef int php_socket_t;
# define SOCK_ERR INVALID_SOCKET
# define SOCK_CONN_ERR SOCKET_ERROR
# define SOCK_RECV_ERR SOCKET_ERROR
# define PHP_TIMEOUT_ERROR_VALUE WSAETIMEDOUT
#else
# define SOCK_ERR -1
# define SOCK_CONN_ERR -1
# define SOCK_RECV_ERR -1
# define PHP_TIMEOUT_ERROR_VALUE ETIMEDOUT
#endif

#define STREAM_SOCKOP_NONE (1 << 0)
Expand Down
4 changes: 4 additions & 0 deletions main/streams/xp_socket.c
Original file line number Diff line number Diff line change
Expand Up @@ -1078,6 +1078,10 @@ static inline int php_tcp_sockop_accept(php_stream *stream, php_netstream_data_t
GC_ADDREF(stream->ctx);
}
}
} else if (xparam->outputs.error_code == PHP_TIMEOUT_ERROR_VALUE
|| PHP_IS_TRANSIENT_ERROR(xparam->outputs.error_code)) {
/* No pending connection, the caller decides how to report it. */
return 0;
}

return xparam->outputs.client == NULL ? -1 : 0;
Expand Down
Loading