mirror of
https://git.haproxy.org/git/haproxy.git/
synced 2026-01-19 00:51:37 +01:00
MINOR: lua: add AppletTCP class and service
This class is used by Lua code for running as an applet called in TCP mode. It defines also the lua service.
This commit is contained in:
parent
5a363e71b2
commit
f0a64b676f
@ -115,6 +115,11 @@ struct appctx {
|
||||
struct list wake_on_read;
|
||||
struct list wake_on_write;
|
||||
} hlua;
|
||||
struct {
|
||||
struct hlua hlua;
|
||||
int flags;
|
||||
struct task *task;
|
||||
} hlua_apptcp;
|
||||
struct {
|
||||
struct dns_resolvers *ptr;
|
||||
} resolvers;
|
||||
|
||||
@ -17,6 +17,7 @@
|
||||
#define CLASS_CHANNEL "Channel"
|
||||
#define CLASS_HTTP "HTTP"
|
||||
#define CLASS_MAP "Map"
|
||||
#define CLASS_APPLET_TCP "AppletTCP"
|
||||
|
||||
struct stream;
|
||||
|
||||
@ -98,6 +99,13 @@ struct hlua_txn {
|
||||
struct proxy *p;
|
||||
};
|
||||
|
||||
/* This struct contains the applet context. */
|
||||
struct hlua_appctx {
|
||||
struct appctx *appctx;
|
||||
luaL_Buffer b; /* buffer used to prepare strings. */
|
||||
struct hlua_txn htxn;
|
||||
};
|
||||
|
||||
/* This struc is used with sample fetches and sample converters. */
|
||||
struct hlua_smp {
|
||||
struct stream *s;
|
||||
|
||||
595
src/hlua.c
595
src/hlua.c
@ -109,6 +109,10 @@ static int hlua_panic_ljmp(lua_State *L) { longjmp(safe_ljmp_env, 1); }
|
||||
lua_atpanic(__L, hlua_panic_safe); \
|
||||
} while(0)
|
||||
|
||||
/* Applet status flags */
|
||||
#define APPLET_DONE 0x1 /* applet processing is done. */
|
||||
#define APPLET_SENT 0x2 /* some data are sent. */
|
||||
|
||||
/* The main Lua execution context. */
|
||||
struct hlua gL;
|
||||
|
||||
@ -138,6 +142,7 @@ static int class_fetches_ref;
|
||||
static int class_converters_ref;
|
||||
static int class_http_ref;
|
||||
static int class_map_ref;
|
||||
static int class_applet_tcp_ref;
|
||||
|
||||
/* Global Lua execution timeout. By default Lua, execution linked
|
||||
* with stream (actions, sample-fetches and converters) have a
|
||||
@ -146,6 +151,7 @@ static int class_map_ref;
|
||||
*/
|
||||
static unsigned int hlua_timeout_session = 4000; /* session timeout. */
|
||||
static unsigned int hlua_timeout_task = TICK_ETERNITY; /* task timeout. */
|
||||
static unsigned int hlua_timeout_applet = 4000; /* applet timeout. */
|
||||
|
||||
/* Interrupts the Lua processing each "hlua_nb_instruction" instructions.
|
||||
* it is used for preventing infinite loops.
|
||||
@ -3134,6 +3140,287 @@ __LJMP static int hlua_run_sample_conv(lua_State *L)
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
*
|
||||
*
|
||||
* Class AppletTCP
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
/* Returns a struct hlua_txn if the stack entry "ud" is
|
||||
* a class stream, otherwise it throws an error.
|
||||
*/
|
||||
__LJMP static struct hlua_appctx *hlua_checkapplet_tcp(lua_State *L, int ud)
|
||||
{
|
||||
return (struct hlua_appctx *)MAY_LJMP(hlua_checkudata(L, ud, class_applet_tcp_ref));
|
||||
}
|
||||
|
||||
/* This function creates and push in the stack an Applet object
|
||||
* according with a current TXN.
|
||||
*/
|
||||
static int hlua_applet_tcp_new(lua_State *L, struct appctx *ctx)
|
||||
{
|
||||
struct hlua_appctx *appctx;
|
||||
struct stream_interface *si = ctx->owner;
|
||||
struct stream *s = si_strm(si);
|
||||
struct proxy *p = s->be;
|
||||
|
||||
/* Check stack size. */
|
||||
if (!lua_checkstack(L, 3))
|
||||
return 0;
|
||||
|
||||
/* Create the object: obj[0] = userdata.
|
||||
* Note that the base of the Converters object is the
|
||||
* same than the TXN object.
|
||||
*/
|
||||
lua_newtable(L);
|
||||
appctx = lua_newuserdata(L, sizeof(*appctx));
|
||||
lua_rawseti(L, -2, 0);
|
||||
appctx->appctx = ctx;
|
||||
appctx->htxn.s = s;
|
||||
appctx->htxn.p = p;
|
||||
|
||||
/* Create the "f" field that contains a list of fetches. */
|
||||
lua_pushstring(L, "f");
|
||||
if (!hlua_fetches_new(L, &appctx->htxn, 0))
|
||||
return 0;
|
||||
lua_settable(L, -3);
|
||||
|
||||
/* Create the "sf" field that contains a list of stringsafe fetches. */
|
||||
lua_pushstring(L, "sf");
|
||||
if (!hlua_fetches_new(L, &appctx->htxn, 1))
|
||||
return 0;
|
||||
lua_settable(L, -3);
|
||||
|
||||
/* Create the "c" field that contains a list of converters. */
|
||||
lua_pushstring(L, "c");
|
||||
if (!hlua_converters_new(L, &appctx->htxn, 0))
|
||||
return 0;
|
||||
lua_settable(L, -3);
|
||||
|
||||
/* Create the "sc" field that contains a list of stringsafe converters. */
|
||||
lua_pushstring(L, "sc");
|
||||
if (!hlua_converters_new(L, &appctx->htxn, 1))
|
||||
return 0;
|
||||
lua_settable(L, -3);
|
||||
|
||||
/* Pop a class stream metatable and affect it to the table. */
|
||||
lua_rawgeti(L, LUA_REGISTRYINDEX, class_applet_tcp_ref);
|
||||
lua_setmetatable(L, -2);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* If expected data not yet available, it returns a yield. This function
|
||||
* consumes the data in the buffer. It returns a string containing the
|
||||
* data. This string can be empty.
|
||||
*/
|
||||
__LJMP static int hlua_applet_tcp_getline_yield(lua_State *L, int status, lua_KContext ctx)
|
||||
{
|
||||
struct hlua_appctx *appctx = MAY_LJMP(hlua_checkapplet_tcp(L, 1));
|
||||
struct stream_interface *si = appctx->appctx->owner;
|
||||
int ret;
|
||||
char *blk1;
|
||||
int len1;
|
||||
char *blk2;
|
||||
int len2;
|
||||
|
||||
/* Read the maximum amount of data avalaible. */
|
||||
ret = bo_getline_nc(si_oc(si), &blk1, &len1, &blk2, &len2);
|
||||
|
||||
/* Data not yet avalaible. return yield. */
|
||||
if (ret == 0) {
|
||||
si_applet_cant_get(si);
|
||||
WILL_LJMP(hlua_yieldk(L, 0, 0, hlua_applet_tcp_getline_yield, TICK_ETERNITY, 0));
|
||||
}
|
||||
|
||||
/* End of data: commit the total strings and return. */
|
||||
if (ret < 0) {
|
||||
luaL_pushresult(&appctx->b);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Ensure that the block 2 length is usable. */
|
||||
if (ret == 1)
|
||||
len2 = 0;
|
||||
|
||||
/* dont check the max length read and dont check. */
|
||||
luaL_addlstring(&appctx->b, blk1, len1);
|
||||
luaL_addlstring(&appctx->b, blk2, len2);
|
||||
|
||||
/* Consume input channel output buffer data. */
|
||||
bo_skip(si_oc(si), len1 + len2);
|
||||
luaL_pushresult(&appctx->b);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Check arguments for the fucntion "hlua_channel_get_yield". */
|
||||
__LJMP static int hlua_applet_tcp_getline(lua_State *L)
|
||||
{
|
||||
struct hlua_appctx *appctx = MAY_LJMP(hlua_checkapplet_tcp(L, 1));
|
||||
|
||||
/* Initialise the string catenation. */
|
||||
luaL_buffinit(L, &appctx->b);
|
||||
|
||||
return MAY_LJMP(hlua_applet_tcp_getline_yield(L, 0, 0));
|
||||
}
|
||||
|
||||
/* If expected data not yet available, it returns a yield. This function
|
||||
* consumes the data in the buffer. It returns a string containing the
|
||||
* data. This string can be empty.
|
||||
*/
|
||||
__LJMP static int hlua_applet_tcp_recv_yield(lua_State *L, int status, lua_KContext ctx)
|
||||
{
|
||||
struct hlua_appctx *appctx = MAY_LJMP(hlua_checkapplet_tcp(L, 1));
|
||||
struct stream_interface *si = appctx->appctx->owner;
|
||||
int len = MAY_LJMP(luaL_checkinteger(L, 2));
|
||||
int ret;
|
||||
char *blk1;
|
||||
int len1;
|
||||
char *blk2;
|
||||
int len2;
|
||||
|
||||
/* Read the maximum amount of data avalaible. */
|
||||
ret = bo_getblk_nc(si_oc(si), &blk1, &len1, &blk2, &len2);
|
||||
|
||||
/* Data not yet avalaible. return yield. */
|
||||
if (ret == 0) {
|
||||
si_applet_cant_get(si);
|
||||
WILL_LJMP(hlua_yieldk(L, 0, 0, hlua_applet_tcp_recv_yield, TICK_ETERNITY, 0));
|
||||
}
|
||||
|
||||
/* End of data: commit the total strings and return. */
|
||||
if (ret < 0) {
|
||||
luaL_pushresult(&appctx->b);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Ensure that the block 2 length is usable. */
|
||||
if (ret == 1)
|
||||
len2 = 0;
|
||||
|
||||
if (len == -1) {
|
||||
|
||||
/* If len == -1, catenate all the data avalaile and
|
||||
* yield because we want to get all the data until
|
||||
* the end of data stream.
|
||||
*/
|
||||
luaL_addlstring(&appctx->b, blk1, len1);
|
||||
luaL_addlstring(&appctx->b, blk2, len2);
|
||||
bo_skip(si_oc(si), len1 + len2);
|
||||
si_applet_cant_get(si);
|
||||
WILL_LJMP(hlua_yieldk(L, 0, 0, hlua_applet_tcp_recv_yield, TICK_ETERNITY, 0));
|
||||
|
||||
} else {
|
||||
|
||||
/* Copy the fisrt block caping to the length required. */
|
||||
if (len1 > len)
|
||||
len1 = len;
|
||||
luaL_addlstring(&appctx->b, blk1, len1);
|
||||
len -= len1;
|
||||
|
||||
/* Copy the second block. */
|
||||
if (len2 > len)
|
||||
len2 = len;
|
||||
luaL_addlstring(&appctx->b, blk2, len2);
|
||||
len -= len2;
|
||||
|
||||
/* Consume input channel output buffer data. */
|
||||
bo_skip(si_oc(si), len1 + len2);
|
||||
|
||||
/* If we are no other data avalaible, yield waiting for new data. */
|
||||
if (len > 0) {
|
||||
lua_pushinteger(L, len);
|
||||
lua_replace(L, 2);
|
||||
si_applet_cant_get(si);
|
||||
WILL_LJMP(hlua_yieldk(L, 0, 0, hlua_applet_tcp_recv_yield, TICK_ETERNITY, 0));
|
||||
}
|
||||
|
||||
/* return the result. */
|
||||
luaL_pushresult(&appctx->b);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* we never executes this */
|
||||
hlua_pusherror(L, "Lua: internal error");
|
||||
WILL_LJMP(lua_error(L));
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Check arguments for the fucntion "hlua_channel_get_yield". */
|
||||
__LJMP static int hlua_applet_tcp_recv(lua_State *L)
|
||||
{
|
||||
struct hlua_appctx *appctx = MAY_LJMP(hlua_checkapplet_tcp(L, 1));
|
||||
int len = -1;
|
||||
|
||||
if (lua_gettop(L) > 2)
|
||||
WILL_LJMP(luaL_error(L, "The 'recv' function requires between 1 and 2 arguments."));
|
||||
if (lua_gettop(L) >= 2) {
|
||||
len = MAY_LJMP(luaL_checkinteger(L, 2));
|
||||
lua_pop(L, 1);
|
||||
}
|
||||
|
||||
/* Confirm or set the required length */
|
||||
lua_pushinteger(L, len);
|
||||
|
||||
/* Initialise the string catenation. */
|
||||
luaL_buffinit(L, &appctx->b);
|
||||
|
||||
return MAY_LJMP(hlua_applet_tcp_recv_yield(L, 0, 0));
|
||||
}
|
||||
|
||||
/* Append data in the output side of the buffer. This data is immediatly
|
||||
* sent. The fcuntion returns the ammount of data writed. If the buffer
|
||||
* cannot contains the data, the function yield. The function returns -1
|
||||
* if the channel is closed.
|
||||
*/
|
||||
__LJMP static int hlua_applet_tcp_send_yield(lua_State *L, int status, lua_KContext ctx)
|
||||
{
|
||||
size_t len;
|
||||
struct hlua_appctx *appctx = MAY_LJMP(hlua_checkapplet_tcp(L, 1));
|
||||
const char *str = MAY_LJMP(luaL_checklstring(L, 2, &len));
|
||||
int l = MAY_LJMP(luaL_checkinteger(L, 3));
|
||||
struct stream_interface *si = appctx->appctx->owner;
|
||||
struct channel *chn = si_ic(si);
|
||||
int max;
|
||||
|
||||
/* Get the max amount of data which can write as input in the channel. */
|
||||
max = channel_recv_max(chn);
|
||||
if (max > (len - l))
|
||||
max = len - l;
|
||||
|
||||
/* Copy data. */
|
||||
bi_putblk(chn, str + l, max);
|
||||
|
||||
/* update counters. */
|
||||
l += max;
|
||||
lua_pop(L, 1);
|
||||
lua_pushinteger(L, l);
|
||||
|
||||
/* If some data is not send, declares the situation to the
|
||||
* applet, and returns a yield.
|
||||
*/
|
||||
if (l < len) {
|
||||
si_applet_cant_put(si);
|
||||
WILL_LJMP(hlua_yieldk(L, 0, 0, hlua_applet_tcp_send_yield, TICK_ETERNITY, 0));
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Just a wraper of "hlua_applet_tcp_send_yield". This wrapper permits
|
||||
* yield the LUA process, and resume it without checking the
|
||||
* input arguments.
|
||||
*/
|
||||
__LJMP static int hlua_applet_tcp_send(lua_State *L)
|
||||
{
|
||||
MAY_LJMP(check_args(L, 2, "send"));
|
||||
lua_pushinteger(L, 0);
|
||||
|
||||
return MAY_LJMP(hlua_applet_tcp_send_yield(L, 0, 0));
|
||||
}
|
||||
|
||||
/*
|
||||
*
|
||||
*
|
||||
@ -4624,6 +4911,176 @@ static enum act_return hlua_action(struct act_rule *rule, struct proxy *px,
|
||||
}
|
||||
}
|
||||
|
||||
struct task *hlua_applet_wakeup(struct task *t)
|
||||
{
|
||||
struct appctx *ctx = t->context;
|
||||
struct stream_interface *si = ctx->owner;
|
||||
|
||||
/* If the applet is wake up without any expected work, the sheduler
|
||||
* remove it from the run queue. This flag indicate that the applet
|
||||
* is waiting for write. If the buffer is full, the main processing
|
||||
* will send some data and after call the applet, otherwise it call
|
||||
* the applet ASAP.
|
||||
*/
|
||||
si_applet_cant_put(si);
|
||||
appctx_wakeup(ctx);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int hlua_applet_tcp_init(struct appctx *ctx, struct proxy *px, struct stream *strm)
|
||||
{
|
||||
struct stream_interface *si = ctx->owner;
|
||||
struct hlua *hlua = &ctx->ctx.hlua_apptcp.hlua;
|
||||
struct task *task;
|
||||
char **arg;
|
||||
|
||||
HLUA_INIT(hlua);
|
||||
ctx->ctx.hlua_apptcp.flags = 0;
|
||||
|
||||
/* Create task used by signal to wakeup applets. */
|
||||
task = task_new();
|
||||
if (!task) {
|
||||
SEND_ERR(px, "Lua applet tcp '%s': out of memory.\n",
|
||||
ctx->rule->arg.hlua_rule->fcn.name);
|
||||
return 0;
|
||||
}
|
||||
task->nice = 0;
|
||||
task->context = ctx;
|
||||
task->process = hlua_applet_wakeup;
|
||||
ctx->ctx.hlua_apptcp.task = task;
|
||||
|
||||
/* In the execution wrappers linked with a stream, the
|
||||
* Lua context can be not initialized. This behavior
|
||||
* permits to save performances because a systematic
|
||||
* Lua initialization cause 5% performances loss.
|
||||
*/
|
||||
if (!hlua_ctx_init(hlua, task)) {
|
||||
SEND_ERR(px, "Lua applet tcp '%s': can't initialize Lua context.\n",
|
||||
ctx->rule->arg.hlua_rule->fcn.name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Set timeout according with the applet configuration. */
|
||||
hlua->expire = tick_add_ifset(now_ms, ctx->applet->timeout);
|
||||
|
||||
/* The following Lua calls can fail. */
|
||||
if (!SET_SAFE_LJMP(hlua->T)) {
|
||||
SEND_ERR(px, "Lua applet tcp '%s': critical error.\n",
|
||||
ctx->rule->arg.hlua_rule->fcn.name);
|
||||
RESET_SAFE_LJMP(hlua->T);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Check stack available size. */
|
||||
if (!lua_checkstack(hlua->T, 1)) {
|
||||
SEND_ERR(px, "Lua applet tcp '%s': full stack.\n",
|
||||
ctx->rule->arg.hlua_rule->fcn.name);
|
||||
RESET_SAFE_LJMP(hlua->T);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Restore the function in the stack. */
|
||||
lua_rawgeti(hlua->T, LUA_REGISTRYINDEX, ctx->rule->arg.hlua_rule->fcn.function_ref);
|
||||
|
||||
/* Create and and push object stream in the stack. */
|
||||
if (!hlua_applet_tcp_new(hlua->T, ctx)) {
|
||||
SEND_ERR(px, "Lua applet tcp '%s': full stack.\n",
|
||||
ctx->rule->arg.hlua_rule->fcn.name);
|
||||
RESET_SAFE_LJMP(hlua->T);
|
||||
return 0;
|
||||
}
|
||||
hlua->nargs = 1;
|
||||
|
||||
/* push keywords in the stack. */
|
||||
for (arg = ctx->rule->arg.hlua_rule->args; arg && *arg; arg++) {
|
||||
if (!lua_checkstack(hlua->T, 1)) {
|
||||
SEND_ERR(px, "Lua applet tcp '%s': full stack.\n",
|
||||
ctx->rule->arg.hlua_rule->fcn.name);
|
||||
RESET_SAFE_LJMP(hlua->T);
|
||||
return 0;
|
||||
}
|
||||
lua_pushstring(hlua->T, *arg);
|
||||
hlua->nargs++;
|
||||
}
|
||||
|
||||
RESET_SAFE_LJMP(hlua->T);
|
||||
|
||||
/* Wakeup the applet ASAP. */
|
||||
si_applet_cant_get(si);
|
||||
si_applet_cant_put(si);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void hlua_applet_tcp_fct(struct appctx *ctx)
|
||||
{
|
||||
struct stream_interface *si = ctx->owner;
|
||||
struct stream *strm = si_strm(si);
|
||||
struct channel *res = si_ic(si);
|
||||
struct act_rule *rule = ctx->rule;
|
||||
struct proxy *px = strm->be;
|
||||
struct hlua *hlua = &ctx->ctx.hlua_apptcp.hlua;
|
||||
|
||||
/* The applet execution is already done. */
|
||||
if (ctx->ctx.hlua_apptcp.flags & APPLET_DONE)
|
||||
return;
|
||||
|
||||
/* If the stream is disconnect or closed, ldo nothing. */
|
||||
if (unlikely(si->state == SI_ST_DIS || si->state == SI_ST_CLO))
|
||||
return;
|
||||
|
||||
/* Execute the function. */
|
||||
switch (hlua_ctx_resume(hlua, 1)) {
|
||||
/* finished. */
|
||||
case HLUA_E_OK:
|
||||
ctx->ctx.hlua_apptcp.flags |= APPLET_DONE;
|
||||
|
||||
/* log time */
|
||||
strm->logs.tv_request = now;
|
||||
|
||||
/* eat the whole request */
|
||||
bo_skip(si_oc(si), si_ob(si)->o);
|
||||
res->flags |= CF_READ_NULL;
|
||||
si_shutr(si);
|
||||
return;
|
||||
|
||||
/* yield. */
|
||||
case HLUA_E_AGAIN:
|
||||
return;
|
||||
|
||||
/* finished with error. */
|
||||
case HLUA_E_ERRMSG:
|
||||
/* Display log. */
|
||||
SEND_ERR(px, "Lua applet tcp '%s': %s.\n",
|
||||
rule->arg.hlua_rule->fcn.name, lua_tostring(hlua->T, -1));
|
||||
lua_pop(hlua->T, 1);
|
||||
goto error;
|
||||
|
||||
case HLUA_E_ERR:
|
||||
/* Display log. */
|
||||
SEND_ERR(px, "Lua applet tcp '%s' return an unknown error.\n",
|
||||
rule->arg.hlua_rule->fcn.name);
|
||||
goto error;
|
||||
|
||||
default:
|
||||
goto error;
|
||||
}
|
||||
|
||||
error:
|
||||
|
||||
/* For all other cases, just close the stream. */
|
||||
si_shutw(si);
|
||||
si_shutr(si);
|
||||
ctx->ctx.hlua_apptcp.flags |= APPLET_DONE;
|
||||
}
|
||||
|
||||
static void hlua_applet_tcp_release(struct appctx *ctx)
|
||||
{
|
||||
task_free(ctx->ctx.hlua_apptcp.task);
|
||||
ctx->ctx.hlua_apptcp.task = NULL;
|
||||
hlua_ctx_destroy(&ctx->ctx.hlua_apptcp.hlua);
|
||||
}
|
||||
|
||||
/* global {tcp|http}-request parser. Return ACT_RET_PRS_OK in
|
||||
* succes case, else return ACT_RET_PRS_ERR.
|
||||
*
|
||||
@ -4731,6 +5188,103 @@ __LJMP static int hlua_register_action(lua_State *L)
|
||||
/* pop the environment string. */
|
||||
lua_pop(L, 1);
|
||||
}
|
||||
return ACT_RET_PRS_OK;
|
||||
}
|
||||
|
||||
static enum act_parse_ret action_register_service_tcp(const char **args, int *cur_arg, struct proxy *px,
|
||||
struct act_rule *rule, char **err)
|
||||
{
|
||||
struct hlua_function *fcn = (struct hlua_function *)rule->kw->private;
|
||||
|
||||
/* Memory for the rule. */
|
||||
rule->arg.hlua_rule = calloc(1, sizeof(*rule->arg.hlua_rule));
|
||||
if (!rule->arg.hlua_rule) {
|
||||
memprintf(err, "out of memory error");
|
||||
return ACT_RET_PRS_ERR;
|
||||
}
|
||||
|
||||
/* Reference the Lua function and store the reference. */
|
||||
rule->arg.hlua_rule->fcn = *fcn;
|
||||
|
||||
/* TODO: later accept arguments. */
|
||||
rule->arg.hlua_rule->args = NULL;
|
||||
|
||||
/* Add applet pointer in the rule. */
|
||||
rule->applet.obj_type = OBJ_TYPE_APPLET;
|
||||
rule->applet.name = fcn->name;
|
||||
rule->applet.init = hlua_applet_tcp_init;
|
||||
rule->applet.fct = hlua_applet_tcp_fct;
|
||||
rule->applet.release = hlua_applet_tcp_release;
|
||||
rule->applet.timeout = hlua_timeout_applet;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* This function is an LUA binding used for registering
|
||||
* "sample-conv" functions. It expects a converter name used
|
||||
* in the haproxy configuration file, and an LUA function.
|
||||
*/
|
||||
__LJMP static int hlua_register_service(lua_State *L)
|
||||
{
|
||||
struct action_kw_list *akl;
|
||||
const char *name;
|
||||
const char *env;
|
||||
int ref;
|
||||
int len;
|
||||
struct hlua_function *fcn;
|
||||
|
||||
MAY_LJMP(check_args(L, 3, "register_service"));
|
||||
|
||||
/* First argument : converter name. */
|
||||
name = MAY_LJMP(luaL_checkstring(L, 1));
|
||||
|
||||
/* Second argument : environment. */
|
||||
env = MAY_LJMP(luaL_checkstring(L, 2));
|
||||
|
||||
/* Third argument : lua function. */
|
||||
ref = MAY_LJMP(hlua_checkfunction(L, 3));
|
||||
|
||||
/* Check required environment. Only accepted "http" or "tcp". */
|
||||
/* Allocate and fill the sample fetch keyword struct. */
|
||||
akl = calloc(1, sizeof(*akl) + sizeof(struct action_kw) * 2);
|
||||
if (!akl)
|
||||
WILL_LJMP(luaL_error(L, "lua out of memory error."));
|
||||
fcn = calloc(1, sizeof(*fcn));
|
||||
if (!fcn)
|
||||
WILL_LJMP(luaL_error(L, "lua out of memory error."));
|
||||
|
||||
/* Fill fcn. */
|
||||
len = strlen("<lua.>") + strlen(name) + 1;
|
||||
fcn->name = calloc(1, len);
|
||||
if (!fcn->name)
|
||||
WILL_LJMP(luaL_error(L, "lua out of memory error."));
|
||||
snprintf((char *)fcn->name, len, "<lua.%s>", name);
|
||||
fcn->function_ref = ref;
|
||||
|
||||
/* List head */
|
||||
akl->list.n = akl->list.p = NULL;
|
||||
|
||||
/* converter keyword. */
|
||||
len = strlen("lua.") + strlen(name) + 1;
|
||||
akl->kw[0].kw = calloc(1, len);
|
||||
if (!akl->kw[0].kw)
|
||||
WILL_LJMP(luaL_error(L, "lua out of memory error."));
|
||||
|
||||
snprintf((char *)akl->kw[0].kw, len, "lua.%s", name);
|
||||
|
||||
if (strcmp(env, "tcp") == 0)
|
||||
akl->kw[0].parse = action_register_service_tcp;
|
||||
else
|
||||
WILL_LJMP(luaL_error(L, "lua service environment '%s' is unknown. 'tcp' is expected."));
|
||||
|
||||
akl->kw[0].match_pfx = 0;
|
||||
akl->kw[0].private = fcn;
|
||||
|
||||
/* End of array. */
|
||||
memset(&akl->kw[1], 0, sizeof(*akl->kw));
|
||||
|
||||
/* Register this new converter */
|
||||
service_keywords_register(akl);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -4765,6 +5319,14 @@ static int hlua_task_timeout(char **args, int section_type, struct proxy *curpx,
|
||||
file, line, err, &hlua_timeout_task);
|
||||
}
|
||||
|
||||
static int hlua_applet_timeout(char **args, int section_type, struct proxy *curpx,
|
||||
struct proxy *defpx, const char *file, int line,
|
||||
char **err)
|
||||
{
|
||||
return hlua_read_timeout(args, section_type, curpx, defpx,
|
||||
file, line, err, &hlua_timeout_applet);
|
||||
}
|
||||
|
||||
static int hlua_forced_yield(char **args, int section_type, struct proxy *curpx,
|
||||
struct proxy *defpx, const char *file, int line,
|
||||
char **err)
|
||||
@ -4860,6 +5422,7 @@ static struct cfg_kw_list cfg_kws = {{ },{
|
||||
{ CFG_GLOBAL, "lua-load", hlua_load },
|
||||
{ CFG_GLOBAL, "tune.lua.session-timeout", hlua_session_timeout },
|
||||
{ CFG_GLOBAL, "tune.lua.task-timeout", hlua_task_timeout },
|
||||
{ CFG_GLOBAL, "tune.lua.applet-timeout", hlua_applet_timeout },
|
||||
{ CFG_GLOBAL, "tune.lua.forced-yield", hlua_forced_yield },
|
||||
{ CFG_GLOBAL, "tune.lua.maxmem", hlua_parse_maxmem },
|
||||
{ 0, NULL, NULL },
|
||||
@ -5005,6 +5568,7 @@ void hlua_init(void)
|
||||
hlua_class_function(gL.T, "register_fetches", hlua_register_fetches);
|
||||
hlua_class_function(gL.T, "register_converters", hlua_register_converters);
|
||||
hlua_class_function(gL.T, "register_action", hlua_register_action);
|
||||
hlua_class_function(gL.T, "register_service", hlua_register_service);
|
||||
hlua_class_function(gL.T, "yield", hlua_yield);
|
||||
hlua_class_function(gL.T, "set_nice", hlua_set_nice);
|
||||
hlua_class_function(gL.T, "sleep", hlua_sleep);
|
||||
@ -5262,6 +5826,37 @@ void hlua_init(void)
|
||||
lua_setfield(gL.T, LUA_REGISTRYINDEX, CLASS_HTTP); /* register class session. */
|
||||
class_http_ref = luaL_ref(gL.T, LUA_REGISTRYINDEX); /* reference class session. */
|
||||
|
||||
/*
|
||||
*
|
||||
* Register class AppletTCP
|
||||
*
|
||||
*/
|
||||
|
||||
/* Create and fill the metatable. */
|
||||
lua_newtable(gL.T);
|
||||
|
||||
/* Create the __tostring identifier */
|
||||
lua_pushstring(gL.T, "__tostring");
|
||||
lua_pushstring(gL.T, CLASS_APPLET_TCP);
|
||||
lua_pushcclosure(gL.T, hlua_dump_object, 1);
|
||||
lua_rawset(gL.T, -3);
|
||||
|
||||
/* Create and fille the __index entry. */
|
||||
lua_pushstring(gL.T, "__index");
|
||||
lua_newtable(gL.T);
|
||||
|
||||
/* Register Lua functions. */
|
||||
hlua_class_function(gL.T, "getline", hlua_applet_tcp_getline);
|
||||
hlua_class_function(gL.T, "receive", hlua_applet_tcp_recv);
|
||||
hlua_class_function(gL.T, "send", hlua_applet_tcp_send);
|
||||
|
||||
lua_settable(gL.T, -3);
|
||||
|
||||
/* Register previous table in the registry with reference and named entry. */
|
||||
lua_pushvalue(gL.T, -1); /* Copy the -1 entry and push it on the stack. */
|
||||
lua_setfield(gL.T, LUA_REGISTRYINDEX, CLASS_APPLET_TCP); /* register class session. */
|
||||
class_applet_tcp_ref = luaL_ref(gL.T, LUA_REGISTRYINDEX); /* reference class session. */
|
||||
|
||||
/*
|
||||
*
|
||||
* Register class TXN
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user