ext/sockets: Adding TCP_FUNCTION_BLK socket option for FreeBSD.

Allows to select an alternate TCP stack. For example with RACK,
a fast loss detection relying on timestamp per packet.

While it works system-wide, it can also apply in an individual socket level too.

close GH-16842
This commit is contained in:
David Carlier 2024-11-18 09:58:08 +00:00
parent f44eaac48a
commit ccda20b8d1
No known key found for this signature in database
GPG Key ID: 8486F847B4B94EF1
6 changed files with 87 additions and 1 deletions

2
NEWS
View File

@ -52,6 +52,8 @@ PHP NEWS
- Sockets:
. Added IPPROTO_ICMP/IPPROTO_ICMPV6 to create raw socket for ICMP usage.
(David Carlier)
. Added TCP_FUNCTION_BLK to change the TCP stack algorithm on FreeBSD.
(David Carlier)
- Standard:
. Fixed crypt() tests on musl when using --with-external-libcrypt

View File

@ -137,6 +137,7 @@ PHP 8.5 UPGRADE NOTES
- Sockets:
. IPPROTO_ICMP/IPPROTO_ICMPV6.
. TCP_FUNCTION_BLK (FreeBSD only).
========================================
11. Changes to INI File Handling

View File

@ -1703,6 +1703,25 @@ PHP_FUNCTION(socket_get_option)
}
}
#endif
#ifdef TCP_FUNCTION_BLK
case TCP_FUNCTION_BLK: {
struct tcp_function_set tsf = {0};
optlen = sizeof(tsf);
if (getsockopt(php_sock->bsd_socket, level, optname, &tsf, &optlen) != 0) {
PHP_SOCKET_ERROR(php_sock, "Unable to retrieve socket option", errno);
RETURN_FALSE;
}
array_init(return_value);
add_assoc_string(return_value, "function_set_name", tsf.function_set_name);
add_assoc_long(return_value, "pcbcnt", tsf.pcbcnt);
return;
}
#endif
}
}
@ -1915,6 +1934,27 @@ PHP_FUNCTION(socket_set_option)
RETURN_TRUE;
}
#endif
#ifdef TCP_FUNCTION_BLK
case TCP_FUNCTION_BLK: {
if (Z_TYPE_P(arg4) != IS_STRING) {
php_error_docref(NULL, E_WARNING, "Invalid tcp stack name argument type");
RETURN_FALSE;
}
struct tcp_function_set tfs = {0};
strlcpy(tfs.function_set_name, Z_STRVAL_P(arg4), TCP_FUNCTION_NAME_LEN_MAX);
optlen = sizeof(tfs);
opt_ptr = &tfs;
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
}
}

View File

@ -640,6 +640,13 @@ const TCP_KEEPINTVL = UNKNOWN;
*/
const TCP_KEEPCNT = UNKNOWN;
#endif
#ifdef TCP_FUNCTION_BLK
/**
* @var int
* @cvalue TCP_FUNCTION_BLK
*/
const TCP_FUNCTION_BLK = UNKNOWN;
#endif
/**
* @var int
* @cvalue PHP_NORMAL_READ

View File

@ -1,5 +1,5 @@
/* This is a generated file, edit the .stub.php file instead.
* Stub hash: 4fdd210a2de6f3b5df10caf5ac7fefa6aa71926c */
* Stub hash: 341bf3dfc486ca410cf1e15e1e22b0c60734277b */
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)
@ -556,6 +556,9 @@ static void register_sockets_symbols(int module_number)
#endif
#if defined(TCP_KEEPIDLE)
REGISTER_LONG_CONSTANT("TCP_KEEPCNT", TCP_KEEPCNT, CONST_PERSISTENT);
#endif
#if defined(TCP_FUNCTION_BLK)
REGISTER_LONG_CONSTANT("TCP_FUNCTION_BLK", TCP_FUNCTION_BLK, CONST_PERSISTENT);
#endif
REGISTER_LONG_CONSTANT("PHP_NORMAL_READ", PHP_NORMAL_READ, CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("PHP_BINARY_READ", PHP_BINARY_READ, CONST_PERSISTENT);

View File

@ -0,0 +1,33 @@
--TEST--
Test if socket_set_option() works, option:TCP_FUNCTION_BLK
--EXTENSIONS--
sockets
--SKIPIF--
<?php
if (!defined("TCP_FUNCTION_BLK")) {
die('SKIP on platforms not supporting TCP_FUNCTION_BLK');
}
?>
--FILE--
<?php
$socket = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
if (!$socket) {
die('Unable to create AF_INET socket [socket]');
}
socket_set_option( $socket, SOL_TCP, TCP_FUNCTION_BLK, "nochancetoexist");
// TCP/RACK and other alternate stacks are not present by default, at least `freebsd` is.
var_dump(socket_set_option( $socket, SOL_TCP, TCP_FUNCTION_BLK, "freebsd"));
var_dump(socket_get_option( $socket, SOL_TCP, TCP_FUNCTION_BLK));
socket_close($socket);
?>
--EXPECTF--
Warning: socket_set_option(): Unable to set socket option [2]: No such file or directory in %s on line %d
bool(true)
array(2) {
["function_set_name"]=>
string(7) "freebsd"
["pcbcnt"]=>
int(%d)
}