]> granicus.if.org Git - php/commitdiff
Added function stream_socket_shutdown(). It is a wraper for system shutdown() functio...
authorDmitry Stogov <dmitry@php.net>
Tue, 19 Dec 2006 08:58:58 +0000 (08:58 +0000)
committerDmitry Stogov <dmitry@php.net>
Tue, 19 Dec 2006 08:58:58 +0000 (08:58 +0000)
NEWS
ext/standard/basic_functions.c
ext/standard/file.c
ext/standard/streamsfuncs.c
ext/standard/streamsfuncs.h
ext/standard/tests/network/shutdown.phpt [new file with mode: 0755]
main/streams/php_stream_transport.h
main/streams/transports.c
main/streams/xp_socket.c

diff --git a/NEWS b/NEWS
index 81d7a2b96a009f20193057aeb8c7047b4416b9d7..afb8a502ad9247368d8465e9d6f730c47c4dad2e 100644 (file)
--- 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
index 65de5bc14997bcafd96255aebb2e3c67f0a9b8cb..fec5918e15f61692aea81e1e6a4746b62613a817 100644 (file)
@@ -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
index 6c98b541a899a231b64820bace54b53035b8a396..8eafe896b1f164161764e1fa1082bfcb512a0f4e 100644 (file)
@@ -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)
index df29974952f37658d8dbbb8ed2534b8a01c161c6..3fbc4dd6ba93f3198178cc552e78b3146404e817 100644 (file)
@@ -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
index 57c5e0290a0e34ac5c32260a17d6afe450e7cd3d..017b56f4a1920735d93cc7988a0799f5fb2e0675 100644 (file)
@@ -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 (executable)
index 0000000..f9ab664
--- /dev/null
@@ -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
index f9da47bee71e3626b778b046aa3f6cb6565968a2..0252ec3ea8e83dbe9d3f1e99bc0a9d89c7962a35 100644 (file)
@@ -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;
index c10a4acfcff48daf9a2b12522b0f00fd2171c78a..54375b74ee2b7710fff3ff2693bed85633fa8d5a 100644 (file)
@@ -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:
index af2a060cffe64c1c1323c9ffabe644eafe0082ae..6528a95b640b0a5d6509e118d6bfc9f829b0599b 100644 (file)
@@ -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;
                        }