1
0
mirror of https://github.com/php/php-src.git synced 2026-03-24 00:02:20 +01:00

Fix TCP_KEEPALIVE no inheriting for accepted sockets on MacOS

This commit is contained in:
Jakub Zelenka
2025-12-30 16:53:22 +01:00
parent 9582d8e6d7
commit 0fd8aae6e8
4 changed files with 81 additions and 23 deletions

View File

@@ -2219,25 +2219,32 @@ static int php_openssl_sockop_stat(php_stream *stream, php_stream_statbuf *ssb)
static inline int php_openssl_tcp_sockop_accept(php_stream *stream, php_openssl_netstream_data_t *sock,
php_stream_xport_param *xparam STREAMS_DC) /* {{{ */
{
bool nodelay = false;
php_sockvals sockvals = {0};
zval *tmpzval = NULL;
xparam->outputs.client = NULL;
if (PHP_STREAM_CONTEXT(stream) &&
(tmpzval = php_stream_context_get_option(PHP_STREAM_CONTEXT(stream), "socket", "tcp_nodelay")) != NULL &&
zend_is_true(tmpzval)) {
nodelay = true;
if (PHP_STREAM_CONTEXT(stream)) {
tmpzval = php_stream_context_get_option(PHP_STREAM_CONTEXT(stream), "socket", "tcp_nodelay");
if (tmpzval != NULL && zend_is_true(tmpzval)) {
sockvals.mask |= PHP_SOCKVAL_TCP_NODELAY;
sockvals.tcp_nodelay = 1;
}
tmpzval = php_stream_context_get_option(PHP_STREAM_CONTEXT(stream), "socket", "tcp_keepidle");
if (tmpzval != NULL && Z_TYPE_P(tmpzval) == IS_LONG) {
sockvals.mask |= PHP_SOCKVAL_TCP_KEEPIDLE;
sockvals.keepalive.keepidle = Z_LVAL_P(tmpzval);
}
}
php_socket_t clisock = php_network_accept_incoming(sock->s.socket,
php_socket_t clisock = php_network_accept_incoming_ex(sock->s.socket,
xparam->want_textaddr ? &xparam->outputs.textaddr : NULL,
xparam->want_addr ? &xparam->outputs.addr : NULL,
xparam->want_addr ? &xparam->outputs.addrlen : NULL,
xparam->inputs.timeout,
xparam->want_errortext ? &xparam->outputs.error_text : NULL,
&xparam->outputs.error_code,
nodelay);
&sockvals);
if (clisock != SOCK_ERR) {
php_openssl_netstream_data_t *clisockdata = (php_openssl_netstream_data_t*) emalloc(sizeof(*clisockdata));

View File

@@ -801,15 +801,22 @@ PHPAPI int php_network_get_sock_name(php_socket_t sock,
* version of the address will be emalloc'd and returned.
* */
/* {{{ php_network_accept_incoming */
PHPAPI php_socket_t php_network_accept_incoming(php_socket_t srvsock,
/* Accept a client connection from a server socket,
* using an optional timeout.
* Returns the peer address in addr/addrlen (it will emalloc
* these, so be sure to efree the result).
* If you specify textaddr, a text-printable
* version of the address will be emalloc'd and returned.
* */
PHPAPI php_socket_t php_network_accept_incoming_ex(php_socket_t srvsock,
zend_string **textaddr,
struct sockaddr **addr,
socklen_t *addrlen,
struct timeval *timeout,
zend_string **error_string,
int *error_code,
int tcp_nodelay
php_sockvals *sockvals
)
{
php_socket_t clisock = -1;
@@ -833,11 +840,19 @@ PHPAPI php_socket_t php_network_accept_incoming(php_socket_t srvsock,
textaddr,
addr, addrlen
);
if (tcp_nodelay) {
#ifdef TCP_NODELAY
if (PHP_SOCKVAL_IS_SET(sockvals, PHP_SOCKVAL_TCP_NODELAY)) {
int tcp_nodelay = 1;
setsockopt(clisock, IPPROTO_TCP, TCP_NODELAY, (char*)&tcp_nodelay, sizeof(tcp_nodelay));
#endif
}
#endif
#ifdef TCP_KEEPALIVE
/* MacOS does not inherit TCP_KEEPALIVE so it needs to be set */
if (PHP_SOCKVAL_IS_SET(sockvals, PHP_SOCKVAL_TCP_KEEPIDLE)) {
setsockopt(clisock, IPPROTO_TCP, TCP_KEEPALIVE,
(char*)&sockvals->keepalive.keepidle, sizeof(sockvals->keepalive.keepidle));
}
#endif
} else {
error = php_socket_errno();
}
@@ -852,7 +867,22 @@ PHPAPI php_socket_t php_network_accept_incoming(php_socket_t srvsock,
return clisock;
}
/* }}} */
PHPAPI php_socket_t php_network_accept_incoming(php_socket_t srvsock,
zend_string **textaddr,
struct sockaddr **addr,
socklen_t *addrlen,
struct timeval *timeout,
zend_string **error_string,
int *error_code,
int tcp_nodelay
)
{
php_sockvals sockvals = { .mask = tcp_nodelay ? PHP_SOCKVAL_TCP_NODELAY : 0 };
return php_network_accept_incoming_ex(srvsock, textaddr, addr, addrlen, timeout, error_string,
error_code, &sockvals);
}
/* Connect to a remote host using an interruptible connect with optional timeout.
* Optionally, the connect can be made asynchronously, which will implicitly

View File

@@ -267,12 +267,16 @@ typedef struct {
} php_sockaddr_storage;
#endif
#define PHP_SOCKVAL_TCP_KEEPIDLE (1 << 0)
#define PHP_SOCKVAL_TCP_KEEPCNT (1 << 1)
#define PHP_SOCKVAL_TCP_KEEPINTVL (1 << 2)
#define PHP_SOCKVAL_TCP_NODELAY (1 << 0)
#define PHP_SOCKVAL_TCP_KEEPIDLE (1 << 1)
#define PHP_SOCKVAL_TCP_KEEPCNT (1 << 2)
#define PHP_SOCKVAL_TCP_KEEPINTVL (1 << 3)
#define PHP_SOCKVAL_IS_SET(sockvals, opt) (sockvals->mask & opt)
typedef struct {
unsigned int mask;
int tcp_nodelay;
struct {
int keepidle;
int keepcnt;
@@ -313,6 +317,16 @@ PHPAPI php_socket_t php_network_bind_socket_to_local_addr(const char *host, unsi
int socktype, long sockopts, zend_string **error_string, int *error_code
);
PHPAPI php_socket_t php_network_accept_incoming_ex(php_socket_t srvsock,
zend_string **textaddr,
struct sockaddr **addr,
socklen_t *addrlen,
struct timeval *timeout,
zend_string **error_string,
int *error_code,
php_sockvals *sockvals
);
PHPAPI php_socket_t php_network_accept_incoming(php_socket_t srvsock,
zend_string **textaddr,
struct sockaddr **addr,

View File

@@ -964,25 +964,32 @@ out:
static inline int php_tcp_sockop_accept(php_stream *stream, php_netstream_data_t *sock,
php_stream_xport_param *xparam STREAMS_DC)
{
bool nodelay = 0;
php_sockvals sockvals = {0};
zval *tmpzval = NULL;
xparam->outputs.client = NULL;
if ((NULL != PHP_STREAM_CONTEXT(stream)) &&
(tmpzval = php_stream_context_get_option(PHP_STREAM_CONTEXT(stream), "socket", "tcp_nodelay")) != NULL &&
zend_is_true(tmpzval)) {
nodelay = 1;
if (PHP_STREAM_CONTEXT(stream)) {
tmpzval = php_stream_context_get_option(PHP_STREAM_CONTEXT(stream), "socket", "tcp_nodelay");
if (tmpzval != NULL && zend_is_true(tmpzval)) {
sockvals.mask |= PHP_SOCKVAL_TCP_NODELAY;
sockvals.tcp_nodelay = 1;
}
tmpzval = php_stream_context_get_option(PHP_STREAM_CONTEXT(stream), "socket", "tcp_keepidle");
if (tmpzval != NULL && Z_TYPE_P(tmpzval) == IS_LONG) {
sockvals.mask |= PHP_SOCKVAL_TCP_KEEPIDLE;
sockvals.keepalive.keepidle = Z_LVAL_P(tmpzval);
}
}
php_socket_t clisock = php_network_accept_incoming(sock->socket,
php_socket_t clisock = php_network_accept_incoming_ex(sock->socket,
xparam->want_textaddr ? &xparam->outputs.textaddr : NULL,
xparam->want_addr ? &xparam->outputs.addr : NULL,
xparam->want_addr ? &xparam->outputs.addrlen : NULL,
xparam->inputs.timeout,
xparam->want_errortext ? &xparam->outputs.error_text : NULL,
&xparam->outputs.error_code,
nodelay);
&sockvals);
if (clisock != SOCK_ERR) {
php_netstream_data_t *clisockdata = (php_netstream_data_t*) emalloc(sizeof(*clisockdata));