summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDmitry Stogov <dmitry@php.net>2006-12-19 08:58:58 +0000
committerDmitry Stogov <dmitry@php.net>2006-12-19 08:58:58 +0000
commit03312cc0d9594b1c70cb563a8e3450be5cc6f505 (patch)
tree956fe2b206234fc346716ea236ec6e216072e3e5
parent8a3a61bcd047c4da7b3355129e33646ae01f917c (diff)
downloadphp-git-03312cc0d9594b1c70cb563a8e3450be5cc6f505.tar.gz
Added function stream_socket_shutdown(). It is a wraper for system shutdown() function, that shut downs part of a full-duplex connection
-rw-r--r--NEWS2
-rw-r--r--ext/standard/basic_functions.c11
-rw-r--r--ext/standard/file.c4
-rw-r--r--ext/standard/streamsfuncs.c30
-rw-r--r--ext/standard/streamsfuncs.h1
-rwxr-xr-xext/standard/tests/network/shutdown.phpt65
-rw-r--r--main/streams/php_stream_transport.h15
-rw-r--r--main/streams/transports.c19
-rw-r--r--main/streams/xp_socket.c18
9 files changed, 164 insertions, 1 deletions
diff --git a/NEWS b/NEWS
index 81d7a2b96a..afb8a502ad 100644
--- a/NEWS
+++ b/NEWS
@@ -1,6 +1,8 @@
PHP NEWS
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
?? Dec 2006, PHP 5.2.1RC2
+- Added function stream_socket_shutdown(). It is a wraper for system shutdown()
+ function, that shut downs part of a full-duplex connection. (Dmitry)
- Added internal heap protection (Dmitry)
. safe unlinking
. cookies
diff --git a/ext/standard/basic_functions.c b/ext/standard/basic_functions.c
index 65de5bc149..fec5918e15 100644
--- a/ext/standard/basic_functions.c
+++ b/ext/standard/basic_functions.c
@@ -2443,6 +2443,14 @@ ZEND_BEGIN_ARG_INFO_EX(arginfo_stream_socket_enable_crypto, 0, 0, 2)
ZEND_ARG_INFO(0, cryptokind)
ZEND_ARG_INFO(0, sessionstream)
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
@@ -3517,6 +3525,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
diff --git a/ext/standard/file.c b/ext/standard/file.c
index 6c98b541a8..8eafe896b1 100644
--- a/ext/standard/file.c
+++ b/ext/standard/file.c
@@ -228,6 +228,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)
diff --git a/ext/standard/streamsfuncs.c b/ext/standard/streamsfuncs.c
index df29974952..3fbc4dd6ba 100644
--- a/ext/standard/streamsfuncs.c
+++ b/ext/standard/streamsfuncs.c
@@ -1341,6 +1341,36 @@ PHP_FUNCTION(stream_socket_enable_crypto)
}
/* }}} */
+#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
diff --git a/ext/standard/streamsfuncs.h b/ext/standard/streamsfuncs.h
index 57c5e0290a..017b56f4a1 100644
--- a/ext/standard/streamsfuncs.h
+++ b/ext/standard/streamsfuncs.h
@@ -53,6 +53,7 @@ PHP_FUNCTION(stream_filter_prepend);
PHP_FUNCTION(stream_filter_append);
PHP_FUNCTION(stream_filter_remove);
PHP_FUNCTION(stream_socket_enable_crypto);
+PHP_FUNCTION(stream_socket_shutdown);
PHP_FUNCTION(stream_socket_pair);
/*
diff --git a/ext/standard/tests/network/shutdown.phpt b/ext/standard/tests/network/shutdown.phpt
new file mode 100755
index 0000000000..f9ab66476f
--- /dev/null
+++ b/ext/standard/tests/network/shutdown.phpt
@@ -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
diff --git a/main/streams/php_stream_transport.h b/main/streams/php_stream_transport.h
index f9da47bee7..0252ec3ea8 100644
--- a/main/streams/php_stream_transport.h
+++ b/main/streams/php_stream_transport.h
@@ -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;
diff --git a/main/streams/transports.c b/main/streams/transports.c
index c10a4acfcf..54375b74ee 100644
--- a/main/streams/transports.c
+++ b/main/streams/transports.c
@@ -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(&param, 0, sizeof(param));
+
+ param.op = STREAM_XPORT_OP_SHUTDOWN;
+ param.how = how;
+
+ ret = php_stream_set_option(stream, PHP_STREAM_OPTION_XPORT_API, 0, &param);
+
+ if (ret == PHP_STREAM_OPTION_RETURN_OK) {
+ return param.outputs.returncode;
+ }
+ return -1;
+}
/*
* Local variables:
diff --git a/main/streams/xp_socket.c b/main/streams/xp_socket.c
index af2a060cff..6528a95b64 100644
--- a/main/streams/xp_socket.c
+++ b/main/streams/xp_socket.c
@@ -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;
}