static int l_node_index(lua_State *L) { struct laura_node *lnode = lua_touserdata(L, 1); const char *name = lua_tostring(L, -1); struct aura_object *o; TRACE(); /* FixMe: Can this get gc-d by the time we actually use it? */ lnode->current_call = name; if (AURA_STATUS_ONLINE != aura_get_status(lnode->node)) return luaL_error(L, "Attempt to call remote method %s when node offline", lnode->current_call); o = aura_etable_find(lnode->node->tbl, lnode->current_call); if (!o) return luaL_error(L, "Internal aura bug: failed to lookup object: %s", lnode->current_call); if (strcmp("__", name) == 0) lua_pushcfunction(L, laura_do_async_call); else if (object_is_method(o)) lua_pushcfunction(L, laura_do_sync_call); else lua_pushnil(L); return 1; }
/* This one is small, but tricky */ static void aura_handle_inbound(struct aura_node *node) { while(1) { struct aura_buffer *buf; struct aura_object *o; buf = aura_dequeue_buffer(&node->inbound_buffers); if (!buf) break; o = buf->object; node->current_object = o; aura_buffer_rewind(buf); slog(4, SLOG_DEBUG, "Handling %s id %d (%s) sync_call_running=%d", object_is_method(o) ? "response" : "event", o->id, o->name, node->sync_call_running); if (object_is_method(o) && !o->pending) { slog(0, SLOG_WARN, "Dropping orphan call result %d (%s)", o->id, o->name); aura_buffer_release(node, buf); } else if (o->calldonecb) { slog(4, SLOG_DEBUG, "Callback for method/event %d (%s)", o->id, o->name); o->calldonecb(node, AURA_CALL_COMPLETED, buf, o->arg); aura_buffer_release(node, buf); } else if (object_is_method(o) && (node->sync_call_running)) { slog(4, SLOG_DEBUG, "Completing call for method %d (%s)", o->id, o->name); node->sync_call_result = AURA_CALL_COMPLETED; node->sync_ret_buf = buf; o->pending--; if (o->pending < 0) BUG(node, "Internal BUG: pending evt count lesser than zero"); } else { /* This one is tricky. We have an event with no callback */ if (node->sync_event_max > 0) { /* Queue it up into event_queue if it's enabled */ /* If we have an overrun - drop the oldest event to free up space first*/ if (node->sync_event_max <= node->sync_event_count) { struct aura_buffer *todrop; const struct aura_object *dummy; int ret = aura_get_next_event(node, &dummy, &todrop); if (ret != 0) BUG(node, "Internal bug, no next event"); aura_buffer_release(node, todrop); } /* Now just queue the next one */ aura_queue_buffer(&node->event_buffers, buf); node->sync_event_count++; slog(4, SLOG_DEBUG, "Queued event %d (%s) for sync readout", o->id, o->name); } else { /* Last resort - try the catch-all event callback */ if (node->unhandled_evt_cb) node->unhandled_evt_cb(node, buf, node->unhandled_evt_arg); else /* Or just drop it with a warning */ slog(0, SLOG_WARN, "Dropping event %d (%s)", o->id, o->name); aura_buffer_release(node, buf); } } } node->current_object = NULL; }
static int laura_do_async_call(lua_State *L) { struct laura_node *lnode = NULL; const char *name; struct aura_buffer *buf; struct aura_object *o; int ret; int callback_ref; TRACE(); /* Sanity */ lnode = lua_fetch_node(L, 1); if (!lnode) { lua_stackdump(L); return aura_typeerror(L, 1, "userdata (node)"); } if (!lua_isstring(L, 2)) { lua_stackdump(L); return aura_typeerror(L, 2, "string (object name)"); } if (!lua_isfunction(L, 3)) { lua_stackdump(L); return aura_typeerror(L, 3, "function (callback)"); } name = lua_tostring(L, 2); o = aura_etable_find(lnode->node->tbl, name); if (!o) return luaL_error(L, "Attempt to call non-existend method"); if (!object_is_method(o)) { lua_stackdump(L); return luaL_error(L, "Attempt to call an event"); } /* Now we're sane! */ buf = lua_to_buffer(L, lnode->node, 5, o); if (!buf) return luaL_error(L, "Serializer failed!"); /* Let's create a table to store our callback and arg */ lua_newtable(L); /* Push the callback function there */ lua_pushnumber(L, 1); lua_pushvalue(L, 3); lua_settable(L, -3); /* And the user argument */ lua_pushnumber(L, 2); lua_pushvalue(L, 4); lua_settable(L, -3); /* And fetch the reference to out table that we'll use in callback */ callback_ref = luaL_ref(L, LUA_REGISTRYINDEX); slog(4, SLOG_DEBUG, "Callback tbl reference: %d", callback_ref); ret = aura_core_start_call(lnode->node, o, calldone_cb, (void *)(long)callback_ref, buf); if (ret != 0) { aura_buffer_release(buf); return luaL_error(L, "Async call for %s failed: %s code (%d)", o->name, strerror(-ret), ret); } return 0; }