diff --git a/NEWS b/NEWS index 324762a5a99..f5801cf7a38 100644 --- a/NEWS +++ b/NEWS @@ -76,6 +76,9 @@ PHP NEWS - Sockets: . Added IP_PORTRANGE* constants for BSD systems to control ephemeral port ranges. (David Carlier) + . Added SOCK_NONBLOCK/SOCK_CLOEXEC constants for socket_create and + socket_create_pair to apply O_NONBLOCK/O_CLOEXEC flags to the + newly created sockets. (David Carlier) - SPL: . The SplFixedArray::__wakeup() method has been deprecated as it implements diff --git a/UPGRADING b/UPGRADING index a03243889f5..5b70973b020 100644 --- a/UPGRADING +++ b/UPGRADING @@ -962,6 +962,8 @@ PHP 8.4 UPGRADE NOTES . IP_PORTRANGE_DEFAULT (FreeBSD/NetBSD/OpenBSD only). . IP_PORTRANGE_HIGH (FreeBSD/NetBSD/OpenBSD only). . IP_PORTRANGE_LOW (FreeBSD/NetBSD/OpenBSD only). + . SOCK_NONBLOCK. + . SOCK_CLOEXEC. - Sodium: . SODIUM_CRYPTO_AEAD_AEGIS128L_KEYBYTES diff --git a/ext/sockets/sockets.c b/ext/sockets/sockets.c index d7e4dc8576e..9e33f4e6cfd 100644 --- a/ext/sockets/sockets.c +++ b/ext/sockets/sockets.c @@ -1096,7 +1096,7 @@ PHP_FUNCTION(socket_getpeername) /* {{{ Creates an endpoint for communication in the domain specified by domain, of type specified by type */ PHP_FUNCTION(socket_create) { - zend_long domain, type, protocol; + zend_long domain, type, checktype, protocol; php_socket *php_sock; ZEND_PARSE_PARAMETERS_START(3, 3) @@ -1114,9 +1114,18 @@ PHP_FUNCTION(socket_create) RETURN_THROWS(); } - if (type > 10) { + checktype = type; +#ifdef SOCK_NONBLOCK + checktype &= ~(SOCK_CLOEXEC | SOCK_NONBLOCK); +#endif + + if (checktype > 10) { zend_argument_value_error(2, "must be one of SOCK_STREAM, SOCK_DGRAM, SOCK_SEQPACKET," - " SOCK_RAW, or SOCK_RDM"); + " SOCK_RAW, or SOCK_RDM" +#ifdef SOCK_NONBLOCK + " optionally OR'ed with SOCK_CLOEXEC, SOCK_NONBLOCK" +#endif + ); RETURN_THROWS(); } @@ -2071,7 +2080,7 @@ PHP_FUNCTION(socket_create_pair) zval retval[2], *fds_array_zval; php_socket *php_sock[2]; PHP_SOCKET fds_array[2]; - zend_long domain, type, protocol; + zend_long domain, type, checktype, protocol; ZEND_PARSE_PARAMETERS_START(4, 4) Z_PARAM_LONG(domain) @@ -2089,9 +2098,18 @@ PHP_FUNCTION(socket_create_pair) RETURN_THROWS(); } - if (type > 10) { + checktype = type; +#ifdef SOCK_NONBLOCK + checktype &= ~(SOCK_CLOEXEC | SOCK_NONBLOCK); +#endif + + if (checktype > 10) { zend_argument_value_error(2, "must be one of SOCK_STREAM, SOCK_DGRAM, SOCK_SEQPACKET," - " SOCK_RAW, or SOCK_RDM"); + " SOCK_RAW, or SOCK_RDM" +#ifdef SOCK_NONBLOCK + " optionally OR'ed with SOCK_CLOEXEC, SOCK_NONBLOCK" +#endif + ); RETURN_THROWS(); } diff --git a/ext/sockets/sockets.stub.php b/ext/sockets/sockets.stub.php index f1724359c7d..a6258bc1f73 100644 --- a/ext/sockets/sockets.stub.php +++ b/ext/sockets/sockets.stub.php @@ -68,6 +68,20 @@ const SOCK_CONN_DGRAM = UNKNOWN; */ const SOCK_DCCP = UNKNOWN; #endif +#ifdef SOCK_CLOEXEC +/** + * @var int + * @cvalue SOCK_CLOEXEC + */ +const SOCK_CLOEXEC = UNKNOWN; +#endif +#ifdef SOCK_NONBLOCK +/** + * @var int + * @cvalue SOCK_NONBLOCK + */ +const SOCK_NONBLOCK = UNKNOWN; +#endif /** * @var int diff --git a/ext/sockets/sockets_arginfo.h b/ext/sockets/sockets_arginfo.h index 85e3796b5f2..a8dc7adaa85 100644 --- a/ext/sockets/sockets_arginfo.h +++ b/ext/sockets/sockets_arginfo.h @@ -1,5 +1,5 @@ /* This is a generated file, edit the .stub.php file instead. - * Stub hash: 434b5b721d0f89b6113de4331e9044c891b2bb16 */ + * Stub hash: dcdacf23e3445748178066972e101cbe0ebd6ad5 */ 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) @@ -352,6 +352,12 @@ static void register_sockets_symbols(int module_number) #endif #if defined(SOCK_DCCP) REGISTER_LONG_CONSTANT("SOCK_DCCP", SOCK_DCCP, CONST_PERSISTENT); +#endif +#if defined(SOCK_CLOEXEC) + REGISTER_LONG_CONSTANT("SOCK_CLOEXEC", SOCK_CLOEXEC, CONST_PERSISTENT); +#endif +#if defined(SOCK_NONBLOCK) + REGISTER_LONG_CONSTANT("SOCK_NONBLOCK", SOCK_NONBLOCK, CONST_PERSISTENT); #endif REGISTER_LONG_CONSTANT("MSG_OOB", MSG_OOB, CONST_PERSISTENT); REGISTER_LONG_CONSTANT("MSG_WAITALL", MSG_WAITALL, CONST_PERSISTENT); diff --git a/ext/sockets/tests/socket_create_pair-wrongparams.phpt b/ext/sockets/tests/socket_create_pair-wrongparams.phpt index b394e22551d..8877e3d5b99 100644 --- a/ext/sockets/tests/socket_create_pair-wrongparams.phpt +++ b/ext/sockets/tests/socket_create_pair-wrongparams.phpt @@ -30,7 +30,7 @@ try { Warning: socket_create_pair(): Unable to create socket pair [%d]: %s not supported in %s on line %d bool(false) socket_create_pair(): Argument #1 ($domain) must be one of AF_UNIX, AF_INET6, or AF_INET -socket_create_pair(): Argument #2 ($type) must be one of SOCK_STREAM, SOCK_DGRAM, SOCK_SEQPACKET, SOCK_RAW, or SOCK_RDM +socket_create_pair(): Argument #2 ($type) must be one of SOCK_STREAM, SOCK_DGRAM, SOCK_SEQPACKET, SOCK_RAW, or SOCK_RDM%A --CREDITS-- Till Klampaeckel, till@php.net Berlin TestFest 2009 diff --git a/ext/sockets/tests/socket_create_pair_sockexec.phpt b/ext/sockets/tests/socket_create_pair_sockexec.phpt new file mode 100644 index 00000000000..5e31b155034 --- /dev/null +++ b/ext/sockets/tests/socket_create_pair_sockexec.phpt @@ -0,0 +1,34 @@ +--TEST-- +Test for socket_create_pair() with SOCK_CLOEXEC/SOCK_NONBLOCK +--EXTENSIONS-- +sockets +--SKIPIF-- + +--FILE-- +getMessage() . PHP_EOL; +} +try { + socket_create_pair(AF_UNIX, 11 | SOCK_NONBLOCK, 0, $sockets); +} catch (\ValueError $e) { + echo $e->getMessage() . PHP_EOL; +} +try { + socket_create_pair(AF_UNIX, 11 | SOCK_CLOEXEC | SOCK_NONBLOCK, 0, $sockets); +} catch (\ValueError $e) { + echo $e->getMessage() . PHP_EOL; +} +var_dump(socket_create_pair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC | SOCK_NONBLOCK, 0, $sockets)); +?> +--EXPECTF-- +socket_create_pair(): Argument #2 ($type) must be one of SOCK_STREAM, SOCK_DGRAM, SOCK_SEQPACKET, SOCK_RAW, or SOCK_RDM%A +socket_create_pair(): Argument #2 ($type) must be one of SOCK_STREAM, SOCK_DGRAM, SOCK_SEQPACKET, SOCK_RAW, or SOCK_RDM%A +socket_create_pair(): Argument #2 ($type) must be one of SOCK_STREAM, SOCK_DGRAM, SOCK_SEQPACKET, SOCK_RAW, or SOCK_RDM%A +bool(true)