⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 ssl_engine_io.c

📁 linux网络服务器工具
💻 C
📖 第 1 页 / 共 5 页
字号:
/* This function will read from a brigade and discard the read buckets as it * proceeds.  It will read at most *len bytes. */static apr_status_t brigade_consume(apr_bucket_brigade *bb,                                    apr_read_type_e block,                                    char *c, apr_size_t *len){    apr_size_t actual = 0;    apr_status_t status = APR_SUCCESS;    while (!APR_BRIGADE_EMPTY(bb)) {        apr_bucket *b = APR_BRIGADE_FIRST(bb);        const char *str;        apr_size_t str_len;        apr_size_t consume;        /* Justin points out this is an http-ism that might         * not fit if brigade_consume is added to APR.  Perhaps         * apr_bucket_read(eos_bucket) should return APR_EOF?         * Then this becomes mainline instead of a one-off.         */        if (APR_BUCKET_IS_EOS(b)) {            status = APR_EOF;            break;        }        /* The reason I'm not offering brigade_consume yet         * across to apr-util is that the following call         * illustrates how borked that API really is.  For         * this sort of case (caller provided buffer) it         * would be much more trivial for apr_bucket_consume         * to do all the work that follows, based on the         * particular characteristics of the bucket we are         * consuming here.         */        status = apr_bucket_read(b, &str, &str_len, block);        if (status != APR_SUCCESS) {            if (APR_STATUS_IS_EOF(status)) {                /* This stream bucket was consumed */                apr_bucket_delete(b);                continue;            }            break;        }        if (str_len > 0) {            /* Do not block once some data has been consumed */            block = APR_NONBLOCK_READ;            /* Assure we don't overflow. */            consume = (str_len + actual > *len) ? *len - actual : str_len;            memcpy(c, str, consume);            c += consume;            actual += consume;            if (consume >= b->length) {                /* This physical bucket was consumed */                apr_bucket_delete(b);            }            else {                /* Only part of this physical bucket was consumed */                b->start += consume;                b->length -= consume;            }        }        else if (b->length == 0) {            apr_bucket_delete(b);        }        /* This could probably be actual == *len, but be safe from stray         * photons. */        if (actual >= *len) {            break;        }    }    *len = actual;    return status;}/* * this is the function called by SSL_read() */static int bio_filter_in_read(BIO *bio, char *in, int inlen){    apr_size_t inl = inlen;    bio_filter_in_ctx_t *inctx = (bio_filter_in_ctx_t *)(bio->ptr);    apr_read_type_e block = inctx->block;    SSLConnRec *sslconn = myConnConfig(inctx->f->c);    inctx->rc = APR_SUCCESS;    /* OpenSSL catches this case, so should we. */    if (!in)        return 0;    /* XXX: flush here only required for SSLv2;     * OpenSSL calls BIO_flush() at the appropriate times for     * the other protocols.     */    if ((SSL_version(inctx->ssl) == SSL2_VERSION) || sslconn->is_proxy) {        if (bio_filter_out_flush(inctx->bio_out) < 0) {            bio_filter_out_ctx_t *outctx =                   (bio_filter_out_ctx_t *)(inctx->bio_out->ptr);            inctx->rc = outctx->rc;            return -1;        }    }    BIO_clear_retry_flags(bio);    if (!inctx->bb) {        inctx->rc = APR_EOF;        return -1;    }    if (APR_BRIGADE_EMPTY(inctx->bb)) {        inctx->rc = ap_get_brigade(inctx->f->next, inctx->bb,                                   AP_MODE_READBYTES, block,                                   inl);        /* If the read returns EAGAIN or success with an empty         * brigade, return an error after setting the retry flag;         * SSL_read() will then return -1, and SSL_get_error() will         * indicate SSL_ERROR_WANT_READ. */        if (APR_STATUS_IS_EAGAIN(inctx->rc) || APR_STATUS_IS_EINTR(inctx->rc)               || (inctx->rc == APR_SUCCESS && APR_BRIGADE_EMPTY(inctx->bb))) {            BIO_set_retry_read(bio);            return -1;        }        if (inctx->rc != APR_SUCCESS) {            /* Unexpected errors discard the brigade */            apr_brigade_cleanup(inctx->bb);            inctx->bb = NULL;            return -1;        }    }    inctx->rc = brigade_consume(inctx->bb, block, in, &inl);    if (inctx->rc == APR_SUCCESS) {        return (int)inl;    }    if (APR_STATUS_IS_EAGAIN(inctx->rc)            || APR_STATUS_IS_EINTR(inctx->rc)) {        BIO_set_retry_read(bio);        return (int)inl;    }    /* Unexpected errors and APR_EOF clean out the brigade.     * Subsequent calls will return APR_EOF.     */    apr_brigade_cleanup(inctx->bb);    inctx->bb = NULL;    if (APR_STATUS_IS_EOF(inctx->rc) && inl) {        /* Provide the results of this read pass,         * without resetting the BIO retry_read flag         */        return (int)inl;    }    return -1;}static BIO_METHOD bio_filter_in_method = {    BIO_TYPE_MEM,    "APR input filter",    NULL,                       /* write is never called */    bio_filter_in_read,    NULL,                       /* puts is never called */    NULL,                       /* gets is never called */    NULL,                       /* ctrl is never called */    bio_filter_create,    bio_filter_destroy,#ifdef OPENSSL_VERSION_NUMBER    NULL /* sslc does not have the callback_ctrl field */#endif};static apr_status_t ssl_io_input_read(bio_filter_in_ctx_t *inctx,                                      char *buf,                                      apr_size_t *len){    apr_size_t wanted = *len;    apr_size_t bytes = 0;    int rc;    *len = 0;    /* If we have something leftover from last time, try that first. */    if ((bytes = char_buffer_read(&inctx->cbuf, buf, wanted))) {        *len = bytes;        if (inctx->mode == AP_MODE_SPECULATIVE) {            /* We want to rollback this read. */            if (inctx->cbuf.length > 0) {                inctx->cbuf.value -= bytes;                inctx->cbuf.length += bytes;            } else {                char_buffer_write(&inctx->cbuf, buf, (int)bytes);            }            return APR_SUCCESS;        }        /* This could probably be *len == wanted, but be safe from stray         * photons.         */        if (*len >= wanted) {            return APR_SUCCESS;        }        if (inctx->mode == AP_MODE_GETLINE) {            if (memchr(buf, APR_ASCII_LF, *len)) {                return APR_SUCCESS;            }        }        else {            /* Down to a nonblock pattern as we have some data already             */            inctx->block = APR_NONBLOCK_READ;        }    }    while (1) {        if (!inctx->filter_ctx->pssl) {            /* Ensure a non-zero error code is returned */            if (inctx->rc == APR_SUCCESS) {                inctx->rc = APR_EGENERAL;            }            break;        }        /* SSL_read may not read because we haven't taken enough data         * from the stack.  This is where we want to consider all of         * the blocking and SPECULATIVE semantics         */        rc = SSL_read(inctx->filter_ctx->pssl, buf + bytes, wanted - bytes);        if (rc > 0) {            *len += rc;            if (inctx->mode == AP_MODE_SPECULATIVE) {                /* We want to rollback this read. */                char_buffer_write(&inctx->cbuf, buf, rc);            }            return inctx->rc;        }        else if (rc == 0) {            /* If EAGAIN, we will loop given a blocking read,             * otherwise consider ourselves at EOF.             */            if (APR_STATUS_IS_EAGAIN(inctx->rc)                    || APR_STATUS_IS_EINTR(inctx->rc)) {                /* Already read something, return APR_SUCCESS instead.                 * On win32 in particular, but perhaps on other kernels,                 * a blocking call isn't 'always' blocking.                 */                if (*len > 0) {                    inctx->rc = APR_SUCCESS;                    break;                }                if (inctx->block == APR_NONBLOCK_READ) {                    break;                }            }            else {                if (*len > 0) {                    inctx->rc = APR_SUCCESS;                }                else {                    inctx->rc = APR_EOF;                }                break;            }        }        else /* (rc < 0) */ {            int ssl_err = SSL_get_error(inctx->filter_ctx->pssl, rc);            conn_rec *c = (conn_rec*)SSL_get_app_data(inctx->filter_ctx->pssl);            if (ssl_err == SSL_ERROR_WANT_READ) {                /*                 * If OpenSSL wants to read more, and we were nonblocking,                 * report as an EAGAIN.  Otherwise loop, pulling more                 * data from network filter.                 *                 * (This is usually the case when the client forces an SSL                 * renegotation which is handled implicitly by OpenSSL.)                 */                inctx->rc = APR_EAGAIN;                if (*len > 0) {                    inctx->rc = APR_SUCCESS;                    break;                }                if (inctx->block == APR_NONBLOCK_READ) {                    break;                }                continue;  /* Blocking and nothing yet?  Try again. */            }            else if (ssl_err == SSL_ERROR_SYSCALL) {                if (APR_STATUS_IS_EAGAIN(inctx->rc)                        || APR_STATUS_IS_EINTR(inctx->rc)) {                    /* Already read something, return APR_SUCCESS instead. */                    if (*len > 0) {                        inctx->rc = APR_SUCCESS;                        break;                    }                    if (inctx->block == APR_NONBLOCK_READ) {                        break;                    }                    continue;  /* Blocking and nothing yet?  Try again. */                }                else {                    ap_log_cerror(APLOG_MARK, APLOG_INFO, inctx->rc, c,                                  "SSL input filter read failed.");                }            }            else /* if (ssl_err == SSL_ERROR_SSL) */ {                /*                 * Log SSL errors and any unexpected conditions.                 */                ap_log_cerror(APLOG_MARK, APLOG_INFO, inctx->rc, c,                              "SSL library error %d reading data", ssl_err);                ssl_log_ssl_error(APLOG_MARK, APLOG_INFO, c->base_server);            }            if (inctx->rc == APR_SUCCESS) {                inctx->rc = APR_EGENERAL;            }            break;        }    }    return inctx->rc;}static apr_status_t ssl_io_input_getline(bio_filter_in_ctx_t *inctx,                                         char *buf,                                         apr_size_t *len){    const char *pos = NULL;    apr_status_t status;    apr_size_t tmplen = *len, buflen = *len, offset = 0;    *len = 0;    /*     * in most cases we get all the headers on the first SSL_read.     * however, in certain cases SSL_read will only get a partial     * chunk of the headers, so we try to read until LF is seen.     */    while (tmplen > 0) {        status = ssl_io_input_read(inctx, buf + offset, &tmplen);        if (status != APR_SUCCESS) {            return status;        }        *len += tmplen;        if ((pos = memchr(buf, APR_ASCII_LF, *len))) {            break;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -