diff --git a/src/ngx_stream_lua_output.c b/src/ngx_stream_lua_output.c index 0a03a121..66b99a8a 100644 --- a/src/ngx_stream_lua_output.c +++ b/src/ngx_stream_lua_output.c @@ -60,6 +60,10 @@ ngx_stream_lua_ngx_echo(lua_State *L, unsigned newline) return luaL_error(L, "no session object found"); } + if (s->connection->type == SOCK_DGRAM) { + return luaL_error(L, "not supported in udp requests"); + } + ctx = ngx_stream_get_module_ctx(s, ngx_stream_lua_module); if (ctx == NULL) { @@ -476,6 +480,10 @@ ngx_stream_lua_ngx_flush(lua_State *L) s = ngx_stream_lua_get_session(L); + if (s->connection->type == SOCK_DGRAM) { + return luaL_error(L, "not supported in udp requests"); + } + wait = 1; /* always wait */ ctx = ngx_stream_get_module_ctx(s, ngx_stream_lua_module); @@ -563,6 +571,10 @@ ngx_stream_lua_ngx_eof(lua_State *L) return luaL_error(L, "no session object found"); } + if (s->connection->type == SOCK_DGRAM) { + return luaL_error(L, "not supported in udp requests"); + } + if (lua_gettop(L) != 0) { return luaL_error(L, "no argument is expected"); } diff --git a/src/ngx_stream_lua_socket_tcp.c b/src/ngx_stream_lua_socket_tcp.c index 68750aa6..f46a1c68 100644 --- a/src/ngx_stream_lua_socket_tcp.c +++ b/src/ngx_stream_lua_socket_tcp.c @@ -95,7 +95,7 @@ static int ngx_stream_lua_socket_receiveuntil_iterator(lua_State *L); static ngx_int_t ngx_stream_lua_socket_compile_pattern(u_char *data, size_t len, ngx_stream_lua_socket_compiled_pattern_t *cp, ngx_log_t *log); static int ngx_stream_lua_socket_cleanup_compiled_pattern(lua_State *L); -static int ngx_stream_lua_req_socket(lua_State *L); +static int ngx_stream_lua_tcp_req_socket(lua_State *L); static void ngx_stream_lua_req_socket_rev_handler(ngx_stream_session_t *s, ngx_stream_lua_ctx_t *ctx); static int ngx_stream_lua_socket_tcp_getreusedtimes(lua_State *L); @@ -193,7 +193,7 @@ enum { static char ngx_stream_lua_req_socket_metatable_key; #endif static char ngx_stream_lua_raw_req_socket_metatable_key; -static char ngx_stream_lua_tcp_socket_metatable_key; +static char ngx_stream_lua_socket_tcp_metatable_key; static char ngx_stream_lua_upstream_udata_metatable_key; static char ngx_stream_lua_downstream_udata_metatable_key; static char ngx_stream_lua_pool_udata_metatable_key; @@ -276,7 +276,7 @@ ngx_stream_lua_inject_socket_tcp_api(ngx_log_t *log, lua_State *L) /* }}} */ /* {{{tcp object metatable */ - lua_pushlightuserdata(L, &ngx_stream_lua_tcp_socket_metatable_key); + lua_pushlightuserdata(L, &ngx_stream_lua_socket_tcp_metatable_key); lua_createtable(L, 0 /* narr */, 11 /* nrec */); lua_pushcfunction(L, ngx_stream_lua_socket_tcp_connect); @@ -364,14 +364,6 @@ ngx_stream_lua_inject_socket_tcp_api(ngx_log_t *log, lua_State *L) } -void -ngx_stream_lua_inject_req_socket_api(lua_State *L) -{ - lua_pushcfunction(L, ngx_stream_lua_req_socket); - lua_setfield(L, -2, "socket"); -} - - static int ngx_stream_lua_socket_tcp(lua_State *L) { @@ -397,7 +389,7 @@ ngx_stream_lua_socket_tcp(lua_State *L) | NGX_STREAM_LUA_CONTEXT_TIMER); lua_createtable(L, 3 /* narr */, 1 /* nrec */); - lua_pushlightuserdata(L, &ngx_stream_lua_tcp_socket_metatable_key); + lua_pushlightuserdata(L, &ngx_stream_lua_socket_tcp_metatable_key); lua_rawget(L, LUA_REGISTRYINDEX); lua_setmetatable(L, -2); @@ -3918,14 +3910,22 @@ ngx_stream_lua_socket_cleanup_compiled_pattern(lua_State *L) } +void +ngx_stream_lua_inject_tcp_req_socket_api(lua_State *L) +{ + lua_pushcfunction(L, ngx_stream_lua_tcp_req_socket); + lua_setfield(L, -2, "socket"); +} + + static int -ngx_stream_lua_req_socket(lua_State *L) +ngx_stream_lua_tcp_req_socket(lua_State *L) { int n, raw; + ngx_stream_session_t *s; ngx_peer_connection_t *pc; ngx_stream_lua_srv_conf_t *lscf; ngx_connection_t *c; - ngx_stream_session_t *s; ngx_stream_lua_ctx_t *ctx; ngx_stream_lua_co_ctx_t *coctx; ngx_stream_lua_cleanup_t *cln; @@ -3956,6 +3956,11 @@ ngx_stream_lua_req_socket(lua_State *L) c = s->connection; + if (c->type != SOCK_STREAM) { + return luaL_error(L, "socket api does not match connection transport", + lua_gettop(L)); + } + #if !defined(nginx_version) || nginx_version < 1003013 lua_pushnil(L); lua_pushliteral(L, "nginx version too old"); diff --git a/src/ngx_stream_lua_socket_tcp.h b/src/ngx_stream_lua_socket_tcp.h index 68bcfb0e..ec6e4d7b 100644 --- a/src/ngx_stream_lua_socket_tcp.h +++ b/src/ngx_stream_lua_socket_tcp.h @@ -147,7 +147,7 @@ typedef struct { void ngx_stream_lua_inject_socket_tcp_api(ngx_log_t *log, lua_State *L); -void ngx_stream_lua_inject_req_socket_api(lua_State *L); +void ngx_stream_lua_inject_tcp_req_socket_api(lua_State *L); void ngx_stream_lua_cleanup_conn_pools(lua_State *L); diff --git a/src/ngx_stream_lua_socket_udp.c b/src/ngx_stream_lua_socket_udp.c index 82329815..dc39d766 100644 --- a/src/ngx_stream_lua_socket_udp.c +++ b/src/ngx_stream_lua_socket_udp.c @@ -31,8 +31,10 @@ static int ngx_stream_lua_socket_udp_setpeername(lua_State *L); static int ngx_stream_lua_socket_udp_send(lua_State *L); static int ngx_stream_lua_socket_udp_receive(lua_State *L); static int ngx_stream_lua_socket_udp_settimeout(lua_State *L); +static int ngx_stream_lua_udp_req_socket(lua_State *L); static void ngx_stream_lua_socket_udp_finalize(ngx_stream_session_t *s, ngx_stream_lua_socket_udp_upstream_t *u); +static int ngx_stream_lua_socket_udp_downstream_destroy(lua_State *L); static int ngx_stream_lua_socket_udp_upstream_destroy(lua_State *L); static int ngx_stream_lua_socket_resolve_retval_handler(ngx_stream_session_t *s, ngx_stream_lua_socket_udp_upstream_t *u, lua_State *L); @@ -69,8 +71,13 @@ enum { }; +#if 0 +static char ngx_stream_lua_req_socket_metatable_key; +#endif +static char ngx_stream_lua_raw_req_socket_metatable_key; static char ngx_stream_lua_socket_udp_metatable_key; -static char ngx_stream_lua_udp_udata_metatable_key; +static char ngx_stream_lua_upstream_udata_metatable_key; +static char ngx_stream_lua_downstream_udata_metatable_key; static u_char ngx_stream_lua_socket_udp_buffer[UDP_MAX_DATAGRAM_SIZE]; @@ -106,18 +113,206 @@ ngx_stream_lua_inject_socket_udp_api(ngx_log_t *log, lua_State *L) lua_rawset(L, LUA_REGISTRYINDEX); /* }}} */ - /* udp socket object metatable */ - lua_pushlightuserdata(L, &ngx_stream_lua_udp_udata_metatable_key); + /* {{{upstream userdata metatable */ + lua_pushlightuserdata(L, &ngx_stream_lua_upstream_udata_metatable_key); lua_createtable(L, 0 /* narr */, 1 /* nrec */); /* metatable */ lua_pushcfunction(L, ngx_stream_lua_socket_udp_upstream_destroy); lua_setfield(L, -2, "__gc"); lua_rawset(L, LUA_REGISTRYINDEX); /* }}} */ + /* {{{downstream userdata metatable */ + lua_pushlightuserdata(L, &ngx_stream_lua_downstream_udata_metatable_key); + lua_createtable(L, 0 /* narr */, 1 /* nrec */); /* metatable */ + lua_pushcfunction(L, ngx_stream_lua_socket_udp_downstream_destroy); + lua_setfield(L, -2, "__gc"); + lua_rawset(L, LUA_REGISTRYINDEX); + /* }}} */ + +#if 0 + /* {{{udp req socket object metatable */ + lua_pushlightuserdata(L, &ngx_stream_lua_req_socket_metatable_key); + lua_createtable(L, 0 /* narr */, 3 /* nrec */); + + lua_pushcfunction(L, ngx_stream_lua_socket_udp_receive); + lua_setfield(L, -2, "receive"); + + lua_pushcfunction(L, ngx_stream_lua_socket_udp_settimeout); + lua_setfield(L, -2, "settimeout"); /* ngx socket mt */ + + lua_pushvalue(L, -1); + lua_setfield(L, -2, "__index"); + + lua_rawset(L, LUA_REGISTRYINDEX); + /* }}} */ +#endif + + /* {{{raw udp req socket object metatable */ + lua_pushlightuserdata(L, &ngx_stream_lua_raw_req_socket_metatable_key); + lua_createtable(L, 0 /* narr */, 4 /* nrec */); + + lua_pushcfunction(L, ngx_stream_lua_socket_udp_receive); + lua_setfield(L, -2, "receive"); + + lua_pushcfunction(L, ngx_stream_lua_socket_udp_send); + lua_setfield(L, -2, "send"); + + lua_pushcfunction(L, ngx_stream_lua_socket_udp_settimeout); + lua_setfield(L, -2, "settimeout"); /* ngx socket mt */ + + lua_pushvalue(L, -1); + lua_setfield(L, -2, "__index"); + lua_rawset(L, LUA_REGISTRYINDEX); + /* }}} */ + lua_pop(L, 1); } +void +ngx_stream_lua_inject_udp_req_socket_api(lua_State *L) +{ + lua_pushcfunction(L, ngx_stream_lua_udp_req_socket); + lua_setfield(L, -2, "udp_socket"); +} + + +static int +ngx_stream_lua_udp_req_socket(lua_State *L) +{ + int n, raw; + ngx_stream_session_t *s; + ngx_stream_lua_udp_connection_t *pc; + ngx_stream_lua_srv_conf_t *lscf; + ngx_connection_t *c; + ngx_stream_lua_ctx_t *ctx; + ngx_stream_lua_co_ctx_t *coctx; + ngx_stream_lua_cleanup_t *cln; + + ngx_stream_lua_socket_udp_upstream_t *u; + + n = lua_gettop(L); + if (n == 0) { + raw = 0; + + } else if (n == 1) { + raw = lua_toboolean(L, 1); + lua_pop(L, 1); + + } else { + return luaL_error(L, "expecting zero arguments, but got %d", + lua_gettop(L)); + } + + s = ngx_stream_lua_get_session(L); + + ctx = ngx_stream_get_module_ctx(s, ngx_stream_lua_module); + if (ctx == NULL) { + return luaL_error(L, "no ctx found"); + } + + ngx_stream_lua_check_context(L, ctx, NGX_STREAM_LUA_CONTEXT_CONTENT); + + c = s->connection; + + if (c->type != SOCK_DGRAM) { + return luaL_error(L, "socket api does not match connection transport", + lua_gettop(L)); + } + +#if !defined(nginx_version) || nginx_version < 1003013 + lua_pushnil(L); + lua_pushliteral(L, "nginx version too old"); + return 2; +#else + if (ctx->downstream_busy_bufs) { + lua_pushnil(L); + lua_pushliteral(L, "pending data to write"); + return 2; + } + + dd("ctx acquired raw req socket: %d", ctx->acquired_raw_req_socket); + + if (ctx->acquired_raw_req_socket) { + lua_pushnil(L); + lua_pushliteral(L, "duplicate call"); + return 2; + } + + ctx->acquired_raw_req_socket = 1; +#endif + + lua_createtable(L, 3 /* narr */, 1 /* nrec */); /* the object */ + + lua_pushlightuserdata(L, &ngx_stream_lua_raw_req_socket_metatable_key); + + lua_rawget(L, LUA_REGISTRYINDEX); + lua_setmetatable(L, -2); + + u = lua_newuserdata(L, sizeof(ngx_stream_lua_socket_udp_upstream_t)); + if (u == NULL) { + return luaL_error(L, "no memory"); + } + +#if 1 + lua_pushlightuserdata(L, &ngx_stream_lua_downstream_udata_metatable_key); + lua_rawget(L, LUA_REGISTRYINDEX); + lua_setmetatable(L, -2); +#endif + + lua_rawseti(L, 1, SOCKET_CTX_INDEX); + + ngx_memzero(u, sizeof(ngx_stream_lua_socket_udp_upstream_t)); + + u->raw_downstream = 1; + + coctx = ctx->cur_co_ctx; + + u->session = s; + + lscf = ngx_stream_get_module_srv_conf(s, ngx_stream_lua_module); + + u->conf = lscf; + + u->read_timeout = u->conf->read_timeout; + + cln = ngx_stream_lua_cleanup_add(s, 0); + if (cln == NULL) { + u->ft_type |= NGX_STREAM_LUA_SOCKET_FT_ERROR; + lua_pushnil(L); + lua_pushliteral(L, "no memory"); + return 2; + } + + cln->handler = ngx_stream_lua_socket_udp_cleanup; + cln->data = u; + + u->cleanup = &cln->handler; + + pc = &u->udp_connection; + pc->log = *c->log; + pc->connection = c; + + dd("setting data to %p", u); + + coctx->data = u; + ctx->downstream = u; + + if (c->read->timer_set) { + ngx_del_timer(c->read); + } + + if (raw) { + if (c->write->timer_set) { + ngx_del_timer(c->write); + } + } + + lua_settop(L, 1); + return 1; +} + + static int ngx_stream_lua_socket_udp(lua_State *L) { @@ -259,7 +454,7 @@ ngx_stream_lua_socket_udp_setpeername(lua_State *L) } #if 1 - lua_pushlightuserdata(L, &ngx_stream_lua_udp_udata_metatable_key); + lua_pushlightuserdata(L, &ngx_stream_lua_upstream_udata_metatable_key); lua_rawget(L, LUA_REGISTRYINDEX); lua_setmetatable(L, -2); #endif @@ -863,7 +1058,7 @@ ngx_stream_lua_socket_udp_send(lua_State *L) dd("sending query %.*s", (int) query.len, query.data); - n = ngx_send(u->udp_connection.connection, query.data, query.len); + n = ngx_udp_send(u->udp_connection.connection, query.data, query.len); dd("ngx_send returns %d (query len %d)", (int) n, (int) query.len); @@ -892,6 +1087,7 @@ ngx_stream_lua_socket_udp_receive(lua_State *L) { ngx_stream_session_t *s; ngx_stream_lua_socket_udp_upstream_t *u; + ngx_connection_t *c; ngx_int_t rc; ngx_stream_lua_ctx_t *ctx; ngx_stream_lua_co_ctx_t *coctx; @@ -961,7 +1157,20 @@ ngx_stream_lua_socket_udp_receive(lua_State *L) "stream lua udp socket receive buffer size: %uz", u->recv_buf_size); - rc = ngx_stream_lua_socket_udp_read(s, u); + c = u->udp_connection.connection; + + if (u->raw_downstream && !u->connected) { + u->received = c->buffer->last - c->buffer->pos; + c->buffer->pos = + ngx_copy(ngx_stream_lua_socket_udp_buffer, c->buffer->pos, + u->received); + ngx_stream_lua_socket_udp_handle_success(s, u); + u->connected = 1; + rc = NGX_OK; + + } else { + rc = ngx_stream_lua_socket_udp_read(s, u); + } if (rc == NGX_ERROR) { dd("read failed: %d", (int) u->ft_type); @@ -1073,7 +1282,7 @@ ngx_stream_lua_socket_udp_finalize(ngx_stream_session_t *s, u->resolved->ctx = NULL; } - if (u->udp_connection.connection) { + if (u->udp_connection.connection && !u->raw_downstream) { ngx_log_debug0(NGX_LOG_DEBUG_STREAM, s->connection->log, 0, "stream lua close socket connection"); @@ -1107,6 +1316,27 @@ ngx_stream_lua_socket_udp_upstream_destroy(lua_State *L) } +static int +ngx_stream_lua_socket_udp_downstream_destroy(lua_State *L) +{ + ngx_stream_lua_socket_udp_upstream_t *u; + + dd("downstream destory"); + + u = lua_touserdata(L, 1); + if (u == NULL) { + dd("u is NULL"); + return 0; + } + + if (u->cleanup) { + ngx_stream_lua_socket_udp_cleanup(u); /* it will clear u->cleanup */ + } + + return 0; +} + + static void ngx_stream_lua_socket_dummy_handler(ngx_stream_session_t *s, ngx_stream_lua_socket_udp_upstream_t *u) @@ -1278,8 +1508,9 @@ ngx_stream_lua_socket_udp_handler(ngx_event_t *ev) c = ev->data; u = c->data; s = u->session; + c = s->connection; - ngx_log_debug1(NGX_LOG_DEBUG_STREAM, s->connection->log, 0, + ngx_log_debug1(NGX_LOG_DEBUG_STREAM, c->log, 0, "stream lua udp socket handler, wev %d", (int) ev->write); u->read_event_handler(s, u); diff --git a/src/ngx_stream_lua_socket_udp.h b/src/ngx_stream_lua_socket_udp.h index 7055c4f6..e7ca378c 100644 --- a/src/ngx_stream_lua_socket_udp.h +++ b/src/ngx_stream_lua_socket_udp.h @@ -46,18 +46,20 @@ struct ngx_stream_lua_socket_udp_upstream_s { ngx_stream_lua_resolved_t *resolved; - ngx_uint_t ft_type; - ngx_err_t socket_errno; - size_t received; /* for receive */ - size_t recv_buf_size; + ngx_uint_t ft_type; + ngx_err_t socket_errno; + size_t received; /* for receive */ + size_t recv_buf_size; ngx_stream_lua_co_ctx_t *co_ctx; - - unsigned waiting; /* :1 */ + unsigned raw_downstream:1; + unsigned waiting:1; + unsigned connected:1; }; void ngx_stream_lua_inject_socket_udp_api(ngx_log_t *log, lua_State *L); +void ngx_stream_lua_inject_udp_req_socket_api(lua_State *L); #endif /* _NGX_STREAM_LUA_SOCKET_UDP_H_INCLUDED_ */ diff --git a/src/ngx_stream_lua_util.c b/src/ngx_stream_lua_util.c index bc161035..f16a9ffb 100644 --- a/src/ngx_stream_lua_util.c +++ b/src/ngx_stream_lua_util.c @@ -3227,9 +3227,9 @@ ngx_stream_lua_inject_req_api(ngx_log_t *log, lua_State *L) { /* ngx.req table */ - lua_createtable(L, 0 /* narr */, 1 /* nrec */); /* .req */ - - ngx_stream_lua_inject_req_socket_api(L); + lua_createtable(L, 0 /* narr */, 2 /* nrec */); /* .req */ + ngx_stream_lua_inject_tcp_req_socket_api(L); + ngx_stream_lua_inject_udp_req_socket_api(L); lua_setfield(L, -2, "req"); } diff --git a/t/062-count.t b/t/062-count.t index bdb531c6..79334639 100644 --- a/t/062-count.t +++ b/t/062-count.t @@ -46,7 +46,7 @@ ngx: 56 ngx.say("n = ", n) } --- stream_response -n = 1 +n = 2 --- no_error_log [error] diff --git a/t/065-tcp-socket-timeout.t b/t/065-tcp-socket-timeout.t index d11cd015..2b952253 100644 --- a/t/065-tcp-socket-timeout.t +++ b/t/065-tcp-socket-timeout.t @@ -138,7 +138,6 @@ lua tcp socket connect timed out --- timeout: 10 - === TEST 5: sock:settimeout(-1) does not override lua_socket_connect_timeout --- stream_server_config lua_socket_connect_timeout 102ms; diff --git a/t/137-udp-count.t b/t/137-udp-count.t new file mode 100644 index 00000000..7eaf00ac --- /dev/null +++ b/t/137-udp-count.t @@ -0,0 +1,70 @@ +# vim:set ft= ts=4 sw=4 et fdm=marker: +use Test::Nginx::Socket::Lua::Dgram; + +#worker_connections(1014); +#master_on(); +#workers(4); +#log_level('warn'); +no_root_location(); + +#repeat_each(2); + +plan tests => repeat_each() * (blocks() * 3); + +our $HtmlDir = html_dir; + +#$ENV{LUA_CPATH} = "/usr/local/openresty/lualib/?.so;" . $ENV{LUA_CPATH}; + +no_long_string(); +run_tests(); + +__DATA__ + + +=== TEST 1: entries under ngx._udp_meta +--- dgram_server_config + content_by_lua_block { + local n = 0 + for k, v in pairs(getmetatable(ngx.socket.udp())) do + print("key:", k) + n = n + 1 + end + + local sock, err = ngx.req.udp_socket() + if not sock then + ngx.log(ngx.ERR, "failed to get the request socket: ", err) + return ngx.exit(ngx.ERROR) + end + + assert(sock:send("n = " .. n)) + } + +--- dgram_response chomp +n = 6 +--- no_error_log +[error] + + + +=== TEST 2: entries under the metatable of req sockets +--- dgram_server_config + content_by_lua_block { + local n = 0 + local sock, err = ngx.req.udp_socket() + if not sock then + ngx.log(ngx.ERR, "failed to get the request socket: ", err) + return ngx.exit(ngx.ERROR) + end + + for k, v in pairs(getmetatable(sock)) do + print("key: ", k) + n = n + 1 + end + + assert(sock:send("n = " .. n)) + } + +--- dgram_response chomp +n = 4 +--- no_error_log +[error] diff --git a/t/138-req-udp-socket.t b/t/138-req-udp-socket.t new file mode 100644 index 00000000..297a4126 --- /dev/null +++ b/t/138-req-udp-socket.t @@ -0,0 +1,181 @@ +# vim:set ft= ts=4 sw=4 et fdm=marker: + +use Test::Nginx::Socket::Lua::Dgram; + +repeat_each(2); + +plan tests => repeat_each() * (blocks() * 3); + +our $HtmlDir = html_dir; + +#$ENV{TEST_NGINX_MEMCACHED_PORT} ||= 11211; + +no_long_string(); +#no_diff(); +#log_level 'warn'; +no_shuffle(); + +run_tests(); + +__DATA__ + +=== TEST 1: sanity +--- dgram_server_config + content_by_lua_block { + local sock, err = ngx.req.udp_socket() + if not sock then + ngx.log(ngx.ERR, "failed to get the request socket: ", err) + return ngx.exit(ngx.ERROR) + end + + local data, err = sock:receive() + if not data then + ngx.log(ngx.ERR, "failed to receive: ", err) + return ngx.exit(ngx.ERROR) + end + + local ok, err = sock:send("received: " .. data) + if not ok then + ngx.log(ngx.ERR, "failed to send: ", err) + return ngx.exit(ngx.ERROR) + end + } + +--- dgram_request +hello world! my +--- dgram_response +received: hello world! my +--- no_error_log +[error] + + +=== TEST 2: ngx.say not supported +--- dgram_server_config + content_by_lua_block { + local sock, err = ngx.req.udp_socket() + sock:send("") + ngx.say("something") + } + +--- dgram_response +--- error_log +not supported in udp requests + + + +=== TEST 3: ngx.print not supported +--- dgram_server_config + content_by_lua_block { + local sock, err = ngx.req.udp_socket() + sock:send("") + ngx.print("something") + } + +--- dgram_response +--- error_log +not supported in udp requests + + + +=== TEST 4: ngx.eof after ngx.req.udp_socket(true) +--- dgram_server_config + content_by_lua_block { + local sock, err = ngx.req.udp_socket(true) + if not sock then + ngx.log(ngx.ERR, "failed to get raw request socket: ", err) + return ngx.exit(ngx.ERROR) + end + assert(sock:send("")) + ngx.eof() +} + +--- config +server_tokens off; + +--- dgram_response +--- error_log +not supported in udp requests + + + +=== TEST 5: ngx.flush after ngx.udp_req.socket(true) +--- dgram_server_config + content_by_lua_block { + local sock, err = ngx.req.udp_socket(true) + if not sock then + ngx.log(ngx.ERR, "failed to get raw request socket: ", err) + return ngx.exit(ngx.ERROR) + end + assert(sock:send("")) + ngx.flush() +} + +--- dgram_response +--- error_log +not supported in udp requests + + + +=== TEST 6: receive (bad arg number) +--- dgram_server_config + content_by_lua_block { + local sock, err = ngx.req.udp_socket() + sock:send("") + sock:receive(5,4) + } + +--- dgram_response +--- error_log +expecting 1 or 2 arguments (including the object), but got 3 + + + +=== TEST 7: failing reread after reading timeout happens +--- SKIP +--- dgram_server_config + content_by_lua_block { + local sock, err = ngx.req.udp_socket() + if not sock then + ngx.log(ngx.ERR, "failed to get the request socket: ", err) + return ngx.exit(ngx.ERROR) + end + + local data, err = sock:receive() -- trigger_dgram_req + + sock:settimeout(100) + data, err = sock:receive() + if err then + sock:send("err: ", err) + end + } + +--- dgram_response chomp +err: timeout +--- error_log +stream lua udp socket read timed out + + + +=== TEST 8: req socket GC'd +--- dgram_server_config + content_by_lua_block { + do + local sock, err = ngx.req.udp_socket() + if not sock then + ngx.log(ngx.ERR, "failed to get the request socket: ", err) + return ngx.exit(ngx.ERROR) + end + + assert(sock:send("done")) + end + collectgarbage() + ngx.log(ngx.WARN, "GC cycle done") + } + +--- dgram_response chomp +done +--- no_error_log +[error] +--- grep_error_log_out +stream lua finalize socket +GC cycle done diff --git a/t/139-bad-udp-sock-self.t b/t/139-bad-udp-sock-self.t new file mode 100644 index 00000000..055cf84c --- /dev/null +++ b/t/139-bad-udp-sock-self.t @@ -0,0 +1,58 @@ +# vim:set ft= ts=4 sw=4 et fdm=marker: + +use Test::Nginx::Socket::Lua::Dgram; +repeat_each(2); + +plan tests => repeat_each() * (blocks() * 3); + +our $HtmlDir = html_dir; + +#$ENV{TEST_NGINX_MEMCACHED_PORT} ||= 11211; + +no_long_string(); +#no_diff(); +#log_level 'warn'; + +run_tests(); + +__DATA__ + +=== TEST 1: receive +--- dgram_server_config + content_by_lua_block { + local sock, err = ngx.req.udp_socket() + sock:send("") + sock.receive("l") + } + +--- dgram_response +--- error_log +bad argument #1 to 'receive' (table expected, got string) + + + +=== TEST 2: send (bad arg number) +--- dgram_server_config + content_by_lua_block { + local sock, err = ngx.req.udp_socket() + sock:send("") + sock.send("hello") + } + +--- dgram_response +--- error_log +expecting 2 arguments (including the object), but got 1 + + + +=== TEST 3: send (bad self) +--- dgram_server_config + content_by_lua_block { + local sock, err = ngx.req.udp_socket() + sock:send("") + sock.send("hello", 32) + } + +--- dgram_response +--- error_log +bad argument #1 to 'send' (table expected, got string) diff --git a/t/140-raw-req-udp-socket.t b/t/140-raw-req-udp-socket.t new file mode 100644 index 00000000..ea5de434 --- /dev/null +++ b/t/140-raw-req-udp-socket.t @@ -0,0 +1,265 @@ +# vim:set ft= ts=4 sw=4 et fdm=marker: + +use Test::Nginx::Socket::Lua::Dgram; + +repeat_each(2); + +plan tests => repeat_each() * (blocks() * 3); + +#plan tests => repeat_each() * 43; + +our $HtmlDir = html_dir; + +$ENV{TEST_NGINX_MEMCACHED_PORT} ||= 11211; +$ENV{TEST_NGINX_RESOLVER} ||= '8.8.8.8'; + +#log_level 'warn'; +log_level 'debug'; + +no_long_string(); +#no_diff(); +run_tests(); + +__DATA__ + +=== TEST 1: sanity +--- dgram_server_config + content_by_lua_block { + local sock, err = ngx.req.udp_socket(true) + if not sock then + ngx.log(ngx.ERR, "failed to get the request socket: ", err) + return ngx.exit(ngx.ERROR) + end + + local data, err = sock:receive() + if not data then + ngx.log(ngx.ERR, "failed to receive: ", err) + return ngx.exit(ngx.ERROR) + end + + local ok, err = sock:send("received: " .. data) + if not ok then + ngx.log(ngx.ERR, "failed to send: ", err) + return ngx.exit(ngx.ERROR) + end + } + +--- dgram_request +hello +--- dgram_response +received: hello +--- no_error_log +[error] + + + +=== TEST 2: multiple raw req sockets +--- dgram_server_config + content_by_lua_block { + local sock, err = ngx.req.udp_socket(true) + if not sock then + ngx.log(ngx.ERR, "failed to get raw request socket: ", err) + return ngx.exit(ngx.ERROR) + end + assert(sock:send("")) + + local sock2, err = ngx.req.udp_socket(true) + if not sock2 then + ngx.log(ngx.ERR, "failed to get raw request socket: ", err) + return ngx.exit(ngx.ERROR) + end + } + +--- stap2 +F(ngx_dgram_header_filter) { + println("header filter") +} +F(ngx_dgram_lua_req_socket) { + println("lua req socket") +} +--- dgram_response +--- error_log +failed to get raw request socket: duplicate call + + + +=== TEST 3: sock:send after ngx.req.udp_socket(true) +--- dgram_server_config + content_by_lua_block { + local sock, err = ngx.req.udp_socket(true) + if not sock then + ngx.log(ngx.ERR, "failed to get raw request socket: ", err) + return ngx.exit(ngx.ERROR) + end + + local ok, err = sock:send("ok") + if not ok then + ngx.log(ngx.ERR, "failed to send: ", err) + return ngx.exit(ngx.ERROR) + end + } + +--- dgram_response chomp +ok +--- no_error_log +[error] + + + +=== TEST 4: receive timeout +--- SKIP +--- dgram_server_config + content_by_lua_block { + local sock, err = ngx.req.udp_socket(true) + if not sock then + ngx.log(ngx.ERR, "failed to get raw request socket: ", err) + return ngx.exit(ngx.ERROR) + end + + local data, err = sock:receive() -- trigger_dgram_req + + sock:settimeout(100) + data, err = sock:receive() + if err then + sock:send("err: ", err) + end + } + +--- dgram_response chomp +err: timeout +--- error_log +stream lua udp socket read timed out + + + +=== TEST 5: on_abort called during ngx.sleep() +--- dgram_server_config + lua_check_client_abort on; + + content_by_lua_block { + local ok, err = ngx.on_abort(function (premature) ngx.log(ngx.WARN, "mysock handler aborted") end) + if not ok then + ngx.log(ngx.ERR, "failed to set on_abort handler: ", err) + return + end + + local sock, err = ngx.req.udp_socket(true) + if not sock then + ngx.log(ngx.ERR, "failed to get raw request socket: ", err) + return ngx.exit(ngx.ERROR) + end + + local data, err = sock:receive() + if not data then + ngx.log(ngx.ERR, "server: failed to receive: ", err) + return ngx.exit(ngx.ERROR) + end + + print("msg received: ", data) + + local bytes, err = sock:send("1: received: " .. data .. "\n") + if not bytes then + ngx.log(ngx.ERR, "server: failed to send: ", err) + return ngx.exit(ngx.ERROR) + end + + ngx.sleep(1) + } + +--- dgram_request +hello +--- dgram_response +receive stream response error: timeout +--- abort +--- timeout: 0.2 +--- warn_log +mysock handler aborted +--- no_error_log +[error] +--- wait: 1.1 + + + +=== TEST 6: on_abort called during sock:receive() +--- dgram_server_config + lua_check_client_abort on; + + content_by_lua_block { + local ok, err = ngx.on_abort(function (premature) ngx.log(ngx.WARN, "mysock handler aborted") end) + if not ok then + ngx.log(ngx.ERR, "failed to set on_abort handler: ", err) + return + end + + + local sock, err = ngx.req.udp_socket(true) + if not sock then + ngx.log(ngx.ERR, "failed to get raw request socket: ", err) + return ngx.exit(ngx.ERROR) + end + + local data, err = sock:receive() + if not data then + ngx.log(ngx.ERR, "server: failed to receive: ", err) + return ngx.exit(ngx.ERROR) + end + + print("msg received: ", data) + + local bytes, err = sock:send("1: received: " .. data .. "\n") + if not bytes then + ngx.log(ngx.ERR, "server: failed to send: ", err) + return ngx.exit(ngx.ERROR) + end + + local data, err = sock:receive() + if not data then + ngx.log(ngx.WARN, "failed to receive a line: ", err) + return + end + } + +--- dgram_response +receive stream response error: timeout +--- timeout: 0.2 +--- abort +--- warn_log +mysock handler aborted +--- no_error_log +[error] +--- wait: 0.1 + + + +=== TEST 7: request body not read yet +--- dgram_server_config + content_by_lua_block { + local sock, err = ngx.req.udp_socket(true) + if not sock then + ngx.log(ngx.ERR, "failed to get raw request socket: ", err) + return ngx.exit(ngx.ERROR) + end + + local data, err = sock:receive() + if not data then + ngx.log(ngx.ERR, "server: failed to receive: ", err) + return ngx.exit(ngx.ERROR) + end + + local ok, err = sock:send("HTTP/1.1 200 OK\r\nContent-Length: 5\r\n\r\n" .. data) + if not ok then + ngx.log(ngx.ERR, "failed to send: ", err) + return ngx.exit(ngx.ERROR) + end + } + +--- dgram_request chomp +hello +--- dgram_response eval +"HTTP/1.1 200 OK\r +Content-Length: 5\r +\r +hello" + +--- no_error_log +[error]