nginx调用openssl函数源码分析

NGINX部分

在ngx_http_init_connection中把recv→handler设置为ngx_http_ssl_handshake。

然后将这个读时间加入到epoll中,主要是分析handshake函数。

receive client hello

static void

ngx_http_ssl_handshake(ngx_event_t *rev)

{

...

    n = recv(c->fd, (char *) buf, size, MSG_PEEK);

    //判断协议

    if (n == 1) {

        if (buf[0] & 0x80 /* SSLv2 */ || buf[0] == 0x16 /* SSLv3/TLSv1 */) {

            // 获取loc conf和server conf
            clcf = ngx_http_get_module_loc_conf(hc->conf_ctx,
                                                ngx_http_core_module);


            if (clcf->tcp_nodelay && ngx_tcp_nodelay(c) != NGX_OK) {
                ngx_http_close_connection(c);
                return;
            }


            sscf = ngx_http_get_module_srv_conf(hc->conf_ctx,
                                                ngx_http_ssl_module);

            // 调用该函数生成ssl

            if (ngx_ssl_create_connection(&sscf->ssl, c, NGX_SSL_BUFFER  != NGX_OK)
            {
                ngx_http_close_connection(c);
                return;
            }
        }

    }
...

}

ngx_ssl_create_connection

ngx_int_t

ngx_ssl_create_connection(ngx_ssl_t *ssl, ngx_connection_t *c, ngx_uint_t flags)

{

...

    sc->session_ctx = ssl->ctx;

    sc->connection = SSL_new(ssl->ctx);


    if (sc->connection == NULL) {

        ngx_ssl_error(NGX_LOG_ALERT, c->log, 0, "SSL_new() failed");

        return NGX_ERROR;

    }

    if (SSL_set_fd(sc->connection, c->fd) == 0) {

        ngx_ssl_error(NGX_LOG_ALERT, c->log, 0, "SSL_set_fd() failed");

        return NGX_ERROR;

    }

...

}

first收到client hello之后,完成初始化。

然后调用ngx_ssl_handshake函数,里面会调用openssl的ssl_do_handshake。

ngx_int_t

ngx_ssl_handshake(ngx_connection_t *c)

{

...

    n = ngx_ssl_handshake_early_data(c);

    n = SSL_do_handshake(c->ssl->connection);

...

}

do handshake的时候调用的是openssl的async job的库

OPENSSL部分

ASYNC JOB

int SSL_do_handshake(SSL *s)

{

...

if (SSL_in_init(s) || SSL_in_before(s)) {

        if ((s->mode & SSL_MODE_ASYNC) && ASYNC_get_current_job() == NULL) {

            struct ssl_async_args args;

            args.s = s;

            ret = ssl_start_async_job(s, &args, ssl_do_handshake_intern);

        } else {

            ret = s->handshake_func(s);

        }

    }

...

}
int ASYNC_start_job(ASYNC_JOB **job, ASYNC_WAIT_CTX *wctx, int *ret,
                    int (*func)(void *), void *args, size_t size)

{

...
    /* Start a new job */
    if ((ctx->currjob = async_get_pool_job()) == NULL)
        return ASYNC_NO_JOBS;
...

}

static ASYNC_JOB *async_get_pool_job(void) {
...
if (job == NULL) {

        /* Pool is empty */

        if ((pool->max_size != 0) && (pool->curr_size >= pool->max_size))

            return NULL;

        job = async_job_new();

        if (job != NULL) {
            if (! async_fibre_makecontext(&job->fibrectx)) {
                async_job_free(job);
                return NULL;
            }
            pool->curr_size++;
        }
    }
...
}

先get context做初始化,然后malloc一个stack,创建堆栈把函数放进去。

makecontext创建调用运行函数async_start_func,函数本身是使用当前job中的func。

int async_fibre_makecontext(async_fibre *fibre)

{

    fibre->env_init = 0;

    if (getcontext(&fibre->fibre) == 0) {           //初始化当前ucontext

        fibre->fibre.uc_stack.ss_sp = OPENSSL_malloc(STACKSIZE);

        if (fibre->fibre.uc_stack.ss_sp != NULL) {

            fibre->fibre.uc_stack.ss_size = STACKSIZE;

            fibre->fibre.uc_link = NULL;

            makecontext(&fibre->fibre, async_start_func, 0);

            return 1;

        }

    } else {

        fibre->fibre.uc_stack.ss_sp = NULL;

    }

    return 0;

}

pause job最关键的是swapcontext,在func中一旦被调用的话,就可以立即切换栈信息。

切回start_job的主函数,根据job→status=ASYNC_JOB_PAUSING来返回

int ASYNC_pause_job(void)

{

...
    if (!async_fibre_swapcontext(&job->fibrectx,
                                 &ctx->dispatcher, 1)) {

        ASYNCerr(ASYNC_F_ASYNC_PAUSE_JOB, ASYNC_R_FAILED_TO_SWAP_CONTEXT);

        return 0;

    }
...

}

切回主函数后可以发现start job是for死循环任务,会根据job的状态进行返回

int ASYNC_start_job(ASYNC_JOB **job, ASYNC_WAIT_CTX *wctx, int *ret,

                    int (*func)(void *), void *args, size_t size)

{

...

    for (;;) {

        if (ctx->currjob != NULL) {

            if (ctx->currjob->status == ASYNC_JOB_PAUSING) {

                *job = ctx->currjob;

                ctx->currjob->status = ASYNC_JOB_PAUSED;

                ctx->currjob = NULL;

                return ASYNC_PAUSE;

            }

            if (ctx->currjob->status == ASYNC_JOB_PAUSED) {

                ctx->currjob = *job;

                /* Resume previous job */

                if (!async_fibre_swapcontext(&ctx->dispatcher,

                        &ctx->currjob->fibrectx, 1)) {

                    ASYNCerr(ASYNC_F_ASYNC_START_JOB,

                             ASYNC_R_FAILED_TO_SWAP_CONTEXT);

                    goto err;

                }

                continue;

            }
...

}
static int ssl_start_async_job(SSL *s, struct ssl_async_args *args,

                               int (*func) (void *))

{

...

    switch (ASYNC_start_job(&s->job, s->waitctx, &ret, func, args,
                            sizeof(struct ssl_async_args))) {

    case ASYNC_ERR:

        s->rwstate = SSL_NOTHING;

        SSLerr(SSL_F_SSL_START_ASYNC_JOB, SSL_R_FAILED_TO_INIT_ASYNC);

        return -1;

    case ASYNC_PAUSE:

        s->rwstate = SSL_ASYNC_PAUSED;

        return -1;

}

...

}

返回的这个状态码,在nginx里面接到就是SSL_ERROR_WANT_ASYNC。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值