diff options
author | Holger Hans Peter Freyther <holger@moiji-mobile.com> | 2018-08-13 09:59:11 +0100 |
---|---|---|
committer | Harald Welte <laforge@gnumonks.org> | 2018-08-24 10:35:21 +0000 |
commit | 90a9ac410c4933b49cecff39c61a4648e5fa02a2 (patch) | |
tree | 7dc11ab8b719fa16b879d6c5f08e416e86573733 /src/host/layer23 | |
parent | 4a466f50074adedfa9e98ad947a4ebfb876d8586 (diff) |
Allow lua code to register a fd for reading with the runtime
To have bi-directional communication we can pass credentials to the
registry server and now we can register a callback when the registry
is sending data to us.
The callback needs to return if the fd should continue to be selected
as I found no way to push the userdata as parameter on the stack. Lua
code will look like:
local host, port = "www.osmocom.org", 80
local tcp = socket.tcp()
tcp:connect(host, port);
tcp:send("GET / HTTP/1.0\r\n\r\n");
local cb = function()
local s, status, partial = tcp:receive()
print(s)
if status == 'closed' then
tcp:close()
return 0
end
return 1
end
local foo = osmo.register_fd(tcp:getfd(), cb)
Change-Id: I8254bdda1df2f8fe0a5eac894b931e7de5b426df
Diffstat (limited to 'src/host/layer23')
-rw-r--r-- | src/host/layer23/src/mobile/script_lua.c | 103 |
1 files changed, 103 insertions, 0 deletions
diff --git a/src/host/layer23/src/mobile/script_lua.c b/src/host/layer23/src/mobile/script_lua.c index 088aab33..924ed6ec 100644 --- a/src/host/layer23/src/mobile/script_lua.c +++ b/src/host/layer23/src/mobile/script_lua.c @@ -28,6 +28,7 @@ #include <osmocom/bb/mobile/primitives.h> +#include <osmocom/core/select.h> #include <osmocom/vty/misc.h> #include <sys/types.h> @@ -37,6 +38,12 @@ struct timer_userdata { int cb_ref; }; +struct fd_userdata { + struct lua_State *state; + struct osmo_fd fd; + int cb_ref; +}; + static char lua_prim_key[] = "osmocom.org-mobile-prim"; static struct mobile_prim_intf *get_primitive(lua_State *L) @@ -435,6 +442,100 @@ static int lua_unix_passcred(lua_State *L) return 1; } +static void lua_fd_do_unregister(lua_State *L, struct fd_userdata *fdu) { + /* Unregister the fd and forget about the callback */ + osmo_fd_unregister(&fdu->fd); + if (fdu->cb_ref != LUA_NOREF) { + luaL_unref(L, LUA_REGISTRYINDEX, fdu->cb_ref); + fdu->cb_ref = LUA_NOREF; + } +} + +static int lua_fd_cb(struct osmo_fd *fd, unsigned int what) { + struct fd_userdata *fdu; + lua_State *L; + int cb_ref; + int err; + + if (!fd->data) { + LOGP(DLUA, LOGL_ERROR, + "fd callback for fd(%d) but no lua callback\n", fd->fd); + return 0; + } + + fdu = fd->data; + L = fdu->state; + cb_ref = fdu->cb_ref; + lua_rawgeti(L, LUA_REGISTRYINDEX, cb_ref); + + err = lua_pcall(L, 0, 1, 0); + if (err) { + LOGP(DLUA, LOGL_ERROR, "lua error: %s\n", lua_tostring(L, -1)); + lua_pop(L, 1); + } + + /* Check if we should continue */ + luaL_argcheck(L, lua_isnumber(L, -1), 1, "needs to be a number"); + if (lua_tonumber(L, -1) == 1) + return 0; + + lua_fd_do_unregister(L, fdu); + return 0; +} + +/* Register the fd */ +static int lua_register_fd(lua_State *L) +{ + struct fd_userdata *fdu; + + /* fd, cb */ + luaL_argcheck(L, lua_isnumber(L, -2), 1, "needs to be a filedescriptor"); + luaL_argcheck(L, lua_isfunction(L, -1), 2, "Callback needs to be a function"); + + /* Cretae a table so a user can unregister (and unregister on GC) */ + fdu = lua_newuserdata(L, sizeof(*fdu)); + fdu->state = L; + fdu->fd.fd = -1; + luaL_getmetatable(L, "Fd"); + lua_setmetatable(L, -2); + + /* Set the filedescriptor */ + fdu->fd.fd = (int) lua_tonumber(L, -3); + fdu->fd.cb = lua_fd_cb; + fdu->fd.when = BSC_FD_READ; + fdu->fd.data = fdu; + + /* Assuming that an error here will lead to a GC */ + if (osmo_fd_register(&fdu->fd) != 0) { + fdu->cb_ref = LUA_NOREF; + lua_pushliteral(L, "Can't register the fd"); + lua_error(L); + return 0; + } + + /* Take the callback and keep a reference to it */ + lua_pushvalue(L, -2); + fdu->cb_ref = luaL_ref(L, LUA_REGISTRYINDEX); + + return 1; +} + +static int lua_fd_unregister(lua_State *L) { + struct fd_userdata *fdu; + + luaL_argcheck(L, lua_isuserdata(L, -1), 1, "No userdata"); + fdu = lua_touserdata(L, -1); + + lua_fd_do_unregister(L, fdu); + return 0; +} + + +static const struct luaL_Reg fd_funcs[] = { + { "unregister", lua_fd_unregister }, + { "__gc", lua_fd_unregister }, +}; + static const struct luaL_Reg ms_funcs[] = { { "imsi", lua_ms_imsi }, { "imei", lua_ms_imei }, @@ -452,6 +553,7 @@ static const struct luaL_Reg ms_funcs[] = { static const struct luaL_Reg osmo_funcs[] = { { "timeout", lua_osmo_timeout }, { "unix_passcred", lua_unix_passcred }, + { "register_fd", lua_register_fd }, { "ms", lua_osmo_ms }, { NULL, NULL }, }; @@ -515,6 +617,7 @@ static void add_runtime(lua_State *L, struct mobile_prim_intf *intf) /* Create metatables so we can GC objects... */ create_meta_table(L, "Timer", timer_funcs); create_meta_table(L, "MS", ms_funcs); + create_meta_table(L, "Fd", fd_funcs); /* Remember the primitive pointer... store it in the registry */ lua_pushlightuserdata(L, lua_prim_key); |