123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532 |
- /*
- +----------------------------------------------------------------------+
- | PHP Version 5 |
- +----------------------------------------------------------------------+
- | Copyright (c) 1997-2016 The PHP Group |
- +----------------------------------------------------------------------+
- | This source file is subject to version 3.01 of the PHP license, |
- | that is bundled with this package in the file LICENSE, and is |
- | available through the world-wide-web at the following url: |
- | http://www.php.net/license/3_01.txt |
- | If you did not receive a copy of the PHP license and are unable to |
- | obtain it through the world-wide-web, please send a note to |
- | license@php.net so we can mail you a copy immediately. |
- +----------------------------------------------------------------------+
- | Author: Wez Furlong <wez@thebrainroom.com> |
- +----------------------------------------------------------------------+
- */
- /* $Id$ */
- #include "php.h"
- #include "php_streams_int.h"
- #include "ext/standard/file.h"
- static HashTable xport_hash;
- PHPAPI HashTable *php_stream_xport_get_hash(void)
- {
- return &xport_hash;
- }
- PHPAPI int php_stream_xport_register(const char *protocol, php_stream_transport_factory factory TSRMLS_DC)
- {
- return zend_hash_update(&xport_hash, protocol, strlen(protocol) + 1, &factory, sizeof(factory), NULL);
- }
- PHPAPI int php_stream_xport_unregister(const char *protocol TSRMLS_DC)
- {
- return zend_hash_del(&xport_hash, protocol, strlen(protocol) + 1);
- }
- #define ERR_REPORT(out_err, fmt, arg) \
- if (out_err) { spprintf(out_err, 0, fmt, arg); } \
- else { php_error_docref(NULL TSRMLS_CC, E_WARNING, fmt, arg); }
- #define ERR_RETURN(out_err, local_err, fmt) \
- if (out_err) { *out_err = local_err; } \
- else { php_error_docref(NULL TSRMLS_CC, E_WARNING, fmt, local_err ? local_err : "Unspecified error"); \
- if (local_err) { efree(local_err); local_err = NULL; } \
- }
-
- PHPAPI php_stream *_php_stream_xport_create(const char *name, size_t namelen, int options,
- int flags, const char *persistent_id,
- struct timeval *timeout,
- php_stream_context *context,
- char **error_string,
- int *error_code
- STREAMS_DC TSRMLS_DC)
- {
- php_stream *stream = NULL;
- php_stream_transport_factory *factory = NULL;
- const char *p, *protocol = NULL;
- int n = 0, failed = 0;
- char *error_text = NULL;
- struct timeval default_timeout = { 0, 0 };
-
- default_timeout.tv_sec = FG(default_socket_timeout);
- if (timeout == NULL) {
- timeout = &default_timeout;
- }
-
- /* check for a cached persistent socket */
- if (persistent_id) {
- switch(php_stream_from_persistent_id(persistent_id, &stream TSRMLS_CC)) {
- case PHP_STREAM_PERSISTENT_SUCCESS:
- /* use a 0 second timeout when checking if the socket
- * has already died */
- if (PHP_STREAM_OPTION_RETURN_OK == php_stream_set_option(stream, PHP_STREAM_OPTION_CHECK_LIVENESS, 0, NULL)) {
- return stream;
- }
- /* dead - kill it */
- php_stream_pclose(stream);
- stream = NULL;
- /* fall through */
- case PHP_STREAM_PERSISTENT_FAILURE:
- default:
- /* failed; get a new one */
- ;
- }
- }
- for (p = name; isalnum((int)*p) || *p == '+' || *p == '-' || *p == '.'; p++) {
- n++;
- }
- if ((*p == ':') && (n > 1) && !strncmp("://", p, 3)) {
- protocol = name;
- name = p + 3;
- namelen -= n + 3;
- } else {
- protocol = "tcp";
- n = 3;
- }
- if (protocol) {
- char *tmp = estrndup(protocol, n);
- if (FAILURE == zend_hash_find(&xport_hash, (char*)tmp, n + 1, (void**)&factory)) {
- char wrapper_name[32];
- if (n >= sizeof(wrapper_name))
- n = sizeof(wrapper_name) - 1;
- PHP_STRLCPY(wrapper_name, protocol, sizeof(wrapper_name), n);
-
- ERR_REPORT(error_string, "Unable to find the socket transport \"%s\" - did you forget to enable it when you configured PHP?",
- wrapper_name);
- efree(tmp);
- return NULL;
- }
- efree(tmp);
- }
- if (factory == NULL) {
- /* should never happen */
- php_error_docref(NULL TSRMLS_CC, E_WARNING, "Could not find a factory !?");
- return NULL;
- }
- stream = (*factory)(protocol, n,
- (char*)name, namelen, persistent_id, options, flags, timeout,
- context STREAMS_REL_CC TSRMLS_CC);
- if (stream) {
- php_stream_context_set(stream, context);
- if ((flags & STREAM_XPORT_SERVER) == 0) {
- /* client */
- if (flags & (STREAM_XPORT_CONNECT|STREAM_XPORT_CONNECT_ASYNC)) {
- if (-1 == php_stream_xport_connect(stream, name, namelen,
- flags & STREAM_XPORT_CONNECT_ASYNC ? 1 : 0,
- timeout, &error_text, error_code TSRMLS_CC)) {
- ERR_RETURN(error_string, error_text, "connect() failed: %s");
- failed = 1;
- }
- }
- } else {
- /* server */
- if (flags & STREAM_XPORT_BIND) {
- if (0 != php_stream_xport_bind(stream, name, namelen, &error_text TSRMLS_CC)) {
- ERR_RETURN(error_string, error_text, "bind() failed: %s");
- failed = 1;
- } else if (flags & STREAM_XPORT_LISTEN) {
- zval **zbacklog = NULL;
- int backlog = 32;
-
- if (stream->context && php_stream_context_get_option(stream->context, "socket", "backlog", &zbacklog) == SUCCESS) {
- zval *ztmp = *zbacklog;
-
- convert_to_long_ex(&ztmp);
- backlog = Z_LVAL_P(ztmp);
- if (ztmp != *zbacklog) {
- zval_ptr_dtor(&ztmp);
- }
- }
-
- if (0 != php_stream_xport_listen(stream, backlog, &error_text TSRMLS_CC)) {
- ERR_RETURN(error_string, error_text, "listen() failed: %s");
- failed = 1;
- }
- }
- }
- }
- }
- if (failed) {
- /* failure means that they don't get a stream to play with */
- if (persistent_id) {
- php_stream_pclose(stream);
- } else {
- php_stream_close(stream);
- }
- stream = NULL;
- }
- return stream;
- }
- /* Bind the stream to a local address */
- PHPAPI int php_stream_xport_bind(php_stream *stream,
- const char *name, size_t namelen,
- char **error_text
- TSRMLS_DC)
- {
- php_stream_xport_param param;
- int ret;
-
- memset(¶m, 0, sizeof(param));
- param.op = STREAM_XPORT_OP_BIND;
- param.inputs.name = (char*)name;
- param.inputs.namelen = namelen;
- param.want_errortext = error_text ? 1 : 0;
- ret = php_stream_set_option(stream, PHP_STREAM_OPTION_XPORT_API, 0, ¶m);
- if (ret == PHP_STREAM_OPTION_RETURN_OK) {
- if (error_text) {
- *error_text = param.outputs.error_text;
- }
- return param.outputs.returncode;
- }
- return ret;
- }
- /* Connect to a remote address */
- PHPAPI int php_stream_xport_connect(php_stream *stream,
- const char *name, size_t namelen,
- int asynchronous,
- struct timeval *timeout,
- char **error_text,
- int *error_code
- TSRMLS_DC)
- {
- php_stream_xport_param param;
- int ret;
-
- memset(¶m, 0, sizeof(param));
- param.op = asynchronous ? STREAM_XPORT_OP_CONNECT_ASYNC: STREAM_XPORT_OP_CONNECT;
- param.inputs.name = (char*)name;
- param.inputs.namelen = namelen;
- param.inputs.timeout = timeout;
- param.want_errortext = error_text ? 1 : 0;
-
- ret = php_stream_set_option(stream, PHP_STREAM_OPTION_XPORT_API, 0, ¶m);
- if (ret == PHP_STREAM_OPTION_RETURN_OK) {
- if (error_text) {
- *error_text = param.outputs.error_text;
- }
- if (error_code) {
- *error_code = param.outputs.error_code;
- }
- return param.outputs.returncode;
- }
- return ret;
- }
- /* Prepare to listen */
- PHPAPI int php_stream_xport_listen(php_stream *stream, int backlog, char **error_text TSRMLS_DC)
- {
- php_stream_xport_param param;
- int ret;
-
- memset(¶m, 0, sizeof(param));
- param.op = STREAM_XPORT_OP_LISTEN;
- param.inputs.backlog = backlog;
- param.want_errortext = error_text ? 1 : 0;
-
- ret = php_stream_set_option(stream, PHP_STREAM_OPTION_XPORT_API, 0, ¶m);
- if (ret == PHP_STREAM_OPTION_RETURN_OK) {
- if (error_text) {
- *error_text = param.outputs.error_text;
- }
- return param.outputs.returncode;
- }
- return ret;
- }
- /* Get the next client and their address (as a string) */
- PHPAPI int php_stream_xport_accept(php_stream *stream, php_stream **client,
- char **textaddr, int *textaddrlen,
- void **addr, socklen_t *addrlen,
- struct timeval *timeout,
- char **error_text
- TSRMLS_DC)
- {
- php_stream_xport_param param;
- int ret;
- memset(¶m, 0, sizeof(param));
- param.op = STREAM_XPORT_OP_ACCEPT;
- param.inputs.timeout = timeout;
- param.want_addr = addr ? 1 : 0;
- param.want_textaddr = textaddr ? 1 : 0;
- param.want_errortext = error_text ? 1 : 0;
-
- ret = php_stream_set_option(stream, PHP_STREAM_OPTION_XPORT_API, 0, ¶m);
- if (ret == PHP_STREAM_OPTION_RETURN_OK) {
- *client = param.outputs.client;
- if (addr) {
- *addr = param.outputs.addr;
- *addrlen = param.outputs.addrlen;
- }
- if (textaddr) {
- *textaddr = param.outputs.textaddr;
- *textaddrlen = param.outputs.textaddrlen;
- }
- if (error_text) {
- *error_text = param.outputs.error_text;
- }
- return param.outputs.returncode;
- }
- return ret;
- }
- PHPAPI int php_stream_xport_get_name(php_stream *stream, int want_peer,
- char **textaddr, int *textaddrlen,
- void **addr, socklen_t *addrlen
- TSRMLS_DC)
- {
- php_stream_xport_param param;
- int ret;
- memset(¶m, 0, sizeof(param));
- param.op = want_peer ? STREAM_XPORT_OP_GET_PEER_NAME : STREAM_XPORT_OP_GET_NAME;
- param.want_addr = addr ? 1 : 0;
- param.want_textaddr = textaddr ? 1 : 0;
-
- ret = php_stream_set_option(stream, PHP_STREAM_OPTION_XPORT_API, 0, ¶m);
- if (ret == PHP_STREAM_OPTION_RETURN_OK) {
- if (addr) {
- *addr = param.outputs.addr;
- *addrlen = param.outputs.addrlen;
- }
- if (textaddr) {
- *textaddr = param.outputs.textaddr;
- *textaddrlen = param.outputs.textaddrlen;
- }
- return param.outputs.returncode;
- }
- return ret;
- }
- PHPAPI int php_stream_xport_crypto_setup(php_stream *stream, php_stream_xport_crypt_method_t crypto_method, php_stream *session_stream TSRMLS_DC)
- {
- php_stream_xport_crypto_param param;
- int ret;
- memset(¶m, 0, sizeof(param));
- param.op = STREAM_XPORT_CRYPTO_OP_SETUP;
- param.inputs.method = crypto_method;
- param.inputs.session = session_stream;
-
- ret = php_stream_set_option(stream, PHP_STREAM_OPTION_CRYPTO_API, 0, ¶m);
- if (ret == PHP_STREAM_OPTION_RETURN_OK) {
- return param.outputs.returncode;
- }
- php_error_docref("streams.crypto" TSRMLS_CC, E_WARNING, "this stream does not support SSL/crypto");
-
- return ret;
- }
- PHPAPI int php_stream_xport_crypto_enable(php_stream *stream, int activate TSRMLS_DC)
- {
- php_stream_xport_crypto_param param;
- int ret;
- memset(¶m, 0, sizeof(param));
- param.op = STREAM_XPORT_CRYPTO_OP_ENABLE;
- param.inputs.activate = activate;
-
- ret = php_stream_set_option(stream, PHP_STREAM_OPTION_CRYPTO_API, 0, ¶m);
- if (ret == PHP_STREAM_OPTION_RETURN_OK) {
- return param.outputs.returncode;
- }
- php_error_docref("streams.crypto" TSRMLS_CC, E_WARNING, "this stream does not support SSL/crypto");
-
- return ret;
- }
- /* Similar to recv() system call; read data from the stream, optionally
- * peeking, optionally retrieving OOB data */
- PHPAPI int php_stream_xport_recvfrom(php_stream *stream, char *buf, size_t buflen,
- long flags, void **addr, socklen_t *addrlen, char **textaddr, int *textaddrlen
- TSRMLS_DC)
- {
- php_stream_xport_param param;
- int ret = 0;
- int recvd_len = 0;
- #if 0
- int oob;
- if (flags == 0 && addr == NULL) {
- return php_stream_read(stream, buf, buflen);
- }
- if (stream->readfilters.head) {
- php_error_docref(NULL TSRMLS_CC, E_WARNING, "cannot peek or fetch OOB data from a filtered stream");
- return -1;
- }
-
- oob = (flags & STREAM_OOB) == STREAM_OOB;
- if (!oob && addr == NULL) {
- /* must be peeking at regular data; copy content from the buffer
- * first, then adjust the pointer/len before handing off to the
- * stream */
- recvd_len = stream->writepos - stream->readpos;
- if (recvd_len > buflen) {
- recvd_len = buflen;
- }
- if (recvd_len) {
- memcpy(buf, stream->readbuf, recvd_len);
- buf += recvd_len;
- buflen -= recvd_len;
- }
- /* if we filled their buffer, return */
- if (buflen == 0) {
- return recvd_len;
- }
- }
- #endif
- /* otherwise, we are going to bypass the buffer */
-
- memset(¶m, 0, sizeof(param));
- param.op = STREAM_XPORT_OP_RECV;
- param.want_addr = addr ? 1 : 0;
- param.want_textaddr = textaddr ? 1 : 0;
- param.inputs.buf = buf;
- param.inputs.buflen = buflen;
- param.inputs.flags = flags;
-
- ret = php_stream_set_option(stream, PHP_STREAM_OPTION_XPORT_API, 0, ¶m);
- if (ret == PHP_STREAM_OPTION_RETURN_OK) {
- if (addr) {
- *addr = param.outputs.addr;
- *addrlen = param.outputs.addrlen;
- }
- if (textaddr) {
- *textaddr = param.outputs.textaddr;
- *textaddrlen = param.outputs.textaddrlen;
- }
- return recvd_len + param.outputs.returncode;
- }
- return recvd_len ? recvd_len : -1;
- }
- /* Similar to send() system call; send data to the stream, optionally
- * 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)
- {
- php_stream_xport_param param;
- int ret = 0;
- int oob;
- #if 0
- if (flags == 0 && addr == NULL) {
- return php_stream_write(stream, buf, buflen);
- }
- #endif
-
- oob = (flags & STREAM_OOB) == STREAM_OOB;
- if ((oob || addr) && stream->writefilters.head) {
- php_error_docref(NULL TSRMLS_CC, E_WARNING, "cannot write OOB data, or data to a targeted address on a filtered stream");
- return -1;
- }
-
- memset(¶m, 0, sizeof(param));
- param.op = STREAM_XPORT_OP_SEND;
- param.want_addr = addr ? 1 : 0;
- param.inputs.buf = (char*)buf;
- param.inputs.buflen = buflen;
- param.inputs.flags = flags;
- param.inputs.addr = addr;
- param.inputs.addrlen = addrlen;
-
- 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;
- }
- /* 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:
- * tab-width: 4
- * c-basic-offset: 4
- * End:
- * vim600: noet sw=4 ts=4 fdm=marker
- * vim<600: noet sw=4 ts=4
- */
|