diff options
author | Chris Wright <daverandom@php.net> | 2014-08-06 16:22:56 +0100 |
---|---|---|
committer | Bob Weinand <bobwei9@hotmail.com> | 2016-05-02 17:08:15 +0200 |
commit | e8abb70fc94247450e4016040272fc9459d18371 (patch) | |
tree | 8af059adf359d345e98230011ec27a93e6dd1ef9 /ext/sockets | |
parent | d5a38280befda7626c2566a9a3461eebd37a5c17 (diff) | |
download | php-git-e8abb70fc94247450e4016040272fc9459d18371.tar.gz |
Implement socket_export_stream()
Diffstat (limited to 'ext/sockets')
-rw-r--r-- | ext/sockets/sockets.c | 108 | ||||
-rw-r--r-- | ext/sockets/tests/socket_export_stream-1.phpt | 27 | ||||
-rw-r--r-- | ext/sockets/tests/socket_export_stream-2.phpt | 48 | ||||
-rw-r--r-- | ext/sockets/tests/socket_export_stream-3.phpt | 47 | ||||
-rw-r--r-- | ext/sockets/tests/socket_export_stream-4-win.phpt | 108 | ||||
-rw-r--r-- | ext/sockets/tests/socket_export_stream-4.phpt | 105 | ||||
-rw-r--r-- | ext/sockets/tests/socket_export_stream-5.phpt | 25 |
7 files changed, 465 insertions, 3 deletions
diff --git a/ext/sockets/sockets.c b/ext/sockets/sockets.c index 6039ac65ba..63674c50d7 100644 --- a/ext/sockets/sockets.c +++ b/ext/sockets/sockets.c @@ -251,6 +251,10 @@ ZEND_BEGIN_ARG_INFO_EX(arginfo_socket_import_stream, 0, 0, 1) ZEND_ARG_INFO(0, stream) ZEND_END_ARG_INFO() +ZEND_BEGIN_ARG_INFO_EX(arginfo_socket_export_stream, 0, 0, 1) + ZEND_ARG_INFO(0, socket) +ZEND_END_ARG_INFO() + ZEND_BEGIN_ARG_INFO_EX(arginfo_socket_sendmsg, 0, 0, 3) ZEND_ARG_INFO(0, socket) ZEND_ARG_INFO(0, msghdr) @@ -305,6 +309,7 @@ PHP_FUNCTION(socket_shutdown); PHP_FUNCTION(socket_last_error); PHP_FUNCTION(socket_clear_error); PHP_FUNCTION(socket_import_stream); +PHP_FUNCTION(socket_export_stream); /* {{{ sockets_functions[] */ @@ -339,6 +344,7 @@ const zend_function_entry sockets_functions[] = { PHP_FE(socket_last_error, arginfo_socket_last_error) PHP_FE(socket_clear_error, arginfo_socket_clear_error) PHP_FE(socket_import_stream, arginfo_socket_import_stream) + PHP_FE(socket_export_stream, arginfo_socket_export_stream) PHP_FE(socket_sendmsg, arginfo_socket_sendmsg) PHP_FE(socket_recvmsg, arginfo_socket_recvmsg) PHP_FE(socket_cmsg_space, arginfo_socket_cmsg_space) @@ -2307,7 +2313,7 @@ error: return NULL; } -/* {{{ proto void socket_import_stream(resource stream) +/* {{{ proto resource socket_import_stream(resource stream) Imports a stream that encapsulates a socket into a socket extension resource. */ PHP_FUNCTION(socket_import_stream) { @@ -2343,8 +2349,7 @@ PHP_FUNCTION(socket_import_stream) #endif /* hold a zval reference to the stream (holding a php_stream* directly could - * also be done, but this might be slightly better if in the future we want - * to provide a socket_export_stream) */ + * also be done, but this makes socket_export_stream a bit simpler) */ ZVAL_COPY(&retsock->zstream, zstream); php_stream_set_option(stream, PHP_STREAM_OPTION_READ_BUFFER, @@ -2354,6 +2359,103 @@ PHP_FUNCTION(socket_import_stream) } /* }}} */ +/* {{{ proto resource socket_export_stream(resource socket) + Exports a socket extension resource into a stream that encapsulates a socket. */ +PHP_FUNCTION(socket_export_stream) +{ + zval *zsocket; + php_socket *socket; + php_stream *stream = NULL; + php_netstream_data_t *stream_data; + char *protocol = NULL; + size_t protocollen = 0; + + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r", &zsocket) == FAILURE) { + return; + } + if ((socket = (php_socket *) zend_fetch_resource(Z_RES_P(zsocket), le_socket_name, le_socket)) == NULL) { + RETURN_FALSE; + } + + /* Either we already exported a stream or the socket came from an import, + * just return the existing stream */ + if (!Z_ISUNDEF(socket->zstream)) { + RETURN_ZVAL(&socket->zstream, 1, 0); + } + + /* Determine if socket is using a protocol with one of the default registered + * socket stream wrappers */ + if (socket->type == PF_INET +#if HAVE_IPV6 + || socket->type == PF_INET6 +#endif + ) { + int protoid; + socklen_t protoidlen = sizeof(protoid); + + getsockopt(socket->bsd_socket, SOL_SOCKET, SO_TYPE, (char *) &protoid, &protoidlen); + + if (protoid == SOCK_STREAM) { + /* SO_PROTOCOL is not (yet?) supported on OS X, so lets assume it's TCP there */ +#ifdef SO_PROTOCOL + protoidlen = sizeof(protoid); + getsockopt(socket->bsd_socket, SOL_SOCKET, SO_PROTOCOL, (char *) &protoid, &protoidlen); + if (protoid == IPPROTO_TCP) +#endif + { + protocol = "tcp"; + protocollen = 3; + } + } else if (protoid == SOCK_DGRAM) { + protocol = "udp"; + protocollen = 3; + } +#ifdef PF_UNIX + } else if (socket->type == PF_UNIX) { + int type; + socklen_t typelen = sizeof(type); + + getsockopt(socket->bsd_socket, SOL_SOCKET, SO_TYPE, (char *) &type, &typelen); + + if (type == SOCK_STREAM) { + protocol = "unix"; + protocollen = 4; + } else if (type == SOCK_DGRAM) { + protocol = "udg"; + protocollen = 3; + } +#endif + } + + /* Try to get a stream with the registered sockops for the protocol in use + * We don't want streams to actually *do* anything though, so don't give it + * anything apart from the protocol */ + if (protocol != NULL) { + stream = php_stream_xport_create(protocol, protocollen, 0, 0, NULL, NULL, NULL, NULL, NULL); + } + + /* Fall back to creating a generic socket stream */ + if (stream == NULL) { + stream = php_stream_sock_open_from_socket(socket->bsd_socket, 0); + + if (stream == NULL) { + php_error_docref(NULL, E_WARNING, "failed to create stream"); + RETURN_FALSE; + } + } + + stream_data = (php_netstream_data_t *) stream->abstract; + stream_data->socket = socket->bsd_socket; + stream_data->is_blocked = socket->blocking; + stream_data->timeout.tv_sec = FG(default_socket_timeout); + stream_data->timeout.tv_usec = 0; + + php_stream_to_zval(stream, &socket->zstream); + + RETURN_ZVAL(&socket->zstream, 1, 0); +} +/* }}} */ + /* * Local variables: * tab-width: 4 diff --git a/ext/sockets/tests/socket_export_stream-1.phpt b/ext/sockets/tests/socket_export_stream-1.phpt new file mode 100644 index 0000000000..498e0a277c --- /dev/null +++ b/ext/sockets/tests/socket_export_stream-1.phpt @@ -0,0 +1,27 @@ +--TEST-- +socket_export_stream: Basic test +--SKIPIF-- +<?php +if (!extension_loaded('sockets')) { + die('SKIP sockets extension not available.'); +} + +--FILE-- +<?php + +$domain = (strtoupper(substr(PHP_OS, 0, 3) == 'WIN') ? AF_INET : AF_UNIX); +socket_create_pair($domain, SOCK_STREAM, 0, $s); + +$s0 = reset($s); +$s1 = next($s); + +$stream = socket_export_stream($s0); +var_dump($stream); + +socket_write($s1, "test message"); +socket_close($s1); + +var_dump(stream_get_contents($stream)); +--EXPECTF-- +resource(%d) of type (stream) +string(12) "test message" diff --git a/ext/sockets/tests/socket_export_stream-2.phpt b/ext/sockets/tests/socket_export_stream-2.phpt new file mode 100644 index 0000000000..98528420fa --- /dev/null +++ b/ext/sockets/tests/socket_export_stream-2.phpt @@ -0,0 +1,48 @@ +--TEST-- +socket_export_stream: Bad arguments +--SKIPIF-- +<?php +if (!extension_loaded('sockets')) { + die('SKIP sockets extension not available.'); +} + +--FILE-- +<?php + +var_dump(socket_export_stream()); +var_dump(socket_export_stream(1, 2)); +var_dump(socket_export_stream(1)); +var_dump(socket_export_stream(new stdclass)); +var_dump(socket_export_stream(fopen(__FILE__, "rb"))); +var_dump(socket_export_stream(stream_socket_server("udp://127.0.0.1:58392", $errno, $errstr, STREAM_SERVER_BIND))); +$s = socket_create(AF_INET, SOCK_DGRAM, SOL_UDP); +var_dump($s); +socket_close($s); +var_dump(socket_export_stream($s)); + + +echo "Done."; +--EXPECTF-- +Warning: socket_export_stream() expects exactly 1 parameter, 0 given in %s on line %d +NULL + +Warning: socket_export_stream() expects exactly 1 parameter, 2 given in %s on line %d +NULL + +Warning: socket_export_stream() expects parameter 1 to be resource, integer given in %s on line %d +NULL + +Warning: socket_export_stream() expects parameter 1 to be resource, object given in %s on line %d +NULL + +Warning: socket_export_stream(): supplied resource is not a valid Socket resource in %s on line %d +bool(false) + +Warning: socket_export_stream(): supplied resource is not a valid Socket resource in %s on line %d +bool(false) +resource(%d) of type (Socket) + +Warning: socket_export_stream(): supplied resource is not a valid Socket resource in %s on line %d +bool(false) +Done. + diff --git a/ext/sockets/tests/socket_export_stream-3.phpt b/ext/sockets/tests/socket_export_stream-3.phpt new file mode 100644 index 0000000000..b13bb34739 --- /dev/null +++ b/ext/sockets/tests/socket_export_stream-3.phpt @@ -0,0 +1,47 @@ +--TEST-- +socket_export_stream: Test with multicasting +--SKIPIF-- +<?php +if (!extension_loaded('sockets')) { + die('SKIP sockets extension not available.'); +} +$s = socket_create(AF_INET, SOCK_DGRAM, SOL_UDP); +$br = socket_bind($s, '0.0.0.0', 58381); +if ($br === false) + die("SKIP IPv4/port 58381 not available"); +$so = socket_set_option($s, IPPROTO_IP, MCAST_JOIN_GROUP, array( + "group" => '224.0.0.23', + "interface" => "lo", +)); +if ($so === false) + die("SKIP joining group 224.0.0.23 on interface lo failed"); +--FILE-- +<?php + +$sock = socket_create(AF_INET, SOCK_DGRAM, SOL_UDP); +socket_bind($sock, '0.0.0.0', 58381); +$stream = socket_export_stream($sock); +var_dump($stream); +$so = socket_set_option($sock, IPPROTO_IP, MCAST_JOIN_GROUP, array( + "group" => '224.0.0.23', + "interface" => "lo", +)); +var_dump($so); + +$sendsock = socket_create(AF_INET, SOCK_DGRAM, SOL_UDP); +var_dump($sendsock); +$br = socket_bind($sendsock, '127.0.0.1'); +$so = socket_sendto($sendsock, $m = "my message", strlen($m), 0, "224.0.0.23", 58381); +var_dump($so); + +stream_set_blocking($stream, 0); +var_dump(fread($stream, strlen($m))); +echo "Done.\n"; +--EXPECTF-- +resource(%d) of type (stream) +bool(true) +resource(%d) of type (Socket) +int(10) +string(10) "my message" +Done. + diff --git a/ext/sockets/tests/socket_export_stream-4-win.phpt b/ext/sockets/tests/socket_export_stream-4-win.phpt new file mode 100644 index 0000000000..e38db7bd08 --- /dev/null +++ b/ext/sockets/tests/socket_export_stream-4-win.phpt @@ -0,0 +1,108 @@ +--TEST-- +socket_export_stream: effects of closing +--SKIPIF-- +<?php +if (!extension_loaded('sockets')) { + die('SKIP sockets extension not available.'); +} +if(substr(PHP_OS, 0, 3) != 'WIN' ) { + die("skip Not Valid for Linux"); +} + +--FILE-- +<?php + +function test($stream, $sock) { + if ($stream !== null) { + echo "stream_set_blocking "; + print_r(stream_set_blocking($stream, 0)); + echo "\n"; + } + if ($sock !== null) { + echo "socket_set_block "; + print_r(socket_set_block($sock)); + echo "\n"; + echo "socket_get_option "; + print_r(socket_get_option($sock, SOL_SOCKET, SO_TYPE)); + echo "\n"; + } + echo "\n"; +} + +echo "normal\n"; +$sock0 = socket_create(AF_INET, SOCK_DGRAM, SOL_UDP); +socket_bind($sock0, '0.0.0.0', 58380); +$stream0 = socket_export_stream($sock0); +test($stream0, $sock0); + +echo "\nunset stream\n"; +$sock1 = socket_create(AF_INET, SOCK_DGRAM, SOL_UDP); +socket_bind($sock1, '0.0.0.0', 58381); +$stream1 = socket_export_stream($sock1); +unset($stream1); +test(null, $sock1); + +echo "\nunset socket\n"; +$sock2 = socket_create(AF_INET, SOCK_DGRAM, SOL_UDP); +socket_bind($sock2, '0.0.0.0', 58382); +$stream2 = socket_export_stream($sock2); +unset($sock2); +test($stream2, null); + +echo "\nclose stream\n"; +$sock3 = socket_create(AF_INET, SOCK_DGRAM, SOL_UDP); +socket_bind($sock3, '0.0.0.0', 58383); +$stream3 = socket_export_stream($sock3); +fclose($stream3); +test($stream3, $sock3); + +echo "\nclose socket\n"; +$sock4 = socket_create(AF_INET, SOCK_DGRAM, SOL_UDP); +socket_bind($sock4, '0.0.0.0', 58484); +$stream4 = socket_export_stream($sock4); +socket_close($sock4); +test($stream4, $sock4); + +echo "Done.\n"; +--EXPECTF-- +normal +stream_set_blocking 1 +socket_set_block 1 +socket_get_option 2 + + +unset stream +socket_set_block 1 +socket_get_option 2 + + +unset socket +stream_set_blocking 1 + + +close stream +stream_set_blocking +Warning: stream_set_blocking(): supplied resource is not a valid stream resource in %s on line %d + +socket_set_block +Warning: socket_set_block(): unable to set blocking mode [%d]: An operation was attempted on something that is not a socket. + in %s on line %d + +socket_get_option +Warning: socket_get_option(): unable to retrieve socket option [%d]: An operation was attempted on something that is not a socket. + in %s on line %d + + + +close socket +stream_set_blocking +Warning: stream_set_blocking(): supplied resource is not a valid stream resource in %s on line %d + +socket_set_block +Warning: socket_set_block(): supplied resource is not a valid Socket resource in %s on line %d + +socket_get_option +Warning: socket_get_option(): supplied resource is not a valid Socket resource in %s on line %d + + +Done. diff --git a/ext/sockets/tests/socket_export_stream-4.phpt b/ext/sockets/tests/socket_export_stream-4.phpt new file mode 100644 index 0000000000..ff329ec795 --- /dev/null +++ b/ext/sockets/tests/socket_export_stream-4.phpt @@ -0,0 +1,105 @@ +--TEST-- +socket_export_stream: effects of closing +--SKIPIF-- +<?php +if (!extension_loaded('sockets')) { + die('SKIP sockets extension not available.'); +} +if(substr(PHP_OS, 0, 3) == 'WIN' ) { + die("skip Not Valid for Windows"); +} +--FILE-- +<?php + +function test($stream, $sock) { + if ($stream !== null) { + echo "stream_set_blocking "; + print_r(stream_set_blocking($stream, 0)); + echo "\n"; + } + if ($sock !== null) { + echo "socket_set_block "; + print_r(socket_set_block($sock)); + echo "\n"; + echo "socket_get_option "; + print_r(socket_get_option($sock, SOL_SOCKET, SO_TYPE)); + echo "\n"; + } + echo "\n"; +} + +echo "normal\n"; +$sock0 = socket_create(AF_INET, SOCK_DGRAM, SOL_UDP); +socket_bind($sock0, '0.0.0.0', 58380); +$stream0 = socket_export_stream($sock0); +test($stream0, $sock0); + +echo "\nunset stream\n"; +$sock1 = socket_create(AF_INET, SOCK_DGRAM, SOL_UDP); +socket_bind($sock1, '0.0.0.0', 58381); +$stream1 = socket_export_stream($sock1); +unset($stream1); +test(null, $sock1); + +echo "\nunset socket\n"; +$sock2 = socket_create(AF_INET, SOCK_DGRAM, SOL_UDP); +socket_bind($sock2, '0.0.0.0', 58382); +$stream2 = socket_export_stream($sock2); +unset($sock2); +test($stream2, null); + +echo "\nclose stream\n"; +$sock3 = socket_create(AF_INET, SOCK_DGRAM, SOL_UDP); +socket_bind($sock3, '0.0.0.0', 58383); +$stream3 = socket_export_stream($sock3); +fclose($stream3); +test($stream3, $sock3); + +echo "\nclose socket\n"; +$sock4 = socket_create(AF_INET, SOCK_DGRAM, SOL_UDP); +socket_bind($sock4, '0.0.0.0', 58484); +$stream4 = socket_export_stream($sock4); +socket_close($sock4); +test($stream4, $sock4); + +echo "Done.\n"; +--EXPECTF-- +normal +stream_set_blocking 1 +socket_set_block 1 +socket_get_option 2 + + +unset stream +socket_set_block 1 +socket_get_option 2 + + +unset socket +stream_set_blocking 1 + + +close stream +stream_set_blocking +Warning: stream_set_blocking(): supplied resource is not a valid stream resource in %s on line %d + +socket_set_block +Warning: socket_set_block(): unable to set blocking mode [%d]: %s in %s on line %d + +socket_get_option +Warning: socket_get_option(): unable to retrieve socket option [%d]: %s in %s on line %d + + + +close socket +stream_set_blocking +Warning: stream_set_blocking(): supplied resource is not a valid stream resource in %s on line %d + +socket_set_block +Warning: socket_set_block(): supplied resource is not a valid Socket resource in %s on line %d + +socket_get_option +Warning: socket_get_option(): supplied resource is not a valid Socket resource in %s on line %d + + +Done. diff --git a/ext/sockets/tests/socket_export_stream-5.phpt b/ext/sockets/tests/socket_export_stream-5.phpt new file mode 100644 index 0000000000..732b2072d0 --- /dev/null +++ b/ext/sockets/tests/socket_export_stream-5.phpt @@ -0,0 +1,25 @@ +--TEST-- +socket_export_stream: effects of leaked handles +--SKIPIF-- +<?php +if (!extension_loaded('sockets')) { + die('SKIP sockets extension not available.'); +} +if (!function_exists('leak_variable')) + die('SKIP only for debug builds'); +--FILE-- +<?php + +$sock0 = socket_create(AF_INET, SOCK_DGRAM, SOL_UDP); +socket_bind($sock0, '0.0.0.0', 58380); +$stream0 = socket_export_stream($sock0); +leak_variable($stream0, true); + +$sock1 = socket_create(AF_INET, SOCK_DGRAM, SOL_UDP); +socket_bind($sock1, '0.0.0.0', 58381); +$stream1 = socket_export_stream($sock1); +leak_variable($sock1, true); + +echo "Done.\n"; +--EXPECT-- +Done. |