diff --git a/docs/changes.txt b/docs/changes.txt index 3f5b767..76d76bb 100644 --- a/docs/changes.txt +++ b/docs/changes.txt @@ -74,3 +74,7 @@ v0.6 * nfqws2: reasm support negative overlaps. gaps are not supported. * nfqws2,zapret-auto: changed retransmission detection scheme. * zapret-auto: udp_in/udp_out failure detection + +v0.6.1 + +* zapret-lib, zapret-auto: condition and stopif orchestrators diff --git a/lua/zapret-auto.lua b/lua/zapret-auto.lua index 7e9115f..0ea49bb 100644 --- a/lua/zapret-auto.lua +++ b/lua/zapret-auto.lua @@ -255,3 +255,54 @@ function circular(ctx, desync) return verdict end + +-- test iff functions +function cond_true(desync) + return true +end +function cond_false(desync) + return false +end +-- arg: percent - of true . 50 by default +function cond_random(desync) + return math.random(0,99)<(tonumber(desync.arg.percent) or 50) +end +-- check iff function available. error if not +function require_iff(desync, name) + if not desync.arg.iff then + error(name..": missing 'iff' function") + end + if type(_G[desync.arg.iff])~="function" then + error(name..": invalid 'iff' function '"..desync.arg.iff.."'") + end +end +-- execute further desync instances only if user-provided 'iff' function returns true +-- for example, this can be used by custom protocol detectors +-- arg: iff - condition function. takes desync as arg and returns bool. (cant use 'if' because of reserved word) +-- arg: neg - invert condition function result +function condition(ctx, desync) + require_iff(desync, "condition") + orchestrate(ctx, desync) + if logical_xor(_G[desync.arg.iff](desync), desync.arg.neg) then + DLOG("condition: true") + return replay_execution_plan(desync) + else + DLOG("condition: false") + plan_clear(desync) + end +end +-- clear execution plan if user provided 'iff' functions returns true +-- can be used with other orchestrators to stop execution conditionally +-- arg: iff - condition function. takes desync as arg and returns bool. (cant use 'if' because of reserved word) +-- arg: neg - invert condition function result +function stopif(ctx, desync) + require_iff(desync, "stopif") + orchestrate(ctx, desync) + if logical_xor(_G[desync.arg.iff](desync), desync.arg.neg) then + DLOG("stopif: true") + plan_clear(desync) + else + -- do not do anything. allow other orchestrator to finish the plan + DLOG("stopif: false") + end +end diff --git a/lua/zapret-lib.lua b/lua/zapret-lib.lua index 30c9c37..f1e75bb 100644 --- a/lua/zapret-lib.lua +++ b/lua/zapret-lib.lua @@ -156,6 +156,9 @@ end function plan_instance_pop(desync) return (desync.plan and #desync.plan>0) and table.remove(desync.plan, 1) end +function plan_clear(desync) + while table.remove(desync.plan) do end +end -- this approach allows nested orchestrators function orchestrate(ctx, desync) if not desync.plan then @@ -170,6 +173,10 @@ function desync_copy(desync) -- preserve lua state dcopy.track.lua_state = desync.track.lua_state end + if desync.plan then + -- preserve execution plan + dcopy.plan = desync.plan + end return dcopy end -- redo what whould be done without orchestration @@ -318,6 +325,9 @@ function str_or_hex(s) return s end end +function logical_xor(a,b) + return a and not b or not a and b +end -- print to DLOG any variable. tables are expanded in the tree form, unprintables strings are hex dumped function var_debug(v) local function dbg(v,level)