X-Git-Url: http://git.openwrt.org/?a=blobdiff_plain;f=lua%2Fubus.c;h=86e34b7c0739f6c568925bfb5feeb4d34ca0d570;hb=8bb34756ce2bd684745d3a49a134dae03073b452;hp=899a8bd3dcadc9ace66e8e5683cad1833b60855c;hpb=c382792d9893ed1b0c1e1b0db2ad9a7eaa7a78e1;p=project%2Fubus.git diff --git a/lua/ubus.c b/lua/ubus.c index 899a8bd..86e34b7 100644 --- a/lua/ubus.c +++ b/lua/ubus.c @@ -17,10 +17,10 @@ #include #include #include +#include - -#define MODNAME "ubus" -#define METANAME MODNAME ".meta" +#define MODNAME "ubus" +#define METANAME MODNAME ".meta" static lua_State *state; @@ -35,6 +35,11 @@ struct ubus_lua_object { int r; }; +struct ubus_lua_event { + struct ubus_event_handler e; + int r; +}; + static int ubus_lua_parse_blob(lua_State *L, struct blob_attr *attr, bool table); @@ -67,7 +72,6 @@ ubus_lua_parse_blob(lua_State *L, struct blob_attr *attr, bool table) int len; int off = 0; void *data; - char buf[32]; if (!blobmsg_check_attr(attr, false)) return 0; @@ -96,9 +100,7 @@ ubus_lua_parse_blob(lua_State *L, struct blob_attr *attr, bool table) break; case BLOBMSG_TYPE_INT64: - /* NB: Lua cannot handle 64bit, format value as string and push that */ - sprintf(buf, "%lld", (long long int) be64_to_cpu(*(uint64_t *)data)); - lua_pushstring(L, buf); + lua_pushnumber(L, (double) be64_to_cpu(*(uint64_t *)data)); break; case BLOBMSG_TYPE_STRING: @@ -137,7 +139,7 @@ ubus_lua_format_blob_is_array(lua_State *L) if (lua_type(L, -2) != LUA_TNUMBER) #endif { - lua_pop(L, 1); + lua_pop(L, 2); return false; } @@ -145,7 +147,7 @@ ubus_lua_format_blob_is_array(lua_State *L) if ((cur - 1) != prv) { - lua_pop(L, 1); + lua_pop(L, 2); return false; } @@ -283,16 +285,28 @@ ubus_method_handler(struct ubus_context *ctx, struct ubus_object *obj, struct blob_attr *msg) { struct ubus_lua_object *o = container_of(obj, struct ubus_lua_object, o); + int rv = 0; lua_getglobal(state, "__ubus_cb"); lua_rawgeti(state, -1, o->r); lua_getfield(state, -1, method); + lua_remove(state, -2); + lua_remove(state, -2); if (lua_isfunction(state, -1)) { lua_pushlightuserdata(state, req); - lua_call(state, 1, 0); + if (!msg) + lua_pushnil(state); + else + ubus_lua_parse_blob_array(state, blob_data(msg), blob_len(msg), true); + lua_call(state, 2, 1); + if (lua_isnumber(state, -1)) + rv = lua_tonumber(state, -1); } - return 0; + + lua_pop(state, 1); + + return rv; } static int lua_gettablelen(lua_State *L, int index) @@ -343,12 +357,11 @@ static int ubus_lua_load_methods(lua_State *L, struct ubus_method *m) /* get the policy table */ lua_pushinteger(L, 2); lua_gettable(L, -3); - plen = lua_gettablelen(L, -1); /* check if the method table is valid */ if ((lua_type(L, -2) != LUA_TFUNCTION) || (lua_type(L, -1) != LUA_TTABLE) || - lua_objlen(L, -1) || !plen) { + lua_objlen(L, -1)) { lua_pop(L, 2); return 1; } @@ -357,8 +370,22 @@ static int ubus_lua_load_methods(lua_State *L, struct ubus_method *m) lua_pushvalue(L, -2); lua_setfield(L, -6, lua_tostring(L, -5)); + m->name = lua_tostring(L, -4); + m->handler = ubus_method_handler; + + plen = lua_gettablelen(L, -1); + + /* exit if policy table is empty */ + if (!plen) { + lua_pop(L, 2); + return 0; + } + /* setup the policy pointers */ p = malloc(sizeof(struct blobmsg_policy) * plen); + if (!p) + return 1; + memset(p, 0, sizeof(struct blobmsg_policy) * plen); m->policy = p; lua_pushnil(L); @@ -380,8 +407,6 @@ static int ubus_lua_load_methods(lua_State *L, struct ubus_method *m) } m->n_policy = pidx; - m->name = lua_tostring(L, -4); - m->handler = ubus_method_handler; lua_pop(L, 2); return 0; @@ -396,6 +421,9 @@ static struct ubus_object* ubus_lua_load_object(lua_State *L) /* setup object pointers */ obj = malloc(sizeof(struct ubus_lua_object)); + if (!obj) + return NULL; + memset(obj, 0, sizeof(struct ubus_lua_object)); obj->o.name = lua_tostring(L, -2); @@ -406,12 +434,17 @@ static struct ubus_object* ubus_lua_load_object(lua_State *L) /* setup type pointers */ obj->o.type = malloc(sizeof(struct ubus_object_type)); + if (!obj->o.type) { + free(obj); + return NULL; + } + memset(obj->o.type, 0, sizeof(struct ubus_object_type)); obj->o.type->name = lua_tostring(L, -2); obj->o.type->id = 0; obj->o.type->methods = obj->o.methods; - /* create the he callback lookup table */ + /* create the callback lookup table */ lua_createtable(L, 1, 0); lua_getglobal(L, "__ubus_cb"); lua_pushvalue(L, -2); @@ -508,10 +541,11 @@ ubus_lua_call_cb(struct ubus_request *req, int type, struct blob_attr *msg) { lua_State *L = (lua_State *)req->priv; - if (!msg) + if (!msg && L) lua_pushnil(L); - ubus_lua_parse_blob_array(L, blob_data(msg), blob_len(msg), true); + if (msg && L) + ubus_lua_parse_blob_array(L, blob_data(msg), blob_len(msg), true); } static int @@ -556,12 +590,102 @@ ubus_lua_call(lua_State *L) return lua_gettop(L) - top; } +static void +ubus_event_handler(struct ubus_context *ctx, struct ubus_event_handler *ev, + const char *type, struct blob_attr *msg) +{ + struct ubus_lua_event *listener = container_of(ev, struct ubus_lua_event, e); + + lua_getglobal(state, "__ubus_cb_event"); + lua_rawgeti(state, -1, listener->r); + lua_remove(state, -2); + + if (lua_isfunction(state, -1)) { + ubus_lua_parse_blob_array(state, blob_data(msg), blob_len(msg), true); + lua_call(state, 1, 0); + } else { + lua_pop(state, 1); + } +} + +static struct ubus_event_handler* +ubus_lua_load_event(lua_State *L) +{ + struct ubus_lua_event* event = NULL; + + event = malloc(sizeof(struct ubus_lua_event)); + if (!event) + return NULL; + + memset(event, 0, sizeof(struct ubus_lua_event)); + event->e.cb = ubus_event_handler; + + /* update the he callback lookup table */ + lua_getglobal(L, "__ubus_cb_event"); + lua_pushvalue(L, -2); + event->r = luaL_ref(L, -2); + lua_setfield(L, -1, lua_tostring(L, -3)); + + return &event->e; +} + +static int +ubus_lua_listen(lua_State *L) { + struct ubus_lua_connection *c = luaL_checkudata(L, 1, METANAME); + + /* verify top level object */ + luaL_checktype(L, 2, LUA_TTABLE); + + /* scan each object */ + lua_pushnil(L); + while (lua_next(L, -2) != 0) { + struct ubus_event_handler *listener; + + /* check if the key is a string and the value is a method */ + if ((lua_type(L, -2) == LUA_TSTRING) && (lua_type(L, -1) == LUA_TFUNCTION)) { + listener = ubus_lua_load_event(L); + if(listener != NULL) { + ubus_register_event_handler(c->ctx, listener, lua_tostring(L, -2)); + } + } + lua_pop(L, 1); + } + return 0; +} + +static int +ubus_lua_send(lua_State *L) +{ + struct ubus_lua_connection *c = luaL_checkudata(L, 1, METANAME); + const char *event = luaL_checkstring(L, 2); + + if (*event == 0) + return luaL_argerror(L, 2, "no event name"); + + // Event content convert to ubus form + luaL_checktype(L, 3, LUA_TTABLE); + blob_buf_init(&c->buf, 0); + + if (!ubus_lua_format_blob_array(L, &c->buf, true)) { + lua_pushnil(L); + lua_pushinteger(L, UBUS_STATUS_INVALID_ARGUMENT); + return 2; + } + + // Send the event + ubus_send_event(c->ctx, event, c->buf.head); + + return 0; +} + + static int ubus_lua__gc(lua_State *L) { struct ubus_lua_connection *c = luaL_checkudata(L, 1, METANAME); + blob_buf_free(&c->buf); if (c->ctx != NULL) { ubus_free(c->ctx); @@ -579,6 +703,8 @@ static const luaL_Reg ubus[] = { { "signatures", ubus_lua_signatures }, { "call", ubus_lua_call }, { "close", ubus_lua__gc }, + { "listen", ubus_lua_listen }, + { "send", ubus_lua_send }, { "__gc", ubus_lua__gc }, { NULL, NULL }, }; @@ -628,5 +754,9 @@ luaopen_ubus(lua_State *L) lua_createtable(L, 1, 0); lua_setglobal(L, "__ubus_cb"); + /* create the event table */ + lua_createtable(L, 1, 0); + lua_setglobal(L, "__ubus_cb_event"); + return 0; }