mirror of
https://github.com/php/php-src.git
synced 2026-04-29 03:03:26 +02:00
Added function stream_socket_shutdown(). It is a wraper for system shutdown() function, that shut downs part of a full-duplex connection
This commit is contained in:
@@ -2449,6 +2449,14 @@ ZEND_BEGIN_ARG_INFO_EX(arginfo_stream_resolve_include_path, 0, 0, 1)
|
||||
ZEND_ARG_INFO(0, filename)
|
||||
ZEND_ARG_INFO(0, context)
|
||||
ZEND_END_ARG_INFO()
|
||||
|
||||
#ifdef HAVE_SHUTDOWN
|
||||
static
|
||||
ZEND_BEGIN_ARG_INFO(arginfo_stream_socket_shutdown, 0)
|
||||
ZEND_ARG_INFO(0, stream)
|
||||
ZEND_ARG_INFO(0, how)
|
||||
ZEND_END_ARG_INFO()
|
||||
#endif
|
||||
/* }}} */
|
||||
/* {{{ string.c */
|
||||
static
|
||||
@@ -3563,6 +3571,9 @@ zend_function_entry basic_functions[] = {
|
||||
PHP_FE(stream_socket_recvfrom, arginfo_stream_socket_recvfrom)
|
||||
PHP_FE(stream_socket_sendto, arginfo_stream_socket_sendto)
|
||||
PHP_FE(stream_socket_enable_crypto, arginfo_stream_socket_enable_crypto)
|
||||
#ifdef HAVE_SHUTDOWN
|
||||
PHP_FE(stream_socket_shutdown, arginfo_stream_socket_shutdown)
|
||||
#endif
|
||||
#if HAVE_SOCKETPAIR
|
||||
PHP_FE(stream_socket_pair, arginfo_stream_socket_pair)
|
||||
#endif
|
||||
|
||||
@@ -227,6 +227,10 @@ PHP_MINIT_FUNCTION(file)
|
||||
REGISTER_LONG_CONSTANT("STREAM_CRYPTO_METHOD_SSLv23_SERVER", STREAM_CRYPTO_METHOD_SSLv23_SERVER, CONST_CS|CONST_PERSISTENT);
|
||||
REGISTER_LONG_CONSTANT("STREAM_CRYPTO_METHOD_TLS_SERVER", STREAM_CRYPTO_METHOD_TLS_SERVER, CONST_CS|CONST_PERSISTENT);
|
||||
|
||||
REGISTER_LONG_CONSTANT("STREAM_SHUT_RD", STREAM_SHUT_RD, CONST_CS|CONST_PERSISTENT);
|
||||
REGISTER_LONG_CONSTANT("STREAM_SHUT_WR", STREAM_SHUT_WR, CONST_CS|CONST_PERSISTENT);
|
||||
REGISTER_LONG_CONSTANT("STREAM_SHUT_RDWR", STREAM_SHUT_RDWR, CONST_CS|CONST_PERSISTENT);
|
||||
|
||||
#ifdef PF_INET
|
||||
REGISTER_LONG_CONSTANT("STREAM_PF_INET", PF_INET, CONST_CS|CONST_PERSISTENT);
|
||||
#elif defined(AF_INET)
|
||||
|
||||
@@ -1645,6 +1645,36 @@ PHP_FUNCTION(stream_resolve_include_path)
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
#ifdef HAVE_SHUTDOWN
|
||||
/* {{{ proto int stream_socket_shutdown(resource stream, int how)
|
||||
causes all or part of a full-duplex connection on the socket associated
|
||||
with stream to be shut down. If how is SHUT_RD, further receptions will
|
||||
be disallowed. If how is SHUT_WR, further transmissions will be disallowed.
|
||||
If how is SHUT_RDWR, further receptions and transmissions will be
|
||||
disallowed. */
|
||||
PHP_FUNCTION(stream_socket_shutdown)
|
||||
{
|
||||
long how;
|
||||
zval *zstream;
|
||||
php_stream *stream;
|
||||
|
||||
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rl", &zstream, &how) == FAILURE) {
|
||||
RETURN_FALSE;
|
||||
}
|
||||
|
||||
if (how != STREAM_SHUT_RD &&
|
||||
how != STREAM_SHUT_WR &&
|
||||
how != STREAM_SHUT_RDWR) {
|
||||
RETURN_FALSE;
|
||||
}
|
||||
|
||||
php_stream_from_zval(stream, &zstream);
|
||||
|
||||
RETURN_BOOL(php_stream_xport_shutdown(stream, (stream_shutdown_t)how TSRMLS_CC) == 0);
|
||||
}
|
||||
#endif
|
||||
/* }}} */
|
||||
|
||||
/*
|
||||
* Local variables:
|
||||
* tab-width: 4
|
||||
|
||||
@@ -54,6 +54,7 @@ PHP_FUNCTION(stream_filter_append);
|
||||
PHP_FUNCTION(stream_filter_remove);
|
||||
PHP_FUNCTION(stream_encoding);
|
||||
PHP_FUNCTION(stream_socket_enable_crypto);
|
||||
PHP_FUNCTION(stream_socket_shutdown);
|
||||
PHP_FUNCTION(stream_socket_pair);
|
||||
PHP_FUNCTION(stream_resolve_include_path);
|
||||
|
||||
|
||||
Executable
+65
@@ -0,0 +1,65 @@
|
||||
--TEST--
|
||||
stream_socket_shutdown() test on IPv4 TCP Loopback
|
||||
--SKIPIF--
|
||||
<?php
|
||||
function_exists('stream_socket_shutdown') or die('skip stream_socket_shutdown() is not supported.');
|
||||
?>
|
||||
--FILE--
|
||||
<?php
|
||||
/* Setup socket server */
|
||||
$server = stream_socket_server('tcp://127.0.0.1:31337');
|
||||
if (!$server) {
|
||||
die('Unable to create AF_INET socket [server]');
|
||||
}
|
||||
|
||||
/* Connect and send request 1 */
|
||||
$client1 = stream_socket_client('tcp://127.0.0.1:31337');
|
||||
if (!$client1) {
|
||||
die('Unable to create AF_INET socket [client]');
|
||||
}
|
||||
@fwrite($client1, "Client 1\n");
|
||||
stream_socket_shutdown($client1, STREAM_SHUT_WR);
|
||||
@fwrite($client1, "Error 1\n");
|
||||
|
||||
/* Connect and send request 2 */
|
||||
$client2 = stream_socket_client('tcp://127.0.0.1:31337');
|
||||
if (!$client2) {
|
||||
die('Unable to create AF_INET socket [client]');
|
||||
}
|
||||
@fwrite($client2, "Client 2\n");
|
||||
stream_socket_shutdown($client2, STREAM_SHUT_WR);
|
||||
@fwrite($client2, "Error 2\n");
|
||||
|
||||
/* Accept connection 1 */
|
||||
$socket = stream_socket_accept($server);
|
||||
if (!$socket) {
|
||||
die('Unable to accept connection');
|
||||
}
|
||||
@fwrite($socket, fgets($socket));
|
||||
@fwrite($socket, fgets($socket));
|
||||
fclose($socket);
|
||||
|
||||
/* Read Response 1 */
|
||||
echo fgets($client1);
|
||||
echo fgets($client1);
|
||||
|
||||
/* Accept connection 2 */
|
||||
$socket = stream_socket_accept($server);
|
||||
if (!$socket) {
|
||||
die('Unable to accept connection');
|
||||
}
|
||||
@fwrite($socket, fgets($socket));
|
||||
@fwrite($socket, fgets($socket));
|
||||
fclose($socket);
|
||||
|
||||
/* Read Response 2 */
|
||||
echo fgets($client2);
|
||||
echo fgets($client2);
|
||||
|
||||
fclose($client1);
|
||||
fclose($client2);
|
||||
fclose($server);
|
||||
?>
|
||||
--EXPECT--
|
||||
Client 1
|
||||
Client 2
|
||||
@@ -104,8 +104,19 @@ PHPAPI int php_stream_xport_recvfrom(php_stream *stream, char *buf, size_t bufle
|
||||
* sending it as OOB data */
|
||||
PHPAPI int php_stream_xport_sendto(php_stream *stream, const char *buf, size_t buflen,
|
||||
long flags, void *addr, socklen_t addrlen TSRMLS_DC);
|
||||
|
||||
typedef enum {
|
||||
STREAM_SHUT_RD,
|
||||
STREAM_SHUT_WR,
|
||||
STREAM_SHUT_RDWR
|
||||
} stream_shutdown_t;
|
||||
|
||||
/* Similar to shutdown() system call; shut down part of a full-duplex
|
||||
* connection */
|
||||
PHPAPI int php_stream_xport_shutdown(php_stream *stream, stream_shutdown_t how TSRMLS_DC);
|
||||
END_EXTERN_C()
|
||||
|
||||
|
||||
/* Structure definition for the set_option interface that the above functions wrap */
|
||||
|
||||
typedef struct _php_stream_xport_param {
|
||||
@@ -116,11 +127,13 @@ typedef struct _php_stream_xport_param {
|
||||
STREAM_XPORT_OP_GET_NAME,
|
||||
STREAM_XPORT_OP_GET_PEER_NAME,
|
||||
STREAM_XPORT_OP_RECV,
|
||||
STREAM_XPORT_OP_SEND
|
||||
STREAM_XPORT_OP_SEND,
|
||||
STREAM_XPORT_OP_SHUTDOWN
|
||||
} op;
|
||||
unsigned int want_addr:1;
|
||||
unsigned int want_textaddr:1;
|
||||
unsigned int want_errortext:1;
|
||||
stream_shutdown_t how:3;
|
||||
|
||||
struct {
|
||||
char *name;
|
||||
|
||||
@@ -486,6 +486,25 @@ PHPAPI int php_stream_xport_sendto(php_stream *stream, const char *buf, size_t b
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Similar to shutdown() system call; shut down part of a full-duplex
|
||||
* connection */
|
||||
PHPAPI int php_stream_xport_shutdown(php_stream *stream, stream_shutdown_t how TSRMLS_DC)
|
||||
{
|
||||
php_stream_xport_param param;
|
||||
int ret = 0;
|
||||
|
||||
memset(¶m, 0, sizeof(param));
|
||||
|
||||
param.op = STREAM_XPORT_OP_SHUTDOWN;
|
||||
param.how = how;
|
||||
|
||||
ret = php_stream_set_option(stream, PHP_STREAM_OPTION_XPORT_API, 0, ¶m);
|
||||
|
||||
if (ret == PHP_STREAM_OPTION_RETURN_OK) {
|
||||
return param.outputs.returncode;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Local variables:
|
||||
|
||||
@@ -369,6 +369,24 @@ static int php_sockop_set_option(php_stream *stream, int option, int value, void
|
||||
return PHP_STREAM_OPTION_RETURN_OK;
|
||||
|
||||
|
||||
#ifdef HAVE_SHUTDOWN
|
||||
# ifndef SHUT_RD
|
||||
# define SHUT_RD 0
|
||||
# endif
|
||||
# ifndef SHUT_WR
|
||||
# define SHUT_WR 1
|
||||
# endif
|
||||
# ifndef SHUT_RDWR
|
||||
# define SHUT_RDWR 2
|
||||
# endif
|
||||
case STREAM_XPORT_OP_SHUTDOWN: {
|
||||
static const int shutdown_how[] = {SHUT_RD, SHUT_WR, SHUT_RDWR};
|
||||
|
||||
xparam->outputs.returncode = shutdown(sock->socket, shutdown_how[xparam->how]);
|
||||
return PHP_STREAM_OPTION_RETURN_OK;
|
||||
}
|
||||
#endif
|
||||
|
||||
default:
|
||||
return PHP_STREAM_OPTION_RETURN_NOTIMPL;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user