void ngx_zeromq_close(ngx_connection_t *c) { void *zmq; if (c->fd == -1) { return; } zmq = c->data; ngx_log_debug3(NGX_LOG_DEBUG_EVENT, c->log, 0, "zmq_close: zmq:%p fd:%d #%d", zmq, c->fd, c->number); if (c->read->timer_set) { ngx_del_timer(c->read); } if (c->write->timer_set) { ngx_del_timer(c->write); } if (ngx_del_conn) { ngx_del_conn(c, NGX_CLOSE_EVENT); } else { if (c->read->active || c->read->disabled) { ngx_del_event(c->read, NGX_READ_EVENT, NGX_CLOSE_EVENT); } if (c->write->active || c->write->disabled) { ngx_del_event(c->write, NGX_WRITE_EVENT, NGX_CLOSE_EVENT); } } if (c->read->prev) { ngx_delete_posted_event(c->read); } if (c->write->prev) { ngx_delete_posted_event(c->write); } c->read->closed = 1; c->write->closed = 1; ngx_reusable_connection(c, 0); ngx_free_connection(c); c->fd = (ngx_socket_t) -1; if (zmq_close(zmq) == -1) { ngx_zeromq_log_error(ngx_cycle->log, "zmq_close()"); } }
static void ngx_tcp_lua_req_keepalive_handler(ngx_tcp_session_t *s) { ngx_connection_t *c; ngx_event_t *rev; c = s->connection; rev = c->read; if (rev->timedout) { ngx_log_error(NGX_LOG_INFO, c->log, NGX_ETIMEDOUT, "client timed out"); ngx_tcp_lua_close_session(s); return; } if (c->close) { ngx_tcp_lua_close_session(s); return; } //have data or close event //tmp ngx_tcp_test_reading(s); if (!c->read->ready) { if (!c->error) { ngx_log_error(NGX_LOG_INFO, c->log, 0, "weird, no event call this function"); return;// XXX . add return due to this weird thing really happened. } ngx_tcp_lua_close_session(s); return; } c->idle = 0; ngx_reusable_connection(c, 0); //s->write_event_handler = ngx_tcp_session_empty_handler; s->read_event_handler = ngx_tcp_lua_check_client_abort_handler; if (rev->timer_set) { ngx_del_timer(rev); } if (ngx_tcp_lua_init_light_session(s) != NGX_OK) { ngx_tcp_close_connection(c); return; } c->log->action = "start new session"; ngx_tcp_lua_req_resume(s); }
void ngx_close_connection(ngx_connection_t *c) { ngx_err_t err; ngx_uint_t log_error, level; ngx_socket_t fd; if (c->fd == (ngx_socket_t) -1) { ngx_log_error(NGX_LOG_ALERT, c->log, 0, "connection already closed"); return; } //首先将连接的读写事件从定时器中取出 if (c->read->timer_set) { ngx_del_timer(c->read); } if (c->write->timer_set) { ngx_del_timer(c->write); } if (ngx_del_conn) { //将读写事件从epoll中移除 ngx_del_conn(c, NGX_CLOSE_EVENT); } else { if (c->read->active || c->read->disabled) { ngx_del_event(c->read, NGX_READ_EVENT, NGX_CLOSE_EVENT); } if (c->write->active || c->write->disabled) { ngx_del_event(c->write, NGX_WRITE_EVENT, NGX_CLOSE_EVENT); } } if (c->read->posted) { ngx_delete_posted_event(c->read); } if (c->write->posted) { ngx_delete_posted_event(c->write); } c->read->closed = 1; c->write->closed = 1; ngx_reusable_connection(c, 0); log_error = c->log_error; //调用ngx_free_connection方法把表示连接的ngx_connection_t结构体归还给ngx_cycle_t核心结构体的空闲连接池 ngx_free_connection(c); fd = c->fd; c->fd = (ngx_socket_t) -1; if (ngx_close_socket(fd) == -1) { //系统调用close err = ngx_socket_errno; if (err == NGX_ECONNRESET || err == NGX_ENOTCONN) { switch (log_error) { case NGX_ERROR_INFO: level = NGX_LOG_INFO; break; case NGX_ERROR_ERR: level = NGX_LOG_ERR; break; default: level = NGX_LOG_CRIT; } } else { level = NGX_LOG_CRIT; } /* we use ngx_cycle->log because c->log was in c->pool */ ngx_log_error(level, ngx_cycle->log, err, ngx_close_socket_n " %d failed", fd); } }
void ngx_close_connection(ngx_connection_t *c) { ngx_err_t err; ngx_uint_t log_error, level; ngx_socket_t fd; if (c->fd == (ngx_socket_t) -1) { ngx_log_error(NGX_LOG_ALERT, c->log, 0, "connection already closed"); return; } if (c->read->timer_set) { ngx_del_timer(c->read); } if (c->write->timer_set) { ngx_del_timer(c->write); } if (!c->shared) { if (ngx_del_conn) { ngx_del_conn(c, NGX_CLOSE_EVENT); } else { if (c->read->active || c->read->disabled) { ngx_del_event(c->read, NGX_READ_EVENT, NGX_CLOSE_EVENT); } if (c->write->active || c->write->disabled) { ngx_del_event(c->write, NGX_WRITE_EVENT, NGX_CLOSE_EVENT); } } } if (c->read->posted) { ngx_delete_posted_event(c->read); } if (c->write->posted) { ngx_delete_posted_event(c->write); } c->read->closed = 1; c->write->closed = 1; ngx_reusable_connection(c, 0); log_error = c->log_error; ngx_free_connection(c); fd = c->fd; c->fd = (ngx_socket_t) -1; if (c->shared) { return; } if (ngx_close_socket(fd) == -1) { err = ngx_socket_errno; if (err == NGX_ECONNRESET || err == NGX_ENOTCONN) { switch (log_error) { case NGX_ERROR_INFO: level = NGX_LOG_INFO; break; case NGX_ERROR_ERR: level = NGX_LOG_ERR; break; default: level = NGX_LOG_CRIT; } } else { level = NGX_LOG_CRIT; } ngx_log_error(level, c->log, err, ngx_close_socket_n " %d failed", fd); } }
void ngx_close_connection(ngx_connection_t *c) { ngx_err_t err; ngx_uint_t log_error, level; ngx_socket_t fd; if (c->fd == -1) { ngx_log_error(NGX_LOG_ALERT, c->log, 0, "connection already closed"); return; } if (c->read->timer_set) { ngx_del_timer(c->read); } if (c->write->timer_set) { ngx_del_timer(c->write); } if (ngx_del_conn) { ngx_del_conn(c, NGX_CLOSE_EVENT); } else { if (c->read->active || c->read->disabled) { ngx_del_event(c->read, NGX_READ_EVENT, NGX_CLOSE_EVENT); } if (c->write->active || c->write->disabled) { ngx_del_event(c->write, NGX_WRITE_EVENT, NGX_CLOSE_EVENT); } } #if (NGX_THREADS) /* * we have to clean the connection information before the closing * because another thread may reopen the same file descriptor * before we clean the connection */ ngx_mutex_lock(ngx_posted_events_mutex); if (c->read->prev) { ngx_delete_posted_event(c->read); } if (c->write->prev) { ngx_delete_posted_event(c->write); } c->read->closed = 1; c->write->closed = 1; if (c->single_connection) { ngx_unlock(&c->lock); c->read->locked = 0; c->write->locked = 0; } ngx_mutex_unlock(ngx_posted_events_mutex); #else if (c->read->prev) { ngx_delete_posted_event(c->read); } if (c->write->prev) { ngx_delete_posted_event(c->write); } c->read->closed = 1; c->write->closed = 1; #endif ngx_reusable_connection(c, 0); log_error = c->log_error; ngx_free_connection(c); fd = c->fd; c->fd = (ngx_socket_t) -1; if (ngx_close_socket(fd) == -1) { err = ngx_socket_errno; if (err == NGX_ECONNRESET || err == NGX_ENOTCONN) { switch (log_error) { case NGX_ERROR_INFO: level = NGX_LOG_INFO; break; case NGX_ERROR_ERR: level = NGX_LOG_ERR; break; default: level = NGX_LOG_CRIT; } } else { level = NGX_LOG_CRIT; } /* we use ngx_cycle->log because c->log was in c->pool */ ngx_log_error(level, ngx_cycle->log, err, ngx_close_socket_n " %d failed", fd); } }
/* ngx_http_close_request方法是更高层的用于关闭请求的方法,当然,HTTP模块一般也不会直接调用它的。在上面几节中反复提到的引用计数, 就是由ngx_http_close_request方法负责检测的,同时它会在引用计数清零时正式调用ngx_http_free_request方法和ngx_http_close_connection(ngx_close_connection) 方法来释放请求、关闭连接,见ngx_http_close_request */ void ngx_close_connection(ngx_connection_t *c) { ngx_err_t err; ngx_uint_t log_error, level; ngx_socket_t fd; if (c->fd == (ngx_socket_t) -1) { ngx_log_error(NGX_LOG_ALERT, c->log, 0, "connection already closed"); return; } /* 首先将连接的读/写事件从定时器中取出。实际上就是检查读/写事件的time_set标志位,如果为1,则证明事件在定时器中,那么需要调 用ngx_del_timer方法把事件从定时器中移除。 */ if (c->read->timer_set) { ngx_del_timer(c->read, NGX_FUNC_LINE); } if (c->write->timer_set) { ngx_del_timer(c->write, NGX_FUNC_LINE); } /* 调用ngx_del_conn宏(或者ngx_del_event宏)将读/写事件从epoll中移除。实际上就是调用ngx_event_actions_t接口 中的del_conn方法,当事件模块是epoll模块时,就是从epoll中移除这个连接的读/写事件。同时,如果这个事件在ngx_posted_accept_events或 者ngx_posted_events队列中,还需要调用ngx_delete_posted_event宏把事件从post事件队列中移除。 */ if (ngx_del_conn) { //ngx_epoll_del_connection ngx_del_conn(c, NGX_CLOSE_EVENT); } else { if (c->read->active || c->read->disabled) { ngx_del_event(c->read, NGX_READ_EVENT, NGX_CLOSE_EVENT); //ngx_epoll_del_event } if (c->write->active || c->write->disabled) { ngx_del_event(c->write, NGX_WRITE_EVENT, NGX_CLOSE_EVENT); } } if (c->read->posted) { ngx_delete_posted_event(c->read); } if (c->write->posted) { ngx_delete_posted_event(c->write); } c->read->closed = 1; c->write->closed = 1; ngx_reusable_connection(c, 0); log_error = c->log_error; /* 调用ngx_free_connection方法把表示连接的ngx_connection-t结构体归还给ngx_ cycle_t核心结构体的空闲连接池free connections。 */ ngx_free_connection(c); fd = c->fd; c->fd = (ngx_socket_t) -1; ngx_log_debugall(ngx_cycle->log, 0, "close socket:%d", fd); //调用系统提供的close方法关闭这个TCP连接套接字。 if (ngx_close_socket(fd) == -1) { err = ngx_socket_errno; if (err == NGX_ECONNRESET || err == NGX_ENOTCONN) { switch (log_error) { case NGX_ERROR_INFO: level = NGX_LOG_INFO; break; case NGX_ERROR_ERR: level = NGX_LOG_ERR; break; default: level = NGX_LOG_CRIT; } } else { level = NGX_LOG_CRIT; } /* we use ngx_cycle->log because c->log was in c->pool */ //由于c已经在前面释放了,因此不能再用C->log了 ngx_log_error(level, ngx_cycle->log, err, ngx_close_socket_n " %d failed", fd); } }
static int ngx_tcp_lua_ngx_wait_next_request(lua_State *L) { ngx_tcp_session_t *s; ngx_connection_t *c; int n; ngx_tcp_core_srv_conf_t *cscf; ngx_tcp_lua_ctx_t *ctx; n = lua_gettop(L); if (n != 0) { return luaL_error(L, "expecting 0 arguments"); } s = ngx_tcp_lua_get_session(L); if (s == NULL) { //init_by_lua no session return luaL_error(L, "no session found"); } c = s->connection; ngx_tcp_lua_finalize_light_session(s); ngx_log_debug0(NGX_LOG_DEBUG_TCP, c->log, 0, "lua req calling wait_next_request() method"); ctx = s->ctx; if (ctx->socket_invalid) { c->close = 1; goto yield; } ngx_tcp_test_reading(s); if (c->error) { c->close = 1; goto yield; } if (c->read->ready) { if(ngx_tcp_lua_init_light_session(s) != NGX_OK){ c->close = 1; goto yield; } c->log->action = "continue with new session"; return 0; } yield: if (c->close) { ctx->exited = 1; return lua_yield(L, 0); } cscf = ngx_tcp_get_module_srv_conf(s,ngx_tcp_core_module); c->log->action = "lua_req_keepalive"; c->idle = 1; ngx_reusable_connection(c, 1); s->write_event_handler = ngx_tcp_session_empty_handler; s->read_event_handler = ngx_tcp_lua_req_keepalive_handler; if (!c->read->timer_set && cscf->keepalive_timeout != NGX_CONF_UNSET_MSEC) { ngx_add_timer(c->read, cscf->keepalive_timeout); } //lua_pushliteral(L, "closed"); return lua_yield(L, 0); }
void ngx_zeromq_close(ngx_zeromq_connection_t *zc) { ngx_connection_t *c; c = &zc->connection; if (c->fd == -1) { return; } ngx_log_debug4(NGX_LOG_DEBUG_EVENT, c->log, 0, "zmq_close: fd:%d #%d zc:%p zmq:%p", c->fd, c->number, zc, zc->socket); if (c->read->timer_set) { ngx_del_timer(c->read); } if (c->write->timer_set) { ngx_del_timer(c->write); } if (ngx_del_conn) { ngx_del_conn(c, NGX_CLOSE_EVENT); } else { if (c->read->active || c->read->disabled) { ngx_del_event(c->read, NGX_READ_EVENT, NGX_CLOSE_EVENT); } if (c->write->active || c->write->disabled) { ngx_del_event(c->write, NGX_WRITE_EVENT, NGX_CLOSE_EVENT); } } #if (nginx_version >= 1007005) if (c->read->posted) { #else if (c->read->prev) { #endif ngx_delete_posted_event(c->read); } #if (nginx_version >= 1007005) if (c->write->posted) { #else if (c->write->prev) { #endif ngx_delete_posted_event(c->write); } c->read->closed = 1; c->write->closed = 1; ngx_reusable_connection(zc->connection_ptr, 0); ngx_free_connection(zc->connection_ptr); c->fd = (ngx_socket_t) -1; zc->connection_ptr->fd = (ngx_socket_t) -1; if (zmq_close(zc->socket) == -1) { ngx_zeromq_log_error(ngx_cycle->log, "zmq_close()"); } zc->socket = NULL; } static void ngx_zeromq_event_handler(ngx_event_t *ev) { ngx_zeromq_connection_t *zc; ngx_connection_t *c; void *zmq; int events; size_t esize; /* * ZeroMQ notifies us about new events in edge-triggered fashion * by changing state of the notification socket to read-ready. * * Write-readiness doesn't indicate anything and can be ignored. */ if (ev->write) { return; } zc = ev->data; zc = zc->send; esize = sizeof(int); #if (NGX_DEBUG) if (zc->recv != zc->send) { zmq = zc->request_sent ? zc->socket : zc->recv->socket; if (zmq_getsockopt(zmq, ZMQ_EVENTS, &events, &esize) == -1) { ngx_zeromq_log_error(ev->log, "zmq_getsockopt(ZMQ_EVENTS)"); ev->error = 1; return; } ngx_log_debug2(NGX_LOG_DEBUG_EVENT, ev->log, 0, "zmq_event: %s:%d (ignored)", zc->request_sent ? "send" : "recv", events); } #endif zmq = zc->request_sent ? zc->recv->socket : zc->socket; if (zmq_getsockopt(zmq, ZMQ_EVENTS, &events, &esize) == -1) { ngx_zeromq_log_error(ev->log, "zmq_getsockopt(ZMQ_EVENTS)"); ev->error = 1; return; } ngx_log_debug2(NGX_LOG_DEBUG_EVENT, ev->log, 0, "zmq_event: %s:%d", zc->request_sent ? "recv" : "send", events); c = &zc->connection; if (zc->request_sent) { c->read->ready = events & ZMQ_POLLIN ? 1 : 0; if (c->read->ready) { zc->handler(c->read); } } else { c->write->ready = events & ZMQ_POLLOUT ? 1 : 0; if (c->write->ready) { zc->handler(c->write); } } } static ssize_t ngx_zeromq_sendmsg(void *zmq, ngx_event_t *ev, zmq_msg_t *msg, int flags) { size_t size; size = zmq_msg_size(msg); for (;;) { if (zmq_msg_send(msg, zmq, ZMQ_DONTWAIT|flags) == -1) { if (ngx_errno == NGX_EAGAIN) { ngx_log_debug0(NGX_LOG_DEBUG_EVENT, ev->log, 0, "zmq_send: not ready"); ev->ready = 0; return NGX_AGAIN; } if (ngx_errno == NGX_EINTR) { ngx_log_debug0(NGX_LOG_DEBUG_EVENT, ev->log, 0, "zmq_send: interrupted"); ev->ready = 0; continue; } ngx_zeromq_log_error(ev->log, "zmq_msg_send()"); ev->error = 1; return NGX_ERROR; } break; } ngx_log_debug2(NGX_LOG_DEBUG_EVENT, ev->log, 0, "zmq_send: %uz eom:%d", size, flags != ZMQ_SNDMORE); return size; }
/* cached session fetching callback to be set with SSL_CTX_sess_set_get_cb */ ngx_ssl_session_t * ngx_http_lua_ssl_sess_fetch_handler(ngx_ssl_conn_t *ssl_conn, u_char *id, int len, int *copy) { lua_State *L; ngx_int_t rc; ngx_connection_t *c, *fc = NULL; ngx_http_request_t *r = NULL; ngx_pool_cleanup_t *cln; ngx_http_connection_t *hc; ngx_http_lua_ssl_ctx_t *cctx; ngx_http_lua_srv_conf_t *lscf; ngx_http_core_loc_conf_t *clcf; /* set copy to 0 as we expect OpenSSL to handle * the memory of returned session */ *copy = 0; c = ngx_ssl_get_connection(ssl_conn); ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0, "ssl session fetch: connection reusable: %ud", c->reusable); cctx = ngx_http_lua_ssl_get_ctx(c->ssl->connection); dd("ssl sess_fetch handler, sess_fetch-ctx=%p", cctx); if (cctx && cctx->entered_sess_fetch_handler) { /* not the first time */ dd("here: %d", (int) cctx->entered_sess_fetch_handler); if (cctx->done) { ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0, "ssl_session_fetch_by_lua*: " "sess get cb exit code: %d", cctx->exit_code); dd("lua ssl sess_fetch done, finally"); return cctx->session; } #ifdef SSL_ERROR_PENDING_SESSION return SSL_magic_pending_session_ptr(); #else ngx_log_error(NGX_LOG_CRIT, c->log, 0, "lua: cannot yield in sess get cb: " "missing async sess get cb support in OpenSSL"); return NULL; #endif } dd("first time"); ngx_reusable_connection(c, 0); hc = c->data; fc = ngx_http_lua_create_fake_connection(NULL); if (fc == NULL) { goto failed; } fc->log->handler = ngx_http_lua_log_ssl_sess_fetch_error; fc->log->data = fc; fc->addr_text = c->addr_text; fc->listening = c->listening; r = ngx_http_lua_create_fake_request(fc); if (r == NULL) { goto failed; } r->main_conf = hc->conf_ctx->main_conf; r->srv_conf = hc->conf_ctx->srv_conf; r->loc_conf = hc->conf_ctx->loc_conf; fc->log->file = c->log->file; fc->log->log_level = c->log->log_level; fc->ssl = c->ssl; clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); #if defined(nginx_version) && nginx_version >= 1003014 # if nginx_version >= 1009000 ngx_set_connection_log(fc, clcf->error_log); # else ngx_http_set_connection_log(fc, clcf->error_log); # endif #else fc->log->file = clcf->error_log->file; if (!(fc->log->log_level & NGX_LOG_DEBUG_CONNECTION)) { fc->log->log_level = clcf->error_log->log_level; } #endif if (cctx == NULL) { cctx = ngx_pcalloc(c->pool, sizeof(ngx_http_lua_ssl_ctx_t)); if (cctx == NULL) { goto failed; /* error */ } } cctx->exit_code = 1; /* successful by default */ cctx->connection = c; cctx->request = r; cctx->session_id.data = id; cctx->session_id.len = len; cctx->entered_sess_fetch_handler = 1; cctx->done = 0; dd("setting cctx = %p", cctx); if (SSL_set_ex_data(c->ssl->connection, ngx_http_lua_ssl_ctx_index, cctx) == 0) { ngx_ssl_error(NGX_LOG_ALERT, c->log, 0, "SSL_set_ex_data() failed"); goto failed; } lscf = ngx_http_get_module_srv_conf(r, ngx_http_lua_module); /* TODO honor lua_code_cache off */ L = ngx_http_lua_get_lua_vm(r, NULL); c->log->action = "fetching SSL session by lua"; rc = lscf->srv.ssl_sess_fetch_handler(r, lscf, L); if (rc >= NGX_OK || rc == NGX_ERROR) { cctx->done = 1; if (cctx->cleanup) { *cctx->cleanup = NULL; } ngx_log_debug2(NGX_LOG_DEBUG_HTTP, c->log, 0, "ssl_session_fetch_by_lua*: handler return value: %i, " "sess get cb exit code: %d", rc, cctx->exit_code); c->log->action = "SSL handshaking"; return cctx->session; } /* rc == NGX_DONE */ cln = ngx_pool_cleanup_add(fc->pool, 0); if (cln == NULL) { goto failed; } cln->handler = ngx_http_lua_ssl_sess_fetch_done; cln->data = cctx; if (cctx->cleanup == NULL) { /* we only want exactly one cleanup handler to be registered with the * connection to clean up cctx when connection is aborted */ cln = ngx_pool_cleanup_add(c->pool, 0); if (cln == NULL) { goto failed; } cln->data = cctx; cctx->cleanup = &cln->handler; } *cctx->cleanup = ngx_http_lua_ssl_sess_fetch_aborted; #ifdef SSL_ERROR_PENDING_SESSION return SSL_magic_pending_session_ptr(); #else ngx_log_error(NGX_LOG_CRIT, c->log, 0, "lua: cannot yield in sess get cb: " "missing async sess get cb support in OpenSSL"); /* fall through to the "failed" label below */ #endif failed: if (r && r->pool) { ngx_http_lua_free_fake_request(r); } if (fc) { ngx_http_lua_close_fake_connection(fc); } return NULL; }