ext/sockets: UDP_SEGMENT support.

UDP segmentation offload is an optimisation attempt by sending multiple
large enough datagrams over UDP which reduces syscalls as by default,
they have to be broke down in small UDP packets, it is better if the
hardware supports it, other handed down to the software implementation.

close GH-18213
This commit is contained in:
David Carlier 2025-03-31 22:38:42 +01:00
parent ea2656277b
commit 4671f8510c
No known key found for this signature in database
GPG key ID: 2FB76A8CE6CD2B41
7 changed files with 61 additions and 2 deletions

2
NEWS
View file

@ -208,6 +208,8 @@ PHP NEWS
(David Carlier)
. Added IP_BINDANY for a socket to bind to any address. (David Carlier)
. Added SO_BUSY_POOL to reduce packets poll latency. (David Carlier)
- Added UDP_SEGMENT support to optimise multiple large datagrams over UDP
if the kernel and hardware supports it. (David Carlier)
- Sodium:
. Fix overall theorical overflows on zend_string buffer allocations.

View file

@ -440,6 +440,7 @@ PHP 8.5 UPGRADE NOTES
. AF_PACKET (Linux only).
. IP_BINDANY (FreeBSD/NetBSD/OpenBSD only).
. SO_BUSY_POLL (Linux only).
. UDP_SEGMENT (Linux only).
========================================
11. Changes to INI File Handling

View file

@ -5,7 +5,7 @@ PHP_ARG_ENABLE([sockets],
if test "$PHP_SOCKETS" != "no"; then
AC_CHECK_FUNCS([hstrerror if_nametoindex if_indextoname sockatmark])
AC_CHECK_HEADERS([sys/sockio.h linux/filter.h linux/if_packet.h linux/if_ether.h])
AC_CHECK_HEADERS([sys/sockio.h linux/filter.h linux/if_packet.h linux/if_ether.h linux/udp.h])
AC_DEFINE([HAVE_SOCKETS], [1],
[Define to 1 if the PHP extension 'sockets' is available.])

View file

@ -70,6 +70,9 @@
# if defined(HAVE_LINUX_IF_ETHER_H)
# include <linux/if_ether.h>
# endif
# if defined(HAVE_LINUX_UDP_H)
# include <linux/udp.h>
# endif
#endif
#include <stddef.h>
@ -2301,6 +2304,22 @@ PHP_FUNCTION(socket_set_option)
}
#endif
#if defined(UDP_SEGMENT)
case UDP_SEGMENT: {
ov = zval_get_long(arg4);
// UDP segmentation offload maximum size or 0 to disable it
if (ov < 0 || ov > USHRT_MAX) {
zend_argument_value_error(4, "must be of between 0 and %u", USHRT_MAX);
RETURN_FALSE;
}
optlen = sizeof(ov);
opt_ptr = &ov;
break;
}
#endif
default:
default_case:
ov = zval_get_long(arg4);

View file

@ -2022,6 +2022,14 @@ const ETH_P_LOOP = UNKNOWN;
const ETH_P_ALL = UNKNOWN;
#endif
#ifdef UDP_SEGMENT
/**
* @var int
* @cvalue UDP_SEGMENT
*/
const UDP_SEGMENT = UNKNOWN;
#endif
/**
* @strict-properties
* @not-serializable

View file

@ -1,5 +1,5 @@
/* This is a generated file, edit the .stub.php file instead.
* Stub hash: 42d486d2666d23569e70860e2b1ef203161792b3 */
* Stub hash: 0ff66adfea41b603b9d58f1f0a82a950f4034cc4 */
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)
@ -1108,6 +1108,9 @@ static void register_sockets_symbols(int module_number)
#if defined(ETH_P_ALL)
REGISTER_LONG_CONSTANT("ETH_P_ALL", ETH_P_ALL, CONST_PERSISTENT);
#endif
#if defined(UDP_SEGMENT)
REGISTER_LONG_CONSTANT("UDP_SEGMENT", UDP_SEGMENT, CONST_PERSISTENT);
#endif
}
static zend_class_entry *register_class_Socket(void)

View file

@ -0,0 +1,26 @@
--TEST--
UDP_SEGMENT setsockopt(), can't really test is as the kernel support might not be enabled.
--EXTENSIONS--
sockets
--SKIPIF--
<?php
if (!defined('UDP_SEGMENT')) { die('skip UDP_SEGMENT is not defined'); }
?>
--FILE--
<?php
$src = socket_create(AF_UNIX, SOCK_DGRAM, 0);
try {
socket_setopt($src, SOL_UDP, UDP_SEGMENT, -1);
} catch (\ValueError $e) {
echo $e->getMessage(), PHP_EOL;
}
try {
socket_setopt($src, SOL_UDP, UDP_SEGMENT, 65536);
} catch (\ValueError $e) {
echo $e->getMessage(), PHP_EOL;
}
?>
--EXPECT--
socket_setopt(): Argument #4 ($value) must be of between 0 and 65535
socket_setopt(): Argument #4 ($value) must be of between 0 and 65535