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

1.1     ! misho       1: /*
        !             2:   +----------------------------------------------------------------------+
        !             3:   | PHP Version 5                                                        |
        !             4:   +----------------------------------------------------------------------+
        !             5:   | Copyright (c) 1997-2012 The PHP Group                                |
        !             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: 
        !            19: /* $Id: transports.c 321634 2012-01-01 13:15:04Z felipe $ */
        !            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>