Commit ca31947f authored by Vladimír Čunát's avatar Vladimír Čunát

lua module layers: passing from C to lua

... without light userdata and yet it should be efficient.
Also with checkout layer, but I have no nice way of testing that one.
parent 748951a2
......@@ -626,6 +626,10 @@ void engine_deinit(struct engine *engine)
if (engine == NULL) {
return;
}
if (!engine->L) {
assert(false);
return;
}
/* Only close sockets and services; no need to clean up mempool. */
/* Network deinit is split up. We first need to stop listening,
......@@ -648,6 +652,7 @@ void engine_deinit(struct engine *engine)
lru_free(engine->resolver.cache_cookie);
network_deinit(&engine->net);
ffimodule_deinit(engine->L);
lua_close(engine->L);
/* Free data structures */
......@@ -702,13 +707,14 @@ int engine_ipc(struct engine *engine, const char *expr)
int engine_load_sandbox(struct engine *engine)
{
/* Init environment */
int ret = l_dosandboxfile(engine->L, LIBDIR "/sandbox.lua");
int ret = l_dosandboxfile(engine->L, LIBDIR "/sandbox.lua");
if (ret != 0) {
fprintf(stderr, "[system] error %s\n", lua_tostring(engine->L, -1));
lua_pop(engine->L, 1);
return kr_error(ENOEXEC);
}
return kr_ok();
ret = ffimodule_init(engine->L);
return ret;
}
int engine_loadconf(struct engine *engine, const char *config_path)
......
......@@ -18,8 +18,10 @@
#include <lua.h>
#include <lauxlib.h>
#include "daemon/bindings/impl.h"
#include "daemon/engine.h"
#include "daemon/ffimodule.h"
#include "daemon/worker.h"
#include "lib/module.h"
#include "lib/layer.h"
......@@ -43,6 +45,9 @@ enum {
};
#define SLOT_size sizeof(int)
/** Lua registry indices for functions that wrap layer callbacks (shared by all lua modules). */
static int l_ffi_wrap_slots[SLOT_count] = { 0 };
/** @internal Helper for retrieving the right function entrypoint. */
static inline lua_State *l_ffi_preface(struct kr_module *module, const char *call) {
lua_State *L = module->lib;
......@@ -142,36 +147,32 @@ static int l_ffi_deinit(struct kr_module *module)
/** @internal Helper for retrieving layer Lua function by name. */
#define LAYER_FFI_CALL(ctx, slot_name) \
const int *cb_slot = (ctx)->api->cb_slots + SLOT_ ## slot_name; \
if (*cb_slot <= 0) { \
return (ctx)->state; \
} \
struct kr_module *module = (ctx)->api->data; \
lua_State *L = module->lib; \
lua_rawgeti(L, LUA_REGISTRYINDEX, *cb_slot); \
lua_pushnumber(L, (ctx)->state)
(ctx)->pkt = NULL; /* for debugging */ \
const int wrap_slot = l_ffi_wrap_slots[SLOT_ ## slot_name]; \
const int cb_slot = (ctx)->api->cb_slots[SLOT_ ## slot_name]; \
assert(wrap_slot > 0 && cb_slot > 0); \
lua_State *L = the_worker->engine->L; \
lua_rawgeti(L, LUA_REGISTRYINDEX, wrap_slot); \
lua_rawgeti(L, LUA_REGISTRYINDEX, cb_slot); \
lua_pushpointer(L, (ctx));
static int l_ffi_layer_begin(kr_layer_t *ctx)
{
LAYER_FFI_CALL(ctx, begin);
lua_pushlightuserdata(L, ctx->req);
return l_ffi_call_layer(L, 2);
}
static int l_ffi_layer_reset(kr_layer_t *ctx)
{
LAYER_FFI_CALL(ctx, reset);
lua_pushlightuserdata(L, ctx->req);
return l_ffi_call_layer(L, 2);
}
static int l_ffi_layer_finish(kr_layer_t *ctx)
{
struct kr_request *req = ctx->req;
LAYER_FFI_CALL(ctx, finish);
lua_pushlightuserdata(L, req);
lua_pushlightuserdata(L, req->answer);
return l_ffi_call_layer(L, 3);
ctx->pkt = ctx->req->answer;
return l_ffi_call_layer(L, 2);
}
static int l_ffi_layer_consume(kr_layer_t *ctx, knot_pkt_t *pkt)
......@@ -180,43 +181,80 @@ static int l_ffi_layer_consume(kr_layer_t *ctx, knot_pkt_t *pkt)
return ctx->state; /* Already failed, skip */
}
LAYER_FFI_CALL(ctx, consume);
lua_pushlightuserdata(L, ctx->req);
lua_pushlightuserdata(L, pkt);
return l_ffi_call_layer(L, 3);
ctx->pkt = pkt;
return l_ffi_call_layer(L, 2);
}
static int l_ffi_layer_produce(kr_layer_t *ctx, knot_pkt_t *pkt)
{
if (ctx->state & (KR_STATE_FAIL)) {
return ctx->state; /* Already failed or done, skip */
if (ctx->state & KR_STATE_FAIL) {
return ctx->state; /* Already failed, skip */
}
LAYER_FFI_CALL(ctx, produce);
lua_pushlightuserdata(L, ctx->req);
lua_pushlightuserdata(L, pkt);
return l_ffi_call_layer(L, 3);
ctx->pkt = pkt;
return l_ffi_call_layer(L, 2);
}
static int l_ffi_layer_checkout(kr_layer_t *ctx, knot_pkt_t *pkt, struct sockaddr *dst, int type)
{
if (ctx->state & (KR_STATE_FAIL)) {
return ctx->state; /* Already failed or done, skip */
if (ctx->state & KR_STATE_FAIL) {
return ctx->state; /* Already failed, skip */
}
LAYER_FFI_CALL(ctx, checkout);
lua_pushlightuserdata(L, ctx->req);
lua_pushlightuserdata(L, pkt);
lua_pushlightuserdata(L, dst);
lua_pushboolean(L, type == SOCK_STREAM);
return l_ffi_call_layer(L, 5);
ctx->pkt = pkt;
ctx->dst = dst;
ctx->is_stream = (type == SOCK_STREAM);
return l_ffi_call_layer(L, 2);
}
static int l_ffi_layer_answer_finalize(kr_layer_t *ctx)
{
LAYER_FFI_CALL(ctx, answer_finalize);
lua_pushlightuserdata(L, ctx->req);
return l_ffi_call_layer(L, 2);
}
#undef LAYER_FFI_CALL
int ffimodule_init(lua_State *L)
{
/* Wrappers defined in ./lua/sandbox.lua */
/* for API: (int state, kr_request_t *req) */
lua_getglobal(L, "modules_ffi_layer_wrap1");
const int wrap1 = luaL_ref(L, LUA_REGISTRYINDEX);
/* for API: (int state, kr_request_t *req, knot_pkt_t *) */
lua_getglobal(L, "modules_ffi_layer_wrap2");
const int wrap2 = luaL_ref(L, LUA_REGISTRYINDEX);
lua_getglobal(L, "modules_ffi_layer_wrap_checkout");
const int wrap_checkout = luaL_ref(L, LUA_REGISTRYINDEX);
if (wrap1 == LUA_REFNIL || wrap2 == LUA_REFNIL || wrap_checkout == LUA_REFNIL) {
return kr_error(ENOENT);
}
const int slots[SLOT_count] = {
[SLOT_begin] = wrap1,
[SLOT_reset] = wrap1,
[SLOT_finish] = wrap2,
[SLOT_consume] = wrap2,
[SLOT_produce] = wrap2,
[SLOT_checkout] = wrap_checkout,
[SLOT_answer_finalize] = wrap1,
};
memcpy(l_ffi_wrap_slots, slots, sizeof(l_ffi_wrap_slots));
return kr_ok();
}
void ffimodule_deinit(lua_State *L)
{
/* Unref each wrapper function from lua.
* It's probably useless, as we're about to destroy lua_State, but... */
const int wrapsIndices[] = {
SLOT_begin,
SLOT_consume,
SLOT_checkout,
};
for (int i = 0; i < sizeof(wrapsIndices) / sizeof(wrapsIndices[0]); ++i) {
luaL_unref(L, LUA_REGISTRYINDEX, l_ffi_wrap_slots[wrapsIndices[i]]);
}
}
/** @internal Conditionally register layer trampoline
* @warning Expects 'module.layer' to be on top of Lua stack. */
#define LAYER_REGISTER(L, api, name) do { \
......@@ -247,8 +285,6 @@ static kr_layer_api_t *l_ffi_layer_create(lua_State *L, struct kr_module *module
LAYER_REGISTER(L, api, checkout);
LAYER_REGISTER(L, api, answer_finalize);
LAYER_REGISTER(L, api, reset);
/* Begin is always set, as it initializes layer baton. */
api->begin = l_ffi_layer_begin;
api->data = module;
}
return api;
......
......@@ -31,3 +31,7 @@
* @return 0 or an error
*/
int ffimodule_register_lua(struct engine *engine, struct kr_module *module, const char *name);
int ffimodule_init(lua_State *L);
void ffimodule_deinit(lua_State *L);
......@@ -41,7 +41,6 @@ typedef struct {
struct kr_module;
typedef char *(kr_prop_cb)(void *, struct kr_module *, const char *);
struct kr_layer;
typedef struct knot_pkt knot_pkt_t;
typedef struct {
uint8_t *ptr[15];
......@@ -229,6 +228,14 @@ struct kr_cache {
struct timeval checkpoint_walltime;
uint64_t checkpoint_monotime;
};
struct kr_layer {
int state;
struct kr_request *req;
const struct kr_layer_api *api;
knot_pkt_t *pkt;
struct sockaddr *dst;
_Bool is_stream;
};
typedef struct kr_layer kr_layer_t;
struct kr_layer_api {
int (*begin)(kr_layer_t *);
......
......@@ -76,7 +76,6 @@ genResType "knot_rrset_t" | sed 's/\<owner\>/_owner/; s/\<ttl\>/_ttl/'
printf "
struct kr_module;
typedef char *(kr_prop_cb)(void *, struct kr_module *, const char *);
struct kr_layer;
"
${CDEFS} ${LIBKRES} types <<-EOF
......@@ -104,6 +103,7 @@ ${CDEFS} ${LIBKRES} types <<-EOF
struct kr_cdb_stats
struct kr_cache
# lib/layer.h
struct kr_layer
kr_layer_t
struct kr_layer_api
kr_layer_api_t
......
......@@ -260,6 +260,20 @@ function modules_create_table_for_c(kr_module_ud)
})
end
-- Utilities internal for lua layer glue; see ../ffimodule.c
modules_ffi_layer_wrap1 = function (layer_cb, ctx_udata)
local ctx = ffi.cast('kr_layer_t **', ctx_udata)[0]
return layer_cb(ctx.state, ctx.req)
end
modules_ffi_layer_wrap2 = function (layer_cb, ctx_udata)
local ctx = ffi.cast('kr_layer_t **', ctx_udata)[0]
return layer_cb(ctx.state, ctx.req, ctx.pkt)
end
modules_ffi_layer_wrap_checkout = function (layer_cb, ctx_udata)
local ctx = ffi.cast('kr_layer_t **', ctx_udata)[0]
return layer_cb(ctx.state, ctx.req, ctx.pkt, ctx.dst, ctx.is_stream)
end
cache.clear = function (name, exact_name, rr_type, chunk_size, callback, prev_state)
if name == nil or (name == '.' and not exact_name) then
-- keep same output format as for 'standard' clear
......
......@@ -62,6 +62,9 @@ typedef struct kr_layer {
int state; /*!< The current state; bitmap of enum kr_layer_state. */
struct kr_request *req; /*!< The corresponding request. */
const struct kr_layer_api *api;
knot_pkt_t *pkt; /*!< In glue for lua kr_layer_api it's used to pass the parameter. */
struct sockaddr *dst; /*!< In glue for checkout layer it's used to pass the parameter. */
bool is_stream; /*!< In glue for checkout layer it's used to pass the parameter. */
} kr_layer_t;
/** Packet processing module API. All functions return the new kr_layer_state. */
......@@ -74,22 +77,26 @@ struct kr_layer_api {
/** Paired to begin, called both on successes and failures. */
int (*finish)(kr_layer_t *ctx);
/** Processing an answer from upstream or the answer to the request. */
/** Processing an answer from upstream or the answer to the request.
* Lua API: call is omitted iff (state & KR_STATE_FAIL). */
int (*consume)(kr_layer_t *ctx, knot_pkt_t *pkt);
/** Produce either an answer to the request or a query for upstream (or fail). */
/** Produce either an answer to the request or a query for upstream (or fail).
* Lua API: call is omitted iff (state & KR_STATE_FAIL). */
int (*produce)(kr_layer_t *ctx, knot_pkt_t *pkt);
/** Finalises the outbound query packet with the knowledge of the IP addresses.
* The checkout layer doesn't persist the state, so canceled subrequests
* don't affect the resolution or rest of the processing. */
* don't affect the resolution or rest of the processing.
* Lua API: call is omitted iff (state & KR_STATE_FAIL). */
int (*checkout)(kr_layer_t *ctx, knot_pkt_t *packet, struct sockaddr *dst, int type);
/** Finalises the answer.
* Last chance to affect what will get into the answer, including EDNS.*/
int (*answer_finalize)(kr_layer_t *ctx);
/** The module can store anything in here. */
/** The module can store anything in here.
* In lua case we store kr_module pointer. */
void *data;
/** Internal to ./daemon/ffimodule.c. */
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment