summaryrefslogtreecommitdiff
path: root/ext/sockets/sockets.c
diff options
context:
space:
mode:
Diffstat (limited to 'ext/sockets/sockets.c')
-rw-r--r--ext/sockets/sockets.c108
1 files changed, 105 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