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
14 changes: 7 additions & 7 deletions UPGRADING
Original file line number Diff line number Diff line change
Expand Up @@ -483,16 +483,16 @@ PHP 8.6 UPGRADE NOTES
tcp_keepintvl and tcp_keepcnt that allow setting socket keepalive
options.
. Added stream socket context option so_linger that sets SO_LINGER on TCP
sockets. A positive value enables lingering for that many seconds, zero
or a negative value disables it. Values above 65535 are clamped as the
and unix sockets. A positive value enables lingering for that many seconds,
zero or a negative value disables it. Values above 65535 are clamped as the
linger time is limited to an unsigned short on some platforms.
. Added stream socket context options so_rcvbuf and so_sndbuf that set the
socket receive and send buffer sizes in bytes (SO_RCVBUF and SO_SNDBUF) on
TCP and UDP sockets. The value must be an integer between 1 and 2147483647,
any other value makes the stream creation fail. The operating system may
round, cap or otherwise adjust the requested size, and may stop sizing that
buffer automatically, so the size read back can differ from the one
requested.
TCP, UDP, unix and unix datagram sockets. The value must be an integer
between 1 and 2147483647, any other value makes the stream creation fail.
The operating system may round, cap or otherwise adjust the requested size,
and may stop sizing that buffer automatically, so the size read back can
differ from the one requested.
. Allowed casting filtered streams as file descriptors for select.
. Added the "write_seek_mode" filter parameter for the bz2, iconv,
zlib, and string stream filters. This parameter must be set via an
Expand Down
85 changes: 85 additions & 0 deletions ext/standard/tests/network/so_linger_unix.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
--TEST--
stream_socket_server() and stream_socket_client() SO_LINGER context option test with unix sockets
--EXTENSIONS--
sockets
--SKIPIF--
<?php
if (array_search("unix", stream_get_transports()) === false) {
die('skip No support for UNIX domain sockets.');
}
?>
--FILE--
<?php
// macOS expresses SO_LINGER in ticks, SO_LINGER_SEC in seconds.
$so_linger = defined('SO_LINGER_SEC') ? SO_LINGER_SEC : SO_LINGER;

function linger($stream): array {
global $so_linger;

return socket_get_option(socket_import_stream($stream), SOL_SOCKET, $so_linger);
}

$server_path = sys_get_temp_dir() . '/' . uniqid('so_linger_server_') . '.sock';
$dgram_path = sys_get_temp_dir() . '/' . uniqid('so_linger_dgram_') . '.sock';

$server = stream_socket_server("unix://$server_path", $errno, $errstr,
STREAM_SERVER_BIND | STREAM_SERVER_LISTEN,
stream_context_create(['socket' => ['so_linger' => 10]]));

if (!$server) {
die('Unable to create server');
}

$client = stream_socket_client("unix://$server_path", $errno, $errstr, 30,
STREAM_CLIENT_CONNECT,
stream_context_create(['socket' => ['so_linger' => 8]]));

if (!$client) {
die('Unable to create client');
}

$accepted = stream_socket_accept($server, 1);

if (!$accepted) {
die('Unable to accept connection');
}

$listen_linger = linger($server);
echo "Listen SO_LINGER", PHP_EOL;
var_dump($listen_linger['l_onoff'] > 0);
var_dump($listen_linger['l_linger']);

$client_linger = linger($client);
echo "Client SO_LINGER", PHP_EOL;
var_dump($client_linger['l_onoff'] > 0);
var_dump($client_linger['l_linger']);

// The option is meaningless on datagram sockets and is not applied there.
$dgram = stream_socket_server("udg://$dgram_path", $errno, $errstr, STREAM_SERVER_BIND,
stream_context_create(['socket' => ['so_linger' => 10]]));

if (!$dgram) {
die('Unable to create server');
}

$dgram_linger = linger($dgram);
echo "Datagram SO_LINGER", PHP_EOL;
var_dump($dgram_linger['l_onoff'] > 0);

fclose($accepted);
fclose($client);
fclose($server);
fclose($dgram);
unlink($server_path);
unlink($dgram_path);

?>
--EXPECT--
Listen SO_LINGER
bool(true)
int(10)
Client SO_LINGER
bool(true)
int(8)
Datagram SO_LINGER
bool(false)
58 changes: 58 additions & 0 deletions ext/standard/tests/network/so_rcvbuf_sndbuf_udg.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
--TEST--
stream_socket_server() SO_RCVBUF and SO_SNDBUF context options test with unix datagram sockets
--EXTENSIONS--
sockets
--SKIPIF--
<?php
if (array_search("udg", stream_get_transports()) === false) {
die('skip No support for UNIX domain sockets.');
}
?>
--FILE--
<?php
function buffers($stream): array {
$sock = socket_import_stream($stream);
return [
socket_get_option($sock, SOL_SOCKET, SO_RCVBUF),
socket_get_option($sock, SOL_SOCKET, SO_SNDBUF),
];
}

