nfqws2: timers

This commit is contained in:
bol-van
2026-04-12 17:41:47 +03:00
parent fe85c6d2db
commit 3364294af6
15 changed files with 417 additions and 56 deletions
+4
View File
@@ -280,3 +280,7 @@ v0.9.4.3
0.9.4.7
* nfqws2: do not fail tls_mod if dupsid,rndsni,padencap fail
0.9.5
* nfqws2: timers
+18 -1
View File
@@ -15,7 +15,7 @@ end
function test_all(...)
test_run({
test_crypto, test_bin, test_time, test_gzip, test_ipstr, test_dissect, test_csum, test_resolve,
test_get_source_ip, test_ifaddrs, test_rawsend},...)
test_get_source_ip, test_ifaddrs, test_rawsend, test_timer},...)
end
@@ -907,6 +907,23 @@ function test_ifaddrs(opts)
end
end
function timer1(name, data)
print("timer "..name.." fired. data="..tostring(data))
end
function timer2(name, data)
data.n = data.n+1
print("timer "..name.." fired. data.n="..tostring(data.n))
if data.n>=3 then
timer_del(name)
end
end
function test_timer(opts)
timer_set("t1","timer1",500,true,"sample_data");
tbl = {n=0}
timer_set("t2","timer2",700,false,tbl);
end
function test_rawsend(opts)
print("* rawsend")
+32 -7
View File
@@ -1627,14 +1627,33 @@ static bool windivert_recv_exit(void)
}
return false;
}
static bool windivert_recv_filter(HANDLE hFilter, uint8_t *packet, size_t *len, WINDIVERT_ADDRESS *wa, unsigned int *wa_count)
static DWORD win_timer_check(t_timer_callback timer_callback, uint64_t *bt_prev)
{
uint64_t bt,dbt;
bt = boottime_ms();
dbt = bt-*bt_prev;
if (dbt>=params.timer_res)
{
timer_callback(bt);
*bt_prev = bt;
return params.timer_res;
}
else
return params.timer_res-(int)dbt;
}
static bool windivert_recv_filter(HANDLE hFilter, uint8_t *packet, size_t *len, WINDIVERT_ADDRESS *wa, unsigned int *wa_count, t_timer_callback timer_callback, uint64_t *bt_prev)
{
UINT recv_len;
DWORD rd;
DWORD rd,twait,tmax;
unsigned int wac;
if (windivert_recv_exit()) return false;
tmax = win_timer_check(timer_callback, bt_prev);
wac = *wa_count * sizeof(WINDIVERT_ADDRESS);
if (WinDivertRecvEx(hFilter, packet, *len, &recv_len, 0, wa, &wac, &ovl))
{
@@ -1647,10 +1666,16 @@ static bool windivert_recv_filter(HANDLE hFilter, uint8_t *packet, size_t *len,
switch(w_win32_error)
{
case ERROR_IO_PENDING:
// make signals working
while (WaitForSingleObject(ovl.hEvent,50)==WAIT_TIMEOUT)
// need to check for signals periodically
for(;;)
{
if (windivert_recv_exit()) return false;
twait = tmax>50 ? 50 : tmax;
tmax -= twait;
// make signals working
if (WaitForSingleObject(ovl.hEvent,twait)!=WAIT_TIMEOUT) break;
if (windivert_recv_exit())
return false;
if (!tmax) tmax = win_timer_check(timer_callback, bt_prev);
}
if (!GetOverlappedResult(hFilter,&ovl,&rd,FALSE))
{
@@ -1675,9 +1700,9 @@ cancel:
GetOverlappedResult(hFilter, &ovl, &rd, TRUE);
return false;
}
bool windivert_recv(uint8_t *packet, size_t *len, WINDIVERT_ADDRESS *wa, unsigned int *wa_count)
bool windivert_recv(uint8_t *packet, size_t *len, WINDIVERT_ADDRESS *wa, unsigned int *wa_count, t_timer_callback timer_callback, uint64_t *bt_prev)
{
return windivert_recv_filter(w_filter,packet,len,wa,wa_count);
return windivert_recv_filter(w_filter,packet,len,wa,wa_count,timer_callback,bt_prev);
}
static bool windivert_send_filter(HANDLE hFilter, const uint8_t *packet, size_t len, const WINDIVERT_ADDRESS *wa)
+2 -1
View File
@@ -135,7 +135,8 @@ bool logical_net_filter_present(void);
bool logical_net_filter_match(void);
bool nlm_list(bool bAll);
bool windivert_init(const char *filter);
bool windivert_recv(uint8_t *packet, size_t *len, WINDIVERT_ADDRESS *wa, unsigned int *wa_count);
typedef void (*t_timer_callback)(uint64_t bt);
bool windivert_recv(uint8_t *packet, size_t *len, WINDIVERT_ADDRESS *wa, unsigned int *wa_count, t_timer_callback timer_callback, uint64_t *bt_prev);
bool windivert_send(const uint8_t *packet, size_t len, const WINDIVERT_ADDRESS *wa);
#else
#define ensure_dir_access(dir) ensure_file_access(dir)
+8
View File
@@ -739,6 +739,14 @@ time_t boottime(void)
struct timespec ts;
return clock_gettime(CLOCK_BOOT_OR_UPTIME, &ts) ? 0 : ts.tv_sec;
}
uint64_t boottime_ms(void)
{
struct timespec ts;
if (clock_gettime(CLOCK_BOOT_OR_UPTIME, &ts))
return 0;
else
return ts.tv_sec*1000ULL + ts.tv_nsec/1000000;
}
#ifdef __CYGWIN__
+1
View File
@@ -122,6 +122,7 @@ bool parse_int16(const char *p, int16_t *v);
#endif
time_t boottime(void);
uint64_t boottime_ms(void);
#ifdef __CYGWIN__
uint32_t mask_from_bitcount(uint32_t zct);
+61 -1
View File
@@ -3787,6 +3787,60 @@ static int luacall_timegm(lua_State *L)
return 1;
}
static int luacall_timer_set(lua_State *L)
{
// timer_set(name, func, period, oneshot, data)
lua_check_argc_range(L,"timer_set",3,5);
LUA_STACK_GUARD_ENTER(L)
int argc=lua_gettop(L);
const char *name = luaL_checkstring(L,1);
const char *func = luaL_checkstring(L,2);
lua_Integer period = luaL_checkinteger(L,3);
if (period<10) luaL_error(L,"invalid timer period. must be >=10 ms");
bool oneshot = argc>=4 && lua_toboolean(L,4);
lua_getglobal(L, func);
bool is_f = lua_isfunction(L, -1);
lua_pop(L, 1);
if (!is_f) luaL_error(L, "timer function '%s' does not exist", func);
timer_pool *timer = TimerPoolSearch(params.timers, name);
if (timer) luaL_error(L,"timer '%s' already present", name);
timer = TimerPoolAdd(&params.timers, name, func, period, oneshot);
if (!timer) luaL_error(L,"could not create timer");
if (argc>=5)
{
lua_pushvalue(L, 5);
timer->lua_ref = luaL_ref(L, LUA_REGISTRYINDEX);
}
DLOG("timer: '%s' created. function '%s' period %llu oneshot %u\n", timer->str, timer->func, timer->period, timer->oneshot);
LUA_STACK_GUARD_RETURN(L,0)
}
static int luacall_timer_del(lua_State *L)
{
// timer_del(name)
lua_check_argc(L,"timer_del",1);
LUA_STACK_GUARD_ENTER(L)
const char *name = luaL_checkstring(L,1);
timer_pool *timer = TimerPoolSearch(params.timers, name);
if (timer)
{
DLOG("timer: '%s' deleted\n", timer->str);
TimerPoolDel(&params.timers, timer);
}
else
DLOG("timer: '%s' not found\n", timer->str);
lua_pushboolean(L, !!timer);
LUA_STACK_GUARD_RETURN(L,1)
}
// ----------------------------------------
void lua_cleanup(lua_State *L)
@@ -3794,6 +3848,8 @@ void lua_cleanup(lua_State *L)
lua_desync_ctx_destroy(L);
// conntrack holds lua state. must clear it before lua shoudown
ConntrackPoolDestroy(&params.conntrack);
// timer can hold custom lua object
TimerPoolDestroy(&params.timers);
}
void lua_shutdown()
@@ -4438,7 +4494,11 @@ static void lua_init_functions(void)
{"localtime",luacall_localtime},
{"gmtime",luacall_gmtime},
{"timelocal",luacall_timelocal},
{"timegm",luacall_timegm}
{"timegm",luacall_timegm},
// timers
{"timer_set",luacall_timer_set},
{"timer_del",luacall_timer_del}
};
for(int i=0;i<(sizeof(lfunc)/sizeof(*lfunc));i++)
lua_register(params.L,lfunc[i].name,lfunc[i].f);
+1 -1
View File
@@ -4,7 +4,7 @@
#include <stdint.h>
#ifdef LUAJIT
#include "luajit.h"
#include <luajit.h>
#else
#include <lua.h>
#endif
+114 -18
View File
@@ -11,6 +11,7 @@
#include "ipset.h"
#include "gzip.h"
#include "pools.h"
#include "timer.h"
#include "lua.h"
#include "crypto/aes.h"
@@ -239,6 +240,28 @@ static int write_pidfile(FILE **Fpid)
return true;
}
void NoInterceptLoop(void)
{
useconds_t usec = params.timer_res * 1000;
if (params.timers)
{
DLOG("processing timers\n");
while(params.timers)
{
if (bQuit) goto quit;
usleep(usec);
if (bQuit) goto quit;
ReloadCheck();
lua_do_gc();
TimerPoolRun(&params.timers, 0);
}
}
quit:
DLOG_CONDUP("quit requested\n");
}
#ifdef __linux__
@@ -417,6 +440,9 @@ static int nfq_main(void)
FILE *Fpid = NULL;
uint8_t *buf=NULL, *mod=NULL;
struct nfq_cb_data cbdata = { .sock = -1, .mod = NULL };
fd_set fdset;
struct timeval tv = {.tv_sec = params.timer_res/1000, .tv_usec = params.timer_res%1000*1000};
unsigned int bt,bt_prev,dbt;
if (*params.pidfile && !(Fpid = fopen(params.pidfile, "w")))
{
@@ -454,6 +480,7 @@ static int nfq_main(void)
if (!params.intercept)
{
NoInterceptLoop();
DLOG_CONDUP("no intercept quit\n");
goto exok;
}
@@ -491,26 +518,58 @@ static int nfq_main(void)
notify_ready();
fd = nfq_fd(h);
bt_prev=0;
do
{
if (bQuit) goto quit;
while ((rd = recv(fd, buf, NFQ_MAX_RECV_SIZE, 0)) >= 0)
for(;;)
{
if (!rd)
FD_ZERO(&fdset);
FD_SET(fd, &fdset);
res = select(fd+1, &fdset, NULL, NULL, &tv);
if (bQuit) goto quit;
if (res == -1)
{
DLOG_ERR("recv from nfq returned 0 !\n");
if (errno == EINTR) continue;
DLOG_PERROR("select");
goto err;
}
ReloadCheck();
lua_do_gc();
ReloadCheck();
if (res)
{
rd = recv(fd, buf, NFQ_MAX_RECV_SIZE, 0);
if (rd<0) break;
if (!rd)
{
DLOG_ERR("recv from nfq returned 0 !\n");
goto err;
}
#ifdef HAS_FILTER_SSID
if (params.filter_ssid_present)
if (!wlan_info_get_rate_limited())
DLOG_ERR("cannot get wlan info\n");
if (params.filter_ssid_present)
if (!wlan_info_get_rate_limited())
DLOG_ERR("cannot get wlan info\n");
#endif
int r = nfq_handle_packet(h, (char *)buf, (int)rd);
if (r<0) DLOG_ERR("nfq_handle_packet result %d, errno %d : %s\n", r, errno, strerror(errno));
if (bQuit) goto quit;
res = nfq_handle_packet(h, (char *)buf, (int)rd);
if (res<0) DLOG_ERR("nfq_handle_packet result %d, errno %d : %s\n", res, errno, strerror(errno));
}
bt = boottime_ms();
dbt = bt-bt_prev;
if (dbt>=params.timer_res)
{
TimerPoolRun(&params.timers, bt);
bt_prev = bt;
tv.tv_sec = params.timer_res/1000;
tv.tv_usec = params.timer_res%1000*1000;
}
else
{
dbt = params.timer_res-dbt;
tv.tv_sec = (time_t)(dbt/1000);
tv.tv_usec = (suseconds_t)(dbt%1000*1000);
}
}
if (errno==EINTR)
continue;
@@ -553,11 +612,13 @@ static int dvt_main(void)
unsigned int id = 0;
socklen_t socklen;
ssize_t rd, wr;
fd_set fdset;
FILE *Fpid = NULL;
struct sockaddr_in bp4;
struct sockaddr_in6 bp6;
uint8_t buf[RECONSTRUCT_MAX_SIZE] __attribute__((aligned));
fd_set fdset;
struct timeval tv = {.tv_sec = params.timer_res/1000, .tv_usec = params.timer_res%1000*1000};
unsigned int bt,bt_prev,dbt;
if (*params.pidfile && !(Fpid = fopen(params.pidfile, "w")))
{
@@ -633,6 +694,7 @@ static int dvt_main(void)
if (!params.intercept)
{
NoInterceptLoop();
DLOG("no intercept quit\n");
goto exitok;
}
@@ -640,7 +702,7 @@ static int dvt_main(void)
if (params.daemon) daemonize();
if (!write_pidfile(&Fpid)) goto exiterr;
for (;;)
for (bt_prev=0;;)
{
if (bQuit)
{
@@ -649,7 +711,7 @@ static int dvt_main(void)
}
FD_ZERO(&fdset);
for (i = 0; i < fdct; i++) FD_SET(fd[i], &fdset);
r = select(fdmax, &fdset, NULL, NULL, NULL);
r = select(fdmax, &fdset, NULL, NULL, &tv);
if (bQuit)
{
DLOG_CONDUP("quit requested\n");
@@ -661,6 +723,8 @@ static int dvt_main(void)
DLOG_PERROR("select");
goto exiterr;
}
ReloadCheck();
lua_do_gc();
for (i = 0; i < fdct; i++)
{
if (FD_ISSET(fd[i], &fdset))
@@ -680,9 +744,6 @@ static int dvt_main(void)
size_t modlen, len = rd;
const char *ifin, *ifout;
ReloadCheck();
lua_do_gc();
// in any BSD addr of incoming packet is set to the first addr of the interface. addr of outgoing packet is set to zero
bool bIncoming = sa_has_addr((struct sockaddr*)&sa_from);
ifin = bIncoming ? "unknown" : "";
@@ -734,6 +795,22 @@ static int dvt_main(void)
}
}
}
bt = boottime_ms();
dbt = bt-bt_prev;
if (dbt>=params.timer_res)
{
TimerPoolRun(&params.timers, bt);
bt_prev = bt;
tv.tv_sec = params.timer_res/1000;
tv.tv_usec = params.timer_res%1000*1000;
}
else
{
dbt = params.timer_res-dbt;
tv.tv_sec = (time_t)(dbt/1000);
tv.tv_usec = (suseconds_t)(dbt%1000*1000);
}
}
exitok:
@@ -754,7 +831,12 @@ exiterr:
// do not make it less than 65536 - loopback packets can be up to 64K
#define WINDIVERT_PACKET_BUF_SIZE 196608 // 3*64K, 128*1500=192000
static int win_main()
static void win_timer_callback(uint64_t bt)
{
TimerPoolRun(&params.timers, bt);
}
static int win_main(void)
{
size_t len, packet_len, left, modlen;
unsigned int id;
@@ -766,6 +848,7 @@ static int win_main()
WINDIVERT_ADDRESS wa[WINDIVERT_BULK_MAX];
uint8_t *packets = NULL, *packet, *mod=NULL;
unsigned int n,wa_count;
uint64_t bt_prev = 0;
// windows emulated fork logic does not cover objects outside of cygwin world. have to daemonize before inits
if (params.daemon) daemonize();
@@ -830,6 +913,7 @@ static int win_main()
if (!params.intercept)
{
NoInterceptLoop();
DLOG("no intercept quit\n");
goto ex;
}
@@ -838,7 +922,7 @@ static int win_main()
{
len = WINDIVERT_PACKET_BUF_SIZE;
wa_count = WINDIVERT_BULK_MAX;
if (!windivert_recv(packets, &len, wa, &wa_count))
if (!windivert_recv(packets, &len, wa, &wa_count, win_timer_callback, &bt_prev))
{
if (errno == ENOBUFS)
{
@@ -1743,6 +1827,7 @@ static void exithelp(void)
" --ipcache-lifetime=<int>\t\t\t\t; time in seconds to keep cached hop count and domain name (default %u). 0 = no expiration\n"
" --ipcache-hostname=[0|1]\t\t\t\t; 1 or no argument enables ip->hostname caching\n"
" --reasm-disable=[type[,type]]\t\t\t\t; disable reasm for these L7 payloads : tls_client_hello quic_initial . if no argument - disable all reasm.\n"
" --timer-res=msec\t\t\t\t\t; Lua timer resolution. default %d ms\n"
#ifdef __CYGWIN__
"\nWINDIVERT FILTER:\n"
" --wf-iface=<int>[.<int>]\t\t\t\t; numeric network interface and subinterface indexes\n"
@@ -1818,6 +1903,7 @@ static void exithelp(void)
#endif
CTRACK_T_SYN, CTRACK_T_EST, CTRACK_T_FIN, CTRACK_T_UDP,
IPCACHE_LIFETIME,
TIMER_RES_DEFAULT,
LUA_GC_INTERVAL,
all_protos,
HOSTLIST_AUTO_FAIL_THRESHOLD_DEFAULT, HOSTLIST_AUTO_FAIL_TIME_DEFAULT,
@@ -1900,6 +1986,7 @@ enum opt_indices {
IDX_IPCACHE_LIFETIME,
IDX_IPCACHE_HOSTNAME,
IDX_REASM_DISABLE,
IDX_TIMER_RES,
#ifdef __linux__
IDX_FWMARK,
#elif defined(SO_USER_COOKIE)
@@ -2005,6 +2092,7 @@ static const struct option long_options[] = {
[IDX_IPCACHE_LIFETIME] = {"ipcache-lifetime", required_argument, 0, 0},
[IDX_IPCACHE_HOSTNAME] = {"ipcache-hostname", optional_argument, 0, 0},
[IDX_REASM_DISABLE] = {"reasm-disable", optional_argument, 0, 0},
[IDX_TIMER_RES] = {"timer-res", required_argument, 0, 0},
#ifdef __linux__
[IDX_FWMARK] = {"fwmark", required_argument, 0, 0},
#elif defined(SO_USER_COOKIE)
@@ -2407,6 +2495,14 @@ int main(int argc, char **argv)
else
params.reasm_payload_disable = L7P_ALL;
break;
case IDX_TIMER_RES:
params.timer_res = atoi(optarg);
if (params.timer_res<10)
{
DLOG_ERR("Invalid timer resolution. must be >=10 ms\n");
exit_clean(1);
}
break;
#if defined(__linux__)
case IDX_FWMARK:
#elif defined(SO_USER_COOKIE)
+2
View File
@@ -559,6 +559,7 @@ void cleanup_params(struct params_s *params)
ipcacheDestroy(&params->ipcache);
blob_collection_destroy(&params->blobs);
strlist_destroy(&params->lua_init_scripts);
TimerPoolDestroy(&params->timers);
#ifdef __CYGWIN__
strlist_destroy(&params->ssid_filter);
@@ -587,6 +588,7 @@ void init_params(struct params_s *params)
params->ctrack_t_fin = CTRACK_T_FIN;
params->ctrack_t_udp = CTRACK_T_UDP;
params->ipcache_lifetime = IPCACHE_LIFETIME;
params->timer_res = TIMER_RES_DEFAULT;
params->lua_gc = LUA_GC_INTERVAL;
LIST_INIT(&params->hostlists);
+6
View File
@@ -7,6 +7,7 @@
#include "protocol.h"
#include "helpers.h"
#include "sec.h"
#include "timer.h"
#include <sys/param.h>
#include <sys/types.h>
@@ -36,6 +37,8 @@
#define IPCACHE_LIFETIME 7200
#define TIMER_RES_DEFAULT 50
#define MAX_GIDS 64
#define MAX_BLOB_SIZE (16*1024)
@@ -192,6 +195,9 @@ struct params_s
bool writeable_dir_enable;
char writeable_dir[PATH_MAX];
int timer_res; // timer resolution in msec
timer_pool *timers;
int lua_gc;
int ref_desync_ctx; // desync ctx userdata registry ref
lua_State *L;
-27
View File
@@ -5,33 +5,6 @@
#include <stdio.h>
#include <arpa/inet.h>
#define DESTROY_STR_POOL(etype, ppool) \
etype *elem, *tmp; \
HASH_ITER(hh, *ppool, elem, tmp) { \
free(elem->str); \
HASH_DEL(*ppool, elem); \
free(elem); \
}
#define ADD_STR_POOL(etype, ppool, keystr, keystr_len) \
etype *elem; \
if (!(elem = (etype*)malloc(sizeof(etype)))) \
return false; \
if (!(elem->str = malloc(keystr_len + 1))) \
{ \
free(elem); \
return false; \
} \
memcpy(elem->str, keystr, keystr_len); \
elem->str[keystr_len] = 0; \
oom = false; \
HASH_ADD_KEYPTR(hh, *ppool, elem->str, keystr_len, elem); \
if (oom) \
{ \
free(elem->str); \
free(elem); \
return false; \
}
#define ADD_HOSTLIST_POOL(etype, ppool, keystr, keystr_len, flg) \
etype *elem_find; \
HASH_FIND(hh, *ppool, keystr, keystr_len, elem_find); \
+28
View File
@@ -27,6 +27,34 @@
else \
LIST_INSERT_HEAD(head, elm, field); }
#define DESTROY_STR_POOL(etype, ppool) \
etype *elem, *tmp; \
HASH_ITER(hh, *ppool, elem, tmp) { \
free(elem->str); \
HASH_DEL(*ppool, elem); \
free(elem); \
}
#define ADD_STR_POOL(etype, ppool, keystr, keystr_len) \
etype *elem; \
if (!(elem = (etype*)malloc(sizeof(etype)))) \
return false; \
if (!(elem->str = malloc(keystr_len + 1))) \
{ \
free(elem); \
return NULL; \
} \
memcpy(elem->str, keystr, keystr_len); \
elem->str[keystr_len] = 0; \
oom = false; \
HASH_ADD_KEYPTR(hh, *ppool, elem->str, keystr_len, elem); \
if (oom) \
{ \
free(elem->str); \
free(elem); \
return NULL; \
}
typedef struct hostlist_pool {
char *str; /* key */
+117
View File
@@ -0,0 +1,117 @@
#include "timer.h"
#include "params.h"
#include "helpers.h"
#include "lua.h"
#undef uthash_nonfatal_oom
#define uthash_nonfatal_oom(elt) ut_oom_recover(elt)
static bool oom = false;
static void ut_oom_recover(void *elem)
{
oom = true;
}
static unsigned int timer_n=0;
static void TimerPoolDestroyItem(timer_pool *elem)
{
free(elem->str);
free(elem->func);
luaL_unref(params.L, LUA_REGISTRYINDEX, elem->lua_ref);
}
void TimerPoolDel(timer_pool **pp, timer_pool *p)
{
TimerPoolDestroyItem(p);
HASH_DEL(*pp,p);
free(p);
}
void TimerPoolDestroy(timer_pool **pp)
{
timer_pool *elem, *tmp;
HASH_ITER(hh, *pp, elem, tmp) TimerPoolDel(pp,elem);
}
struct timer_pool *TimerPoolSearch(timer_pool *p, const char *str)
{
timer_pool *elem_find;
HASH_FIND_STR(p, str, elem_find);
return elem_find;
}
struct timer_pool *TimerPoolAdd(timer_pool **pp, const char *str, const char *func, uint64_t period, bool oneshot)
{
ADD_STR_POOL(timer_pool, pp, str, strlen(str))
if (!(elem->func = strdup(func)))
{
TimerPoolDel(pp,elem);
return NULL;
}
elem->period = period;
elem->oneshot = oneshot;
elem->lua_ref = LUA_NOREF;
elem->bt_prev = boottime_ms();
elem->n = ++timer_n;
return elem;
}
static bool TimerPoolRunTimer(timer_pool *p)
{
lua_getglobal(params.L, p->func);
if (!lua_isfunction(params.L, -1))
{
lua_pop(params.L, 1);
DLOG_ERR("timer: '%s' function '%s' does not exist\n",p->str,p->func);
return false;
}
lua_pushstring(params.L, p->str);
lua_rawgeti(params.L, LUA_REGISTRYINDEX, p->lua_ref);
DLOG("\ntimer: '%s' function '%s' period %llu oneshot %u\n",p->str,p->func,p->period,p->oneshot);
int status = lua_pcall(params.L, 2, 0, 0);
if (status)
{
lua_dlog_error();
return false;
}
return true;
}
void TimerPoolRun(timer_pool **pp, uint64_t bt)
{
if (!pp) return; // no timers
if (!bt) bt = boottime_ms();
timer_pool *elem, *tmp, *p;
char *name;
const char *del;
unsigned int n;
HASH_ITER(hh, *pp, elem, tmp)
{
if (bt >= (elem->bt_prev + elem->period))
{
if (!(name = strdup(elem->str)))
return;
n = elem->n;
del = NULL;
if (!TimerPoolRunTimer(elem))
del = "timer: '%s' deleted because of error\n";
else if (elem->oneshot)
del = "timer: '%s' deleted because of oneshot\n";
if (del)
{
// timer function could delete the timer itself or recreate with the same name
p = TimerPoolSearch(*pp, name);
if (p==elem && p->n==n)
{
DLOG(del,name);
TimerPoolDel(pp, elem);
}
}
else
elem->bt_prev = bt;
free(name);
}
}
}
+23
View File
@@ -0,0 +1,23 @@
#pragma once
#include <stdint.h>
#include <stdbool.h>
#include "pools.h"
typedef struct timer_pool {
char *str; /* key */
char *func;
uint64_t period;
bool oneshot;
int lua_ref;
uint64_t bt_prev;
unsigned int n;
UT_hash_handle hh; /* makes this structure hashable */
} timer_pool;
void TimerPoolDestroy(timer_pool **pp);
struct timer_pool *TimerPoolSearch(timer_pool *p, const char *str);
struct timer_pool *TimerPoolAdd(timer_pool **pp, const char *str, const char *func, uint64_t period, bool oneshot);
void TimerPoolDel(timer_pool **pp, timer_pool *p);
void TimerPoolRun(timer_pool **pp, uint64_t bt);