tor

The Tor anonymity network
git clone https://git.dasho.dev/tor.git
Log | Files | Refs | README | LICENSE

timeout-lua.c (7163B)


      1 #include <assert.h>
      2 #include <string.h>
      3 
      4 #include <lua.h>
      5 #include <lualib.h>
      6 #include <lauxlib.h>
      7 
      8 #if LUA_VERSION_NUM != 503
      9 #error only Lua 5.3 supported
     10 #endif
     11 
     12 #define TIMEOUT_PUBLIC static
     13 #include "timeout.h"
     14 #include "timeout.c"
     15 
     16 #define TIMEOUT_METANAME "struct timeout"
     17 #define TIMEOUTS_METANAME "struct timeouts*"
     18 
     19 static struct timeout *
     20 to_checkudata(lua_State *L, int index)
     21 {
     22 return luaL_checkudata(L, index, TIMEOUT_METANAME);
     23 }
     24 
     25 static struct timeouts *
     26 tos_checkudata(lua_State *L, int index)
     27 {
     28 return *(struct timeouts **)luaL_checkudata(L, index, TIMEOUTS_METANAME);
     29 }
     30 
     31 static void
     32 tos_bind(lua_State *L, int tos_index, int to_index)
     33 {
     34 lua_getuservalue(L, tos_index);
     35 lua_pushlightuserdata(L, to_checkudata(L, to_index));
     36 lua_pushvalue(L, to_index);
     37 lua_rawset(L, -3);
     38 lua_pop(L, 1);
     39 }
     40 
     41 static void
     42 tos_unbind(lua_State *L, int tos_index, int to_index)
     43 {
     44 lua_getuservalue(L, tos_index);
     45 lua_pushlightuserdata(L, to_checkudata(L, to_index));
     46 lua_pushnil(L);
     47 lua_rawset(L, -3);
     48 lua_pop(L, 1);
     49 }
     50 
     51 static int
     52 to__index(lua_State *L)
     53 {
     54 struct timeout *to = to_checkudata(L, 1);
     55 
     56 if (lua_type(L, 2 == LUA_TSTRING)) {
     57 	const char *key = lua_tostring(L, 2);
     58 
     59 	if (!strcmp(key, "flags")) {
     60 		lua_pushinteger(L, to->flags);
     61 
     62 		return 1;
     63 	} else if (!strcmp(key, "expires")) {
     64 		lua_pushinteger(L, to->expires);
     65 
     66 		return 1;
     67 	}
     68 }
     69 
     70 if (LUA_TNIL != lua_getuservalue(L, 1)) {
     71 	lua_pushvalue(L, 2);
     72 	if (LUA_TNIL != lua_rawget(L, -2))
     73 		return 1;
     74 }
     75 
     76 lua_pushvalue(L, 2);
     77 if (LUA_TNIL != lua_rawget(L, lua_upvalueindex(1)))
     78 	return 1;
     79 
     80 return 0;
     81 }
     82 
     83 static int
     84 to__newindex(lua_State *L)
     85 {
     86 if (LUA_TNIL == lua_getuservalue(L, 1)) {
     87 	lua_newtable(L);
     88 	lua_pushvalue(L, -1);
     89 	lua_setuservalue(L, 1);
     90 }
     91 
     92 lua_pushvalue(L, 2);
     93 lua_pushvalue(L, 3);
     94 lua_rawset(L, -3);
     95 
     96 return 0;
     97 }
     98 
     99 static int
    100 to__gc(lua_State *L)
    101 {
    102 struct timeout *to = to_checkudata(L, 1);
    103 
    104 /*
    105  * NB: On script exit it's possible for a timeout to still be
    106  * associated with a timeouts object, particularly when the timeouts
    107  * object was created first.
    108  */
    109 timeout_del(to);
    110 
    111 return 0;
    112 }
    113 
    114 static int
    115 to_new(lua_State *L)
    116 {
    117 int flags = luaL_optinteger(L, 1, 0);
    118 struct timeout *to;
    119 
    120 to = lua_newuserdata(L, sizeof *to);
    121 timeout_init(to, flags);
    122 luaL_setmetatable(L, TIMEOUT_METANAME);
    123 
    124 return 1;
    125 }
    126 
    127 static const luaL_Reg to_methods[] = {
    128 { NULL,  NULL },
    129 };
    130 
    131 static const luaL_Reg to_metatable[] = {
    132 { "__index",    &to__index },
    133 { "__newindex", &to__newindex },
    134 { "__gc",       &to__gc },
    135 { NULL,         NULL },
    136 };
    137 
    138 static const luaL_Reg to_globals[] = {
    139 { "new", &to_new },
    140 { NULL,  NULL },
    141 };
    142 
    143 static void
    144 to_newmetatable(lua_State *L)
    145 {
    146 if (luaL_newmetatable(L, TIMEOUT_METANAME)) {
    147 	/*
    148 	 * fill metamethod table, capturing the methods table as an
    149 	 * upvalue for use by __index metamethod
    150 	 */
    151 	luaL_newlib(L, to_methods);
    152 	luaL_setfuncs(L, to_metatable, 1);
    153 }
    154 }
    155 
    156 int
    157 luaopen_timeout(lua_State *L)
    158 {
    159 to_newmetatable(L);
    160 
    161 luaL_newlib(L, to_globals);
    162 lua_pushinteger(L, TIMEOUT_INT);
    163 lua_setfield(L, -2, "INT");
    164 lua_pushinteger(L, TIMEOUT_ABS);
    165 lua_setfield(L, -2, "ABS");
    166 
    167 return 1;
    168 }
    169 
    170 static int
    171 tos_update(lua_State *L)
    172 {
    173 struct timeouts *T = tos_checkudata(L, 1);
    174 lua_Number n = luaL_checknumber(L, 2);
    175 
    176 timeouts_update(T, timeouts_f2i(T, n));
    177 
    178 lua_pushvalue(L, 1);
    179 
    180 return 1;
    181 }
    182 
    183 static int
    184 tos_step(lua_State *L)
    185 {
    186 struct timeouts *T = tos_checkudata(L, 1);
    187 lua_Number n = luaL_checknumber(L, 2);
    188 
    189 timeouts_step(T, timeouts_f2i(T, n));
    190 
    191 lua_pushvalue(L, 1);
    192 
    193 return 1;
    194 }
    195 
    196 static int
    197 tos_timeout(lua_State *L)
    198 {
    199 struct timeouts *T = tos_checkudata(L, 1);
    200 
    201 lua_pushnumber(L, timeouts_i2f(T, timeouts_timeout(T)));
    202 
    203 return 1;
    204 }
    205 
    206 static int
    207 tos_add(lua_State *L)
    208 {
    209 struct timeouts *T = tos_checkudata(L, 1);
    210 struct timeout *to = to_checkudata(L, 2);
    211 lua_Number timeout = luaL_checknumber(L, 3);
    212 
    213 tos_bind(L, 1, 2);
    214 timeouts_addf(T, to, timeout);
    215 
    216 return lua_pushvalue(L, 1), 1;
    217 }
    218 
    219 static int
    220 tos_del(lua_State *L)
    221 {
    222 struct timeouts *T = tos_checkudata(L, 1);
    223 struct timeout *to = to_checkudata(L, 2);
    224 
    225 timeouts_del(T, to);
    226 tos_unbind(L, 1, 2);
    227 
    228 return lua_pushvalue(L, 1), 1;
    229 }
    230 
    231 static int
    232 tos_get(lua_State *L)
    233 {
    234 struct timeouts *T = tos_checkudata(L, 1);
    235 struct timeout *to;
    236 
    237 if (!(to = timeouts_get(T)))
    238 	return 0;
    239 
    240 lua_getuservalue(L, 1);
    241 lua_rawgetp(L, -1, to);
    242 
    243 if (!timeout_pending(to))
    244 	tos_unbind(L, 1, lua_absindex(L, -1));
    245 
    246 return 1;
    247 }
    248 
    249 static int
    250 tos_pending(lua_State *L)
    251 {
    252 struct timeouts *T = tos_checkudata(L, 1);
    253 
    254 lua_pushboolean(L, timeouts_pending(T));
    255 
    256 return 1;
    257 }
    258 
    259 static int
    260 tos_expired(lua_State *L)
    261 {
    262 struct timeouts *T = tos_checkudata(L, 1);
    263 
    264 lua_pushboolean(L, timeouts_expired(T));
    265 
    266 return 1;
    267 }
    268 
    269 static int
    270 tos_check(lua_State *L)
    271 {
    272 struct timeouts *T = tos_checkudata(L, 1);
    273 
    274 lua_pushboolean(L, timeouts_check(T, NULL));
    275 
    276 return 1;
    277 }
    278 
    279 static int
    280 tos__next(lua_State *L)
    281 {
    282 struct timeouts *T = tos_checkudata(L, lua_upvalueindex(1));
    283 struct timeouts_it *it = lua_touserdata(L, lua_upvalueindex(2));
    284 struct timeout *to;
    285 
    286 if (!(to = timeouts_next(T, it)))
    287 	return 0;
    288 
    289 lua_getuservalue(L, lua_upvalueindex(1));
    290 lua_rawgetp(L, -1, to);
    291 
    292 return 1;
    293 }
    294 
    295 static int
    296 tos_timeouts(lua_State *L)
    297 {
    298 int flags = luaL_checkinteger(L, 2);
    299 struct timeouts_it *it;
    300 
    301 tos_checkudata(L, 1);
    302 lua_pushvalue(L, 1);
    303 it = lua_newuserdata(L, sizeof *it);
    304 TIMEOUTS_IT_INIT(it, flags);
    305 lua_pushcclosure(L, &tos__next, 2);
    306 
    307 return 1;
    308 }
    309 
    310 static int
    311 tos__gc(lua_State *L)
    312 {
    313 struct timeouts **tos = luaL_checkudata(L, 1, TIMEOUTS_METANAME);
    314 struct timeout *to;
    315 
    316 TIMEOUTS_FOREACH(to, *tos, TIMEOUTS_ALL) {
    317 	timeouts_del(*tos, to);
    318 }
    319 
    320 timeouts_close(*tos);
    321 *tos = NULL;
    322 
    323 return 0;
    324 }
    325 
    326 static int
    327 tos_new(lua_State *L)
    328 {
    329 timeout_t hz = luaL_optinteger(L, 1, 0);
    330 struct timeouts **T;
    331 int error;
    332 
    333 T = lua_newuserdata(L, sizeof *T);
    334 luaL_setmetatable(L, TIMEOUTS_METANAME);
    335 
    336 lua_newtable(L);
    337 lua_setuservalue(L, -2);
    338 
    339 if (!(*T = timeouts_open(hz, &error)))
    340 	return luaL_error(L, "%s", strerror(error));
    341 
    342 return 1;
    343 }
    344 
    345 static const luaL_Reg tos_methods[] = {
    346 { "update",   &tos_update },
    347 { "step",     &tos_step },
    348 { "timeout",  &tos_timeout },
    349 { "add",      &tos_add },
    350 { "del",      &tos_del },
    351 { "get",      &tos_get },
    352 { "pending",  &tos_pending },
    353 { "expired",  &tos_expired },
    354 { "check",    &tos_check },
    355 { "timeouts", &tos_timeouts },
    356 { NULL,       NULL },
    357 };
    358 
    359 static const luaL_Reg tos_metatable[] = {
    360 { "__gc", &tos__gc },
    361 { NULL,   NULL },
    362 };
    363 
    364 static const luaL_Reg tos_globals[] = {
    365 { "new", &tos_new },
    366 { NULL,  NULL },
    367 };
    368 
    369 static void
    370 tos_newmetatable(lua_State *L)
    371 {
    372 if (luaL_newmetatable(L, TIMEOUTS_METANAME)) {
    373 	luaL_setfuncs(L, tos_metatable, 0);
    374 	luaL_newlib(L, tos_methods);
    375 	lua_setfield(L, -2, "__index");
    376 }
    377 }
    378 
    379 int
    380 luaopen_timeouts(lua_State *L)
    381 {
    382 to_newmetatable(L);
    383 tos_newmetatable(L);
    384 
    385 luaL_newlib(L, tos_globals);
    386 lua_pushinteger(L, TIMEOUTS_PENDING);
    387 lua_setfield(L, -2, "PENDING");
    388 lua_pushinteger(L, TIMEOUTS_EXPIRED);
    389 lua_setfield(L, -2, "EXPIRED");
    390 lua_pushinteger(L, TIMEOUTS_ALL);
    391 lua_setfield(L, -2, "ALL");
    392 lua_pushinteger(L, TIMEOUTS_CLEAR);
    393 lua_setfield(L, -2, "CLEAR");
    394 
    395 return 1;
    396 }