From: Chris Wright Date: Wed, 6 Aug 2014 15:22:56 +0000 (+0100) Subject: Implement socket_export_stream() X-Git-Tag: php-7.0.7RC1~36 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=e8abb70fc94247450e4016040272fc9459d18371;p=php Implement socket_export_stream() --- 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-- + '224.0.0.23', + "interface" => "lo", +)); +if ($so === false) + die("SKIP joining group 224.0.0.23 on interface lo failed"); +--FILE-- + '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-- +