$control_path = sys_get_temp_dir() . '/' . uniqid('so_buf_control_') . '.sock';
$server_path = sys_get_temp_dir() . '/' . uniqid('so_buf_server_') . '.sock';

$control = stream_socket_server("udg://$control_path", $errno, $errstr, STREAM_SERVER_BIND);

if (!$control) {
die('Unable to create server');
}

[$rcvbuf, $sndbuf] = buffers($control);

// Shrinking is always honoured, while growing may be capped by the system maximum.
$context = stream_context_create(['socket' => [
'so_rcvbuf' => intdiv($rcvbuf, 4),
'so_sndbuf' => intdiv($sndbuf, 4),
]]);

$server = stream_socket_server("udg://$server_path", $errno, $errstr, STREAM_SERVER_BIND, $context);

if (!$server) {
die('Unable to create server');
}

[$server_rcvbuf, $server_sndbuf] = buffers($server);
echo "Server buffers", PHP_EOL;
var_dump($server_rcvbuf < $rcvbuf);
var_dump($server_sndbuf < $sndbuf);

fclose($server);
fclose($control);
unlink($server_path);
unlink($control_path);

?>
--EXPECT--
Server buffers
bool(true)
bool(true)
108 changes: 108 additions & 0 deletions ext/standard/tests/network/so_rcvbuf_sndbuf_unix.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
--TEST--
stream_socket_server() and stream_socket_client() SO_RCVBUF and SO_SNDBUF context options test with unix sockets
--EXTENSIONS--
sockets
--SKIPIF--
<?php
if (array_search("unix", stream_get_transports()) === false) {
die('skip No support for UNIX domain sockets.');
}
?>
--FILE--
<?php
function buffers($stream): array {
$sock = socket_import_stream($stream);
return [
socket_get_option($sock, SOL_SOCKET, SO_RCVBUF),
socket_get_option($sock, SOL_SOCKET, SO_SNDBUF),
];
}

$control_path = sys_get_temp_dir() . '/' . uniqid('so_buf_control_') . '.sock';
$server_path = sys_get_temp_dir() . '/' . uniqid('so_buf_server_') . '.sock';

$control = stream_socket_server("unix://$control_path", $errno, $errstr,
STREAM_SERVER_BIND | STREAM_SERVER_LISTEN);

if (!$control) {
die('Unable to create server');
}

$control_client = stream_socket_client("unix://$control_path", $errno, $errstr, 30);

if (!$control_client) {
die('Unable to create client');
}

[$rcvbuf, $sndbuf] = buffers($control);
[$client_rcvbuf, $client_sndbuf] = buffers($control_client);

// Shrinking is always honoured, while growing may be capped by the system maximum.
function context(int $rcvbuf, int $sndbuf) {
return stream_context_create(['socket' => [
'so_rcvbuf' => intdiv($rcvbuf, 4),
'so_sndbuf' => intdiv($sndbuf, 4),
]]);
}

$server = stream_socket_server("unix://$server_path", $errno, $errstr,
STREAM_SERVER_BIND | STREAM_SERVER_LISTEN, context($rcvbuf, $sndbuf));

if (!$server) {
die('Unable to create server');
}

echo "Listen buffers", PHP_EOL;
[$listen_rcvbuf, $listen_sndbuf] = buffers($server);
var_dump($listen_rcvbuf < $rcvbuf);
var_dump($listen_sndbuf < $sndbuf);

$client = stream_socket_client("unix://$server_path", $errno, $errstr, 30,
STREAM_CLIENT_CONNECT, context($client_rcvbuf, $client_sndbuf));

if (!$client) {
die('Unable to create client');
}

$accepted = stream_socket_accept($server, 1);

if (!$accepted) {
die('Unable to accept connection');
}

echo "Client buffers", PHP_EOL;
[$rcvbuf2, $sndbuf2] = buffers($client);
var_dump($rcvbuf2 < $client_rcvbuf);
var_dump($sndbuf2 < $client_sndbuf);

$invalid = stream_context_create(['socket' => ['so_rcvbuf' => 0]]);

echo "Invalid buffer size", PHP_EOL;
var_dump(@stream_socket_server("unix://$server_path.invalid", $errno, $errstr,
STREAM_SERVER_BIND | STREAM_SERVER_LISTEN, $invalid));
echo $errstr, PHP_EOL;
var_dump(@stream_socket_client("unix://$server_path", $errno, $errstr, 30,
STREAM_CLIENT_CONNECT, $invalid));
echo $errstr, PHP_EOL;

fclose($accepted);
fclose($client);
fclose($server);
fclose($control_client);
fclose($control);
unlink($server_path);
unlink($control_path);

?>
--EXPECT--
Listen buffers
bool(true)
bool(true)
Client buffers
bool(true)
bool(true)
Invalid buffer size
bool(false)
so_rcvbuf context option must be between 1 and 2147483647
bool(false)
so_rcvbuf context option must be between 1 and 2147483647
Loading
Loading