1
0
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:
Joe Watkins
2016-04-27 22:56:15 +01:00
parent 12f826d7df
commit 66fc5a3436
7 changed files with 175 additions and 50 deletions

View File

@@ -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)++;
}
}

View 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)

View File

@@ -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)

View File

@@ -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)

View File

@@ -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);

View File

@@ -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,

View File

@@ -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)++;
}
}
}