mirror of
https://github.com/php/php-src.git
synced 2026-03-24 00:02:20 +01:00
ext/sockets: adding Linux's TCP_USER_TIMEOUT constant.
Set TCP_USER_TIMEOUT to cap (ms) how long TCP will wait for ACKs on in-flight data before aborting the connection; prevents stuck/half-open sessions and enables faster failover vs default retransmission timeouts. Co-authored-by: David Carlier <devnexen@gmail.com> close GH-20708
This commit is contained in:
committed by
David Carlier
parent
b6f786a7ca
commit
46e55dd97c
4
NEWS
4
NEWS
@@ -57,6 +57,10 @@ PHP NEWS
|
||||
. Soap::__setCookie() when cookie name is a digit is now not stored and represented
|
||||
as a string anymore but a int. (David Carlier)
|
||||
|
||||
- Sockets:
|
||||
. Added the TCP_USER_TIMEOUT constant for Linux to set the maximum time in milliseconds
|
||||
transmitted data can remain unacknowledged. (James Lucas)
|
||||
|
||||
- SPL:
|
||||
. DirectoryIterator key can now work better with filesystem supporting larger
|
||||
directory indexing. (David Carlier)
|
||||
|
||||
@@ -94,6 +94,9 @@ PHP 8.6 UPGRADE NOTES
|
||||
10. New Global Constants
|
||||
========================================
|
||||
|
||||
- Sockets:
|
||||
. TCP_USER_TIMEOUT (Linux only).
|
||||
|
||||
========================================
|
||||
11. Changes to INI File Handling
|
||||
========================================
|
||||
|
||||
@@ -1773,7 +1773,7 @@ PHP_FUNCTION(socket_sendto)
|
||||
RETURN_THROWS();
|
||||
}
|
||||
|
||||
memset(&sll, 0, sizeof(sll));
|
||||
memset(&sll, 0, sizeof(sll));
|
||||
sll.sll_family = AF_PACKET;
|
||||
sll.sll_ifindex = port;
|
||||
|
||||
@@ -2130,6 +2130,28 @@ PHP_FUNCTION(socket_set_option)
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(TCP_USER_TIMEOUT)
|
||||
case TCP_USER_TIMEOUT: {
|
||||
zend_long timeout = zval_get_long(arg4);
|
||||
|
||||
// TCP_USER_TIMEOUT unsigned int
|
||||
if (timeout < 0 || timeout > UINT_MAX) {
|
||||
zend_argument_value_error(4, "must be of between 0 and %u", UINT_MAX);
|
||||
RETURN_THROWS();
|
||||
}
|
||||
|
||||
unsigned int val = (unsigned int)timeout;
|
||||
optlen = sizeof(val);
|
||||
opt_ptr = &val;
|
||||
if (setsockopt(php_sock->bsd_socket, level, optname, opt_ptr, optlen) != 0) {
|
||||
PHP_SOCKET_ERROR(php_sock, "Unable to set socket option", errno);
|
||||
RETURN_FALSE;
|
||||
}
|
||||
|
||||
RETURN_TRUE;
|
||||
}
|
||||
#endif
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -602,6 +602,13 @@ const TCP_CONGESTION = UNKNOWN;
|
||||
*/
|
||||
const TCP_SYNCNT = UNKNOWN;
|
||||
#endif
|
||||
#ifdef TCP_USER_TIMEOUT
|
||||
/**
|
||||
* @var int
|
||||
* @cvalue TCP_USER_TIMEOUT
|
||||
*/
|
||||
const TCP_USER_TIMEOUT = UNKNOWN;
|
||||
#endif
|
||||
#ifdef SO_ZEROCOPY
|
||||
/**
|
||||
* @var int
|
||||
|
||||
5
ext/sockets/sockets_arginfo.h
generated
5
ext/sockets/sockets_arginfo.h
generated
@@ -1,5 +1,5 @@
|
||||
/* This is a generated file, edit the .stub.php file instead.
|
||||
* Stub hash: f754368e28f6e45bf3a63a403e49f5659c29d2c6 */
|
||||
* Stub hash: 038081ca7bb98076d4b559d93b4c9300acc47160 */
|
||||
|
||||
ZEND_BEGIN_ARG_WITH_RETURN_TYPE_MASK_EX(arginfo_socket_select, 0, 4, MAY_BE_LONG|MAY_BE_FALSE)
|
||||
ZEND_ARG_TYPE_INFO(1, read, IS_ARRAY, 1)
|
||||
@@ -527,6 +527,9 @@ static void register_sockets_symbols(int module_number)
|
||||
#if defined(TCP_SYNCNT)
|
||||
REGISTER_LONG_CONSTANT("TCP_SYNCNT", TCP_SYNCNT, CONST_PERSISTENT);
|
||||
#endif
|
||||
#if defined(TCP_USER_TIMEOUT)
|
||||
REGISTER_LONG_CONSTANT("TCP_USER_TIMEOUT", TCP_USER_TIMEOUT, CONST_PERSISTENT);
|
||||
#endif
|
||||
#if defined(SO_ZEROCOPY)
|
||||
REGISTER_LONG_CONSTANT("SO_ZEROCOPY", SO_ZEROCOPY, CONST_PERSISTENT);
|
||||
#endif
|
||||
|
||||
34
ext/sockets/tests/socket_setoption_tcpusertimeout_32bit.phpt
Normal file
34
ext/sockets/tests/socket_setoption_tcpusertimeout_32bit.phpt
Normal file
@@ -0,0 +1,34 @@
|
||||
--TEST--
|
||||
Test if socket_set_option() works, option:TCP_USER_TIMEOUT
|
||||
--EXTENSIONS--
|
||||
sockets
|
||||
--SKIPIF--
|
||||
<?php
|
||||
if (!defined('TCP_USER_TIMEOUT')) { die('skip TCP_USER_TIMEOUT is not defined'); }
|
||||
if (PHP_INT_SIZE != 4) { die("skip 32-bit only"); }
|
||||
?>
|
||||
--FILE--
|
||||
<?php
|
||||
$socket = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
|
||||
if (!$socket) {
|
||||
die('Unable to create AF_INET socket [socket]');
|
||||
}
|
||||
socket_set_block($socket);
|
||||
|
||||
try {
|
||||
socket_setopt($socket, SOL_TCP, TCP_USER_TIMEOUT, -1);
|
||||
} catch (\ValueError $e) {
|
||||
echo $e->getMessage(), PHP_EOL;
|
||||
}
|
||||
|
||||
$timeout = 200;
|
||||
$retval_2 = socket_set_option($socket, SOL_TCP, TCP_USER_TIMEOUT, $timeout);
|
||||
$retval_3 = socket_get_option($socket, SOL_TCP, TCP_USER_TIMEOUT);
|
||||
var_dump($retval_2);
|
||||
var_dump($retval_3 === $timeout);
|
||||
socket_close($socket);
|
||||
?>
|
||||
--EXPECTF--
|
||||
socket_setopt(): Argument #4 ($value) must be of between 0 and %d
|
||||
bool(true)
|
||||
bool(true)
|
||||
41
ext/sockets/tests/socket_setoption_tcpusertimeout_64bit.phpt
Normal file
41
ext/sockets/tests/socket_setoption_tcpusertimeout_64bit.phpt
Normal file
@@ -0,0 +1,41 @@
|
||||
--TEST--
|
||||
Test if socket_set_option() works, option:TCP_USER_TIMEOUT
|
||||
--EXTENSIONS--
|
||||
sockets
|
||||
--SKIPIF--
|
||||
<?php
|
||||
if (!defined('TCP_USER_TIMEOUT')) { die('skip TCP_USER_TIMEOUT is not defined'); }
|
||||
if (PHP_INT_SIZE != 8) { die("skip 64-bit only"); }
|
||||
?>
|
||||
--FILE--
|
||||
<?php
|
||||
$socket = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
|
||||
if (!$socket) {
|
||||
die('Unable to create AF_INET socket [socket]');
|
||||
}
|
||||
socket_set_block($socket);
|
||||
|
||||
try {
|
||||
socket_setopt($socket, SOL_TCP, TCP_USER_TIMEOUT, -1);
|
||||
} catch (\ValueError $e) {
|
||||
echo $e->getMessage(), PHP_EOL;
|
||||
}
|
||||
|
||||
try {
|
||||
socket_setopt($socket, SOL_TCP, TCP_USER_TIMEOUT, PHP_INT_MAX);
|
||||
} catch (\ValueError $e) {
|
||||
echo $e->getMessage(), PHP_EOL;
|
||||
}
|
||||
|
||||
$timeout = 200;
|
||||
$retval_2 = socket_set_option($socket, SOL_TCP, TCP_USER_TIMEOUT, $timeout);
|
||||
$retval_3 = socket_get_option($socket, SOL_TCP, TCP_USER_TIMEOUT);
|
||||
var_dump($retval_2);
|
||||
var_dump($retval_3 === $timeout);
|
||||
socket_close($socket);
|
||||
?>
|
||||
--EXPECTF--
|
||||
socket_setopt(): Argument #4 ($value) must be of between 0 and %d
|
||||
socket_setopt(): Argument #4 ($value) must be of between 0 and %d
|
||||
bool(true)
|
||||
bool(true)
|
||||
Reference in New Issue
Block a user