From f866755e22ed291fff380f983a86ecaa061c688f Mon Sep 17 00:00:00 2001 From: rainingmaster <312841925@qq.com> Date: Mon, 19 Oct 2020 13:07:23 +0800 Subject: [PATCH 1/9] feature: support socket in some not yieldable phase. --- config | 13 ++ src/event/ngx_http_lua_epoll.c | 177 +++++++++++++++++++ src/event/ngx_http_lua_kqueue.c | 131 ++++++++++++++ src/event/ngx_http_lua_poll.c | 113 +++++++++++++ src/ngx_http_lua_event.h | 87 ++++++++++ src/ngx_http_lua_initworkerby.c | 5 + src/ngx_http_lua_socket_tcp.c | 291 +++++++++++++++++++++++++++++++- src/ngx_http_lua_util.h | 5 + t/058-tcp-socket.t | 63 ++++++- 9 files changed, 878 insertions(+), 7 deletions(-) create mode 100644 src/event/ngx_http_lua_epoll.c create mode 100644 src/event/ngx_http_lua_kqueue.c create mode 100644 src/event/ngx_http_lua_poll.c create mode 100644 src/ngx_http_lua_event.h diff --git a/config b/config index 14870a04e8..d89cb6f65d 100644 --- a/config +++ b/config @@ -300,6 +300,18 @@ HTTP_LUA_SRCS=" \ $ngx_addon_dir/src/ngx_http_lua_worker_thread.c \ " +if echo "$EVENT_MODULES" | grep ngx_epoll_module 2>&1 >/dev/null; then + HTTP_LUA_SRCS="$HTTP_LUA_SRCS $ngx_addon_dir/src/event/ngx_http_lua_epoll.c" +fi + +if echo "$EVENT_MODULES" | grep ngx_poll_module 2>&1 >/dev/null; then + HTTP_LUA_SRCS="$HTTP_LUA_SRCS $ngx_addon_dir/src/event/ngx_http_lua_poll.c" +fi + +if echo "$EVENT_MODULES" | grep ngx_kqueue_module 2>&1 >/dev/null; then + HTTP_LUA_SRCS="$HTTP_LUA_SRCS $ngx_addon_dir/src/event/ngx_http_lua_kqueue.c" +fi + HTTP_LUA_DEPS=" \ $ngx_addon_dir/src/ddebug.h \ $ngx_addon_dir/src/ngx_http_lua_autoconf.h \ @@ -359,6 +371,7 @@ HTTP_LUA_DEPS=" \ $ngx_addon_dir/src/ngx_http_lua_input_filters.h \ $ngx_addon_dir/src/ngx_http_lua_pipe.h \ $ngx_addon_dir/src/ngx_http_lua_worker_thread.h \ + $ngx_addon_dir/src/ngx_http_lua_event.h \ " # ---------------------------------------- diff --git a/src/event/ngx_http_lua_epoll.c b/src/event/ngx_http_lua_epoll.c new file mode 100644 index 0000000000..bfafc0a947 --- /dev/null +++ b/src/event/ngx_http_lua_epoll.c @@ -0,0 +1,177 @@ + +/* + * Copyright (C) Yichun Zhang (agentzh) + */ + + +#include +#include +#include +#include "../ngx_http_lua_event.h" + + +static ngx_int_t ngx_http_lua_epoll_init_event(ngx_cycle_t *cycle); +static ngx_int_t ngx_http_lua_epoll_set_event(ngx_event_t *ev, ngx_int_t event); +static ngx_int_t ngx_http_lua_epoll_clear_event(ngx_event_t *ev, + ngx_int_t event); +static ngx_int_t ngx_http_lua_epoll_process_event(ngx_http_request_t *r, + ngx_msec_t timer); + +static int ep = -1; +static struct epoll_event eev; + +ngx_http_lua_event_actions_t ngx_http_lua_epoll = { + ngx_http_lua_epoll_init_event, + ngx_http_lua_epoll_set_event, + ngx_http_lua_epoll_clear_event, + ngx_http_lua_epoll_process_event, +}; + + +static ngx_int_t +ngx_http_lua_epoll_init_event(ngx_cycle_t *cycle) +{ + ep = epoll_create(1); + + if (ep == -1) { + ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_errno, + "lua epoll_create() failed"); + + return NGX_ERROR; + } + + return NGX_OK; +} + + +static ngx_int_t +ngx_http_lua_epoll_set_event(ngx_event_t *ev, ngx_int_t event) +{ + uint32_t events; + ngx_connection_t *c; + struct epoll_event ee; + + c = ev->data; + + events = (uint32_t) event; + + if (event == NGX_READ_EVENT) { +#if (NGX_READ_EVENT != EPOLLIN|EPOLLRDHUP) + events = EPOLLIN|EPOLLRDHUP; +#endif + + } else { +#if (NGX_WRITE_EVENT != EPOLLOUT) + events = EPOLLOUT; +#endif + } + + ee.events = events; + ee.data.ptr = c; + + if (epoll_ctl(ep, EPOLL_CTL_ADD, c->fd, &ee) == -1) { + ngx_log_error(NGX_LOG_ALERT, ev->log, ngx_errno, + "lua epoll_ctl(EPOLL_CTL_ADD, %d) failed, add event: %d", + c->fd, events); + + return NGX_ERROR; + } + + ev->active = 1; + + return NGX_OK; +} + + +static ngx_int_t +ngx_http_lua_epoll_clear_event(ngx_event_t *ev, ngx_int_t event) +{ + ngx_connection_t *c; + struct epoll_event ee; + + c = ev->data; + + ee.events = 0; + ee.data.ptr = NULL; + + if (epoll_ctl(ep, EPOLL_CTL_DEL, c->fd, &ee) == -1) { + ngx_log_error(NGX_LOG_ALERT, ev->log, ngx_errno, + "lua epoll_ctl(EPOLL_CTL_DEL, %d) failed", c->fd); + + return NGX_ERROR; + } + + ev->active = 0; + + return NGX_OK; +} + + +static ngx_int_t +ngx_http_lua_epoll_process_event(ngx_http_request_t *r, ngx_msec_t timer) +{ + int events; + uint32_t revents; + ngx_err_t err; + ngx_event_t *rev, *wev; + ngx_connection_t *c; + + events = epoll_wait(ep, &eev, 1, timer); + + err = (events == -1) ? ngx_errno : 0; + + if (err) { + ngx_log_error(NGX_LOG_ALERT, r->connection->log, err, + "lua epoll_wait() failed"); + + return NGX_ERROR; + } + + if (events == 0) { + ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0, + "lua epoll_wait() returned no events without timeout"); + + return NGX_ERROR; + } + + c = eev.data.ptr; + revents = eev.events; + + if (revents & (EPOLLERR|EPOLLHUP)) { + ngx_log_debug2(NGX_LOG_DEBUG_EVENT, r->connection->log, 0, + "epoll_wait() error on fd:%d ev:%04XD", + c->fd, revents); + + /* + * if the error events were returned, add EPOLLIN and EPOLLOUT + * to handle the events at least in one active handler + */ + + revents |= EPOLLIN|EPOLLOUT; + } + + rev = c->read; + + if ((revents & EPOLLIN) && rev->active) { + +#if (NGX_HAVE_EPOLLRDHUP) + if (revents & EPOLLRDHUP) { + rev->pending_eof = 1; + } +#endif + + rev->ready = 1; + rev->available = -1; + } + + wev = c->write; + + if ((revents & EPOLLOUT) && wev->active) { + wev->ready = 1; +#if (NGX_THREADS) + wev->complete = 1; +#endif + } + + return NGX_OK; +} diff --git a/src/event/ngx_http_lua_kqueue.c b/src/event/ngx_http_lua_kqueue.c new file mode 100644 index 0000000000..4df450f714 --- /dev/null +++ b/src/event/ngx_http_lua_kqueue.c @@ -0,0 +1,131 @@ + +/* + * Copyright (C) Yichun Zhang (agentzh) + */ + + +#include +#include +#include +#include "../ngx_http_lua_event.h" + + +static ngx_int_t ngx_http_lua_kqueue_init_event(ngx_cycle_t *cycle); +static ngx_int_t ngx_http_lua_kqueue_set_event(ngx_event_t *ev, + ngx_int_t event); +static ngx_int_t ngx_http_lua_kqueue_clear_event(ngx_event_t *ev, + ngx_int_t event); +static ngx_int_t ngx_http_lua_kqueue_process_event(ngx_http_request_t *r, + ngx_msec_t timer); + +int kq = -1; +static struct kevent kch; +static struct kevent kev; + +ngx_http_lua_event_actions_t ngx_http_lua_kqueue = { + ngx_http_lua_kqueue_init_event, + ngx_http_lua_kqueue_set_event, + ngx_http_lua_kqueue_clear_event, + ngx_http_lua_kqueue_process_event, +}; + + +static ngx_int_t +ngx_http_lua_kqueue_init_event(ngx_cycle_t *cycle) +{ + kq = kqueue(); + + if (kq == -1) { + ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_errno, + "lua kqueue() failed"); + + return NGX_ERROR; + } + + return NGX_OK; +} + + +static ngx_int_t +ngx_http_lua_kqueue_set_event(ngx_event_t *ev, ngx_int_t event) +{ + ngx_connection_t *c; + + c = ev->data; + + ev->active = 1; + + kch.ident = c->fd; + kch.filter = (short) event; + kch.flags = EV_ADD|EV_ENABLE; + kch.udata = NGX_KQUEUE_UDATA_T (ev); + + return NGX_OK; +} + + +static ngx_int_t +ngx_http_lua_kqueue_clear_event(ngx_event_t *ev, ngx_int_t event) +{ + ngx_connection_t *c; + + c = ev->data; + + ev->active = 0; + + kch.ident = c->fd; + kch.filter = (short) event; + kch.flags = EV_DELETE; + kch.udata = NGX_KQUEUE_UDATA_T (ev); + + if (kevent(kq, &kch, 1, NULL, 0, NULL) == -1) { + ngx_log_error(NGX_LOG_ALERT, r->connection->log, err, + "lua kevent() failed"); + + return NGX_ERROR; + } + + return NGX_OK; +} + + +static ngx_int_t +ngx_http_lua_kqueue_process_event(ngx_http_request_t *r, ngx_msec_t timer) +{ + int events; + struct timespec ts; + ngx_event_t *ev; + ngx_err_t err; + + ts.tv_sec = timer / 1000; + ts.tv_nsec = (timer % 1000) * 1000000; + + events = kevent(kq, &kch, 1, &kev, 1, &ts); + + err = (events == -1) ? ngx_errno : 0; + + if (err) { + ngx_log_error(NGX_LOG_ALERT, r->connection->log, err, + "lua kevent() failed"); + + return NGX_ERROR; + } + + if (events == 0) { + ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0, + "lua kevent() returned no events without timeout"); + + return NGX_ERROR; + } + + ev = (ngx_event_t *) kev.udata; + + ev->available = kev.data; + ev->ready = 1; + + if (kev.flags & EV_EOF) { + ev->pending_eof = 1; + } + + return NGX_OK; +} diff --git a/src/event/ngx_http_lua_poll.c b/src/event/ngx_http_lua_poll.c new file mode 100644 index 0000000000..c255b0d47d --- /dev/null +++ b/src/event/ngx_http_lua_poll.c @@ -0,0 +1,113 @@ + +/* + * Copyright (C) Yichun Zhang (agentzh) + */ + + +#include +#include +#include +#include "../ngx_http_lua_event.h" + + +static ngx_int_t ngx_http_lua_poll_init_event(ngx_cycle_t *cycle); +static ngx_int_t ngx_http_lua_poll_set_event(ngx_event_t *ev, ngx_int_t event); +static ngx_int_t ngx_http_lua_poll_clear_event(ngx_event_t *ev, + ngx_int_t event); +static ngx_int_t ngx_http_lua_poll_process_event(ngx_http_request_t *r, + ngx_msec_t timer); + +static struct pollfd pev; + +ngx_http_lua_event_actions_t ngx_http_lua_poll = { + ngx_http_lua_poll_init_event, + ngx_http_lua_poll_set_event, + ngx_http_lua_poll_clear_event, + ngx_http_lua_poll_process_event, +}; + + +static ngx_int_t +ngx_http_lua_poll_init_event(ngx_cycle_t *cycle) +{ + return NGX_OK; +} + + +static ngx_int_t +ngx_http_lua_poll_set_event(ngx_event_t *ev, ngx_int_t event) +{ + ngx_connection_t *c; + + c = ev->data; + + ev->active = 1; + + if (event == NGX_READ_EVENT) { +#if (NGX_READ_EVENT != POLLIN) + event = POLLIN; +#endif + + } else { +#if (NGX_WRITE_EVENT != POLLOUT) + event = POLLOUT; +#endif + } + + pev.fd = c->fd; + pev.events = (short) event; + pev.revents = 0; + + return NGX_OK; +} + + +static ngx_int_t +ngx_http_lua_poll_clear_event(ngx_event_t *ev, ngx_int_t event) +{ + return NGX_OK; +} + + +static ngx_int_t +ngx_http_lua_poll_process_event(ngx_http_request_t *r, ngx_msec_t timer) +{ + int ready, revents; + ngx_event_t *ev; + ngx_err_t err; + ngx_connection_t *c; + + ready = poll(&pev, 1, (int) timer); + + err = (ready == -1) ? ngx_errno : 0; + + if (err) { + ngx_log_error(NGX_LOG_ALERT, r->connection->log, err, + "lua poll() failed"); + + return NGX_ERROR; + } + + if (ready == 0) { + ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0, + "lua poll() returned no events without timeout"); + + return NGX_ERROR; + } + + revents = pev.revents; + c = ngx_cycle->files[pev.fd]; + + if ((revents & POLLIN) && c->read->active) { + ev = c->read; + ev->ready = 1; + ev->available = -1; + } + + if ((revents & POLLOUT) && c->write->active) { + ev = c->write; + ev->ready = 1; + } + + return NGX_OK; +} diff --git a/src/ngx_http_lua_event.h b/src/ngx_http_lua_event.h new file mode 100644 index 0000000000..5b0dd37091 --- /dev/null +++ b/src/ngx_http_lua_event.h @@ -0,0 +1,87 @@ + +/* + * Copyright (C) Yichun Zhang (agentzh) + */ + + +#ifndef _NGX_HTTP_LUA_EVENT_H_INCLUDED_ +#define _NGX_HTTP_LUA_EVENT_H_INCLUDED_ + + +#include "ngx_http_lua_common.h" + + +typedef struct { + ngx_int_t (*init_event)(ngx_cycle_t *cycle); + ngx_int_t (*set_event)(ngx_event_t *ev, ngx_int_t event); + ngx_int_t (*clear_event)(ngx_event_t *ev, ngx_int_t event); + ngx_int_t (*process_event)(ngx_http_request_t *r, ngx_msec_t timer); +} ngx_http_lua_event_actions_t; + + +ngx_http_lua_event_actions_t ngx_http_lua_event_actions; + +extern ngx_http_lua_event_actions_t ngx_http_lua_epoll; +extern ngx_http_lua_event_actions_t ngx_http_lua_poll; +extern ngx_http_lua_event_actions_t ngx_http_lua_kqueue; + + +#define ngx_http_lua_set_event ngx_http_lua_event_actions.set_event +#define ngx_http_lua_clear_event ngx_http_lua_event_actions.clear_event +#define ngx_http_lua_process_event ngx_http_lua_event_actions.process_event + + +static ngx_inline ngx_int_t +ngx_http_lua_init_event(ngx_cycle_t *cycle) +{ + void ***ccf; + ngx_event_conf_t *ecf; + + ccf = ngx_get_conf(cycle->conf_ctx, ngx_events_module); + if (ccf == NULL) { + ngx_log_error(NGX_LOG_EMERG, cycle->log, 0, + "no \"events\" section in configuration"); + + return NGX_ERROR; + } + + ecf = (*ccf)[ngx_event_core_module.ctx_index]; + +#if (NGX_HAVE_EPOLL) && !(NGX_TEST_BUILD_EPOLL) + + if (ngx_strcmp(ecf->name, "epoll") == 0) { + ngx_http_lua_event_actions = ngx_http_lua_epoll; + } else + +#endif + +#if (NGX_HAVE_POLL) + + if (ngx_strcmp(ecf->name, "poll") == 0) { + ngx_http_lua_event_actions = ngx_http_lua_poll; + } else + +#endif + +#if (NGX_HAVE_KQUEUE) + + if (ngx_strcmp(ecf->name, "kqueue") == 0) { + ngx_http_lua_event_actions = ngx_http_lua_kqueue; + } else + +#endif + + { + ngx_log_error(NGX_LOG_EMERG, cycle->log, 0, + "invalid event type \"%V\"", ecf->name); + + return NGX_ERROR; + } + + return ngx_http_lua_event_actions.init_event(cycle); +} + + +#endif /* _NGX_HTTP_LUA_EVENT_H_INCLUDED_ */ + +/* vi:set ft=c ts=4 sw=4 et fdm=marker: */ diff --git a/src/ngx_http_lua_initworkerby.c b/src/ngx_http_lua_initworkerby.c index 3235a4d30a..bc792403e3 100644 --- a/src/ngx_http_lua_initworkerby.c +++ b/src/ngx_http_lua_initworkerby.c @@ -13,6 +13,7 @@ #include "ngx_http_lua_initworkerby.h" #include "ngx_http_lua_util.h" #include "ngx_http_lua_pipe.h" +#include "ngx_http_lua_event.h" static u_char *ngx_http_lua_log_init_worker_error(ngx_log_t *log, @@ -46,6 +47,10 @@ ngx_http_lua_init_worker(ngx_cycle_t *cycle) return NGX_OK; } + if (ngx_http_lua_init_event(cycle) == NGX_ERROR) { + return NGX_ERROR; + } + /* lmcf != NULL && lmcf->lua != NULL */ #if !(NGX_WIN32) diff --git a/src/ngx_http_lua_socket_tcp.c b/src/ngx_http_lua_socket_tcp.c index 26467fddbc..02c26f781c 100644 --- a/src/ngx_http_lua_socket_tcp.c +++ b/src/ngx_http_lua_socket_tcp.c @@ -17,6 +17,7 @@ #include "ngx_http_lua_output.h" #include "ngx_http_lua_contentby.h" #include "ngx_http_lua_probe.h" +#include "ngx_http_lua_event.h" static int ngx_http_lua_socket_tcp(lua_State *L); @@ -156,6 +157,14 @@ static void ngx_http_lua_ssl_handshake_handler(ngx_connection_t *c); static int ngx_http_lua_ssl_free_session(lua_State *L); #endif static void ngx_http_lua_socket_tcp_close_connection(ngx_connection_t *c); +static ngx_int_t ngx_http_lua_socket_tcp_blocked_conn(ngx_http_request_t *r, + ngx_http_lua_socket_tcp_upstream_t *u); +static ngx_int_t ngx_http_lua_socket_tcp_blocked_sslhandshake( + ngx_http_request_t *r, ngx_http_lua_socket_tcp_upstream_t *u); +static ngx_int_t ngx_http_lua_socket_tcp_blocked_write(ngx_http_request_t *r, + ngx_http_lua_socket_tcp_upstream_t *u); +static ngx_int_t ngx_http_lua_socket_tcp_blocked_read(ngx_http_request_t *r, + ngx_http_lua_socket_tcp_upstream_t *u); enum { @@ -449,7 +458,7 @@ ngx_http_lua_socket_tcp(lua_State *L) return luaL_error(L, "no ctx found"); } - ngx_http_lua_check_context(L, ctx, NGX_HTTP_LUA_CONTEXT_YIELDABLE); + ngx_http_lua_check_context(L, ctx, NGX_HTTP_LUA_CONTEXT_COSOCKET); lua_createtable(L, 5 /* narr */, 1 /* nrec */); lua_pushlightuserdata(L, ngx_http_lua_lightudata_mask( @@ -683,7 +692,10 @@ ngx_http_lua_socket_tcp_connect_helper(lua_State *L, ngx_memzero(&url, sizeof(ngx_url_t)); url.url = host; url.default_port = port; - url.no_resolve = 1; + + if (ctx->context & NGX_HTTP_LUA_CONTEXT_YIELDABLE) { + url.no_resolve = 1; + } coctx = ctx->cur_co_ctx; @@ -891,7 +903,7 @@ ngx_http_lua_socket_tcp_connect(lua_State *L) return luaL_error(L, "no ctx found"); } - ngx_http_lua_check_context(L, ctx, NGX_HTTP_LUA_CONTEXT_YIELDABLE); + ngx_http_lua_check_context(L, ctx, NGX_HTTP_LUA_CONTEXT_COSOCKET); luaL_checktype(L, 1, LUA_TTABLE); @@ -1473,11 +1485,18 @@ ngx_http_lua_socket_resolve_retval_handler(ngx_http_request_t *r, u->writer.last = &u->writer.out; #endif - ctx = ngx_http_get_module_ctx(r, ngx_http_lua_module); + dd("setting data to %p", u); - coctx = ctx->cur_co_ctx; + ctx = ngx_http_get_module_ctx(r, ngx_http_lua_module); - dd("setting data to %p", u); + if (rc == NGX_AGAIN + && (ctx->context & NGX_HTTP_LUA_CONTEXT_BLOCKED_COSOCKET)) + { + rc = ngx_http_lua_socket_tcp_blocked_conn(r, u); + if (rc == NGX_ERROR) { + return ngx_http_lua_socket_conn_error_retval_handler(r, u, L); + } + } if (rc == NGX_OK) { ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, @@ -1513,6 +1532,8 @@ ngx_http_lua_socket_resolve_retval_handler(ngx_http_request_t *r, /* rc == NGX_AGAIN */ + coctx = ctx->cur_co_ctx; + ngx_http_lua_cleanup_pending_operation(coctx); coctx->cleanup = ngx_http_lua_coctx_cleanup; coctx->data = u; @@ -1776,6 +1797,12 @@ ngx_http_lua_socket_tcp_sslhandshake(lua_State *L) dd("ngx_ssl_handshake returned %d", (int) rc); + if (rc == NGX_AGAIN + && (ctx->context & NGX_HTTP_LUA_CONTEXT_BLOCKED_COSOCKET)) + { + rc = ngx_http_lua_socket_tcp_blocked_sslhandshake(r, u); + } + if (rc == NGX_AGAIN) { if (c->write->timer_set) { ngx_del_timer(c->write); @@ -2101,6 +2128,12 @@ ngx_http_lua_socket_tcp_receive_helper(ngx_http_request_t *r, rc = ngx_http_lua_socket_tcp_read(r, u); + if (rc == NGX_AGAIN + && (ctx->context & NGX_HTTP_LUA_CONTEXT_BLOCKED_COSOCKET)) + { + rc = ngx_http_lua_socket_tcp_blocked_read(r, u); + } + if (rc == NGX_ERROR) { dd("read failed: %d", (int) u->ft_type); rc = ngx_http_lua_socket_tcp_receive_retval_handler(r, u, L); @@ -2913,6 +2946,12 @@ ngx_http_lua_socket_tcp_send(lua_State *L) dd("socket send returned %d", (int) rc); + if (rc == NGX_AGAIN + && (ctx->context & NGX_HTTP_LUA_CONTEXT_BLOCKED_COSOCKET)) + { + rc = ngx_http_lua_socket_tcp_blocked_write(r, u); + } + if (rc == NGX_ERROR) { return ngx_http_lua_socket_write_error_retval_handler(r, u, L); } @@ -4487,6 +4526,12 @@ ngx_http_lua_socket_receiveuntil_iterator(lua_State *L) rc = ngx_http_lua_socket_tcp_read(r, u); + if (rc == NGX_AGAIN + && (ctx->context & NGX_HTTP_LUA_CONTEXT_BLOCKED_COSOCKET)) + { + rc = ngx_http_lua_socket_tcp_blocked_read(r, u); + } + if (rc == NGX_ERROR) { dd("read failed: %d", (int) u->ft_type); rc = ngx_http_lua_socket_tcp_receive_retval_handler(r, u, L); @@ -6100,6 +6145,240 @@ ngx_http_lua_coctx_cleanup(void *data) ngx_http_lua_socket_tcp_finalize(u->request, u); } +static ngx_int_t +ngx_http_lua_socket_tcp_blocked_conn(ngx_http_request_t *r, + ngx_http_lua_socket_tcp_upstream_t *u) +{ + ngx_connection_t *c; + ngx_uint_t ft_type; + ngx_msec_t timeout, start_time; + + ft_type = 0; + c = u->peer.connection; + + if (c->write->timer_set) { + ngx_del_timer(c->write); + } + + if (c->write->active) { + ngx_del_event(c->write, NGX_WRITE_EVENT, 0); + } + + if (ngx_http_lua_set_event(c->write, NGX_WRITE_EVENT) == NGX_ERROR) { + ft_type = NGX_HTTP_LUA_SOCKET_FT_ERROR; + goto finish; + } + + timeout = u->connect_timeout; + start_time = ngx_current_msec; + + if (ngx_http_lua_process_event(r, timeout) == NGX_ERROR) { + ft_type = NGX_HTTP_LUA_SOCKET_FT_ERROR; + goto finish; + } + + ngx_time_update(); + + if (ngx_current_msec - start_time >= timeout) { + ft_type = NGX_HTTP_LUA_SOCKET_FT_TIMEOUT; + } + +finish: + + if (ngx_http_lua_clear_event(c->write, NGX_WRITE_EVENT) == NGX_ERROR) { + ft_type = NGX_HTTP_LUA_SOCKET_FT_ERROR; + } + + if (ft_type != 0) { + ngx_http_lua_socket_handle_conn_error(r, u, ft_type); + + return NGX_ERROR; + } + + return NGX_OK; +} + +static ngx_int_t +ngx_http_lua_socket_tcp_blocked_sslhandshake(ngx_http_request_t *r, + ngx_http_lua_socket_tcp_upstream_t *u) +{ + ngx_connection_t *c; + ngx_int_t rc; + ngx_msec_t timer, start_time; + + rc = NGX_OK; + c = u->peer.connection; + + if (c->read->timer_set) { + ngx_del_timer(c->read); + } + + if (c->read->active) { + ngx_del_event(c->read, NGX_READ_EVENT, 0); + } + + rc = ngx_http_lua_set_event(c->read, NGX_READ_EVENT); + if (rc == NGX_ERROR) { + goto finish; + } + + timer = u->connect_timeout; + start_time = ngx_current_msec; + + rc = ngx_http_lua_process_event(r, timer); + if (rc == NGX_ERROR) { + goto finish; + } + + ngx_time_update(); + + if (ngx_current_msec - start_time >= timer) { + c->read->timedout = 1; + + rc = NGX_ERROR; + goto finish; + } + + ngx_http_lua_ssl_handshake_retval_handler(r, u, u->write_co_ctx->co); + +finish: + + if (ngx_http_lua_clear_event(c->read, NGX_READ_EVENT) == NGX_ERROR) { + return NGX_ERROR; + } + + return rc; +} + + +static ngx_int_t +ngx_http_lua_socket_tcp_blocked_write(ngx_http_request_t *r, + ngx_http_lua_socket_tcp_upstream_t *u) +{ + ngx_connection_t *c; + ngx_uint_t ft_type; + ngx_msec_t timeout, start_time; + + ft_type = 0; + c = u->peer.connection; + + if (c->write->timer_set) { + ngx_del_timer(c->write); + } + + if (c->write->active) { + ngx_del_event(c->write, NGX_WRITE_EVENT, 0); + } + + if (ngx_http_lua_set_event(c->write, NGX_WRITE_EVENT) == NGX_ERROR) { + ft_type = NGX_HTTP_LUA_SOCKET_FT_ERROR; + goto finish; + } + + timeout = u->send_timeout; + start_time = ngx_current_msec; + + if (ngx_http_lua_process_event(r, timeout) == NGX_ERROR) { + ft_type = NGX_HTTP_LUA_SOCKET_FT_ERROR; + goto finish; + } + + ngx_time_update(); + + if (ngx_current_msec - start_time >= timeout) { + ft_type = NGX_HTTP_LUA_SOCKET_FT_TIMEOUT; + } + +finish: + + if (ngx_http_lua_clear_event(c->write, NGX_WRITE_EVENT) == NGX_ERROR) { + ft_type = NGX_HTTP_LUA_SOCKET_FT_ERROR; + } + + if (ft_type != 0) { + ngx_http_lua_socket_handle_write_error(r, u, ft_type); + + return NGX_ERROR; + } + + return NGX_OK; +} + + +static ngx_int_t +ngx_http_lua_socket_tcp_blocked_read(ngx_http_request_t *r, + ngx_http_lua_socket_tcp_upstream_t *u) +{ + ngx_connection_t *c; + ngx_int_t rc; + ngx_uint_t ft_type; + ngx_msec_t timeout, timer, start_time; + + rc = NGX_OK; + ft_type = 0; + c = u->peer.connection; + + if (c->read->timer_set) { + ngx_del_timer(c->read); + } + + if (c->read->active) { + ngx_del_event(c->read, NGX_READ_EVENT, 0); + } + + if (ngx_http_lua_set_event(c->read, NGX_READ_EVENT) == NGX_ERROR) { + ft_type = NGX_HTTP_LUA_SOCKET_FT_ERROR; + goto finish; + } + + timeout = u->read_timeout; + start_time = ngx_current_msec; + + for (;;) { + + timer = timeout - (ngx_current_msec - start_time); + + if (ngx_http_lua_process_event(r, timer) == NGX_ERROR) { + ft_type = NGX_HTTP_LUA_SOCKET_FT_ERROR; + goto finish; + } + + if (c->read->pending_eof) { + ft_type = NGX_HTTP_LUA_SOCKET_FT_ERROR; + goto finish; + } + + ngx_time_update(); + + if (ngx_current_msec - start_time >= timeout) { + ft_type = NGX_HTTP_LUA_SOCKET_FT_TIMEOUT; + goto finish; + } + + rc = ngx_http_lua_socket_tcp_read(r, u); + + if (rc == NGX_ERROR || rc == NGX_OK) { + break; + } + + /* NGX_AGAIN, continue in loop*/ + } + +finish: + + if (ngx_http_lua_clear_event(c->read, NGX_READ_EVENT) == NGX_ERROR) { + ft_type = NGX_HTTP_LUA_SOCKET_FT_ERROR; + } + + if (ft_type != 0) { + ngx_http_lua_socket_handle_read_error(r, u, ft_type); + + return NGX_ERROR; + } + + return rc; +} + #if (NGX_HTTP_SSL) diff --git a/src/ngx_http_lua_util.h b/src/ngx_http_lua_util.h index 9ad34b93ea..8d9b22c9e8 100644 --- a/src/ngx_http_lua_util.h +++ b/src/ngx_http_lua_util.h @@ -40,6 +40,11 @@ | NGX_HTTP_LUA_CONTEXT_SSL_CERT \ | NGX_HTTP_LUA_CONTEXT_SSL_SESS_FETCH) +#define NGX_HTTP_LUA_CONTEXT_BLOCKED_COSOCKET NGX_HTTP_LUA_CONTEXT_INIT_WORKER + +#define NGX_HTTP_LUA_CONTEXT_COSOCKET (NGX_HTTP_LUA_CONTEXT_YIELDABLE \ + | NGX_HTTP_LUA_CONTEXT_BLOCKED_COSOCKET) + /* key in Lua vm registry for all the "ngx.ctx" tables */ #define ngx_http_lua_ctx_tables_key "ngx_lua_ctx_tables" diff --git a/t/058-tcp-socket.t b/t/058-tcp-socket.t index 593e49461f..65f4e41acc 100644 --- a/t/058-tcp-socket.t +++ b/t/058-tcp-socket.t @@ -4,7 +4,7 @@ use Test::Nginx::Socket::Lua; repeat_each(2); -plan tests => repeat_each() * 231; +plan tests => repeat_each() * 234; our $HtmlDir = html_dir; @@ -4367,3 +4367,64 @@ connect failed: missing the port number finish --- no_error_log [error] + + + +=== TEST 73: run in init_worker_by_lua +--- http_config + init_worker_by_lua_block { + local sock = ngx.socket.tcp() + local port = 80 + local ok, err = sock:connect("agentzh.org", port) + if not ok then + ngx.log(ngx.ERR, "failed to connect: ", err) + return + end + + ngx.log(ngx.INFO, "connected: ", ok) + + local req = "GET / HTTP/1.0\r\nHost: agentzh.org\r\nConnection: close\r\n\r\n" + -- req = "OK" + + local bytes, err = sock:send(req) + if not bytes then + ngx.log(ngx.ERR, "failed to send request: ", err) + return + end + + ngx.log(ngx.INFO, "request sent: ", bytes) + + local line, err = sock:receive() + if line then + ngx.log(ngx.INFO, "first line received: ", line) + + else + ngx.log(ngx.ERR, "failed to receive the first line: ", err) + end + + line, err = sock:receive() + if line then + ngx.log(ngx.INFO, "second line received: ", line) + + else + ngx.log(ngx.ERR, "failed to receive the second line: ", err) + end + } +--- config + location /t { + content_by_lua_block { + ngx.say("hello") + } + } +--- request +GET /t +--- response_body +hello +--- error_log_like +connected: 1 +request sent: 56 +first line received: HTTP\/1\.1 200 OK +second line received: (?:Date|Server): .*? +--- no_error_log +[error] +--- timeout: 10 From 1cdd6588404e674a772c8ef6eb6193209d13b493 Mon Sep 17 00:00:00 2001 From: rainingmaster <312841925@qq.com> Date: Sat, 5 Dec 2020 10:03:28 +0800 Subject: [PATCH 2/9] tests: add more test case --- t/129-ssl-socket.t | 76 +++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 71 insertions(+), 5 deletions(-) diff --git a/t/129-ssl-socket.t b/t/129-ssl-socket.t index c26f0cec53..7d8a1a0c7f 100644 --- a/t/129-ssl-socket.t +++ b/t/129-ssl-socket.t @@ -2732,11 +2732,6 @@ received: HTTP/1.1 200 OK close: 1 nil --- log_level: debug ---- grep_error_log eval: qr/lua ssl (?:set|save|free) session: [0-9A-F]+/ ---- grep_error_log_out eval -qr/^lua ssl save session: ([0-9A-F]+) -lua ssl free session: ([0-9A-F]+) -$/ --- error_log eval ['lua ssl server name: "test.com"', qr/SSL: TLSv1.3, cipher: "TLS_AES_128_GCM_SHA256 TLSv1.3/] @@ -2834,3 +2829,74 @@ SSL reused session [alert] [emerg] --- timeout: 10 + + + +=== TEST 35: www.google.com in init_worker_by_lua +--- http_config + init_worker_by_lua_block { + local sock = ngx.socket.tcp() + sock:settimeout(2000) + local ok, err = sock:connect("www.google.com", 443) + if not ok then + ngx.log(ngx.ERR, "failed to connect: ", err) + return + end + + ngx.log(ngx.ERR, "connected: ", ok) + + local sess, err = sock:sslhandshake() + if not sess then + ngx.log(ngx.ERR, "failed to do SSL handshake: ", err) + return + end + + ngx.log(ngx.INFO, "ssl handshake: ", type(sess)) + + local req = "GET / HTTP/1.1\\r\\nHost: www.google.com\\r\\nConnection: close\\r\\n\\r\\n" + local bytes, err = sock:send(req) + if not bytes then + ngx.log(ngx.ERR, "failed to send http request: ", err) + return + end + + ngx.log(ngx.INFO, "sent http request: ", bytes, " bytes.") + + local line, err = sock:receive() + if not line then + ngx.log(ngx.ERR, "failed to receive response status line: ", err) + return + end + + ngx.log(ngx.INFO, "received: ", line) + + local ok, err = sock:close() + ngx.log(ngx.INFO, "close: ", ok, " ", err) + } +--- config + location /t { + content_by_lua_block { + ngx.say("hello") + } + } +--- request +GET /t +--- response_body +hello +--- error_log_like chop +\Aconnected: 1 +ssl handshake: userdata +sent http request: 59 bytes. +received: HTTP/1.1 (?:200 OK|302 Found) +close: 1 nil +\z +--- grep_error_log eval: qr/lua ssl (?:set|save|free) session: [0-9A-F]+/ +--- grep_error_log_out eval +qr/^lua ssl save session: ([0-9A-F]+) +lua ssl free session: ([0-9A-F]+) +$/ +--- no_error_log +lua ssl server name: +SSL reused session +[error] +--- timeout: 5 From 04a769b44e78e8d1ec49529eee9fa6f0f3687067 Mon Sep 17 00:00:00 2001 From: rainingmaster <312841925@qq.com> Date: Tue, 15 Dec 2020 21:56:57 +0800 Subject: [PATCH 3/9] fix: for ssl test cases --- src/event/ngx_http_lua_epoll.c | 44 ++++++++- src/event/ngx_http_lua_kqueue.c | 32 ++++--- src/event/ngx_http_lua_poll.c | 13 ++- src/ngx_http_lua_socket_tcp.c | 158 ++++++++++++++++++-------------- src/ngx_http_lua_util.h | 2 +- t/129-ssl-socket.t | 12 +-- 6 files changed, 159 insertions(+), 102 deletions(-) diff --git a/src/event/ngx_http_lua_epoll.c b/src/event/ngx_http_lua_epoll.c index bfafc0a947..f09ec2cc41 100644 --- a/src/event/ngx_http_lua_epoll.c +++ b/src/event/ngx_http_lua_epoll.c @@ -47,8 +47,10 @@ ngx_http_lua_epoll_init_event(ngx_cycle_t *cycle) static ngx_int_t ngx_http_lua_epoll_set_event(ngx_event_t *ev, ngx_int_t event) { - uint32_t events; + int op; + uint32_t events, prev; ngx_connection_t *c; + ngx_event_t *e; struct epoll_event ee; c = ev->data; @@ -56,20 +58,32 @@ ngx_http_lua_epoll_set_event(ngx_event_t *ev, ngx_int_t event) events = (uint32_t) event; if (event == NGX_READ_EVENT) { + e = c->write; + prev = EPOLLOUT; #if (NGX_READ_EVENT != EPOLLIN|EPOLLRDHUP) events = EPOLLIN|EPOLLRDHUP; #endif } else { + e = c->read; + prev = EPOLLIN|EPOLLRDHUP; #if (NGX_WRITE_EVENT != EPOLLOUT) events = EPOLLOUT; #endif } + if (e->active) { + op = EPOLL_CTL_MOD; + events |= prev; + + } else { + op = EPOLL_CTL_ADD; + } + ee.events = events; ee.data.ptr = c; - if (epoll_ctl(ep, EPOLL_CTL_ADD, c->fd, &ee) == -1) { + if (epoll_ctl(ep, op, c->fd, &ee) == -1) { ngx_log_error(NGX_LOG_ALERT, ev->log, ngx_errno, "lua epoll_ctl(EPOLL_CTL_ADD, %d) failed, add event: %d", c->fd, events); @@ -86,15 +100,35 @@ ngx_http_lua_epoll_set_event(ngx_event_t *ev, ngx_int_t event) static ngx_int_t ngx_http_lua_epoll_clear_event(ngx_event_t *ev, ngx_int_t event) { + ngx_event_t *e; ngx_connection_t *c; + int op; + uint32_t prev; struct epoll_event ee; c = ev->data; - ee.events = 0; - ee.data.ptr = NULL; + if (event == NGX_READ_EVENT) { + e = c->write; + prev = EPOLLOUT; + + } else { + e = c->read; + prev = EPOLLIN|EPOLLRDHUP; + } + + if (e->active) { + op = EPOLL_CTL_MOD; + ee.events = prev; + ee.data.ptr = c; + + } else { + op = EPOLL_CTL_DEL; + ee.events = 0; + ee.data.ptr = NULL; + } - if (epoll_ctl(ep, EPOLL_CTL_DEL, c->fd, &ee) == -1) { + if (epoll_ctl(ep, op, c->fd, &ee) == -1) { ngx_log_error(NGX_LOG_ALERT, ev->log, ngx_errno, "lua epoll_ctl(EPOLL_CTL_DEL, %d) failed", c->fd); diff --git a/src/event/ngx_http_lua_kqueue.c b/src/event/ngx_http_lua_kqueue.c index 4df450f714..345012cda9 100644 --- a/src/event/ngx_http_lua_kqueue.c +++ b/src/event/ngx_http_lua_kqueue.c @@ -19,8 +19,9 @@ static ngx_int_t ngx_http_lua_kqueue_process_event(ngx_http_request_t *r, ngx_msec_t timer); int kq = -1; -static struct kevent kch; +static struct kevent kch[2]; static struct kevent kev; +static ngx_uint_t nchanges; ngx_http_lua_event_actions_t ngx_http_lua_kqueue = { ngx_http_lua_kqueue_init_event, @@ -33,6 +34,7 @@ ngx_http_lua_event_actions_t ngx_http_lua_kqueue = { static ngx_int_t ngx_http_lua_kqueue_init_event(ngx_cycle_t *cycle) { + nchanges = 0; kq = kqueue(); if (kq == -1) { @@ -55,10 +57,12 @@ ngx_http_lua_kqueue_set_event(ngx_event_t *ev, ngx_int_t event) ev->active = 1; - kch.ident = c->fd; - kch.filter = (short) event; - kch.flags = EV_ADD|EV_ENABLE; - kch.udata = NGX_KQUEUE_UDATA_T (ev); + kch[nchanges].ident = c->fd; + kch[nchanges].filter = (short) event; + kch[nchanges].flags = EV_ADD|EV_ENABLE; + kch[nchanges].udata = NGX_KQUEUE_UDATA_T (ev); + + nchanges++; return NGX_OK; } @@ -73,13 +77,13 @@ ngx_http_lua_kqueue_clear_event(ngx_event_t *ev, ngx_int_t event) ev->active = 0; - kch.ident = c->fd; - kch.filter = (short) event; - kch.flags = EV_DELETE; - kch.udata = NGX_KQUEUE_UDATA_T (ev); + kch[0].ident = c->fd; + kch[0].filter = (short) event; + kch[0].flags = EV_DELETE; + kch[0].udata = NGX_KQUEUE_UDATA_T (ev); - if (kevent(kq, &kch, 1, NULL, 0, NULL) == -1) { - ngx_log_error(NGX_LOG_ALERT, r->connection->log, err, + if (kevent(kq, kch, 1, NULL, 0, NULL) == -1) { + ngx_log_error(NGX_LOG_ALERT, ev->log, ngx_errno, "lua kevent() failed"); return NGX_ERROR; @@ -100,8 +104,9 @@ ngx_http_lua_kqueue_process_event(ngx_http_request_t *r, ngx_msec_t timer) ts.tv_sec = timer / 1000; ts.tv_nsec = (timer % 1000) * 1000000; - events = kevent(kq, &kch, 1, &kev, 1, &ts); + events = kevent(kq, kch, nchanges, &kev, 1, &ts); + nchanges = 0; err = (events == -1) ? ngx_errno : 0; if (err) { @@ -125,6 +130,9 @@ ngx_http_lua_kqueue_process_event(ngx_http_request_t *r, ngx_msec_t timer) if (kev.flags & EV_EOF) { ev->pending_eof = 1; + + ngx_log_error(NGX_LOG_ALERT, r->connection->log, kev.fflags, + "lua kevent() reported that connect() failed"); } return NGX_OK; diff --git a/src/event/ngx_http_lua_poll.c b/src/event/ngx_http_lua_poll.c index c255b0d47d..11790f689f 100644 --- a/src/event/ngx_http_lua_poll.c +++ b/src/event/ngx_http_lua_poll.c @@ -54,9 +54,14 @@ ngx_http_lua_poll_set_event(ngx_event_t *ev, ngx_int_t event) #endif } - pev.fd = c->fd; - pev.events = (short) event; - pev.revents = 0; + if (pev.fd != c->fd) { + pev.fd = c->fd; + pev.events = (short) event; + pev.revents = 0; + + } else { + pev.events |= (short) event; + } return NGX_OK; } @@ -65,6 +70,8 @@ ngx_http_lua_poll_set_event(ngx_event_t *ev, ngx_int_t event) static ngx_int_t ngx_http_lua_poll_clear_event(ngx_event_t *ev, ngx_int_t event) { + ev->active = 0; + return NGX_OK; } diff --git a/src/ngx_http_lua_socket_tcp.c b/src/ngx_http_lua_socket_tcp.c index 02c26f781c..3dc3e6dde3 100644 --- a/src/ngx_http_lua_socket_tcp.c +++ b/src/ngx_http_lua_socket_tcp.c @@ -157,9 +157,10 @@ static void ngx_http_lua_ssl_handshake_handler(ngx_connection_t *c); static int ngx_http_lua_ssl_free_session(lua_State *L); #endif static void ngx_http_lua_socket_tcp_close_connection(ngx_connection_t *c); +static void ngx_http_lua_socket_tcp_clean_events(ngx_connection_t *c); static ngx_int_t ngx_http_lua_socket_tcp_blocked_conn(ngx_http_request_t *r, ngx_http_lua_socket_tcp_upstream_t *u); -static ngx_int_t ngx_http_lua_socket_tcp_blocked_sslhandshake( +static void ngx_http_lua_socket_tcp_blocked_sslhandshake( ngx_http_request_t *r, ngx_http_lua_socket_tcp_upstream_t *u); static ngx_int_t ngx_http_lua_socket_tcp_blocked_write(ngx_http_request_t *r, ngx_http_lua_socket_tcp_upstream_t *u); @@ -1795,38 +1796,38 @@ ngx_http_lua_socket_tcp_sslhandshake(lua_State *L) rc = ngx_ssl_handshake(c); - dd("ngx_ssl_handshake returned %d", (int) rc); - - if (rc == NGX_AGAIN - && (ctx->context & NGX_HTTP_LUA_CONTEXT_BLOCKED_COSOCKET)) - { - rc = ngx_http_lua_socket_tcp_blocked_sslhandshake(r, u); - } + dd("ngx_ssl_handshake returned %d", (int) rc); if (rc == NGX_AGAIN) { - if (c->write->timer_set) { - ngx_del_timer(c->write); - } + if (ctx->context & NGX_HTTP_LUA_CONTEXT_BLOCKED_COSOCKET) { + ngx_http_lua_socket_tcp_blocked_sslhandshake(r, u); - ngx_add_timer(c->read, u->connect_timeout); + } else { + if (c->write->timer_set) { + ngx_del_timer(c->write); + } - u->conn_waiting = 1; - u->write_prepare_retvals = ngx_http_lua_ssl_handshake_retval_handler; + ngx_add_timer(c->read, u->connect_timeout); - ngx_http_lua_cleanup_pending_operation(coctx); - coctx->cleanup = ngx_http_lua_coctx_cleanup; - coctx->data = u; + u->conn_waiting = 1; + u->write_prepare_retvals = + ngx_http_lua_ssl_handshake_retval_handler; - c->ssl->handler = ngx_http_lua_ssl_handshake_handler; + ngx_http_lua_cleanup_pending_operation(coctx); + coctx->cleanup = ngx_http_lua_coctx_cleanup; + coctx->data = u; - if (ctx->entered_content_phase) { - r->write_event_handler = ngx_http_lua_content_wev_handler; + c->ssl->handler = ngx_http_lua_ssl_handshake_handler; - } else { - r->write_event_handler = ngx_http_core_run_phases; - } + if (ctx->entered_content_phase) { + r->write_event_handler = ngx_http_lua_content_wev_handler; - return lua_yield(L, 0); + } else { + r->write_event_handler = ngx_http_core_run_phases; + } + + return lua_yield(L, 0); + } } top = lua_gettop(L); @@ -1863,7 +1864,13 @@ ngx_http_lua_ssl_handshake_handler(ngx_connection_t *c) waiting = u->conn_waiting; dc = r->connection; - L = u->write_co_ctx->co; + + if (ctx->context & NGX_HTTP_LUA_CONTEXT_BLOCKED_COSOCKET) { + L = ngx_http_lua_get_lua_vm(r, ctx); + + } else { + L = u->write_co_ctx->co; + } if (c->read->timedout) { lua_pushnil(L); @@ -6145,6 +6152,28 @@ ngx_http_lua_coctx_cleanup(void *data) ngx_http_lua_socket_tcp_finalize(u->request, u); } + +static void +ngx_http_lua_socket_tcp_clean_events(ngx_connection_t *c) +{ + if (c->read->timer_set) { + ngx_del_timer(c->read); + } + + if (c->read->active) { + ngx_del_event(c->read, NGX_READ_EVENT, 0); + } + + if (c->write->timer_set) { + ngx_del_timer(c->write); + } + + if (c->write->active) { + ngx_del_event(c->write, NGX_WRITE_EVENT, 0); + } +} + + static ngx_int_t ngx_http_lua_socket_tcp_blocked_conn(ngx_http_request_t *r, ngx_http_lua_socket_tcp_upstream_t *u) @@ -6156,13 +6185,7 @@ ngx_http_lua_socket_tcp_blocked_conn(ngx_http_request_t *r, ft_type = 0; c = u->peer.connection; - if (c->write->timer_set) { - ngx_del_timer(c->write); - } - - if (c->write->active) { - ngx_del_event(c->write, NGX_WRITE_EVENT, 0); - } + ngx_http_lua_socket_tcp_clean_events(c); if (ngx_http_lua_set_event(c->write, NGX_WRITE_EVENT) == NGX_ERROR) { ft_type = NGX_HTTP_LUA_SOCKET_FT_ERROR; @@ -6198,56 +6221,59 @@ ngx_http_lua_socket_tcp_blocked_conn(ngx_http_request_t *r, return NGX_OK; } -static ngx_int_t + +static void ngx_http_lua_socket_tcp_blocked_sslhandshake(ngx_http_request_t *r, ngx_http_lua_socket_tcp_upstream_t *u) { ngx_connection_t *c; ngx_int_t rc; - ngx_msec_t timer, start_time; + ngx_msec_t timer, timeout, start_time; rc = NGX_OK; c = u->peer.connection; - if (c->read->timer_set) { - ngx_del_timer(c->read); - } + ngx_http_lua_socket_tcp_clean_events(c); - if (c->read->active) { - ngx_del_event(c->read, NGX_READ_EVENT, 0); + if (ngx_http_lua_set_event(c->read, NGX_READ_EVENT)) { + goto finish; } - rc = ngx_http_lua_set_event(c->read, NGX_READ_EVENT); - if (rc == NGX_ERROR) { + if (ngx_http_lua_set_event(c->write, NGX_WRITE_EVENT)) { goto finish; } - timer = u->connect_timeout; + timeout = u->connect_timeout; start_time = ngx_current_msec; - rc = ngx_http_lua_process_event(r, timer); - if (rc == NGX_ERROR) { - goto finish; - } + for (;;) { - ngx_time_update(); + timer = timeout - (ngx_current_msec - start_time); - if (ngx_current_msec - start_time >= timer) { - c->read->timedout = 1; + if (ngx_http_lua_process_event(r, timer) == NGX_ERROR) { + goto finish; + } - rc = NGX_ERROR; - goto finish; - } + ngx_time_update(); - ngx_http_lua_ssl_handshake_retval_handler(r, u, u->write_co_ctx->co); + if (ngx_current_msec - start_time >= timeout) { + c->read->timedout = 1; + goto finish; + } -finish: + rc = ngx_ssl_handshake(c); - if (ngx_http_lua_clear_event(c->read, NGX_READ_EVENT) == NGX_ERROR) { - return NGX_ERROR; + if (rc == NGX_ERROR || rc == NGX_OK) { + break; + } + + /* NGX_AGAIN, continue in loop*/ } - return rc; +finish: + + ngx_http_lua_clear_event(c->read, NGX_READ_EVENT); + ngx_http_lua_clear_event(c->write, NGX_WRITE_EVENT); } @@ -6262,13 +6288,7 @@ ngx_http_lua_socket_tcp_blocked_write(ngx_http_request_t *r, ft_type = 0; c = u->peer.connection; - if (c->write->timer_set) { - ngx_del_timer(c->write); - } - - if (c->write->active) { - ngx_del_event(c->write, NGX_WRITE_EVENT, 0); - } + ngx_http_lua_socket_tcp_clean_events(c); if (ngx_http_lua_set_event(c->write, NGX_WRITE_EVENT) == NGX_ERROR) { ft_type = NGX_HTTP_LUA_SOCKET_FT_ERROR; @@ -6318,13 +6338,7 @@ ngx_http_lua_socket_tcp_blocked_read(ngx_http_request_t *r, ft_type = 0; c = u->peer.connection; - if (c->read->timer_set) { - ngx_del_timer(c->read); - } - - if (c->read->active) { - ngx_del_event(c->read, NGX_READ_EVENT, 0); - } + ngx_http_lua_socket_tcp_clean_events(c); if (ngx_http_lua_set_event(c->read, NGX_READ_EVENT) == NGX_ERROR) { ft_type = NGX_HTTP_LUA_SOCKET_FT_ERROR; @@ -6343,10 +6357,12 @@ ngx_http_lua_socket_tcp_blocked_read(ngx_http_request_t *r, goto finish; } +#if (NGX_HAVE_KQUEUE) if (c->read->pending_eof) { ft_type = NGX_HTTP_LUA_SOCKET_FT_ERROR; goto finish; } +#endif ngx_time_update(); diff --git a/src/ngx_http_lua_util.h b/src/ngx_http_lua_util.h index 8d9b22c9e8..46200f8977 100644 --- a/src/ngx_http_lua_util.h +++ b/src/ngx_http_lua_util.h @@ -40,7 +40,7 @@ | NGX_HTTP_LUA_CONTEXT_SSL_CERT \ | NGX_HTTP_LUA_CONTEXT_SSL_SESS_FETCH) -#define NGX_HTTP_LUA_CONTEXT_BLOCKED_COSOCKET NGX_HTTP_LUA_CONTEXT_INIT_WORKER +#define NGX_HTTP_LUA_CONTEXT_BLOCKED_COSOCKET (NGX_HTTP_LUA_CONTEXT_INIT_WORKER) #define NGX_HTTP_LUA_CONTEXT_COSOCKET (NGX_HTTP_LUA_CONTEXT_YIELDABLE \ | NGX_HTTP_LUA_CONTEXT_BLOCKED_COSOCKET) diff --git a/t/129-ssl-socket.t b/t/129-ssl-socket.t index 7d8a1a0c7f..5816e0c423 100644 --- a/t/129-ssl-socket.t +++ b/t/129-ssl-socket.t @@ -2843,7 +2843,7 @@ SSL reused session return end - ngx.log(ngx.ERR, "connected: ", ok) + ngx.log(ngx.INFO, "connected: ", ok) local sess, err = sock:sslhandshake() if not sess then @@ -2853,7 +2853,7 @@ SSL reused session ngx.log(ngx.INFO, "ssl handshake: ", type(sess)) - local req = "GET / HTTP/1.1\\r\\nHost: www.google.com\\r\\nConnection: close\\r\\n\\r\\n" + local req = "GET / HTTP/1.1\r\nHost: www.google.com\r\nConnection: close\r\n\r\n" local bytes, err = sock:send(req) if not bytes then ngx.log(ngx.ERR, "failed to send http request: ", err) @@ -2890,13 +2890,5 @@ sent http request: 59 bytes. received: HTTP/1.1 (?:200 OK|302 Found) close: 1 nil \z ---- grep_error_log eval: qr/lua ssl (?:set|save|free) session: [0-9A-F]+/ ---- grep_error_log_out eval -qr/^lua ssl save session: ([0-9A-F]+) -lua ssl free session: ([0-9A-F]+) -$/ ---- no_error_log -lua ssl server name: -SSL reused session [error] --- timeout: 5 From 8f94f3e3a0673e15ae55e2a3016a4002e78e6fc1 Mon Sep 17 00:00:00 2001 From: jiahao Date: Tue, 31 Aug 2021 23:37:03 +0800 Subject: [PATCH 4/9] bugfix: make declaration in .h file, and make definition in .c file. --- src/ngx_http_lua_event.h | 2 +- src/ngx_http_lua_initworkerby.c | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/src/ngx_http_lua_event.h b/src/ngx_http_lua_event.h index 5b0dd37091..0369b06dad 100644 --- a/src/ngx_http_lua_event.h +++ b/src/ngx_http_lua_event.h @@ -19,7 +19,7 @@ typedef struct { } ngx_http_lua_event_actions_t; -ngx_http_lua_event_actions_t ngx_http_lua_event_actions; +extern ngx_http_lua_event_actions_t ngx_http_lua_event_actions; extern ngx_http_lua_event_actions_t ngx_http_lua_epoll; extern ngx_http_lua_event_actions_t ngx_http_lua_poll; diff --git a/src/ngx_http_lua_initworkerby.c b/src/ngx_http_lua_initworkerby.c index bc792403e3..9e0a81b8ed 100644 --- a/src/ngx_http_lua_initworkerby.c +++ b/src/ngx_http_lua_initworkerby.c @@ -16,6 +16,8 @@ #include "ngx_http_lua_event.h" +ngx_http_lua_event_actions_t ngx_http_lua_event_actions; + static u_char *ngx_http_lua_log_init_worker_error(ngx_log_t *log, u_char *buf, size_t len); From b370b8c4fe4d74386fdc739f2b784b73dd1e5d62 Mon Sep 17 00:00:00 2001 From: jiahao Date: Wed, 1 Sep 2021 00:25:30 +0800 Subject: [PATCH 5/9] style: need a blank line before else code blocks. --- src/ngx_http_lua_event.h | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/ngx_http_lua_event.h b/src/ngx_http_lua_event.h index 0369b06dad..e8cf48cb77 100644 --- a/src/ngx_http_lua_event.h +++ b/src/ngx_http_lua_event.h @@ -51,6 +51,7 @@ ngx_http_lua_init_event(ngx_cycle_t *cycle) if (ngx_strcmp(ecf->name, "epoll") == 0) { ngx_http_lua_event_actions = ngx_http_lua_epoll; + } else #endif @@ -59,6 +60,7 @@ ngx_http_lua_init_event(ngx_cycle_t *cycle) if (ngx_strcmp(ecf->name, "poll") == 0) { ngx_http_lua_event_actions = ngx_http_lua_poll; + } else #endif @@ -67,6 +69,7 @@ ngx_http_lua_init_event(ngx_cycle_t *cycle) if (ngx_strcmp(ecf->name, "kqueue") == 0) { ngx_http_lua_event_actions = ngx_http_lua_kqueue; + } else #endif From 5609bcd6b82dce52f47700c75d9baef874078cf0 Mon Sep 17 00:00:00 2001 From: jiahao Date: Wed, 1 Sep 2021 15:02:49 +0800 Subject: [PATCH 6/9] optimize: put ev variable as local variable. --- src/event/ngx_http_lua_epoll.c | 8 ++++---- src/event/ngx_http_lua_kqueue.c | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/event/ngx_http_lua_epoll.c b/src/event/ngx_http_lua_epoll.c index f09ec2cc41..bf862cc8a0 100644 --- a/src/event/ngx_http_lua_epoll.c +++ b/src/event/ngx_http_lua_epoll.c @@ -18,7 +18,6 @@ static ngx_int_t ngx_http_lua_epoll_process_event(ngx_http_request_t *r, ngx_msec_t timer); static int ep = -1; -static struct epoll_event eev; ngx_http_lua_event_actions_t ngx_http_lua_epoll = { ngx_http_lua_epoll_init_event, @@ -149,8 +148,9 @@ ngx_http_lua_epoll_process_event(ngx_http_request_t *r, ngx_msec_t timer) ngx_err_t err; ngx_event_t *rev, *wev; ngx_connection_t *c; + struct epoll_event ee; - events = epoll_wait(ep, &eev, 1, timer); + events = epoll_wait(ep, &ee, 1, timer); err = (events == -1) ? ngx_errno : 0; @@ -168,8 +168,8 @@ ngx_http_lua_epoll_process_event(ngx_http_request_t *r, ngx_msec_t timer) return NGX_ERROR; } - c = eev.data.ptr; - revents = eev.events; + c = ee.data.ptr; + revents = ee.events; if (revents & (EPOLLERR|EPOLLHUP)) { ngx_log_debug2(NGX_LOG_DEBUG_EVENT, r->connection->log, 0, diff --git a/src/event/ngx_http_lua_kqueue.c b/src/event/ngx_http_lua_kqueue.c index 345012cda9..f8ecf92ca4 100644 --- a/src/event/ngx_http_lua_kqueue.c +++ b/src/event/ngx_http_lua_kqueue.c @@ -20,7 +20,6 @@ static ngx_int_t ngx_http_lua_kqueue_process_event(ngx_http_request_t *r, int kq = -1; static struct kevent kch[2]; -static struct kevent kev; static ngx_uint_t nchanges; ngx_http_lua_event_actions_t ngx_http_lua_kqueue = { @@ -100,6 +99,7 @@ ngx_http_lua_kqueue_process_event(ngx_http_request_t *r, ngx_msec_t timer) struct timespec ts; ngx_event_t *ev; ngx_err_t err; + struct kevent kev; ts.tv_sec = timer / 1000; ts.tv_nsec = (timer % 1000) * 1000000; From 994c6722efef299b04d8a565f703b92f4ba1880c Mon Sep 17 00:00:00 2001 From: jiahao Date: Fri, 3 Sep 2021 16:57:27 +0800 Subject: [PATCH 7/9] bugfix: added error handler for unimplemented event handlding. --- src/ngx_http_lua_event.h | 7 +------ src/ngx_http_lua_initworkerby.c | 6 ++++-- src/ngx_http_lua_socket_tcp.c | 30 +++++++++++++++++++++++++++--- 3 files changed, 32 insertions(+), 11 deletions(-) diff --git a/src/ngx_http_lua_event.h b/src/ngx_http_lua_event.h index e8cf48cb77..3c6598534c 100644 --- a/src/ngx_http_lua_event.h +++ b/src/ngx_http_lua_event.h @@ -25,6 +25,7 @@ extern ngx_http_lua_event_actions_t ngx_http_lua_epoll; extern ngx_http_lua_event_actions_t ngx_http_lua_poll; extern ngx_http_lua_event_actions_t ngx_http_lua_kqueue; +extern int ngx_http_lua_event_inited; #define ngx_http_lua_set_event ngx_http_lua_event_actions.set_event #define ngx_http_lua_clear_event ngx_http_lua_event_actions.clear_event @@ -39,9 +40,6 @@ ngx_http_lua_init_event(ngx_cycle_t *cycle) ccf = ngx_get_conf(cycle->conf_ctx, ngx_events_module); if (ccf == NULL) { - ngx_log_error(NGX_LOG_EMERG, cycle->log, 0, - "no \"events\" section in configuration"); - return NGX_ERROR; } @@ -75,9 +73,6 @@ ngx_http_lua_init_event(ngx_cycle_t *cycle) #endif { - ngx_log_error(NGX_LOG_EMERG, cycle->log, 0, - "invalid event type \"%V\"", ecf->name); - return NGX_ERROR; } diff --git a/src/ngx_http_lua_initworkerby.c b/src/ngx_http_lua_initworkerby.c index 9e0a81b8ed..7013deb73c 100644 --- a/src/ngx_http_lua_initworkerby.c +++ b/src/ngx_http_lua_initworkerby.c @@ -16,6 +16,8 @@ #include "ngx_http_lua_event.h" +int ngx_http_lua_event_inited = 0; + ngx_http_lua_event_actions_t ngx_http_lua_event_actions; static u_char *ngx_http_lua_log_init_worker_error(ngx_log_t *log, @@ -49,8 +51,8 @@ ngx_http_lua_init_worker(ngx_cycle_t *cycle) return NGX_OK; } - if (ngx_http_lua_init_event(cycle) == NGX_ERROR) { - return NGX_ERROR; + if (ngx_http_lua_init_event(cycle) == NGX_OK) { + ngx_http_lua_event_inited = 1; } /* lmcf != NULL && lmcf->lua != NULL */ diff --git a/src/ngx_http_lua_socket_tcp.c b/src/ngx_http_lua_socket_tcp.c index 3dc3e6dde3..0d76bbeacb 100644 --- a/src/ngx_http_lua_socket_tcp.c +++ b/src/ngx_http_lua_socket_tcp.c @@ -459,7 +459,19 @@ ngx_http_lua_socket_tcp(lua_State *L) return luaL_error(L, "no ctx found"); } - ngx_http_lua_check_context(L, ctx, NGX_HTTP_LUA_CONTEXT_COSOCKET); + /* only a few events is suppported in init_worker_by_* */ + if (ngx_http_lua_event_inited) { + ngx_http_lua_check_context(L, ctx, NGX_HTTP_LUA_CONTEXT_COSOCKET); + + } else if (ctx->context & NGX_HTTP_LUA_CONTEXT_BLOCKED_COSOCKET) { + return luaL_error(L, "API disabled in the context of %s except when " \ + "using the event handling methods of poll, epoll " \ + "or kqueue", + ngx_http_lua_context_name((ctx)->context)); + + } else { + ngx_http_lua_check_context(L, ctx, NGX_HTTP_LUA_CONTEXT_YIELDABLE); + } lua_createtable(L, 5 /* narr */, 1 /* nrec */); lua_pushlightuserdata(L, ngx_http_lua_lightudata_mask( @@ -904,7 +916,19 @@ ngx_http_lua_socket_tcp_connect(lua_State *L) return luaL_error(L, "no ctx found"); } - ngx_http_lua_check_context(L, ctx, NGX_HTTP_LUA_CONTEXT_COSOCKET); + /* only a few events is suppported in init_worker_by_* */ + if (ngx_http_lua_event_inited) { + ngx_http_lua_check_context(L, ctx, NGX_HTTP_LUA_CONTEXT_COSOCKET); + + } else if (ctx->context & NGX_HTTP_LUA_CONTEXT_BLOCKED_COSOCKET) { + return luaL_error(L, "API disabled in the context of %s except when " \ + "using the event handling methods of poll, epoll " \ + "or kqueue", + ngx_http_lua_context_name((ctx)->context)); + + } else { + ngx_http_lua_check_context(L, ctx, NGX_HTTP_LUA_CONTEXT_YIELDABLE); + } luaL_checktype(L, 1, LUA_TTABLE); @@ -1796,7 +1820,7 @@ ngx_http_lua_socket_tcp_sslhandshake(lua_State *L) rc = ngx_ssl_handshake(c); - dd("ngx_ssl_handshake returned %d", (int) rc); + dd("ngx_ssl_handshake returned %d", (int) rc); if (rc == NGX_AGAIN) { if (ctx->context & NGX_HTTP_LUA_CONTEXT_BLOCKED_COSOCKET) { From fc3f1bbd7582f662125e0bbf06a678b0650dc115 Mon Sep 17 00:00:00 2001 From: jiahao Date: Wed, 8 Sep 2021 23:24:58 +0800 Subject: [PATCH 8/9] style: ep -> epoll_created. --- src/event/ngx_http_lua_epoll.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/event/ngx_http_lua_epoll.c b/src/event/ngx_http_lua_epoll.c index bf862cc8a0..1667637f95 100644 --- a/src/event/ngx_http_lua_epoll.c +++ b/src/event/ngx_http_lua_epoll.c @@ -17,7 +17,7 @@ static ngx_int_t ngx_http_lua_epoll_clear_event(ngx_event_t *ev, static ngx_int_t ngx_http_lua_epoll_process_event(ngx_http_request_t *r, ngx_msec_t timer); -static int ep = -1; +static int epoll_created = -1; ngx_http_lua_event_actions_t ngx_http_lua_epoll = { ngx_http_lua_epoll_init_event, @@ -30,9 +30,9 @@ ngx_http_lua_event_actions_t ngx_http_lua_epoll = { static ngx_int_t ngx_http_lua_epoll_init_event(ngx_cycle_t *cycle) { - ep = epoll_create(1); + epoll_created = epoll_create(1); - if (ep == -1) { + if (epoll_created == -1) { ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_errno, "lua epoll_create() failed"); @@ -82,7 +82,7 @@ ngx_http_lua_epoll_set_event(ngx_event_t *ev, ngx_int_t event) ee.events = events; ee.data.ptr = c; - if (epoll_ctl(ep, op, c->fd, &ee) == -1) { + if (epoll_ctl(epoll_created, op, c->fd, &ee) == -1) { ngx_log_error(NGX_LOG_ALERT, ev->log, ngx_errno, "lua epoll_ctl(EPOLL_CTL_ADD, %d) failed, add event: %d", c->fd, events); @@ -127,7 +127,7 @@ ngx_http_lua_epoll_clear_event(ngx_event_t *ev, ngx_int_t event) ee.data.ptr = NULL; } - if (epoll_ctl(ep, op, c->fd, &ee) == -1) { + if (epoll_ctl(epoll_created, op, c->fd, &ee) == -1) { ngx_log_error(NGX_LOG_ALERT, ev->log, ngx_errno, "lua epoll_ctl(EPOLL_CTL_DEL, %d) failed", c->fd); @@ -150,7 +150,7 @@ ngx_http_lua_epoll_process_event(ngx_http_request_t *r, ngx_msec_t timer) ngx_connection_t *c; struct epoll_event ee; - events = epoll_wait(ep, &ee, 1, timer); + events = epoll_wait(epoll_created, &ee, 1, timer); err = (events == -1) ? ngx_errno : 0; From 9d3c4ad233657c2afb846c20f08ae755734e4cdd Mon Sep 17 00:00:00 2001 From: jiahao Date: Fri, 15 Oct 2021 16:32:02 +0800 Subject: [PATCH 9/9] wip: try to implement socket in init_by_lua* phase. --- src/ngx_http_lua_common.h | 1 + src/ngx_http_lua_event.h | 109 ++++++++++++-- src/ngx_http_lua_initworkerby.c | 9 -- src/ngx_http_lua_module.c | 245 +++++++++++++++++++++++++++++++- src/ngx_http_lua_socket_tcp.c | 2 +- src/ngx_http_lua_util.h | 6 +- t/058-tcp-socket.t | 3 +- t/129-ssl-socket.t | 5 +- 8 files changed, 355 insertions(+), 25 deletions(-) diff --git a/src/ngx_http_lua_common.h b/src/ngx_http_lua_common.h index 017e2a0434..8e7230e294 100644 --- a/src/ngx_http_lua_common.h +++ b/src/ngx_http_lua_common.h @@ -141,6 +141,7 @@ typedef struct { #define NGX_HTTP_LUA_CONTEXT_SSL_SESS_FETCH 0x1000 #define NGX_HTTP_LUA_CONTEXT_EXIT_WORKER 0x2000 #define NGX_HTTP_LUA_CONTEXT_SSL_CLIENT_HELLO 0x4000 +#define NGX_HTTP_LUA_CONTEXT_INIT 0x8000 #define NGX_HTTP_LUA_FFI_NO_REQ_CTX -100 diff --git a/src/ngx_http_lua_event.h b/src/ngx_http_lua_event.h index 3c6598534c..dd3cf92b32 100644 --- a/src/ngx_http_lua_event.h +++ b/src/ngx_http_lua_event.h @@ -35,19 +35,63 @@ extern int ngx_http_lua_event_inited; static ngx_inline ngx_int_t ngx_http_lua_init_event(ngx_cycle_t *cycle) { - void ***ccf; - ngx_event_conf_t *ecf; + ngx_module_t *module; + ngx_module_t **modules; + ngx_event_module_t *event_module; + ngx_uint_t i; + ngx_connection_t *c, *next; + ngx_event_t *rev, *wev; + + module = NULL; + +#if (nginx_version >= 1009011) + modules = cycle->modules; +#else + modules = ngx_modules; +#endif + + for (i = 0; modules[i]; i++) { + if (modules[i]->type != NGX_EVENT_MODULE) { + continue; + } + + event_module = modules[i]->ctx; + if (ngx_strcmp(event_module->name->data, "event_core") == 0) + { + continue; + } - ccf = ngx_get_conf(cycle->conf_ctx, ngx_events_module); - if (ccf == NULL) { + module = modules[i]; + break; + } + + if (module == NULL) { + ngx_log_error(NGX_LOG_EMERG, cycle->log, 0, "no events module found"); return NGX_ERROR; } - ecf = (*ccf)[ngx_event_core_module.ctx_index]; + event_module = module->ctx; + + /* FIXME: should init event_module actions here, like: + * ``` + * if (event_module->actions.init(cycle, ngx_timer_resolution) != NGX_OK) { + * ``` + * + * but `epcf` is not initial here before + * ``` + * static ngx_int_t + * ngx_epoll_init(ngx_cycle_t *cycle, ngx_msec_t timer) + * { + * ngx_epoll_conf_t *epcf; + * + * // Segmentation fault below + * epcf = ngx_event_get_conf(cycle->conf_ctx, ngx_epoll_module); + * ``` + */ #if (NGX_HAVE_EPOLL) && !(NGX_TEST_BUILD_EPOLL) - if (ngx_strcmp(ecf->name, "epoll") == 0) { + if (ngx_strcmp(event_module->name->data, "epoll") == 0) { ngx_http_lua_event_actions = ngx_http_lua_epoll; } else @@ -56,7 +100,7 @@ ngx_http_lua_init_event(ngx_cycle_t *cycle) #if (NGX_HAVE_POLL) - if (ngx_strcmp(ecf->name, "poll") == 0) { + if (ngx_strcmp(event_module->name->data, "poll") == 0) { ngx_http_lua_event_actions = ngx_http_lua_poll; } else @@ -65,7 +109,7 @@ ngx_http_lua_init_event(ngx_cycle_t *cycle) #if (NGX_HAVE_KQUEUE) - if (ngx_strcmp(ecf->name, "kqueue") == 0) { + if (ngx_strcmp(event_module->name->data, "kqueue") == 0) { ngx_http_lua_event_actions = ngx_http_lua_kqueue; } else @@ -76,6 +120,55 @@ ngx_http_lua_init_event(ngx_cycle_t *cycle) return NGX_ERROR; } + cycle->connection_n = 128; + cycle->connections = + ngx_alloc(sizeof(ngx_connection_t) * cycle->connection_n, cycle->log); + if (cycle->connections == NULL) { + return NGX_ERROR; + } + + c = cycle->connections; + + cycle->read_events = ngx_alloc(sizeof(ngx_event_t) * cycle->connection_n, + cycle->log); + if (cycle->read_events == NULL) { + return NGX_ERROR; + } + + rev = cycle->read_events; + for (i = 0; i < cycle->connection_n; i++) { + rev[i].closed = 1; + rev[i].instance = 1; + } + + cycle->write_events = ngx_alloc(sizeof(ngx_event_t) * cycle->connection_n, + cycle->log); + if (cycle->write_events == NULL) { + return NGX_ERROR; + } + + wev = cycle->write_events; + for (i = 0; i < cycle->connection_n; i++) { + wev[i].closed = 1; + } + + i = cycle->connection_n; + next = NULL; + + do { + i--; + + c[i].data = next; + c[i].read = &cycle->read_events[i]; + c[i].write = &cycle->write_events[i]; + c[i].fd = (ngx_socket_t) -1; + + next = &c[i]; + } while (i); + + cycle->free_connections = next; + cycle->free_connection_n = cycle->connection_n; + return ngx_http_lua_event_actions.init_event(cycle); } diff --git a/src/ngx_http_lua_initworkerby.c b/src/ngx_http_lua_initworkerby.c index 7013deb73c..3235a4d30a 100644 --- a/src/ngx_http_lua_initworkerby.c +++ b/src/ngx_http_lua_initworkerby.c @@ -13,13 +13,8 @@ #include "ngx_http_lua_initworkerby.h" #include "ngx_http_lua_util.h" #include "ngx_http_lua_pipe.h" -#include "ngx_http_lua_event.h" -int ngx_http_lua_event_inited = 0; - -ngx_http_lua_event_actions_t ngx_http_lua_event_actions; - static u_char *ngx_http_lua_log_init_worker_error(ngx_log_t *log, u_char *buf, size_t len); @@ -51,10 +46,6 @@ ngx_http_lua_init_worker(ngx_cycle_t *cycle) return NGX_OK; } - if (ngx_http_lua_init_event(cycle) == NGX_OK) { - ngx_http_lua_event_inited = 1; - } - /* lmcf != NULL && lmcf->lua != NULL */ #if !(NGX_WIN32) diff --git a/src/ngx_http_lua_module.c b/src/ngx_http_lua_module.c index 09fd0a91f8..429d041317 100644 --- a/src/ngx_http_lua_module.c +++ b/src/ngx_http_lua_module.c @@ -32,6 +32,11 @@ #include "ngx_http_lua_ssl_session_fetchby.h" #include "ngx_http_lua_headers.h" #include "ngx_http_lua_pipe.h" +#include "ngx_http_lua_event.h" + +int ngx_http_lua_event_inited = 0; + +ngx_http_lua_event_actions_t ngx_http_lua_event_actions; static void *ngx_http_lua_create_main_conf(ngx_conf_t *cf); @@ -715,6 +720,22 @@ ngx_http_lua_init(ngx_conf_t *cf) ngx_http_lua_main_conf_t *lmcf; ngx_pool_cleanup_t *cln; ngx_str_t name = ngx_string("host"); + ngx_connection_t *c = NULL; + ngx_http_request_t *r; + ngx_http_lua_ctx_t *ctx; + ngx_conf_t conf; + ngx_open_file_t *file, *ofile; + ngx_list_part_t *part; + ngx_cycle_t *fake_cycle, *cycle; + ngx_http_conf_ctx_t *conf_ctx, http_ctx; + ngx_conf_file_t cf_file; + char *rv; + void *cur, *prev; + ngx_uint_t i; + ngx_module_t **modules; + ngx_http_module_t *module; + ngx_http_lua_loc_conf_t *top_llcf; + ngx_http_core_loc_conf_t *top_clcf; if (ngx_process == NGX_PROCESS_SIGNALLER || ngx_test_config) { return NGX_OK; @@ -890,15 +911,233 @@ ngx_http_lua_init(ngx_conf_t *cf) ngx_http_lua_assert(lmcf->lua != NULL); if (!lmcf->requires_shm && lmcf->init_handler) { + cycle = cf->cycle; + + conf_ctx = (ngx_http_conf_ctx_t *) + cycle->conf_ctx[ngx_http_module.index]; + http_ctx.main_conf = conf_ctx->main_conf; + + top_clcf = conf_ctx->loc_conf[ngx_http_core_module.ctx_index]; + top_llcf = conf_ctx->loc_conf[ngx_http_lua_module.ctx_index]; + + ngx_memzero(&conf, sizeof(ngx_conf_t)); + + conf.temp_pool = ngx_create_pool(NGX_CYCLE_POOL_SIZE, cycle->log); + if (conf.temp_pool == NULL) { + return NGX_ERROR; + } + + conf.temp_pool->log = cf->cycle->log; + + /* we fake a temporary ngx_cycle_t here because some + * modules' merge conf handler may produce side effects in + * cf->cycle (like ngx_proxy vs cf->cycle->paths). + * also, we cannot allocate our temp cycle on the stack + * because some modules like ngx_http_core_module reference + * addresses within cf->cycle (i.e., via "&cf->cycle->new_log") + */ + fake_cycle = ngx_palloc(cycle->pool, sizeof(ngx_cycle_t)); + if (fake_cycle == NULL) { + goto failed; + } + + ngx_memcpy(fake_cycle, cycle, sizeof(ngx_cycle_t)); + + ngx_queue_init(&fake_cycle->reusable_connections_queue); + + if (ngx_array_init(&fake_cycle->listening, cycle->pool, + cycle->listening.nelts || 1, + sizeof(ngx_listening_t)) + != NGX_OK) + { + goto failed; + } + + if (ngx_array_init(&fake_cycle->paths, cycle->pool, cycle->paths.nelts || 1, + sizeof(ngx_path_t *)) + != NGX_OK) + { + goto failed; + } + + part = &cycle->open_files.part; + ofile = part->elts; + + if (ngx_list_init(&fake_cycle->open_files, cycle->pool, part->nelts || 1, + sizeof(ngx_open_file_t)) + != NGX_OK) + { + goto failed; + } + + for (i = 0; /* void */ ; i++) { + + if (i >= part->nelts) { + if (part->next == NULL) { + break; + } + + part = part->next; + ofile = part->elts; + i = 0; + } + + file = ngx_list_push(&fake_cycle->open_files); + if (file == NULL) { + goto failed; + } + + ngx_memcpy(file, ofile, sizeof(ngx_open_file_t)); + } + + if (ngx_list_init(&fake_cycle->shared_memory, cycle->pool, 1, + sizeof(ngx_shm_zone_t)) + != NGX_OK) + { + goto failed; + } + saved_cycle = ngx_cycle; - ngx_cycle = cf->cycle; + ngx_cycle = fake_cycle; - rc = lmcf->init_handler(cf->log, lmcf, lmcf->lua); + if (ngx_http_lua_init_event(fake_cycle) == NGX_OK) { + ngx_http_lua_event_inited = 1; + } - ngx_cycle = saved_cycle; + conf.ctx = &http_ctx; + conf.cycle = fake_cycle; + conf.pool = fake_cycle->pool; + conf.log = cycle->log; + http_ctx.loc_conf = ngx_pcalloc(conf.pool, + sizeof(void *) * ngx_http_max_module); + if (http_ctx.loc_conf == NULL) { + goto failed; + } + + http_ctx.srv_conf = ngx_pcalloc(conf.pool, + sizeof(void *) * ngx_http_max_module); + if (http_ctx.srv_conf == NULL) { + goto failed; + } + + ngx_memzero(&cf_file, sizeof(cf_file)); + cf_file.file.name = cycle->conf_file; + conf.conf_file = &cf_file; + +#if (nginx_version >= 1009011) + modules = cf->cycle->modules; +#else + modules = ngx_modules; +#endif + + for (i = 0; modules[i]; i++) { + if (modules[i]->type != NGX_HTTP_MODULE) { + continue; + } + + module = modules[i]->ctx; + + if (module->create_srv_conf) { + cur = module->create_srv_conf(&conf); + if (cur == NULL) { + goto failed; + } + + http_ctx.srv_conf[modules[i]->ctx_index] = cur; + + if (module->merge_srv_conf) { + prev = module->create_srv_conf(&conf); + if (prev == NULL) { + goto failed; + } + + rv = module->merge_srv_conf(&conf, prev, cur); + if (rv != NGX_CONF_OK) { + goto failed; + } + } + } + + if (module->create_loc_conf) { + cur = module->create_loc_conf(&conf); + if (cur == NULL) { + goto failed; + } + + http_ctx.loc_conf[modules[i]->ctx_index] = cur; + + if (module->merge_loc_conf) { + if (modules[i] == &ngx_http_lua_module) { + prev = top_llcf; + + } else if (modules[i] == &ngx_http_core_module) { + prev = top_clcf; + + } else { + prev = module->create_loc_conf(&conf); + if (prev == NULL) { + goto failed; + } + } + + rv = module->merge_loc_conf(&conf, prev, cur); + if (rv != NGX_CONF_OK) { + goto failed; + } + } + } + } + + ngx_destroy_pool(conf.temp_pool); + conf.temp_pool = NULL; + + c = ngx_http_lua_create_fake_connection(NULL); + if (c == NULL) { + goto failed; + } + + c->log->handler = cf->log->handler; + + r = ngx_http_lua_create_fake_request(c); + if (r == NULL) { + goto failed; + } + + r->main_conf = http_ctx.main_conf; + r->srv_conf = http_ctx.srv_conf; + r->loc_conf = http_ctx.loc_conf; + + /* create ctx */ + ctx = ngx_http_lua_create_ctx(r); + if (ctx == NULL) { + goto failed; + } + + ctx->context = NGX_HTTP_LUA_CONTEXT_INIT; + + ngx_http_lua_set_req(lmcf->lua, r); + + rc = lmcf->init_handler(cf->log, lmcf, lmcf->lua); if (rc != NGX_OK) { /* an error happened */ + goto failed; + } + + ngx_cycle = saved_cycle; + + if (0) { + + failed: + + if (conf.temp_pool) { + ngx_destroy_pool(conf.temp_pool); + } + + if (c) { + ngx_http_lua_close_fake_connection(c); + } + return NGX_ERROR; } } diff --git a/src/ngx_http_lua_socket_tcp.c b/src/ngx_http_lua_socket_tcp.c index 0d76bbeacb..feeaae9adb 100644 --- a/src/ngx_http_lua_socket_tcp.c +++ b/src/ngx_http_lua_socket_tcp.c @@ -459,7 +459,7 @@ ngx_http_lua_socket_tcp(lua_State *L) return luaL_error(L, "no ctx found"); } - /* only a few events is suppported in init_worker_by_* */ + /* only a few events is suppported in init_by_* */ if (ngx_http_lua_event_inited) { ngx_http_lua_check_context(L, ctx, NGX_HTTP_LUA_CONTEXT_COSOCKET); diff --git a/src/ngx_http_lua_util.h b/src/ngx_http_lua_util.h index 46200f8977..cf00692066 100644 --- a/src/ngx_http_lua_util.h +++ b/src/ngx_http_lua_util.h @@ -40,7 +40,10 @@ | NGX_HTTP_LUA_CONTEXT_SSL_CERT \ | NGX_HTTP_LUA_CONTEXT_SSL_SESS_FETCH) -#define NGX_HTTP_LUA_CONTEXT_BLOCKED_COSOCKET (NGX_HTTP_LUA_CONTEXT_INIT_WORKER) +#define NGX_HTTP_LUA_CONTEXT_BLOCKED_COSOCKET \ + (NGX_HTTP_LUA_CONTEXT_INIT \ + | NGX_HTTP_LUA_CONTEXT_EXIT_WORKER) + #define NGX_HTTP_LUA_CONTEXT_COSOCKET (NGX_HTTP_LUA_CONTEXT_YIELDABLE \ | NGX_HTTP_LUA_CONTEXT_BLOCKED_COSOCKET) @@ -69,6 +72,7 @@ "ssl_session_store_by_lua*" \ : (c) == NGX_HTTP_LUA_CONTEXT_SSL_SESS_FETCH ? \ "ssl_session_fetch_by_lua*" \ + : (c) == NGX_HTTP_LUA_CONTEXT_INIT ? "init_by_lua*" \ : "(unknown)") diff --git a/t/058-tcp-socket.t b/t/058-tcp-socket.t index 65f4e41acc..6488b11db6 100644 --- a/t/058-tcp-socket.t +++ b/t/058-tcp-socket.t @@ -4372,7 +4372,7 @@ finish === TEST 73: run in init_worker_by_lua --- http_config - init_worker_by_lua_block { + init_by_lua_block { local sock = ngx.socket.tcp() local port = 80 local ok, err = sock:connect("agentzh.org", port) @@ -4428,3 +4428,4 @@ second line received: (?:Date|Server): .*? --- no_error_log [error] --- timeout: 10 +--- ONLY diff --git a/t/129-ssl-socket.t b/t/129-ssl-socket.t index 5816e0c423..646ba2572c 100644 --- a/t/129-ssl-socket.t +++ b/t/129-ssl-socket.t @@ -2832,9 +2832,9 @@ SSL reused session -=== TEST 35: www.google.com in init_worker_by_lua +=== TEST 35: access www.google.com in init_by_lua --- http_config - init_worker_by_lua_block { + init_by_lua_block { local sock = ngx.socket.tcp() sock:settimeout(2000) local ok, err = sock:connect("www.google.com", 443) @@ -2892,3 +2892,4 @@ close: 1 nil \z [error] --- timeout: 5 +--- ONLY