nginx调用openssl函数源码分析

阅读: 评论:0

nginx调用openssl函数源码分析

nginx调用openssl函数源码分析

NGINX部分

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

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

receive client hello

static voidngx_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 confclcf = 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);// 调用该函数生成sslif (ngx_ssl_create_connection(&sscf->ssl, c, NGX_SSL_BUFFER  != NGX_OK){ngx_http_close_connection(c);return;}}}
...}

ngx_ssl_create_connection

ngx_int_tngx_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_tngx_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) {           //初始化当前ucontextfibre->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。

本文发布于:2024-01-28 08:38:39,感谢您对本站的认可!

本文链接:https://www.4u4v.net/it/17064023256168.html

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。

标签:函数   源码   nginx   openssl
留言与评论(共有 0 条评论)
   
验证码:

Copyright ©2019-2022 Comsenz Inc.Powered by ©

网站地图1 网站地图2 网站地图3 网站地图4 网站地图5 网站地图6 网站地图7 网站地图8 网站地图9 网站地图10 网站地图11 网站地图12 网站地图13 网站地图14 网站地图15 网站地图16 网站地图17 网站地图18 网站地图19 网站地图20 网站地图21 网站地图22/a> 网站地图23