技术标签: 网络 nginx nginx开发学习汇总 网络协议 ssl nginx反向代理
在ngx_http_init_connection中把recv→handler设置为ngx_http_ssl_handshake。
然后将这个读时间加入到epoll中,主要是分析handshake函数。
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_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的库
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。
eclipse TypeError: read_excel() got an unexpected keyword argument ‘encoding’代码中有 enconding=“utf8”, 但是在最新的 pandas read_excel()函数中没有关于编码的规定,所以会报typeerror。 我自己的做法是直接删除 enconding=“utf8”。如果是其他的编码格式,我自己也不大清楚怎么办了。以后弄了我再来补吧。当然也欢迎大佬赐教..._read_excel encoding
成鹏致远 不了解成鹏致远? 没关系!慢慢往下看! 得知己者,得天下;得天下,安知己!650) this.width=650;" src="http://img1.51cto.com/attachment/201306/150355372.gif" title="成鹏致远,相信自己.gif" />650) this.width=650;" src="http://img1.51ct
记着点赞<!DOCTYPE html><html style="height:100%"><head> <meta name="viewport" charset="utf-8" content="width=device-width, initial-scale=1, shrink-to-fit=no" > <tit..._极简404页面模板
dialog 小程序中的对话框。_小程序 diaglog
列表宽度设置前:第一步:需要设置css的table-layout属性值为fixed,默认auto,<style type="text/css"> .table {table-layout:fixed;}</style>table-layout可能值描述auto默认。列宽度由单元格内容设定。fixed列宽由表格宽度和列宽度设定。inherit规定应该从父元素继承 table-layout 属性的值。第二步:在每一列设置w_bootstrap table 列宽
随着数据湖概念的流行,涌现了很多关于Apache Hudi的文章,但很多文章在阐述时仅仅将Hudi当做一种表格式,这引发了社区的思考,思考Hudi的愿景到底是什么,并且在Hudi社区发起了..._hudi 论坛
function getlucky() { log("开始红包") let gz = boundsFindCon("关注", device.width * 0.35, device.height * 0.35, device.width * 0.65, device.height * 0.65, -1) let jz = boundsFindCon("价值", device.width * 0.35, device.height * 0.5, device.width * 0.65._福袋脚本
个人项目_线路负载及故障检测装置设计方案
_v 此vc 此 此 茈呲呲 cccc
explode 与 lateral view详解_hive exploded
目录Bootstrap 有三个类型的容器实战.container 演练.container-fluid 演练.container-sm .container-md .container-lg 演练.container-xl.container-xxl 演练Sass 映射 - 修改预定义的容器类可视化大屏设计 - 总目录导读:大屏案例参考YYDatav的数据可视化大屏《精彩案例汇总》(Python&Echarts源码)_YYDataV的博客-程序员宅基地._bootstrap container容器
继续找类似的文章,发现网上还是有在windows server 2012环境下使用admodify的案例,见如下链接,http://www.dotblogs.com.tw/swater111/archive/2013/06/25/106062.aspx,下面就开始着手演示下三种修改邮箱地址方法的操作步骤。第一种、使用Powershell+Exce...