static void ngx_stream_return_write_handler(ngx_event_t *ev) { ssize_t n; ngx_buf_t *b; ngx_connection_t *c; ngx_stream_session_t *s; ngx_stream_return_ctx_t *ctx; c = ev->data; s = c->data; if (ev->timedout) { ngx_connection_error(c, NGX_ETIMEDOUT, "connection timed out"); ngx_stream_close_connection(c); return; } if (ev->ready) { ctx = ngx_stream_get_module_ctx(s, ngx_stream_return_module); b = &ctx->buf; n = c->send(c, b->pos, b->last - b->pos); if (n == NGX_ERROR) { ngx_stream_close_connection(c); return; } if (n > 0) { b->pos += n; if (b->pos == b->last) { ngx_stream_close_connection(c); return; } } } if (ngx_handle_write_event(ev, 0) != NGX_OK) { ngx_stream_close_connection(c); return; } ngx_add_timer(ev, 5000); }
static void ngx_stream_hello_handler(ngx_stream_session_t *s) { ngx_stream_hello_srv_conf_t *hscf; hscf = ngx_stream_get_module_srv_conf(s, ngx_stream_hello_module); s->connection->send(s->connection, hscf->hello.data, hscf->hello.len); ngx_stream_close_connection(s->connection); }
static void ngx_stream_return_handler(ngx_stream_session_t *s) { ngx_str_t text; ngx_connection_t *c; ngx_stream_return_ctx_t *ctx; ngx_stream_return_srv_conf_t *rscf; c = s->connection; c->log->action = "returning text"; rscf = ngx_stream_get_module_srv_conf(s, ngx_stream_return_module); if (ngx_stream_complex_value(s, &rscf->text, &text) != NGX_OK) { ngx_stream_close_connection(c); return; } ngx_log_debug1(NGX_LOG_DEBUG_STREAM, c->log, 0, "stream return text: \"%V\"", &text); if (text.len == 0) { ngx_stream_close_connection(c); return; } ctx = ngx_pcalloc(c->pool, sizeof(ngx_stream_return_ctx_t)); if (ctx == NULL) { ngx_stream_close_connection(c); return; } ngx_stream_set_ctx(s, ctx, ngx_stream_return_module); ctx->buf.pos = text.data; ctx->buf.last = text.data + text.len; c->write->handler = ngx_stream_return_write_handler; ngx_stream_return_write_handler(c->write); }
static void ngx_stream_ssl_handshake_handler(ngx_connection_t *c) { if (!c->ssl->handshaked) { ngx_stream_close_connection(c); return; } if (c->read->timer_set) { ngx_del_timer(c->read); } ngx_stream_init_session(c); }
static void conn_srv_close_connection(ngx_connection_t *c) { conn_node_data *conn_node = c->data; if (!conn_node) goto done; int ret; do { ret = del_list_buf(&conn_node->recv); } while (ret == 0); do { ret = del_list_buf(&conn_node->send); } while (ret == 0); done: ngx_stream_close_connection(c); }
static void ngx_stream_init_session(ngx_connection_t *c) { ngx_stream_session_t *s; ngx_stream_core_srv_conf_t *cscf; s = c->data; c->log->action = "handling client connection"; cscf = ngx_stream_get_module_srv_conf(s, ngx_stream_core_module); s->ctx = ngx_pcalloc(c->pool, sizeof(void *) * ngx_stream_max_module); if (s->ctx == NULL) { ngx_stream_close_connection(c); return; } cscf->handler(s); }
static void ngx_stream_proxy_finalize(ngx_stream_session_t *s, ngx_int_t rc) { ngx_connection_t *pc; ngx_stream_upstream_t *u; ngx_log_debug1(NGX_LOG_DEBUG_STREAM, s->connection->log, 0, "finalize stream proxy: %i", rc); u = s->upstream; if (u == NULL) { goto noupstream; } if (u->peer.free && u->peer.sockaddr) { u->peer.free(&u->peer, u->peer.data, 0); u->peer.sockaddr = NULL; } pc = u->peer.connection; if (pc) { ngx_log_debug1(NGX_LOG_DEBUG_STREAM, s->connection->log, 0, "close stream proxy upstream connection: %d", pc->fd); #if (NGX_STREAM_SSL) if (pc->ssl) { pc->ssl->no_wait_shutdown = 1; (void) ngx_ssl_shutdown(pc); } #endif ngx_close_connection(pc); u->peer.connection = NULL; } noupstream: ngx_stream_close_connection(s->connection); }
static void ngx_stream_app_handler(ngx_stream_session_t *s) { ngx_connection_t *c; ngx_stream_app_srv_conf_t *pscf; c = s->connection; pscf = ngx_stream_get_module_srv_conf(s, ngx_stream_app_module); ngx_log_debug0(NGX_LOG_DEBUG_STREAM, c->log, 0, "NGX_LOG_DEBUG_STREAM:app connection handler"); s->upstream = NULL; s->log_handler = ngx_stream_app_log_error; c->write->handler = ngx_stream_app_finalize; c->read->handler = ngx_app_wait_request_handler; if (c->read->ready) { c->read->handler(c->read); return; } if (!c->read->timer_set) { ngx_add_timer(c->read, pscf->client_timeout); } // ngx_reusable_connection(c, 1); if (ngx_handle_read_event(c->read, 0) != NGX_OK) { ngx_stream_close_connection(c); return; } }
// 在ngx_stream_optimize_servers里设置有连接发生时的回调函数 // 调用发生在ngx_event_accept.c:ngx_event_accept() // // 创建一个处理tcp的会话对象 // 要先检查限速和访问限制这两个功能模块 // 最后调用ngx_stream_init_session // 创建ctx数组,用于存储模块的ctx数据 // 调用handler,处理tcp数据,收发等等 void ngx_stream_init_connection(ngx_connection_t *c) { int tcp_nodelay; u_char text[NGX_SOCKADDR_STRLEN]; size_t len; ngx_int_t rc; ngx_uint_t i; struct sockaddr *sa; ngx_stream_port_t *port; struct sockaddr_in *sin; ngx_stream_in_addr_t *addr; ngx_stream_session_t *s; ngx_stream_addr_conf_t *addr_conf; #if (NGX_HAVE_INET6) struct sockaddr_in6 *sin6; ngx_stream_in6_addr_t *addr6; #endif ngx_stream_core_srv_conf_t *cscf; ngx_stream_core_main_conf_t *cmcf; /* find the server configuration for the address:port */ // 取监听同一端口的server信息 port = c->listening->servers; if (port->naddrs > 1) { /* * There are several addresses on this port and one of them * is the "*:port" wildcard so getsockname() is needed to determine * the server address. * * AcceptEx() already gave this address. */ if (ngx_connection_local_sockaddr(c, NULL, 0) != NGX_OK) { ngx_stream_close_connection(c); return; } sa = c->local_sockaddr; switch (sa->sa_family) { #if (NGX_HAVE_INET6) case AF_INET6: sin6 = (struct sockaddr_in6 *) sa; addr6 = port->addrs; /* the last address is "*" */ for (i = 0; i < port->naddrs - 1; i++) { if (ngx_memcmp(&addr6[i].addr6, &sin6->sin6_addr, 16) == 0) { break; } } addr_conf = &addr6[i].conf; break; #endif default: /* AF_INET */ sin = (struct sockaddr_in *) sa; addr = port->addrs; /* the last address is "*" */ for (i = 0; i < port->naddrs - 1; i++) { if (addr[i].addr == sin->sin_addr.s_addr) { break; } } addr_conf = &addr[i].conf; break; } } else { // 唯一监听端口的server // addr_conf就是端口所在的server的配置数组 switch (c->local_sockaddr->sa_family) { #if (NGX_HAVE_INET6) case AF_INET6: addr6 = port->addrs; addr_conf = &addr6[0].conf; break; #endif default: /* AF_INET */ addr = port->addrs; addr_conf = &addr[0].conf; break; } } // 创建一个处理tcp的会话对象 s = ngx_pcalloc(c->pool, sizeof(ngx_stream_session_t)); if (s == NULL) { ngx_stream_close_connection(c); return; } // 设置会话对象的标志 s->signature = NGX_STREAM_MODULE; //设置会话正确的配置结构体 // addr_conf就是端口所在的server的配置数组 // 之后就可以用宏正确地获取模块的配置信息 s->main_conf = addr_conf->ctx->main_conf; s->srv_conf = addr_conf->ctx->srv_conf; // 设置会话关联的连接对象 s->connection = c; // 连接的data指针指向会话对象 c->data = s; // 获取相关的core配置 cscf = ngx_stream_get_module_srv_conf(s, ngx_stream_core_module); ngx_set_connection_log(c, cscf->error_log); len = ngx_sock_ntop(c->sockaddr, c->socklen, text, NGX_SOCKADDR_STRLEN, 1); ngx_log_error(NGX_LOG_INFO, c->log, 0, "*%uA client %*s connected to %V", c->number, len, text, &addr_conf->addr_text); // log的一些参数 c->log->connection = c->number; c->log->handler = ngx_stream_log_error; c->log->data = s; c->log->action = "initializing connection"; c->log_error = NGX_ERROR_INFO; // 一个stream{}块只能有一个main conf // 所以连接限速、访问限制的处理函数是相同的 // 但配置参数每个server可以不同 cmcf = ngx_stream_get_module_main_conf(s, ngx_stream_core_module); // 是否有连接限速设置,在ngx_stream_limit_conn_module.c里设置 if (cmcf->limit_conn_handler) { rc = cmcf->limit_conn_handler(s); if (rc != NGX_DECLINED) { ngx_stream_close_connection(c); return; } } // 是否有访问限制 if (cmcf->access_handler) { rc = cmcf->access_handler(s); if (rc != NGX_OK && rc != NGX_DECLINED) { ngx_stream_close_connection(c); return; } } // 设置TCP_NODELAY,默认启用 if (cscf->tcp_nodelay && c->tcp_nodelay == NGX_TCP_NODELAY_UNSET) { ngx_log_debug0(NGX_LOG_DEBUG_STREAM, c->log, 0, "tcp_nodelay"); tcp_nodelay = 1; if (setsockopt(c->fd, IPPROTO_TCP, TCP_NODELAY, (const void *) &tcp_nodelay, sizeof(int)) == -1) { ngx_connection_error(c, ngx_socket_errno, "setsockopt(TCP_NODELAY) failed"); ngx_stream_close_connection(c); return; } c->tcp_nodelay = NGX_TCP_NODELAY_SET; } #if (NGX_STREAM_SSL) { ngx_stream_ssl_conf_t *sslcf; sslcf = ngx_stream_get_module_srv_conf(s, ngx_stream_ssl_module); if (addr_conf->ssl) { c->log->action = "SSL handshaking"; if (sslcf->ssl.ctx == NULL) { ngx_log_error(NGX_LOG_ERR, c->log, 0, "no \"ssl_certificate\" is defined " "in server listening on SSL port"); ngx_stream_close_connection(c); return; } ngx_stream_ssl_init_connection(&sslcf->ssl, c); return; } } #endif // 创建ctx数组,用于存储模块的ctx数据 // 调用handler,处理tcp数据,收发等等 ngx_stream_init_session(c); }
void ngx_stream_init_connection(ngx_connection_t *c) { u_char text[NGX_SOCKADDR_STRLEN]; size_t len; ngx_int_t rc; ngx_uint_t i; struct sockaddr *sa; ngx_stream_port_t *port; struct sockaddr_in *sin; ngx_stream_in_addr_t *addr; ngx_stream_session_t *s; ngx_stream_addr_conf_t *addr_conf; #if (NGX_HAVE_INET6) struct sockaddr_in6 *sin6; ngx_stream_in6_addr_t *addr6; #endif ngx_stream_core_srv_conf_t *cscf; ngx_stream_core_main_conf_t *cmcf; /* find the server configuration for the address:port */ port = c->listening->servers; if (port->naddrs > 1) { /* * There are several addresses on this port and one of them * is the "*:port" wildcard so getsockname() is needed to determine * the server address. * * AcceptEx() already gave this address. */ if (ngx_connection_local_sockaddr(c, NULL, 0) != NGX_OK) { ngx_stream_close_connection(c); return; } sa = c->local_sockaddr; switch (sa->sa_family) { #if (NGX_HAVE_INET6) case AF_INET6: sin6 = (struct sockaddr_in6 *) sa; addr6 = port->addrs; /* the last address is "*" */ for (i = 0; i < port->naddrs - 1; i++) { if (ngx_memcmp(&addr6[i].addr6, &sin6->sin6_addr, 16) == 0) { break; } } addr_conf = &addr6[i].conf; break; #endif default: /* AF_INET */ sin = (struct sockaddr_in *) sa; addr = port->addrs; /* the last address is "*" */ for (i = 0; i < port->naddrs - 1; i++) { if (addr[i].addr == sin->sin_addr.s_addr) { break; } } addr_conf = &addr[i].conf; break; } } else { switch (c->local_sockaddr->sa_family) { #if (NGX_HAVE_INET6) case AF_INET6: addr6 = port->addrs; addr_conf = &addr6[0].conf; break; #endif default: /* AF_INET */ addr = port->addrs; addr_conf = &addr[0].conf; break; } } s = ngx_pcalloc(c->pool, sizeof(ngx_stream_session_t)); if (s == NULL) { ngx_stream_close_connection(c); return; } s->signature = NGX_STREAM_MODULE; s->main_conf = addr_conf->ctx->main_conf; s->srv_conf = addr_conf->ctx->srv_conf; s->connection = c; c->data = s; cscf = ngx_stream_get_module_srv_conf(s, ngx_stream_core_module); ngx_set_connection_log(c, cscf->error_log); len = ngx_sock_ntop(c->sockaddr, c->socklen, text, NGX_SOCKADDR_STRLEN, 1); ngx_log_error(NGX_LOG_INFO, c->log, 0, "*%uA client %*s connected to %V", c->number, len, text, &addr_conf->addr_text); c->log->connection = c->number; c->log->handler = ngx_stream_log_error; c->log->data = s; c->log->action = "initializing connection"; c->log_error = NGX_ERROR_INFO; cmcf = ngx_stream_get_module_main_conf(s, ngx_stream_core_module); if (cmcf->access_handler) { rc = cmcf->access_handler(s); if (rc != NGX_OK && rc != NGX_DECLINED) { ngx_stream_close_connection(c); return; } } #if (NGX_STREAM_SSL) { ngx_stream_ssl_conf_t *sslcf; sslcf = ngx_stream_get_module_srv_conf(s, ngx_stream_ssl_module); if (addr_conf->ssl) { c->log->action = "SSL handshaking"; if (sslcf->ssl.ctx == NULL) { ngx_log_error(NGX_LOG_ERR, c->log, 0, "no \"ssl_certificate\" is defined " "in server listening on SSL port"); ngx_stream_close_connection(c); return; } ngx_stream_ssl_init_connection(&sslcf->ssl, c); return; } } #endif ngx_stream_init_session(c); }
/* static void ngx_app_empty_handler(ngx_event_t *wev) { } */ static void ngx_app_wait_request_handler(ngx_event_t *ev) { ngx_connection_t *c; ngx_stream_session_t *s; ngx_stream_app_main_conf_t *cscf; ngx_stream_app_srv_conf_t *ascf; ngx_stream_app_ctx_t *s_ctx; ngx_app_task_t *t; ngx_buf_t *b; ngx_str_t log_buf; ssize_t n; size_t size; u_char *tmp; c = ev->data; s = c->data; if (ev->timedout) { ngx_log_error(NGX_LOG_INFO, c->log, NGX_ETIMEDOUT, "client timed out"); ngx_stream_close_connection(c); return; } if (c->close) { ngx_stream_close_connection(c); return; } cscf = ngx_stream_get_module_main_conf(s, ngx_stream_app_module); ascf = ngx_stream_get_module_srv_conf(s, ngx_stream_app_module); s_ctx = ngx_stream_get_module_ctx(s,ngx_stream_app_module); if(s_ctx == NULL){ s_ctx = ngx_palloc(c->pool, sizeof(ngx_stream_app_ctx_t)); if(s_ctx == NULL) return; s_ctx->header = 0; ngx_stream_set_ctx(s,s_ctx,ngx_stream_app_module); } b = c->buffer; if (b == NULL) { size = ascf->header_len; b = ngx_create_temp_buf(c->pool, size); if (b == NULL) { ngx_stream_close_connection(c); return; } c->buffer = b; } else if (b->start == NULL) { size = s_ctx->header == 0?ascf->header_len:s_ctx->body_len; b->start = ngx_palloc(c->pool, size); if (b->start == NULL) { ngx_stream_close_connection(c); return; } b->pos = b->start; b->last = b->start; b->end = b->last + size; } else { size = ascf->header_len + s_ctx->body_len - s->received; // size = b->end - b->last; } n = c->recv(c, b->last, size); if (n == NGX_AGAIN) { if (!c->read->timer_set) { ngx_add_timer(c->read, ascf->client_timeout); } if (ngx_handle_read_event(c->read, 0) != NGX_OK) { ngx_stream_close_connection(c); return; } return; } if (n == NGX_ERROR) { ngx_stream_close_connection(c); return; } if (n == 0) { ngx_log_error(NGX_LOG_INFO, c->log, 0, "client closed connection"); ngx_stream_close_connection(c); return; } b->last += n; s->received +=n; c->log->action = "reading client request line"; log_buf.len = s->received; log_buf.data = b->start; ngx_log_error(NGX_LOG_ALERT, c->log, 0, "%d recved [%V],[%d:%d]",n,&log_buf,b->end,b->last); if(b->end != b->last){ if (ngx_handle_read_event(c->read, 0) != NGX_OK) { ngx_stream_close_connection(c); return; } } else { if(s_ctx->header == 0){ s_ctx->body_len = ngx_atoi(b->start,ascf->header_len); s_ctx->header = 1; if(s_ctx->body_len > 0 ){ tmp = ngx_pcalloc(c->pool, ascf->header_len + s_ctx->body_len); if (tmp == NULL) { ngx_stream_close_connection(c); return; } ngx_memcpy(tmp,b->start,ascf->header_len); ngx_pfree(c->pool, b->start); b->start = tmp; b->pos = b->start + ascf->header_len; b->last = b->pos; b->end = b->last + s_ctx->body_len; ngx_app_wait_request_handler(ev); } else{ ngx_log_error(NGX_LOG_INFO, c->log, 0, "empty request body"); ngx_stream_close_connection(c); return; } ngx_log_error(NGX_LOG_ALERT, c->log, 0, "recv header,len[%d]",s_ctx->body_len); } else{ // c->read->handler = ngx_app_empty_handler; t = (ngx_app_task_t *)ngx_thread_task_alloc(c->pool, sizeof(ngx_app_task_t) - sizeof(ngx_thread_task_t)); if(t == NULL){ ngx_log_error(NGX_LOG_ERR, c->log, 0, "create thread task failed"); ngx_stream_close_connection(c); } t->data = s; t->task.handler = ngx_stream_app_process; t->task.event.handler = ngx_stream_app_finalize; t->task.event.data= c; ngx_log_error(NGX_LOG_ALERT, c->log, 0, "t->data[%d]=[%d][%d]",t->data,t->task.ctx,t); if(ngx_thread_task_post(cscf->tp,(ngx_thread_task_t *)t) != NGX_OK){ ngx_log_error(NGX_LOG_ERR, c->log, 0, "post task to thread pool failed"); ngx_stream_close_connection(c); return; } ngx_log_error(NGX_LOG_ALERT, c->log, 0, "after post task"); } } return; }