diff options
author | Dmitry Stogov <dmitry@php.net> | 2006-12-19 08:58:58 +0000 |
---|---|---|
committer | Dmitry Stogov <dmitry@php.net> | 2006-12-19 08:58:58 +0000 |
commit | 03312cc0d9594b1c70cb563a8e3450be5cc6f505 (patch) | |
tree | 956fe2b206234fc346716ea236ec6e216072e3e5 | |
parent | 8a3a61bcd047c4da7b3355129e33646ae01f917c (diff) | |
download | php-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-- | NEWS | 2 | ||||
-rw-r--r-- | ext/standard/basic_functions.c | 11 | ||||
-rw-r--r-- | ext/standard/file.c | 4 | ||||
-rw-r--r-- | ext/standard/streamsfuncs.c | 30 | ||||
-rw-r--r-- | ext/standard/streamsfuncs.h | 1 | ||||
-rwxr-xr-x | ext/standard/tests/network/shutdown.phpt | 65 | ||||
-rw-r--r-- | main/streams/php_stream_transport.h | 15 | ||||
-rw-r--r-- | main/streams/transports.c | 19 | ||||
-rw-r--r-- | main/streams/xp_socket.c | 18 |
9 files changed, 164 insertions, 1 deletions
@@ -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(¶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: 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; } |