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

📄 ssl_engine_io.c

📁 apache服务器源代码(版本号:2.2.2)
💻 C
📖 第 1 页 / 共 4 页
字号:
}/* * 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;        }        offset += tmplen;        tmplen = buflen - offset;    }    if (pos) {        char *value;        int length;        apr_size_t bytes = pos - buf;        bytes += 1;        value = buf + bytes;        length = *len - bytes;        char_buffer_write(&inctx->cbuf, value, length);        *len = bytes;    }    return APR_SUCCESS;}static apr_status_t ssl_filter_write(ap_filter_t *f,                                     const char *data,                                     apr_size_t len){    ssl_filter_ctx_t *filter_ctx = f->ctx;    bio_filter_out_ctx_t *outctx;    int res;    /* write SSL */    if (filter_ctx->pssl == NULL) {        return APR_EGENERAL;    }    outctx = (bio_filter_out_ctx_t *)filter_ctx->pbioWrite->ptr;    res = SSL_write(filter_ctx->pssl, (unsigned char *)data, len);    if (res < 0) {        int ssl_err = SSL_get_error(filter_ctx->pssl, res);        conn_rec *c = (conn_rec*)SSL_get_app_data(outctx->filter_ctx->pssl);        if (ssl_err == SSL_ERROR_WANT_WRITE) {            /*             * If OpenSSL wants to write more, and we were nonblocking,             * report as an EAGAIN.  Otherwise loop, pushing more             * data at the network filter.             *             * (This is usually the case when the client forces an SSL             * renegotation which is handled implicitly by OpenSSL.)             */            outctx->rc = APR_EAGAIN;        }        else if (ssl_err == SSL_ERROR_SYSCALL) {            ap_log_cerror(APLOG_MARK, APLOG_INFO, outctx->rc, c,                          "SSL output filter write failed.");        }        else /* if (ssl_err == SSL_ERROR_SSL) */ {            /*             * Log SSL errors             */            ap_log_cerror(APLOG_MARK, APLOG_INFO, outctx->rc, c,                          "SSL library error %d writing data", ssl_err);            ssl_log_ssl_error(APLOG_MARK, APLOG_INFO, c->base_server);        }        if (outctx->rc == APR_SUCCESS) {            outctx->rc = APR_EGENERAL;        }    }    else if ((apr_size_t)res != len) {        conn_rec *c = f->c;        char *reason = "reason unknown";        /* XXX: probably a better way to determine this */        if (SSL_total_renegotiations(filter_ctx->pssl)) {            reason = "likely due to failed renegotiation";        }        ap_log_cerror(APLOG_MARK, APLOG_INFO, outctx->rc, c,                      "failed to write %" APR_SSIZE_T_FMT                      " of %" APR_SIZE_T_FMT " bytes (%s)",                      len - (apr_size_t)res, len, reason);        outctx->rc = APR_EGENERAL;    }    return outctx->rc;}/* Just use a simple request.  Any request will work for this, because * we use a flag in the conn_rec->conn_vector now.  The fake request just * gets the request back to the Apache core so that a response can be sent. * * To avoid calling back for more data from the socket, use an HTTP/0.9 * request, and tack on an EOS bucket. */#define HTTP_ON_HTTPS_PORT \    "GET /" CRLF#define HTTP_ON_HTTPS_PORT_BUCKET(alloc) \    apr_bucket_immortal_create(HTTP_ON_HTTPS_PORT, \                               sizeof(HTTP_ON_HTTPS_PORT) - 1, \                               alloc)static void ssl_io_filter_disable(SSLConnRec *sslconn, ap_filter_t *f){    bio_filter_in_ctx_t *inctx = f->ctx;    SSL_free(inctx->ssl);    sslconn->ssl = NULL;    inctx->ssl = NULL;    inctx->filter_ctx->pssl = NULL;}static apr_status_t ssl_io_filter_error(ap_filter_t *f,                                        apr_bucket_brigade *bb,                                        apr_status_t status){    SSLConnRec *sslconn = myConnConfig(f->c);    apr_bucket *bucket;    switch (status) {      case HTTP_BAD_REQUEST:            /* log the situation */            ap_log_cerror(APLOG_MARK, APLOG_INFO, 0, f->c,                         "SSL handshake failed: HTTP spoken on HTTPS port; "                         "trying to send HTML error page");            ssl_log_ssl_error(APLOG_MARK, APLOG_INFO, f->c->base_server);            sslconn->non_ssl_request = 1;            ssl_io_filter_disable(sslconn, f);            /* fake the request line */            bucket = HTTP_ON_HTTPS_PORT_BUCKET(f->c->bucket_alloc);            break;      default:        return status;    }    APR_BRIGADE_INSERT_TAIL(bb, bucket);    bucket = apr_bucket_eos_create(f->c->bucket_alloc);    APR_BRIGADE_INSERT_TAIL(bb, bucket);    return APR_SUCCESS;}static const char ssl_io_filter[] = "SSL/TLS Filter";static const char ssl_io_buffer[] = "SSL/TLS Buffer";/* *  Close the SSL part of the socket connection *  (called immediately _before_ the socket is closed) *  or called with */static apr_status_t ssl_filter_io_shutdown(ssl_filter_ctx_t *filter_ctx,                                           conn_rec *c,                                           int abortive){    SSL *ssl = filter_ctx->pssl;    const char *type = "";    SSLConnRec *sslconn = myConnConfig(c);

⌨️ 快捷键说明

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