summaryrefslogtreecommitdiffstats
path: root/src/host/layer23/src/mobile
diff options
context:
space:
mode:
authorHolger Hans Peter Freyther <holger@moiji-mobile.com>2018-08-13 09:59:11 +0100
committerHarald Welte <laforge@gnumonks.org>2018-08-24 10:35:21 +0000
commit90a9ac410c4933b49cecff39c61a4648e5fa02a2 (patch)
tree7dc11ab8b719fa16b879d6c5f08e416e86573733 /src/host/layer23/src/mobile
parent4a466f50074adedfa9e98ad947a4ebfb876d8586 (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/src/mobile')
-rw-r--r--src/host/layer23/src/mobile/script_lua.c103
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);