mirror of
https://github.com/php/php-src.git
synced 2026-03-24 00:02:20 +01:00
Implement #51879 stream context socket option tcp_nodelay
This commit is contained in:
@@ -2199,39 +2199,39 @@ static inline int php_openssl_tcp_sockop_accept(php_stream *stream, php_openssl_
|
||||
php_stream_xport_param *xparam STREAMS_DC)
|
||||
{
|
||||
int clisock;
|
||||
|
||||
zend_bool nodelay = 0;
|
||||
zval *tmpzval = NULL;
|
||||
|
||||
xparam->outputs.client = NULL;
|
||||
|
||||
if ((tmpzval = php_stream_context_get_option(PHP_STREAM_CONTEXT(stream), "socket", "tcp_nodelay")) != NULL &&
|
||||
zend_is_true(tmpzval)) {
|
||||
nodelay = 1;
|
||||
}
|
||||
|
||||
clisock = php_network_accept_incoming(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
|
||||
);
|
||||
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);
|
||||
|
||||
if (clisock >= 0) {
|
||||
php_openssl_netstream_data_t *clisockdata;
|
||||
php_openssl_netstream_data_t *clisockdata = (php_openssl_netstream_data_t*) emalloc(sizeof(*clisockdata));
|
||||
|
||||
clisockdata = emalloc(sizeof(*clisockdata));
|
||||
/* copy underlying tcp fields */
|
||||
memset(clisockdata, 0, sizeof(*clisockdata));
|
||||
memcpy(clisockdata, sock, sizeof(clisockdata->s));
|
||||
|
||||
if (clisockdata == NULL) {
|
||||
closesocket(clisock);
|
||||
/* technically a fatal error */
|
||||
} else {
|
||||
/* copy underlying tcp fields */
|
||||
memset(clisockdata, 0, sizeof(*clisockdata));
|
||||
memcpy(clisockdata, sock, sizeof(clisockdata->s));
|
||||
clisockdata->s.socket = clisock;
|
||||
|
||||
clisockdata->s.socket = clisock;
|
||||
|
||||
xparam->outputs.client = php_stream_alloc_rel(stream->ops, clisockdata, NULL, "r+");
|
||||
if (xparam->outputs.client) {
|
||||
xparam->outputs.client->ctx = stream->ctx;
|
||||
if (stream->ctx) {
|
||||
GC_REFCOUNT(stream->ctx)++;
|
||||
}
|
||||
xparam->outputs.client = php_stream_alloc_rel(stream->ops, clisockdata, NULL, "r+");
|
||||
if (xparam->outputs.client) {
|
||||
xparam->outputs.client->ctx = stream->ctx;
|
||||
if (stream->ctx) {
|
||||
GC_REFCOUNT(stream->ctx)++;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
22
ext/standard/tests/streams/stream_context_tcp_nodelay.phpt
Normal file
22
ext/standard/tests/streams/stream_context_tcp_nodelay.phpt
Normal file
@@ -0,0 +1,22 @@
|
||||
--TEST--
|
||||
stream context tcp_nodelay
|
||||
--SKIPIF--
|
||||
<?php if (!extension_loaded("sockets")) die("skip: need sockets") ?>
|
||||
--FILE--
|
||||
<?php
|
||||
$ctxt = stream_context_create([
|
||||
"socket" => [
|
||||
"tcp_nodelay" => true
|
||||
]
|
||||
]);
|
||||
|
||||
$stream = stream_socket_client(
|
||||
"tcp://www.php.net:80", $errno, $errstr, 10, STREAM_CLIENT_CONNECT, $ctxt);
|
||||
|
||||
$socket =
|
||||
socket_import_stream($stream);
|
||||
|
||||
var_dump(socket_get_option($socket, SOL_TCP, TCP_NODELAY));
|
||||
?>
|
||||
--EXPECT--
|
||||
int(1)
|
||||
@@ -0,0 +1,21 @@
|
||||
--TEST--
|
||||
stream context tcp_nodelay fopen
|
||||
--SKIPIF--
|
||||
<?php if (!extension_loaded("sockets")) die("skip: need sockets") ?>
|
||||
--FILE--
|
||||
<?php
|
||||
$ctxt = stream_context_create([
|
||||
"socket" => [
|
||||
"tcp_nodelay" => true
|
||||
]
|
||||
]);
|
||||
|
||||
$stream = fopen("http://www.php.net", "r", false, $ctxt);
|
||||
|
||||
$socket =
|
||||
@socket_import_stream($stream);
|
||||
|
||||
var_dump(socket_get_option($socket, STREAM_IPPROTO_TCP, TCP_NODELAY));
|
||||
?>
|
||||
--EXPECT--
|
||||
int(1)
|
||||
@@ -0,0 +1,47 @@
|
||||
--TEST--
|
||||
stream context tcp_nodelay server
|
||||
--SKIPIF--
|
||||
<?php if (!extension_loaded("sockets")) die("skip: need sockets") ?>
|
||||
--FILE--
|
||||
<?php
|
||||
$serverCode = <<<'CODE'
|
||||
$ctxt = stream_context_create([
|
||||
"socket" => [
|
||||
"tcp_nodelay" => true
|
||||
]
|
||||
]);
|
||||
|
||||
$server = stream_socket_server(
|
||||
"tcp://127.0.0.1:9099", $errno, $errstr, STREAM_SERVER_BIND | STREAM_SERVER_LISTEN, $ctxt);
|
||||
|
||||
$client = stream_socket_accept($server);
|
||||
|
||||
var_dump(socket_get_option(
|
||||
socket_import_stream($server),
|
||||
SOL_TCP, TCP_NODELAY));
|
||||
|
||||
var_dump(socket_get_option(
|
||||
socket_import_stream($client),
|
||||
SOL_TCP, TCP_NODELAY));
|
||||
|
||||
fclose($client);
|
||||
fclose($server);
|
||||
CODE;
|
||||
|
||||
$clientCode = <<<'CODE'
|
||||
$test = stream_socket_client(
|
||||
"tcp://127.0.0.1:9099", $errno, $errstr, 10);
|
||||
|
||||
sleep(1);
|
||||
|
||||
fclose($test);
|
||||
CODE;
|
||||
|
||||
include sprintf(
|
||||
"%s/../../../openssl/tests/ServerClientTestCase.inc",
|
||||
dirname(__FILE__));
|
||||
ServerClientTestCase::getInstance()->run($serverCode, $clientCode);
|
||||
?>
|
||||
--EXPECT--
|
||||
int(0)
|
||||
int(1)
|
||||
@@ -487,6 +487,11 @@ php_socket_t php_network_bind_socket_to_local_addr(const char *host, unsigned po
|
||||
setsockopt(sock, SOL_SOCKET, SO_BROADCAST, (char*)&sockoptval, sizeof(sockoptval));
|
||||
}
|
||||
#endif
|
||||
#ifdef TCP_NODELAY
|
||||
if (sockopts & STREAM_SOCKOP_TCP_NODELAY) {
|
||||
setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, (char*)&sockoptval, sizeof(sockoptval));
|
||||
}
|
||||
#endif
|
||||
|
||||
n = bind(sock, sa, socklen);
|
||||
|
||||
@@ -726,7 +731,8 @@ PHPAPI php_socket_t php_network_accept_incoming(php_socket_t srvsock,
|
||||
socklen_t *addrlen,
|
||||
struct timeval *timeout,
|
||||
zend_string **error_string,
|
||||
int *error_code
|
||||
int *error_code,
|
||||
int tcp_nodelay
|
||||
)
|
||||
{
|
||||
php_socket_t clisock = -1;
|
||||
@@ -750,6 +756,11 @@ PHPAPI php_socket_t php_network_accept_incoming(php_socket_t srvsock,
|
||||
textaddr,
|
||||
addr, addrlen
|
||||
);
|
||||
if (tcp_nodelay) {
|
||||
#ifdef TCP_NODELAY
|
||||
setsockopt(clisock, IPPROTO_TCP, TCP_NODELAY, (char*)&tcp_nodelay, sizeof(tcp_nodelay));
|
||||
#endif
|
||||
}
|
||||
} else {
|
||||
error = php_socket_errno();
|
||||
}
|
||||
@@ -767,7 +778,6 @@ PHPAPI php_socket_t php_network_accept_incoming(php_socket_t srvsock,
|
||||
/* }}} */
|
||||
|
||||
|
||||
|
||||
/* Connect to a remote host using an interruptible connect with optional timeout.
|
||||
* Optionally, the connect can be made asynchronously, which will implicitly
|
||||
* enable non-blocking mode on the socket.
|
||||
@@ -902,6 +912,15 @@ skip_bind:
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef TCP_NODELAY
|
||||
{
|
||||
int val = 1;
|
||||
if (sockopts & STREAM_SOCKOP_TCP_NODELAY) {
|
||||
setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, (char*)&val, sizeof(val));
|
||||
}
|
||||
}
|
||||
#endif
|
||||
n = php_network_connect_socket(sock, sa, socklen, asynchronous,
|
||||
timeout ? &working_timeout : NULL,
|
||||
error_string, error_code);
|
||||
|
||||
@@ -28,6 +28,7 @@
|
||||
#else
|
||||
# undef closesocket
|
||||
# define closesocket close
|
||||
# include <netinet/tcp.h>
|
||||
#endif
|
||||
|
||||
#ifndef HAVE_SHUTDOWN
|
||||
@@ -115,6 +116,7 @@ typedef int php_socket_t;
|
||||
#define STREAM_SOCKOP_SO_BROADCAST (1 << 2)
|
||||
#define STREAM_SOCKOP_IPV6_V6ONLY (1 << 3)
|
||||
#define STREAM_SOCKOP_IPV6_V6ONLY_ENABLED (1 << 4)
|
||||
#define STREAM_SOCKOP_TCP_NODELAY (1 << 5)
|
||||
|
||||
|
||||
/* uncomment this to debug poll(2) emulation on systems that have poll(2) */
|
||||
@@ -265,7 +267,8 @@ PHPAPI php_socket_t php_network_accept_incoming(php_socket_t srvsock,
|
||||
socklen_t *addrlen,
|
||||
struct timeval *timeout,
|
||||
zend_string **error_string,
|
||||
int *error_code
|
||||
int *error_code,
|
||||
int tcp_nodelay
|
||||
);
|
||||
|
||||
PHPAPI int php_network_get_sock_name(php_socket_t sock,
|
||||
|
||||
@@ -742,6 +742,18 @@ static inline int php_tcp_sockop_connect(php_stream *stream, php_netstream_data_
|
||||
}
|
||||
#endif
|
||||
|
||||
if (stream->ops != &php_stream_udp_socket_ops /* TCP_NODELAY is only applicable for TCP */
|
||||
#ifdef AF_UNIX
|
||||
&& stream->ops != &php_stream_unix_socket_ops
|
||||
&& stream->ops != &php_stream_unixdg_socket_ops
|
||||
#endif
|
||||
&& PHP_STREAM_CONTEXT(stream)
|
||||
&& (tmpzval = php_stream_context_get_option(PHP_STREAM_CONTEXT(stream), "socket", "tcp_nodelay")) != NULL
|
||||
&& zend_is_true(tmpzval)
|
||||
) {
|
||||
sockopts |= STREAM_SOCKOP_TCP_NODELAY;
|
||||
}
|
||||
|
||||
/* Note: the test here for php_stream_udp_socket_ops is important, because we
|
||||
* want the default to be TCP sockets so that the openssl extension can
|
||||
* re-use this code. */
|
||||
@@ -783,36 +795,37 @@ static inline int php_tcp_sockop_accept(php_stream *stream, php_netstream_data_t
|
||||
php_stream_xport_param *xparam STREAMS_DC)
|
||||
{
|
||||
int clisock;
|
||||
zend_bool nodelay = 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;
|
||||
}
|
||||
|
||||
clisock = php_network_accept_incoming(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
|
||||
);
|
||||
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);
|
||||
|
||||
if (clisock >= 0) {
|
||||
php_netstream_data_t *clisockdata;
|
||||
php_netstream_data_t *clisockdata = (php_netstream_data_t*) emalloc(sizeof(*clisockdata));
|
||||
|
||||
clisockdata = emalloc(sizeof(*clisockdata));
|
||||
memcpy(clisockdata, sock, sizeof(*clisockdata));
|
||||
clisockdata->socket = clisock;
|
||||
|
||||
if (clisockdata == NULL) {
|
||||
close(clisock);
|
||||
/* technically a fatal error */
|
||||
} else {
|
||||
memcpy(clisockdata, sock, sizeof(*clisockdata));
|
||||
clisockdata->socket = clisock;
|
||||
|
||||
xparam->outputs.client = php_stream_alloc_rel(stream->ops, clisockdata, NULL, "r+");
|
||||
if (xparam->outputs.client) {
|
||||
xparam->outputs.client->ctx = stream->ctx;
|
||||
if (stream->ctx) {
|
||||
GC_REFCOUNT(stream->ctx)++;
|
||||
}
|
||||
xparam->outputs.client = php_stream_alloc_rel(stream->ops, clisockdata, NULL, "r+");
|
||||
if (xparam->outputs.client) {
|
||||
xparam->outputs.client->ctx = stream->ctx;
|
||||
if (stream->ctx) {
|
||||
GC_REFCOUNT(stream->ctx)++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user