Skip to content

Commit

Permalink
feature: add cdata type support for tcpsock.send and udpsock.send.
Browse files Browse the repository at this point in the history
  • Loading branch information
zhuizhuhaomeng committed Mar 25, 2024
1 parent bea8a0c commit 53ad133
Show file tree
Hide file tree
Showing 20 changed files with 962 additions and 159 deletions.
318 changes: 310 additions & 8 deletions src/ngx_stream_lua_socket_tcp.c

Large diffs are not rendered by default.

2 changes: 2 additions & 0 deletions src/ngx_stream_lua_socket_tcp.h
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,8 @@ struct ngx_stream_lua_socket_tcp_upstream_s {

ngx_uint_t reused;

const char *error_ret;

#if (NGX_STREAM_SSL)
ngx_str_t ssl_name;
#endif
Expand Down
156 changes: 153 additions & 3 deletions src/ngx_stream_lua_socket_udp.c
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,11 @@ static char ngx_stream_lua_socket_udp_downstream_udata_metatable_key;
static u_char ngx_stream_lua_socket_udp_buffer[UDP_MAX_DATAGRAM_SIZE];


#define ngx_stream_lua_udp_socket_metatable_literal_key "__udp_cosocket_mt"
#define ngx_stream_lua_raw_udp_socket_metatable_literal_key \
"__raw_udp_cosocket_mt"


void
ngx_stream_lua_inject_socket_udp_api(ngx_log_t *log, lua_State *L)
{
Expand All @@ -101,7 +106,7 @@ ngx_stream_lua_inject_socket_udp_api(ngx_log_t *log, lua_State *L)
/* udp upstream socket object metatable */
lua_pushlightuserdata(L, ngx_stream_lua_lightudata_mask(
socket_udp_metatable_key));
lua_createtable(L, 0 /* narr */, 6 /* nrec */);
lua_createtable(L, 0 /* narr */, 7 /* nrec */);

lua_pushcfunction(L, ngx_stream_lua_socket_udp_setpeername);
lua_setfield(L, -2, "setpeername"); /* ngx socket mt */
Expand All @@ -121,6 +126,12 @@ ngx_stream_lua_inject_socket_udp_api(ngx_log_t *log, lua_State *L)
lua_pushvalue(L, -1);
lua_setfield(L, -2, "__index");
lua_rawset(L, LUA_REGISTRYINDEX);

lua_pushliteral(L, ngx_stream_lua_udp_socket_metatable_literal_key);
lua_pushlightuserdata(L, ngx_stream_lua_lightudata_mask(
socket_udp_metatable_key));
lua_rawget(L, LUA_REGISTRYINDEX);
lua_rawset(L, LUA_REGISTRYINDEX);
/* }}} */

/* udp downstream socket object metatable */
Expand All @@ -140,6 +151,12 @@ ngx_stream_lua_inject_socket_udp_api(ngx_log_t *log, lua_State *L)
lua_pushvalue(L, -1);
lua_setfield(L, -2, "__index");
lua_rawset(L, LUA_REGISTRYINDEX);

lua_pushliteral(L, ngx_stream_lua_raw_udp_socket_metatable_literal_key);
lua_pushlightuserdata(L, ngx_stream_lua_lightudata_mask(
socket_udp_raw_req_socket_metatable_key));
lua_rawget(L, LUA_REGISTRYINDEX);
lua_rawset(L, LUA_REGISTRYINDEX);
/* }}} */

/* udp upstream socket object metatable */
Expand Down Expand Up @@ -547,7 +564,8 @@ ngx_stream_lua_socket_resolve_handler(ngx_resolver_ctx_t *ctx)
addr.data = text;

for (i = 0; i < ctx->naddrs; i++) {
addr.len = ngx_sock_ntop(ur->addrs[i].sockaddr, ur->addrs[i].socklen,
addr.len = ngx_sock_ntop(ur->addrs[i].sockaddr,
ur->addrs[i].socklen,
text, NGX_SOCKADDR_STRLEN, 0);

ngx_log_debug1(NGX_LOG_DEBUG_STREAM, r->connection->log, 0,
Expand Down Expand Up @@ -912,7 +930,7 @@ ngx_stream_lua_socket_udp_send(lua_State *L)

u->ft_type = 0;

/* mimic ngx_http_upstream_init_request here */
/* mimic ngx_stream_upstream_init_request here */

#if 1
u->waiting = 0;
Expand Down Expand Up @@ -1949,6 +1967,138 @@ ngx_stream_lua_udp_sendmsg(ngx_connection_t *c, ngx_iovec_t *vec)
return n;
}


static void
ngx_stream_lua_socket_send_cdata_err_retval_handler(ngx_stream_lua_request_t *r,
ngx_stream_lua_socket_udp_upstream_t *u, const char **errmsg)
{
static u_char errstr[NGX_MAX_ERROR_STR];
u_char *p;

ngx_log_debug0(NGX_LOG_DEBUG_STREAM, r->connection->log, 0,
"lua udp socket send cdata error retval handler");

if (u->ft_type & NGX_STREAM_LUA_SOCKET_FT_RESOLVER) {
*errmsg = "failed to start the resolver";

} else if (u->ft_type & NGX_STREAM_LUA_SOCKET_FT_PARTIALWRITE) {
*errmsg = "partial write";

} else if (u->ft_type & NGX_STREAM_LUA_SOCKET_FT_TIMEOUT) {
*errmsg = "timeout";

} else if (u->ft_type & NGX_STREAM_LUA_SOCKET_FT_CLOSED) {
*errmsg = "closed";

} else if (u->ft_type & NGX_STREAM_LUA_SOCKET_FT_BUFTOOSMALL) {
*errmsg = "buffer too small";

} else if (u->ft_type & NGX_STREAM_LUA_SOCKET_FT_NOMEM) {
*errmsg = "no memory";

} else {

if (u->socket_errno) {
p = ngx_strerror(u->socket_errno, errstr, sizeof(errstr));
/* for compatibility with LuaSocket */
ngx_strlow(errstr, errstr, p - errstr);
*errmsg = (const char *) errstr;

} else {
*errmsg = "error";
}
}
}


int
ngx_stream_lua_ffi_socket_udp_send_cdata(ngx_stream_lua_request_t *r,
ngx_stream_lua_socket_udp_upstream_t *u, void *cdata, size_t len,
const char **errmsg)
{
ssize_t n;
#ifndef NGX_WIN32
ngx_iovec_t vec;
struct iovec iovs[1];
#endif

ngx_stream_lua_loc_conf_t *llcf;

if (u == NULL || u->udp_connection.connection == NULL) {
llcf = ngx_stream_lua_get_module_loc_conf(r, ngx_stream_lua_module);

if (llcf->log_socket_errors) {
ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
"attempt to send data on a closed socket: u:%p, c:%p",
u, u ? u->udp_connection.connection : NULL);
}

*errmsg = "closed";

return NGX_ERROR;
}

if (u->request != r) {
*errmsg = "bad request";
return NGX_ERROR;
}

if (u->ft_type) {
u->ft_type = 0;
}

if (u->waiting) {
*errmsg = "socket busy";
return NGX_ERROR;
}

u->ft_type = 0;

/* mimic ngx_stream_upstream_init_request here */

#if 1
u->waiting = 0;
#endif

dd("sending query %.*s", (int) len, cdata);
#ifdef NGX_WIN32
n = ngx_udp_send(u->udp_connection.connection, cdata, len);
dd("ngx_udp_send returns %d (query len %d)", (int) n, (int) len);

#else
vec.iovs = iovs;
vec.nalloc = 1;
vec.count = 1;
iovs[0].iov_base = cdata;
iovs[0].iov_len = len;
vec.size = len;
n = ngx_stream_lua_udp_sendmsg(u->udp_connection.connection, &vec);

dd("ngx_stream_lua_udp_sendmsg returns %d (query len %d)",
(int) n, (int) len);
#endif

if (n == NGX_ERROR || n == NGX_AGAIN) {
u->socket_errno = ngx_socket_errno;
ngx_stream_lua_socket_send_cdata_err_retval_handler(r, u, errmsg);

return NGX_ERROR;
}

if (n != (ssize_t) len) {
dd("not the while query was sent");

u->ft_type |= NGX_STREAM_LUA_SOCKET_FT_PARTIALWRITE;
ngx_stream_lua_socket_send_cdata_err_retval_handler(r, u, errmsg);

return NGX_ERROR;
}

dd("n == len");

return NGX_OK;
}

#endif

/* vi:set ft=c ts=4 sw=4 et fdm=marker: */
4 changes: 2 additions & 2 deletions t/009-log.t
Original file line number Diff line number Diff line change
Expand Up @@ -201,12 +201,12 @@ qr/\[error\] \S+: \S+ stream \[lua\] content_by_lua\(nginx\.conf:\d+\):2: truefa
=== TEST 13: ngx.log() big data
--- stream_server_config
content_by_lua_block {
ngx.log(ngx.ERR, "a" .. string.rep("h", 1970) .. "b")
ngx.log(ngx.ERR, "a" .. string.rep("h", 1940) .. "b")
ngx.say("hi")
}
--- response_headers
--- error_log eval
[qr/ah{1970}b/]
[qr/ah{1940}b/]



Expand Down
60 changes: 1 addition & 59 deletions t/023-preread/req-socket.t
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
use Test::Nginx::Socket::Lua::Stream;
repeat_each(2);

plan tests => repeat_each() * (blocks() * 3 + 11);
plan tests => repeat_each() * (blocks() * 3 + 6);

our $HtmlDir = html_dir;

Expand Down Expand Up @@ -510,61 +510,3 @@ attempt to peek on a consumed socket
--- no_error_log
[warn]



=== TEST 12: peek works with other preread handlers
--- stream_server_config
ssl_preread on;
preread_by_lua_block {
local rsock = assert(ngx.req.socket())

local data, err = rsock:peek(2)
if not data then
ngx.log(ngx.ERR, "failed to peek the request socket: ", err)
return
end

local n = ngx.var.ssl_preread_server_name
if not n or n == '' then
ngx.log(ngx.INFO, "$ssl_preread_server_name is empty")

else
ngx.log(ngx.INFO, "$ssl_preread_server_name = ", n)
end


if n == "my.sni.server.name" then
assert(string.byte(data:sub(1, 1)) == 0x16)
assert(string.byte(data:sub(2, 2)) == 0x03)
ngx.exit(200)
end

local sock = ngx.socket.tcp()
local ok, err = sock:connect("127.0.0.1", tonumber(ngx.var.server_port))
if not ok then
ngx.say(err)
return ngx.exit(500)
end

local _, err = sock:sslhandshake(nil, "my.sni.server.name")
if not err then
ngx.say("did not error as expected")
return ngx.exit(500)
end

sock:close()
}

return done;
--- stream_request chop
hello
--- stream_response chop
done
--- error_log
$ssl_preread_server_name is empty while prereading client data
$ssl_preread_server_name = my.sni.server.name while prereading client data
--- no_error_log
[crit]
[warn]
assertion failed!
lua entry thread aborted
Loading

0 comments on commit 53ad133

Please sign in to comment.