Annotation of embedaddon/php/main/streams/transports.c, revision 1.1.1.3

1.1       misho       1: /*
                      2:   +----------------------------------------------------------------------+
                      3:   | PHP Version 5                                                        |
                      4:   +----------------------------------------------------------------------+
1.1.1.3 ! misho       5:   | Copyright (c) 1997-2013 The PHP Group                                |
1.1       misho       6:   +----------------------------------------------------------------------+
                      7:   | This source file is subject to version 3.01 of the PHP license,      |
                      8:   | that is bundled with this package in the file LICENSE, and is        |
                      9:   | available through the world-wide-web at the following url:           |
                     10:   | http://www.php.net/license/3_01.txt                                  |
                     11:   | If you did not receive a copy of the PHP license and are unable to   |
                     12:   | obtain it through the world-wide-web, please send a note to          |
                     13:   | license@php.net so we can mail you a copy immediately.               |
                     14:   +----------------------------------------------------------------------+
                     15:   | Author: Wez Furlong <wez@thebrainroom.com>                           |
                     16:   +----------------------------------------------------------------------+
                     17: */
                     18: 
1.1.1.2   misho      19: /* $Id$ */
1.1       misho      20: 
                     21: #include "php.h"
                     22: #include "php_streams_int.h"
                     23: #include "ext/standard/file.h"
                     24: 
                     25: static HashTable xport_hash;
                     26: 
                     27: PHPAPI HashTable *php_stream_xport_get_hash(void)
                     28: {
                     29:        return &xport_hash;
                     30: }
                     31: 
                     32: PHPAPI int php_stream_xport_register(char *protocol, php_stream_transport_factory factory TSRMLS_DC)
                     33: {
                     34:        return zend_hash_update(&xport_hash, protocol, strlen(protocol) + 1, &factory, sizeof(factory), NULL);
                     35: }
                     36: 
                     37: PHPAPI int php_stream_xport_unregister(char *protocol TSRMLS_DC)
                     38: {
                     39:        return zend_hash_del(&xport_hash, protocol, strlen(protocol) + 1);
                     40: }
                     41: 
                     42: #define ERR_REPORT(out_err, fmt, arg) \
                     43:        if (out_err) { spprintf(out_err, 0, fmt, arg); } \
                     44:        else { php_error_docref(NULL TSRMLS_CC, E_WARNING, fmt, arg); }
                     45: 
                     46: #define ERR_RETURN(out_err, local_err, fmt) \
                     47:        if (out_err) { *out_err = local_err; } \
                     48:        else { php_error_docref(NULL TSRMLS_CC, E_WARNING, fmt, local_err ? local_err : "Unspecified error"); \
                     49:                if (local_err) { efree(local_err); local_err = NULL; } \
                     50:        }
                     51:        
                     52: PHPAPI php_stream *_php_stream_xport_create(const char *name, long namelen, int options,
                     53:                int flags, const char *persistent_id,
                     54:                struct timeval *timeout,
                     55:                php_stream_context *context,
                     56:                char **error_string,
                     57:                int *error_code
                     58:                STREAMS_DC TSRMLS_DC)
                     59: {
                     60:        php_stream *stream = NULL;
                     61:        php_stream_transport_factory *factory = NULL;
                     62:        const char *p, *protocol = NULL;
                     63:        int n = 0, failed = 0;
                     64:        char *error_text = NULL;
                     65:        struct timeval default_timeout = { 0, 0 };
                     66:        
                     67:        default_timeout.tv_sec = FG(default_socket_timeout);
                     68: 
                     69:        if (timeout == NULL) {
                     70:                timeout = &default_timeout;
                     71:        }
                     72:        
                     73:        /* check for a cached persistent socket */
                     74:        if (persistent_id) {
                     75:                switch(php_stream_from_persistent_id(persistent_id, &stream TSRMLS_CC)) {
                     76:                        case PHP_STREAM_PERSISTENT_SUCCESS:
                     77:                                /* use a 0 second timeout when checking if the socket
                     78:                                 * has already died */
                     79:                                if (PHP_STREAM_OPTION_RETURN_OK == php_stream_set_option(stream, PHP_STREAM_OPTION_CHECK_LIVENESS, 0, NULL)) {
                     80:                                        return stream;
                     81:                                }
                     82:                                /* dead - kill it */
                     83:                                php_stream_pclose(stream);
                     84:                                stream = NULL;
                     85: 
                     86:                                /* fall through */
                     87: 
                     88:                        case PHP_STREAM_PERSISTENT_FAILURE:
                     89:                        default:
                     90:                                /* failed; get a new one */
                     91:                                ;
                     92:                }
                     93:        }
                     94: 
                     95:        for (p = name; isalnum((int)*p) || *p == '+' || *p == '-' || *p == '.'; p++) {
                     96:                n++;
                     97:        }
                     98: 
                     99:        if ((*p == ':') && (n > 1) && !strncmp("://", p, 3)) {
                    100:                protocol = name;
                    101:                name = p + 3;
                    102:                namelen -= n + 3;
                    103:        } else {
                    104:                protocol = "tcp";
                    105:                n = 3;
                    106:        }
                    107: 
                    108:        if (protocol) {
                    109:                char *tmp = estrndup(protocol, n);
                    110:                if (FAILURE == zend_hash_find(&xport_hash, (char*)tmp, n + 1, (void**)&factory)) {
                    111:                        char wrapper_name[32];
                    112: 
                    113:                        if (n >= sizeof(wrapper_name))
                    114:                                n = sizeof(wrapper_name) - 1;
                    115:                        PHP_STRLCPY(wrapper_name, protocol, sizeof(wrapper_name), n);
                    116:                
                    117:                        ERR_REPORT(error_string, "Unable to find the socket transport \"%s\" - did you forget to enable it when you configured PHP?",
                    118:                                        wrapper_name);
                    119: 
                    120:                        efree(tmp);
                    121:                        return NULL;
                    122:                }
                    123:                efree(tmp);
                    124:        }
                    125: 
                    126:        if (factory == NULL) {
                    127:                /* should never happen */
                    128:                php_error_docref(NULL TSRMLS_CC, E_WARNING, "Could not find a factory !?");
                    129:                return NULL;
                    130:        }
                    131: 
                    132:        stream = (*factory)(protocol, n,
                    133:                        (char*)name, namelen, persistent_id, options, flags, timeout,
                    134:                        context STREAMS_REL_CC TSRMLS_CC);
                    135: 
                    136:        if (stream) {
                    137:                php_stream_context_set(stream, context);
                    138: 
                    139:                if ((flags & STREAM_XPORT_SERVER) == 0) {
                    140:                        /* client */
                    141: 
                    142:                        if (flags & (STREAM_XPORT_CONNECT|STREAM_XPORT_CONNECT_ASYNC)) {
                    143:                                if (-1 == php_stream_xport_connect(stream, name, namelen,
                    144:                                                        flags & STREAM_XPORT_CONNECT_ASYNC ? 1 : 0,
                    145:                                                        timeout, &error_text, error_code TSRMLS_CC)) {
                    146: 
                    147:                                        ERR_RETURN(error_string, error_text, "connect() failed: %s");
                    148: 
                    149:                                        failed = 1;
                    150:                                }
                    151:                        }
                    152: 
                    153:                } else {
                    154:                        /* server */
                    155:                        if (flags & STREAM_XPORT_BIND) {
                    156:                                if (0 != php_stream_xport_bind(stream, name, namelen, &error_text TSRMLS_CC)) {
                    157:                                        ERR_RETURN(error_string, error_text, "bind() failed: %s");
                    158:                                        failed = 1;
                    159:                                } else if (flags & STREAM_XPORT_LISTEN) {
                    160:                                        zval **zbacklog = NULL;
                    161:                                        int backlog = 32;
                    162:                                        
                    163:                                        if (stream->context && php_stream_context_get_option(stream->context, "socket", "backlog", &zbacklog) == SUCCESS) {
                    164:                                                zval *ztmp = *zbacklog;
                    165:                                                
                    166:                                                convert_to_long_ex(&ztmp);
                    167:                                                backlog = Z_LVAL_P(ztmp);
                    168:                                                if (ztmp != *zbacklog) {
                    169:                                                        zval_ptr_dtor(&ztmp);
                    170:                                                }
                    171:                                        }
                    172:                                        
                    173:                                        if (0 != php_stream_xport_listen(stream, backlog, &error_text TSRMLS_CC)) {
                    174:                                                ERR_RETURN(error_string, error_text, "listen() failed: %s");
                    175:                                                failed = 1;
                    176:                                        }
                    177:                                }
                    178:                        }
                    179:                }
                    180:        }
                    181: 
                    182:        if (failed) {
                    183:                /* failure means that they don't get a stream to play with */
                    184:                if (persistent_id) {
                    185:                        php_stream_pclose(stream);
                    186:                } else {
                    187:                        php_stream_close(stream);
                    188:                }
                    189:                stream = NULL;
                    190:        }
                    191: 
                    192:        return stream;
                    193: }
                    194: 
                    195: /* Bind the stream to a local address */
                    196: PHPAPI int php_stream_xport_bind(php_stream *stream,
                    197:                const char *name, long namelen,
                    198:                char **error_text
                    199:                TSRMLS_DC)
                    200: {
                    201:        php_stream_xport_param param;
                    202:        int ret;
                    203:        
                    204:        memset(&param, 0, sizeof(param));
                    205:        param.op = STREAM_XPORT_OP_BIND;
                    206:        param.inputs.name = (char*)name;
                    207:        param.inputs.namelen = namelen;
                    208:        param.want_errortext = error_text ? 1 : 0;
                    209: 
                    210:        ret = php_stream_set_option(stream, PHP_STREAM_OPTION_XPORT_API, 0, &param);
                    211: 
                    212:        if (ret == PHP_STREAM_OPTION_RETURN_OK) {
                    213:                if (error_text) {
                    214:                        *error_text = param.outputs.error_text;
                    215:                }
                    216: 
                    217:                return param.outputs.returncode;
                    218:        }
                    219: 
                    220:        return ret;
                    221: }
                    222: 
                    223: /* Connect to a remote address */
                    224: PHPAPI int php_stream_xport_connect(php_stream *stream,
                    225:                const char *name, long namelen,
                    226:                int asynchronous,
                    227:                struct timeval *timeout,
                    228:                char **error_text,
                    229:                int *error_code
                    230:                TSRMLS_DC)
                    231: {
                    232:        php_stream_xport_param param;
                    233:        int ret;
                    234:        
                    235:        memset(&param, 0, sizeof(param));
                    236:        param.op = asynchronous ? STREAM_XPORT_OP_CONNECT_ASYNC: STREAM_XPORT_OP_CONNECT;
                    237:        param.inputs.name = (char*)name;
                    238:        param.inputs.namelen = namelen;
                    239:        param.inputs.timeout = timeout;
                    240: 
                    241:        param.want_errortext = error_text ? 1 : 0;
                    242:        
                    243:        ret = php_stream_set_option(stream, PHP_STREAM_OPTION_XPORT_API, 0, &param);
                    244: 
                    245:        if (ret == PHP_STREAM_OPTION_RETURN_OK) {
                    246:                if (error_text) {
                    247:                        *error_text = param.outputs.error_text;
                    248:                }
                    249:                if (error_code) {
                    250:                        *error_code = param.outputs.error_code;
                    251:                }
                    252:                return param.outputs.returncode;
                    253:        }
                    254: 
                    255:        return ret;
                    256: 
                    257: }
                    258: 
                    259: /* Prepare to listen */
                    260: PHPAPI int php_stream_xport_listen(php_stream *stream, int backlog, char **error_text TSRMLS_DC)
                    261: {
                    262:        php_stream_xport_param param;
                    263:        int ret;
                    264:        
                    265:        memset(&param, 0, sizeof(param));
                    266:        param.op = STREAM_XPORT_OP_LISTEN;
                    267:        param.inputs.backlog = backlog;
                    268:        param.want_errortext = error_text ? 1 : 0;
                    269:        
                    270:        ret = php_stream_set_option(stream, PHP_STREAM_OPTION_XPORT_API, 0, &param);
                    271: 
                    272:        if (ret == PHP_STREAM_OPTION_RETURN_OK) {
                    273:                if (error_text) {
                    274:                        *error_text = param.outputs.error_text;
                    275:                }
                    276: 
                    277:                return param.outputs.returncode;
                    278:        }
                    279: 
                    280:        return ret;
                    281: }
                    282: 
                    283: /* Get the next client and their address (as a string) */
                    284: PHPAPI int php_stream_xport_accept(php_stream *stream, php_stream **client,
                    285:                char **textaddr, int *textaddrlen,
                    286:                void **addr, socklen_t *addrlen,
                    287:                struct timeval *timeout,
                    288:                char **error_text
                    289:                TSRMLS_DC)
                    290: {
                    291:        php_stream_xport_param param;
                    292:        int ret;
                    293: 
                    294:        memset(&param, 0, sizeof(param));
                    295: 
                    296:        param.op = STREAM_XPORT_OP_ACCEPT;
                    297:        param.inputs.timeout = timeout;
                    298:        param.want_addr = addr ? 1 : 0;
                    299:        param.want_textaddr = textaddr ? 1 : 0;
                    300:        param.want_errortext = error_text ? 1 : 0;
                    301:        
                    302:        ret = php_stream_set_option(stream, PHP_STREAM_OPTION_XPORT_API, 0, &param);
                    303: 
                    304:        if (ret == PHP_STREAM_OPTION_RETURN_OK) {
                    305:                *client = param.outputs.client;
                    306:                if (addr) {
                    307:                        *addr = param.outputs.addr;
                    308:                        *addrlen = param.outputs.addrlen;
                    309:                }
                    310:                if (textaddr) {
                    311:                        *textaddr = param.outputs.textaddr;
                    312:                        *textaddrlen = param.outputs.textaddrlen;
                    313:                }
                    314:                if (error_text) {
                    315:                        *error_text = param.outputs.error_text;
                    316:                }
                    317: 
                    318:                return param.outputs.returncode;
                    319:        }
                    320:        return ret;
                    321: }
                    322: 
                    323: PHPAPI int php_stream_xport_get_name(php_stream *stream, int want_peer,
                    324:                char **textaddr, int *textaddrlen,
                    325:                void **addr, socklen_t *addrlen
                    326:                TSRMLS_DC)
                    327: {
                    328:        php_stream_xport_param param;
                    329:        int ret;
                    330: 
                    331:        memset(&param, 0, sizeof(param));
                    332: 
                    333:        param.op = want_peer ? STREAM_XPORT_OP_GET_PEER_NAME : STREAM_XPORT_OP_GET_NAME;
                    334:        param.want_addr = addr ? 1 : 0;
                    335:        param.want_textaddr = textaddr ? 1 : 0;
                    336:        
                    337:        ret = php_stream_set_option(stream, PHP_STREAM_OPTION_XPORT_API, 0, &param);
                    338: 
                    339:        if (ret == PHP_STREAM_OPTION_RETURN_OK) {
                    340:                if (addr) {
                    341:                        *addr = param.outputs.addr;
                    342:                        *addrlen = param.outputs.addrlen;
                    343:                }
                    344:                if (textaddr) {
                    345:                        *textaddr = param.outputs.textaddr;
                    346:                        *textaddrlen = param.outputs.textaddrlen;
                    347:                }
                    348: 
                    349:                return param.outputs.returncode;
                    350:        }
                    351:        return ret;
                    352: }
                    353: 
                    354: PHPAPI int php_stream_xport_crypto_setup(php_stream *stream, php_stream_xport_crypt_method_t crypto_method, php_stream *session_stream TSRMLS_DC)
                    355: {
                    356:        php_stream_xport_crypto_param param;
                    357:        int ret;
                    358: 
                    359:        memset(&param, 0, sizeof(param));
                    360:        param.op = STREAM_XPORT_CRYPTO_OP_SETUP;
                    361:        param.inputs.method = crypto_method;
                    362:        param.inputs.session = session_stream;
                    363:        
                    364:        ret = php_stream_set_option(stream, PHP_STREAM_OPTION_CRYPTO_API, 0, &param);
                    365: 
                    366:        if (ret == PHP_STREAM_OPTION_RETURN_OK) {
                    367:                return param.outputs.returncode;
                    368:        }
                    369: 
                    370:        php_error_docref("streams.crypto" TSRMLS_CC, E_WARNING, "this stream does not support SSL/crypto");
                    371:        
                    372:        return ret;
                    373: }
                    374: 
                    375: PHPAPI int php_stream_xport_crypto_enable(php_stream *stream, int activate TSRMLS_DC)
                    376: {
                    377:        php_stream_xport_crypto_param param;
                    378:        int ret;
                    379: 
                    380:        memset(&param, 0, sizeof(param));
                    381:        param.op = STREAM_XPORT_CRYPTO_OP_ENABLE;
                    382:        param.inputs.activate = activate;
                    383:        
                    384:        ret = php_stream_set_option(stream, PHP_STREAM_OPTION_CRYPTO_API, 0, &param);
                    385: 
                    386:        if (ret == PHP_STREAM_OPTION_RETURN_OK) {
                    387:                return param.outputs.returncode;
                    388:        }
                    389: 
                    390:        php_error_docref("streams.crypto" TSRMLS_CC, E_WARNING, "this stream does not support SSL/crypto");
                    391:        
                    392:        return ret;
                    393: }
                    394: 
                    395: /* Similar to recv() system call; read data from the stream, optionally
                    396:  * peeking, optionally retrieving OOB data */
                    397: PHPAPI int php_stream_xport_recvfrom(php_stream *stream, char *buf, size_t buflen,
                    398:                long flags, void **addr, socklen_t *addrlen, char **textaddr, int *textaddrlen
                    399:                TSRMLS_DC)
                    400: {
                    401:        php_stream_xport_param param;
                    402:        int ret = 0;
                    403:        int recvd_len = 0;
                    404: #if 0
                    405:        int oob;
                    406: 
                    407:        if (flags == 0 && addr == NULL) {
                    408:                return php_stream_read(stream, buf, buflen);
                    409:        }
                    410: 
                    411:        if (stream->readfilters.head) {
                    412:                php_error_docref(NULL TSRMLS_CC, E_WARNING, "cannot peek or fetch OOB data from a filtered stream");
                    413:                return -1;
                    414:        }
                    415:        
                    416:        oob = (flags & STREAM_OOB) == STREAM_OOB;
                    417: 
                    418:        if (!oob && addr == NULL) {
                    419:                /* must be peeking at regular data; copy content from the buffer
                    420:                 * first, then adjust the pointer/len before handing off to the
                    421:                 * stream */
                    422:                recvd_len = stream->writepos - stream->readpos;
                    423:                if (recvd_len > buflen) {
                    424:                        recvd_len = buflen;
                    425:                }
                    426:                if (recvd_len) {
                    427:                        memcpy(buf, stream->readbuf, recvd_len);
                    428:                        buf += recvd_len;
                    429:                        buflen -= recvd_len;
                    430:                }
                    431:                /* if we filled their buffer, return */
                    432:                if (buflen == 0) {
                    433:                        return recvd_len;
                    434:                }
                    435:        }
                    436: #endif
                    437: 
                    438:        /* otherwise, we are going to bypass the buffer */
                    439:        
                    440:        memset(&param, 0, sizeof(param));
                    441: 
                    442:        param.op = STREAM_XPORT_OP_RECV;
                    443:        param.want_addr = addr ? 1 : 0;
                    444:        param.want_textaddr = textaddr ? 1 : 0;
                    445:        param.inputs.buf = buf;
                    446:        param.inputs.buflen = buflen;
                    447:        param.inputs.flags = flags;
                    448:        
                    449:        ret = php_stream_set_option(stream, PHP_STREAM_OPTION_XPORT_API, 0, &param);
                    450: 
                    451:        if (ret == PHP_STREAM_OPTION_RETURN_OK) {
                    452:                if (addr) {
                    453:                        *addr = param.outputs.addr;
                    454:                        *addrlen = param.outputs.addrlen;
                    455:                }
                    456:                if (textaddr) {
                    457:                        *textaddr = param.outputs.textaddr;
                    458:                        *textaddrlen = param.outputs.textaddrlen;
                    459:                }
                    460:                return recvd_len + param.outputs.returncode;
                    461:        }
                    462:        return recvd_len ? recvd_len : -1;
                    463: }
                    464: 
                    465: /* Similar to send() system call; send data to the stream, optionally
                    466:  * sending it as OOB data */
                    467: PHPAPI int php_stream_xport_sendto(php_stream *stream, const char *buf, size_t buflen,
                    468:                long flags, void *addr, socklen_t addrlen TSRMLS_DC)
                    469: {
                    470:        php_stream_xport_param param;
                    471:        int ret = 0;
                    472:        int oob;
                    473: 
                    474: #if 0
                    475:        if (flags == 0 && addr == NULL) {
                    476:                return php_stream_write(stream, buf, buflen);
                    477:        }
                    478: #endif
                    479:        
                    480:        oob = (flags & STREAM_OOB) == STREAM_OOB;
                    481: 
                    482:        if ((oob || addr) && stream->writefilters.head) {
                    483:                php_error_docref(NULL TSRMLS_CC, E_WARNING, "cannot write OOB data, or data to a targeted address on a filtered stream");
                    484:                return -1;
                    485:        }
                    486:        
                    487:        memset(&param, 0, sizeof(param));
                    488: 
                    489:        param.op = STREAM_XPORT_OP_SEND;
                    490:        param.want_addr = addr ? 1 : 0;
                    491:        param.inputs.buf = (char*)buf;
                    492:        param.inputs.buflen = buflen;
                    493:        param.inputs.flags = flags;
                    494:        param.inputs.addr = addr;
                    495:        param.inputs.addrlen = addrlen;
                    496:        
                    497:        ret = php_stream_set_option(stream, PHP_STREAM_OPTION_XPORT_API, 0, &param);
                    498: 
                    499:        if (ret == PHP_STREAM_OPTION_RETURN_OK) {
                    500:                return param.outputs.returncode;
                    501:        }
                    502:        return -1;
                    503: }
                    504: 
                    505: /* Similar to shutdown() system call; shut down part of a full-duplex
                    506:  * connection */
                    507: PHPAPI int php_stream_xport_shutdown(php_stream *stream, stream_shutdown_t how TSRMLS_DC)
                    508: {
                    509:        php_stream_xport_param param;
                    510:        int ret = 0;
                    511: 
                    512:        memset(&param, 0, sizeof(param));
                    513: 
                    514:        param.op = STREAM_XPORT_OP_SHUTDOWN;
                    515:        param.how = how;
                    516:        
                    517:        ret = php_stream_set_option(stream, PHP_STREAM_OPTION_XPORT_API, 0, &param);
                    518: 
                    519:        if (ret == PHP_STREAM_OPTION_RETURN_OK) {
                    520:                return param.outputs.returncode;
                    521:        }
                    522:        return -1;
                    523: }
                    524: 
                    525: /*
                    526:  * Local variables:
                    527:  * tab-width: 4
                    528:  * c-basic-offset: 4
                    529:  * End:
                    530:  * vim600: noet sw=4 ts=4 fdm=marker
                    531:  * vim<600: noet sw=4 ts=4
                    532:  */

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>