<p>Harald Welte <strong>merged</strong> this change.</p><p><a href="https://gerrit.osmocom.org/10439">View Change</a></p><div style="white-space:pre-wrap">Approvals:
  Harald Welte: Looks good to me, approved
  Jenkins Builder: Verified

</div><pre style="font-family: monospace,monospace; white-space: pre-wrap;">Allow lua code to register a fd for reading with the runtime<br><br>To have bi-directional communication we can pass credentials to the<br>registry server and now we can register a callback when the registry<br>is sending data to us.<br><br>The callback needs to return if the fd should continue to be selected<br>as I found no way to push the userdata as parameter on the stack. Lua<br>code will look like:<br><br>  local host, port = "www.osmocom.org", 80<br>  local tcp = socket.tcp()<br>  tcp:connect(host, port);<br>  tcp:send("GET / HTTP/1.0\r\n\r\n");<br>  local cb = function()<br>    local s, status, partial = tcp:receive()<br>    print(s)<br>    if status == 'closed' then<br>     tcp:close()<br>     return 0<br>    end<br>    return 1<br>  end<br>  local foo = osmo.register_fd(tcp:getfd(), cb)<br><br>Change-Id: I8254bdda1df2f8fe0a5eac894b931e7de5b426df<br>---<br>M src/host/layer23/src/mobile/script_lua.c<br>1 file changed, 103 insertions(+), 0 deletions(-)<br><br></pre><pre style="font-family: monospace,monospace; white-space: pre-wrap;"><span>diff --git a/src/host/layer23/src/mobile/script_lua.c b/src/host/layer23/src/mobile/script_lua.c</span><br><span>index 088aab3..924ed6e 100644</span><br><span>--- a/src/host/layer23/src/mobile/script_lua.c</span><br><span>+++ b/src/host/layer23/src/mobile/script_lua.c</span><br><span>@@ -28,6 +28,7 @@</span><br><span> </span><br><span> #include <osmocom/bb/mobile/primitives.h></span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/core/select.h></span><br><span> #include <osmocom/vty/misc.h></span><br><span> </span><br><span> #include <sys/types.h></span><br><span>@@ -37,6 +38,12 @@</span><br><span>       int cb_ref;</span><br><span> };</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+struct fd_userdata {</span><br><span style="color: hsl(120, 100%, 40%);">+   struct lua_State *state;</span><br><span style="color: hsl(120, 100%, 40%);">+      struct osmo_fd fd;</span><br><span style="color: hsl(120, 100%, 40%);">+    int cb_ref;</span><br><span style="color: hsl(120, 100%, 40%);">+};</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> static char lua_prim_key[] = "osmocom.org-mobile-prim";</span><br><span> </span><br><span> static struct mobile_prim_intf *get_primitive(lua_State *L)</span><br><span>@@ -435,6 +442,100 @@</span><br><span>    return 1;</span><br><span> }</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+static void lua_fd_do_unregister(lua_State *L, struct fd_userdata *fdu) {</span><br><span style="color: hsl(120, 100%, 40%);">+ /* Unregister the fd and forget about the callback */</span><br><span style="color: hsl(120, 100%, 40%);">+ osmo_fd_unregister(&fdu->fd);</span><br><span style="color: hsl(120, 100%, 40%);">+  if (fdu->cb_ref != LUA_NOREF) {</span><br><span style="color: hsl(120, 100%, 40%);">+            luaL_unref(L, LUA_REGISTRYINDEX, fdu->cb_ref);</span><br><span style="color: hsl(120, 100%, 40%);">+             fdu->cb_ref = LUA_NOREF;</span><br><span style="color: hsl(120, 100%, 40%);">+   }</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static int lua_fd_cb(struct osmo_fd *fd, unsigned int what) {</span><br><span style="color: hsl(120, 100%, 40%);">+ struct fd_userdata *fdu;</span><br><span style="color: hsl(120, 100%, 40%);">+      lua_State *L;</span><br><span style="color: hsl(120, 100%, 40%);">+ int cb_ref;</span><br><span style="color: hsl(120, 100%, 40%);">+   int err;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    if (!fd->data) {</span><br><span style="color: hsl(120, 100%, 40%);">+           LOGP(DLUA, LOGL_ERROR,</span><br><span style="color: hsl(120, 100%, 40%);">+                        "fd callback for fd(%d) but no lua callback\n", fd->fd);</span><br><span style="color: hsl(120, 100%, 40%);">+         return 0;</span><br><span style="color: hsl(120, 100%, 40%);">+     }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   fdu = fd->data;</span><br><span style="color: hsl(120, 100%, 40%);">+    L = fdu->state;</span><br><span style="color: hsl(120, 100%, 40%);">+    cb_ref = fdu->cb_ref;</span><br><span style="color: hsl(120, 100%, 40%);">+      lua_rawgeti(L, LUA_REGISTRYINDEX, cb_ref);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+  err = lua_pcall(L, 0, 1, 0);</span><br><span style="color: hsl(120, 100%, 40%);">+  if (err) {</span><br><span style="color: hsl(120, 100%, 40%);">+            LOGP(DLUA, LOGL_ERROR, "lua error: %s\n", lua_tostring(L, -1));</span><br><span style="color: hsl(120, 100%, 40%);">+             lua_pop(L, 1);</span><br><span style="color: hsl(120, 100%, 40%);">+        }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   /* Check if we should continue */</span><br><span style="color: hsl(120, 100%, 40%);">+     luaL_argcheck(L, lua_isnumber(L, -1), 1, "needs to be a number");</span><br><span style="color: hsl(120, 100%, 40%);">+   if (lua_tonumber(L, -1) == 1)</span><br><span style="color: hsl(120, 100%, 40%);">+         return 0;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   lua_fd_do_unregister(L, fdu);</span><br><span style="color: hsl(120, 100%, 40%);">+ return 0;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/* Register the fd */</span><br><span style="color: hsl(120, 100%, 40%);">+static int lua_register_fd(lua_State *L)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+    struct fd_userdata *fdu;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    /* fd, cb */</span><br><span style="color: hsl(120, 100%, 40%);">+  luaL_argcheck(L, lua_isnumber(L, -2), 1, "needs to be a filedescriptor");</span><br><span style="color: hsl(120, 100%, 40%);">+   luaL_argcheck(L, lua_isfunction(L, -1), 2, "Callback needs to be a function");</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    /* Cretae a table so a user can unregister (and unregister on GC) */</span><br><span style="color: hsl(120, 100%, 40%);">+  fdu = lua_newuserdata(L, sizeof(*fdu));</span><br><span style="color: hsl(120, 100%, 40%);">+       fdu->state = L;</span><br><span style="color: hsl(120, 100%, 40%);">+    fdu->fd.fd = -1;</span><br><span style="color: hsl(120, 100%, 40%);">+   luaL_getmetatable(L, "Fd");</span><br><span style="color: hsl(120, 100%, 40%);">+ lua_setmetatable(L, -2);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    /* Set the filedescriptor */</span><br><span style="color: hsl(120, 100%, 40%);">+  fdu->fd.fd = (int) lua_tonumber(L, -3);</span><br><span style="color: hsl(120, 100%, 40%);">+    fdu->fd.cb = lua_fd_cb;</span><br><span style="color: hsl(120, 100%, 40%);">+    fdu->fd.when = BSC_FD_READ;</span><br><span style="color: hsl(120, 100%, 40%);">+        fdu->fd.data = fdu;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+      /* Assuming that an error here will lead to a GC */</span><br><span style="color: hsl(120, 100%, 40%);">+   if (osmo_fd_register(&fdu->fd) != 0) {</span><br><span style="color: hsl(120, 100%, 40%);">+         fdu->cb_ref = LUA_NOREF;</span><br><span style="color: hsl(120, 100%, 40%);">+           lua_pushliteral(L, "Can't register the fd");</span><br><span style="color: hsl(120, 100%, 40%);">+            lua_error(L);</span><br><span style="color: hsl(120, 100%, 40%);">+         return 0;</span><br><span style="color: hsl(120, 100%, 40%);">+     }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   /* Take the callback and keep a reference to it */</span><br><span style="color: hsl(120, 100%, 40%);">+    lua_pushvalue(L, -2);</span><br><span style="color: hsl(120, 100%, 40%);">+ fdu->cb_ref = luaL_ref(L, LUA_REGISTRYINDEX);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    return 1;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static int lua_fd_unregister(lua_State *L) {</span><br><span style="color: hsl(120, 100%, 40%);">+  struct fd_userdata *fdu;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    luaL_argcheck(L, lua_isuserdata(L, -1), 1, "No userdata");</span><br><span style="color: hsl(120, 100%, 40%);">+  fdu = lua_touserdata(L, -1);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+        lua_fd_do_unregister(L, fdu);</span><br><span style="color: hsl(120, 100%, 40%);">+ return 0;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static const struct luaL_Reg fd_funcs[] = {</span><br><span style="color: hsl(120, 100%, 40%);">+ { "unregister", lua_fd_unregister },</span><br><span style="color: hsl(120, 100%, 40%);">+        { "__gc", lua_fd_unregister },</span><br><span style="color: hsl(120, 100%, 40%);">+};</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> static const struct luaL_Reg ms_funcs[] = {</span><br><span>        { "imsi", lua_ms_imsi },</span><br><span>   { "imei", lua_ms_imei },</span><br><span>@@ -452,6 +553,7 @@</span><br><span> static const struct luaL_Reg osmo_funcs[] = {</span><br><span>    { "timeout",  lua_osmo_timeout },</span><br><span>  { "unix_passcred", lua_unix_passcred },</span><br><span style="color: hsl(120, 100%, 40%);">+     { "register_fd", lua_register_fd },</span><br><span>        { "ms",       lua_osmo_ms },</span><br><span>       { NULL, NULL },</span><br><span> };</span><br><span>@@ -515,6 +617,7 @@</span><br><span>  /* Create metatables so we can GC objects... */</span><br><span>      create_meta_table(L, "Timer", timer_funcs);</span><br><span>        create_meta_table(L, "MS", ms_funcs);</span><br><span style="color: hsl(120, 100%, 40%);">+       create_meta_table(L, "Fd", fd_funcs);</span><br><span> </span><br><span>  /* Remember the primitive pointer... store it in the registry */</span><br><span>     lua_pushlightuserdata(L, lua_prim_key);</span><br><span></span><br></pre><p>To view, visit <a href="https://gerrit.osmocom.org/10439">change 10439</a>. To unsubscribe, or for help writing mail filters, visit <a href="https://gerrit.osmocom.org/settings">settings</a>.</p><div itemscope itemtype="http://schema.org/EmailMessage"><div itemscope itemprop="action" itemtype="http://schema.org/ViewAction"><link itemprop="url" href="https://gerrit.osmocom.org/10439"/><meta itemprop="name" content="View Change"/></div></div>

<div style="display:none"> Gerrit-Project: osmocom-bb </div>
<div style="display:none"> Gerrit-Branch: master </div>
<div style="display:none"> Gerrit-MessageType: merged </div>
<div style="display:none"> Gerrit-Change-Id: I8254bdda1df2f8fe0a5eac894b931e7de5b426df </div>
<div style="display:none"> Gerrit-Change-Number: 10439 </div>
<div style="display:none"> Gerrit-PatchSet: 3 </div>
<div style="display:none"> Gerrit-Owner: Holger Freyther <holger@freyther.de> </div>
<div style="display:none"> Gerrit-Reviewer: Harald Welte <laforge@gnumonks.org> </div>
<div style="display:none"> Gerrit-Reviewer: Jenkins Builder (1000002) </div>