void init() { lua_State *L = m_L; lua_createtable(L, 1, 8); // Environment lua_pushvalue(L, 2); // Permanent objects lua_rawseti(L, -2, 1); lua_createtable(L, 1, 0); // Environment metatable lua_pushvalue(L, 2); // Permanent objects lua_pushvalue(L, 1); // self lua_pushcclosure(L, l_writer_mt_index, 2); lua_setfield(L, -2, "__index"); lua_setmetatable(L, -2); lua_setfenv(L, 1); lua_createtable(L, 1, 4); // Metatable lua_pushcclosure(L, l_crude_gc<LuaPersistBasicWriter>, 0); lua_setfield(L, -2, "__gc"); lua_pushvalue(L, luaT_upvalueindex(1)); // Prototype persistance names lua_rawseti(L, -2, 1); lua_setmetatable(L, 1); m_iNextIndex = 1; m_iDataLength = 0; m_bHadError = false; }
bool CLuaHandleSynced::SetupUnsyncedFunction(lua_State *L, const char* funcName) { // copy the function from UNSYNCED into // the registry, and setfenv() it to UNSYNCED lua_settop(L, 0); unsyncedStr.GetRegistry(L); if (!lua_istable(L, -1)) { lua_settop(L, 0); // FIXME LOG_L(L_ERROR, "missing UNSYNCED table for %s", name.c_str()); return false; } const int unsynced = lua_gettop(L); lua_pushstring(L, funcName); lua_pushstring(L, funcName); lua_gettable(L, unsynced); if (lua_isnil(L, -1)) { lua_rawset(L, LUA_REGISTRYINDEX); lua_settop(L, 0); return true; } else if (!lua_isfunction(L, -1)) { lua_settop(L, 0); LOG_L(L_WARNING, "%s in %s is not a function", funcName, GetName().c_str()); return false; } lua_pushvalue(L, unsynced); lua_setfenv(L, -2); lua_rawset(L, LUA_REGISTRYINDEX); lua_settop(L, 0); return true; }
// Generates a temporary file, and returns a file handle as well as the file name int mkstemp(lua_State *L) { std::string templ; if (lua_gettop(L) > 0) { templ = LuaHelpers::pops(L); } FILE **pf = (FILE **)lua_newuserdata(L, sizeof *pf); *pf = 0; luaL_getmetatable(L, LUA_FILEHANDLE); lua_setmetatable(L, -2); // Register custom __close() function // (From lua posix module by Luiz Henrique de Figueiredo) lua_getfield(L, LUA_REGISTRYINDEX, "PEPPER_UTILS_FILE"); if (lua_isnil(L, -1)) { lua_pop(L, 1); lua_newtable(L); lua_pushvalue(L, -1); lua_pushcfunction(L, fclose); lua_setfield(L, -2, "__close"); lua_setfield(L, LUA_REGISTRYINDEX, "PEPPER_UTILS_FILE"); } lua_setfenv(L, -2); // Gemerate the file std::string filename; try { *pf = sys::fs::mkstemp(&filename, templ); } catch (const PepperException &ex) { return LuaHelpers::pushError(L, ex.what(), ex.where()); } LuaHelpers::push(L, filename); return 2; }
static int l_create_server(lua_State *L) { const char *msg = NULL; struct httpserver *hs = NULL; struct mg_server *server = NULL; hs = (struct httpserver*)lua_newuserdata(L, sizeof(struct httpserver)); memset(hs, 0, sizeof(struct httpserver)); server = mg_create_server(L, ev_handler); if (!hs || !server) { msg = "mg_create_server fail"; goto error_ret; } hs->server = server; luaL_getmetatable(L, META_HTTPAUTH); lua_setmetatable(L, -2); lua_createtable(L, 1, 0); lua_setfenv(L, -2); return 1; error_ret: if (server) mg_destroy_server(&server); lua_pushnil(L); lua_pushfstring(L, "%s", msg); return 2; }
/** * Set environment table for the given code closure. * * Before: * | code closure | <- top * | ... | * * After: * | code closure | <- top * | ... | * */ static void ngx_http_lua_header_filter_by_lua_env(lua_State *L, ngx_http_request_t *r) { /* set nginx request pointer to current lua thread's globals table */ ngx_http_lua_set_req(L, r); /** * we want to create empty environment for current script * * newt = {} * newt["_G"] = newt * setmetatable(newt, {__index = _G}) * * if a function or symbol is not defined in our env, __index will lookup * in the global env. * * all variables created in the script-env will be thrown away at the end * of the script run. * */ ngx_http_lua_create_new_globals_table(L, 0 /* narr */, 1 /* nrec */); /* {{{ initialize ngx.* namespace */ lua_pushlightuserdata(L, &ngx_http_lua_headerfilterby_ngx_key); lua_rawget(L, LUA_REGISTRYINDEX); lua_setfield(L, -2, "ngx"); /* }}} */ /* {{{ make new env inheriting main thread's globals table */ lua_createtable(L, 0, 1 /* nrec */); /* the metatable for the new env */ ngx_http_lua_get_globals_table(L); lua_setfield(L, -2, "__index"); lua_setmetatable(L, -2); /* setmetatable({}, {__index = _G}) */ /* }}} */ lua_setfenv(L, -2); /* set new running env for the code closure */ }
/* l_obj[".c_instance"] = c_obj */ return 0; } #ifdef LUA_VERSION_NUM /* lua 5.1 */ static int tolua_bnd_setpeer(lua_State *L) { /* stack: userdata, table */ if (!lua_isuserdata(L, -2)) { lua_pushstring(L, "Invalid argument #1 to setpeer: userdata expected."); lua_error(L); } if (lua_isnil(L, -1)) { lua_pop(L, 1); lua_pushvalue(L, TOLUA_NOPEER); } #if LUA_VERSION_NUM > 501 lua_setuservalue(L, -2); #else lua_setfenv(L, -2); #endif return 0; }
LUALIB_API int luaopen_io(lua_State * L) { createmeta(L); /* create (private) environment (with fields IO_INPUT, IO_OUTPUT, __close) */ lua_createtable(L, 2, 1); lua_replace(L, LUA_ENVIRONINDEX); /* open library */ luaL_register(L, LUA_IOLIBNAME, iolib); /* create (and set) default files */ createstdfile(L, stdin, IO_INPUT, "stdin"); createstdfile(L, stdout, IO_OUTPUT, "stdout"); createstdfile(L, stderr, 0, "stderr"); /* create environment for 'popen' */ lua_getfield(L, -1, "popen"); lua_createtable(L, 0, 1); lua_pushcfunction(L, io_pclose); lua_setfield(L, -2, "__close"); lua_setfenv(L, -2); lua_pop(L, 1); /* pop 'popen' */ /* set default close function */ lua_pushcfunction(L, io_fclose); lua_setfield(L, LUA_ENVIRONINDEX, "__close"); return 1; }
static void unpersistfunction(int ref, UnpersistInfo *upi) { /* perms reftbl ... */ LClosure *lcl; int i; lu_byte nupvalues; verify(luaZ_read(&upi->zio, &nupvalues, sizeof(lu_byte)) == 0); lcl = (LClosure*)luaF_newLclosure(upi->L, nupvalues, &upi->L->_gt); pushclosure(upi->L, (Closure*)lcl); /* perms reftbl ... func */ /* Put *some* proto in the closure, before the GC can find it */ lcl->p = makefakeproto(upi->L, nupvalues); /* Also, we need to temporarily fill the upvalues */ lua_pushnil(upi->L); /* perms reftbl ... func nil */ for(i=0; i<nupvalues; i++) { lcl->upvals[i] = makeupval(upi->L, -1); } lua_pop(upi->L, 1); /* perms reftbl ... func */ /* I can't see offhand how a function would ever get to be self- * referential, but just in case let's register it early */ registerobject(ref, upi); /* Now that it's safe, we can get the real proto */ unpersist(upi); /* perms reftbl ... func proto? */ lua_assert(lua_type(upi->L, -1) == LUA_TPROTO); /* perms reftbl ... func proto */ lcl->p = toproto(upi->L, -1); lua_pop(upi->L, 1); /* perms reftbl ... func */ for(i=0; i<nupvalues; i++) { /* perms reftbl ... func */ unpersist(upi); /* perms reftbl ... func func2 */ unboxupval(upi->L); /* perms reftbl ... func upval */ lcl->upvals[i] = toupval(upi->L, -1); lua_pop(upi->L, 1); /* perms reftbl ... func */ } /* perms reftbl ... func */ /* Finally, the fenv */ unpersist(upi); /* perms reftbl ... func fenv/nil? */ lua_assert(lua_type(upi->L, -1) == LUA_TNIL || lua_type(upi->L, -1) == LUA_TTABLE); /* perms reftbl ... func fenv/nil */ if(!lua_isnil(upi->L, -1)) { /* perms reftbl ... func fenv */ lua_setfenv(upi->L, -2); /* perms reftbl ... func */ } else { /* perms reftbl ... func nil */ lua_pop(upi->L, 1); /* perms reftbl ... func */ } /* perms reftbl ... func */ }
void thread_particle_init(particle_thread *pt, plist *l) { lua_State *L = pt->L; particles_type *ps = l->ps; int tile_w, tile_h; int base_size = 0; // Load the particle definition // Returns: generator_fct:1, update_fct:2, max:3, gl:4, no_stop:5 if (!luaL_loadfile(L, ps->name_def)) { // Make a new table to serve as environment for the function lua_newtable(L); if (!luaL_loadstring(L, ps->args)) { lua_pushvalue(L, -2); // Copy the evn table lua_setfenv(L, -2); // Set it as the function env if (lua_pcall(L, 0, 0, 0)) { printf("Particle args init error %x (%s): %s\n", (int)l, ps->args, lua_tostring(L, -1)); lua_pop(L, 1); } } else { lua_pop(L, 1); printf("Loading particle arguments failed: %s\n", ps->args); } // Copy tile_w and tile_h for compatibility with old code lua_pushstring(L, "engine"); lua_newtable(L); lua_pushstring(L, "Map"); lua_newtable(L); lua_pushstring(L, "tile_w"); lua_pushstring(L, "tile_w"); lua_gettable(L, -7); tile_w = lua_tonumber(L, -1); lua_settable(L, -3); lua_pushstring(L, "tile_h"); lua_pushstring(L, "tile_h"); lua_gettable(L, -7); tile_h = lua_tonumber(L, -1); lua_settable(L, -3); lua_settable(L, -3); lua_settable(L, -3); // The metatable which references the global space lua_newtable(L); lua_pushstring(L, "__index"); lua_pushvalue(L, LUA_GLOBALSINDEX); lua_settable(L, -3); // Set the environment metatable lua_setmetatable(L, -2); // Set the environment lua_pushvalue(L, -1); lua_setfenv(L, -3); lua_insert(L, -2); // Call the method if (lua_pcall(L, 0, 5, 0)) { printf("Particle run error %x (%s): %s\n", (int)l, ps->args, lua_tostring(L, -1)); lua_pop(L, 1); } // Check base size lua_pushstring(L, "base_size"); lua_gettable(L, -7); base_size = lua_tonumber(L, -1); lua_pop(L, 1); lua_remove(L, -6); } else { lua_pop(L, 1); return; } int nb = lua_isnumber(L, 3) ? lua_tonumber(L, 3) : 1000; nb = (nb * ps->density) / 100; if (!nb) nb = 1; ps->nb = nb; ps->no_stop = lua_toboolean(L, 5); ps->zoom = 1; if (base_size) { ps->zoom = (((float)tile_w + (float)tile_h) / 2) / (float)base_size; } int batch = nb; ps->batch_nb = 0; ps->vertices = calloc(2*4*batch, sizeof(GLfloat)); // 2 coords, 4 vertices per particles ps->colors = calloc(4*4*batch, sizeof(GLfloat)); // 4 color data, 4 vertices per particles ps->texcoords = calloc(2*4*batch, sizeof(GLshort)); ps->particles = calloc(nb, sizeof(particle_type)); // Locate the updator lua_getglobal(L, "__fcts"); l->updator_ref = lua_objlen(L, -1) + 1; lua_pushnumber(L, lua_objlen(L, -1) + 1); lua_pushvalue(L, 2); lua_rawset(L, -3); lua_pop(L, 1); // Grab all parameters lua_pushvalue(L, 1); lua_pushstring(L, "system_rotation"); lua_gettable(L, -2); ps->rotate = lua_tonumber(L, -1); lua_pop(L, 1); lua_pushstring(L, "system_rotationv"); lua_gettable(L, -2); ps->rotate_v = lua_tonumber(L, -1); lua_pop(L, 1); lua_pushstring(L, "engine"); lua_gettable(L, -2); ps->engine = lua_tonumber(L, -1); lua_pop(L, 1); lua_pushstring(L, "blend_mode"); lua_gettable(L, -2); ps->blend_mode = lua_tonumber(L, -1); lua_pop(L, 1); lua_pushstring(L, "generator"); lua_gettable(L, -2); if (lua_isnil(L, -1)) { lua_pop(L, 1); l->generator_ref = LUA_NOREF; } else { lua_getglobal(L, "__fcts"); l->generator_ref = lua_objlen(L, -1) + 1; lua_pushnumber(L, lua_objlen(L, -1) + 1); lua_pushvalue(L, -3); lua_rawset(L, -3); lua_pop(L, 2); } if (l->generator_ref == LUA_NOREF) { lua_pushstring(L, "base"); lua_gettable(L, -2); ps->base = (float)lua_tonumber(L, -1); lua_pop(L, 1); getinitfield(L, "life", &(ps->life_min), &(ps->life_max)); getinitfield(L, "angle", &(ps->angle_min), &(ps->angle_max)); getinitfield(L, "anglev", &(ps->anglev_min), &(ps->anglev_max)); getinitfield(L, "anglea", &(ps->anglea_min), &(ps->anglea_max)); getinitfield(L, "size", &(ps->size_min), &(ps->size_max)); getinitfield(L, "sizev", &(ps->sizev_min), &(ps->sizev_max)); getinitfield(L, "sizea", &(ps->sizea_min), &(ps->sizea_max)); getinitfield(L, "r", &(ps->r_min), &(ps->r_max)); getinitfield(L, "rv", &(ps->rv_min), &(ps->rv_max)); getinitfield(L, "ra", &(ps->ra_min), &(ps->ra_max)); getinitfield(L, "g", &(ps->g_min), &(ps->g_max)); getinitfield(L, "gv", &(ps->gv_min), &(ps->gv_max)); getinitfield(L, "ga", &(ps->ga_min), &(ps->ga_max)); getinitfield(L, "b", &(ps->b_min), &(ps->b_max)); getinitfield(L, "bv", &(ps->bv_min), &(ps->bv_max)); getinitfield(L, "ba", &(ps->ba_min), &(ps->ba_max)); getinitfield(L, "a", &(ps->a_min), &(ps->a_max)); getinitfield(L, "av", &(ps->av_min), &(ps->av_max)); getinitfield(L, "aa", &(ps->aa_min), &(ps->aa_max)); // printf("Particle emiter using default generator\n"); } else { // printf("Particle emiter using custom generator\n"); } lua_pop(L, 1); // Pop all returns lua_pop(L, 5); // Push a special emitter lua_newtable(L); lua_pushstring(L, "ps"); lua_newtable(L); lua_pushstring(L, "emit"); lua_pushlightuserdata(L, l); lua_pushcclosure(L, particles_emit, 1); lua_settable(L, -3); lua_settable(L, -3); lua_getglobal(L, "__fcts"); l->emit_ref = lua_objlen(L, -1) + 1; lua_pushnumber(L, lua_objlen(L, -1) + 1); lua_pushvalue(L, -3); lua_rawset(L, -3); lua_pop(L, 1); lua_pop(L, 1); free((char*)ps->name_def); free((char*)ps->args); ps->name_def = ps->args = NULL; ps->init = TRUE; }
static ngx_int_t ngx_http_lua_access_by_chunk(lua_State *L, ngx_http_request_t *r) { int cc_ref; ngx_int_t rc; lua_State *cc; ngx_http_lua_ctx_t *ctx; ngx_http_cleanup_t *cln; /* {{{ new coroutine to handle request */ cc = ngx_http_lua_new_thread(r, L, &cc_ref); if (cc == NULL) { ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "lua: failed to create new coroutine " "to handle request"); return NGX_HTTP_INTERNAL_SERVER_ERROR; } /* move code closure to new coroutine */ lua_xmove(L, cc, 1); /* set closure's env table to new coroutine's globals table */ lua_pushvalue(cc, LUA_GLOBALSINDEX); lua_setfenv(cc, -2); /* save reference of code to ease forcing stopping */ lua_pushvalue(cc, -1); lua_setglobal(cc, GLOBALS_SYMBOL_RUNCODE); /* save nginx request in coroutine globals table */ lua_pushlightuserdata(cc, r); lua_setglobal(cc, GLOBALS_SYMBOL_REQUEST); /* }}} */ /* {{{ initialize request context */ ctx = ngx_http_get_module_ctx(r, ngx_http_lua_module); dd("ctx = %p", ctx); if (ctx == NULL) { return NGX_ERROR; } ngx_http_lua_reset_ctx(r, L, ctx); ctx->entered_access_phase = 1; ctx->cc = cc; ctx->cc_ref = cc_ref; /* }}} */ /* {{{ register request cleanup hooks */ if (ctx->cleanup == NULL) { cln = ngx_http_cleanup_add(r, 0); if (cln == NULL) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } cln->handler = ngx_http_lua_request_cleanup; cln->data = r; ctx->cleanup = &cln->handler; } /* }}} */ rc = ngx_http_lua_run_thread(L, r, ctx, 0); dd("returned %d", (int) rc); if (rc == NGX_ERROR || rc >= NGX_HTTP_SPECIAL_RESPONSE) { return rc; } if (rc == NGX_AGAIN) { return NGX_DONE; } if (rc == NGX_DONE) { ngx_http_finalize_request(r, NGX_DONE); return NGX_DONE; } if (rc >= NGX_HTTP_OK && rc < NGX_HTTP_SPECIAL_RESPONSE) { return rc; } if (rc == NGX_OK) { return NGX_OK; } return NGX_DECLINED; }
/* ** Create a new 'ktable' to the pattern at the top of the stack. */ static void newktable (lua_State *L, int n) { lua_createtable(L, n, 0); /* create a fresh table */ lua_setfenv(L, -2); /* set it as 'ktable' for pattern */ }
// __depersist metamethod handler static int l_str_depersist(lua_State *L) { lua_settop(L, 2); lua_insert(L, 1); LuaPersistReader *pReader = (LuaPersistReader*)lua_touserdata(L, 1); // Read the instructions for re-creating the value if(!pReader->readStackObject()) return 0; if(lua_type(L, 3) == LUA_TBOOLEAN && lua_toboolean(L, 3) == 1) { // The current code uses a boolean marker to indicate that the // instructions were stored in the environment. Replace the marker // with them. lua_getfenv(L, 2); lua_replace(L, 3); } else { // Older versions of the code wrote the instructions here, or nil for // no instructions. Convert nil to the empty table, and store the // instructions as the userdata's environment. if(lua_type(L, 3) == LUA_TNIL) { lua_newtable(L); lua_replace(L, 3); } lua_pushvalue(L, 3); lua_setfenv(L, 2); } // Prepare t, k for saving the value aux_push_weak_table(L, 0); lua_pushvalue(L, 2); if(lua_objlen(L, 3) == 0) { // No instructions provided, so read the value itself if(!pReader->readStackObject()) return 0; } else { // The instructions are a table of values; unpack them and replace // proxies with their values. bool bIsIndexOperation = false; int iCount = (int)lua_objlen(L, 3); lua_checkstack(L, iCount + 1); for(int i = 1; i <= iCount; ++i) { lua_rawgeti(L, 3, i); if(lua_type(L, -1) == LUA_TUSERDATA) { if(i == 1) bIsIndexOperation = true; lua_rawget(L, 4); } } if(iCount == 2 && bIsIndexOperation) { // If there were two values, and the first was a proxy, then the // instruction is to perform a table lookup. lua_gettable(L, -2); lua_replace(L, -2); } else { // Otherwise, the first value was a method or method name. if(lua_type(L, 6) != LUA_TFUNCTION) { lua_pushvalue(L, 6); lua_gettable(L, 7); lua_replace(L, 6); } lua_call(L, iCount - 1, 1); } } // Save the value lua_rawset(L, 4); return 0; }
virtual bool readStackObject() { uint64_t iIndex; if(!readVUInt(iIndex)) { setError("Expected stack object"); return false; } lua_State *L = m_L; if(lua_type(L, 1) != LUA_TTABLE) { // Ensure that index #1 is self environment lua_getfenv(L, 1); lua_replace(L, 1); } if(iIndex >= PERSIST_TCOUNT) { iIndex += 1 - PERSIST_TCOUNT; if(iIndex < (uint64_t)INT_MAX) lua_rawgeti(L, 1, (int)iIndex); else { lua_pushnumber(L, (lua_Number)iIndex); lua_rawget(L, 1); } if(lua_isnil(L, -1)) { setError("Cycle while depersisting permanent object key or userdata metatable"); return false; } } else { uint8_t iType = (uint8_t)iIndex; switch(iType) { case LUA_TNIL: lua_pushnil(L); break; case PERSIST_TPERMANENT: { uint64_t iOldIndex = m_iNextIndex; ++m_iNextIndex; // Temporary marker lua_rawgeti(L, 1, 0); // Permanents table if(!readStackObject()) return false; lua_gettable(L, -2); lua_replace(L, -2); // Replace marker with actual object uint64_t iNewIndex = m_iNextIndex; m_iNextIndex = iOldIndex; saveStackObject(); m_iNextIndex = iNewIndex; break; } case LUA_TBOOLEAN: lua_pushboolean(L, 0); break; case PERSIST_TTRUE: lua_pushboolean(L, 1); break; case LUA_TSTRING: { size_t iLength; if(!readVUInt(iLength)) return false; while(iLength > m_iStringBufferLength) { m_iStringBufferLength *= 2; m_sStringBuffer = (char*)realloc(m_sStringBuffer, m_iStringBufferLength); } if(!readByteStream((uint8_t*)m_sStringBuffer, iLength)) return false; lua_pushlstring(L, m_sStringBuffer, iLength); saveStackObject(); break; } case LUA_TTABLE: lua_newtable(L); saveStackObject(); if(!lua_checkstack(L, 8)) return false; if(!readTableContents()) return false; break; case PERSIST_TTABLE_WITH_META: lua_newtable(L); saveStackObject(); if(!lua_checkstack(L, 8)) return false; if(!readStackObject()) return false; lua_setmetatable(L, -2); if(!readTableContents()) return false; break; case LUA_TNUMBER: { double fValue; if(!readByteStream(reinterpret_cast<uint8_t*>(&fValue), sizeof(double))) return false; lua_pushnumber(L, fValue); break; } case LUA_TFUNCTION: { if(!lua_checkstack(L, 8)) return false; uint64_t iOldIndex = m_iNextIndex; ++m_iNextIndex; // Temporary marker if(!readStackObject()) return false; lua_call(L, 0, 2); // Replace marker with closure uint64_t iNewIndex = m_iNextIndex; m_iNextIndex = iOldIndex; saveStackObject(); m_iNextIndex = iNewIndex; // Set upvalues lua_insert(L, -2); int iNups, i; if(!readVUInt(iNups)) return false; size_t iIDSize; if(!readVUInt(iIDSize)) return false; for(i = 0; i < iNups; ++i) { if(!readStackObject()) return false; // For now, just skip over the upvalue IDs. In the future, // the ID may be used to rejoin shared upvalues. if(!readByteStream(NULL, iIDSize)) return false; } lua_call(L, iNups, 0); // Read environment if(!readStackObject()) return false; lua_setfenv(L, -2); break; } case PERSIST_TPROTOTYPE: { if(!lua_checkstack(L, 8)) return false; uint64_t iOldIndex = m_iNextIndex; ++m_iNextIndex; // Temporary marker int iNups; if(!readVUInt(iNups)) return false; if(iNups == 0) lua_pushliteral(L, "return function() end,"); else { lua_pushliteral(L, "local "); lua_checkstack(L, (iNups + 1) * 2); for(int i = 0; i < iNups; ++i) { if(i != 0) lua_pushliteral(L, ","); if(!readStackObject()) return false; if(lua_type(L, -1) != LUA_TSTRING) { setError("Upvalue name not a string"); return false; } } lua_concat(L, iNups * 2 - 1); lua_pushliteral(L, ";return function(...)"); lua_pushvalue(L, -2); lua_pushliteral(L, "=...end,"); lua_concat(L, 5); } // Fetch name and then lookup filename and code if(!readStackObject()) return false; lua_pushliteral(L, "@"); lua_rawgeti(L, 1, -1); lua_pushvalue(L, -3); lua_gettable(L, -2); lua_replace(L, -2); if(lua_isnil(L, -1)) { setError(lua_pushfstring(L, "Unable to depersist prototype" " \'%s\'", lua_tostring(L, -3))); return false; } lua_concat(L, 2); // Prepend the @ to the filename lua_rawgeti(L, 1, -2); lua_pushvalue(L, -3); lua_gettable(L, -2); lua_replace(L, -2); lua_remove(L, -3); // Construct the closure factory LoadMultiBuffer_t ls; ls.s[0] = lua_tolstring(L, -3, &ls.i[0]); ls.s[1] = lua_tolstring(L, -1, &ls.i[1]); if(lua_load(L, LoadMultiBuffer_t::load_fn, &ls, lua_tostring(L, -2)) != 0) { // Should never happen lua_error(L); return false; } lua_replace(L, -4); lua_pop(L, 2); // Replace marker with closure factory uint64_t iNewIndex = m_iNextIndex; m_iNextIndex = iOldIndex; saveStackObject(); m_iNextIndex = iNewIndex; break; } case LUA_TUSERDATA: { bool bHasSetMetatable = false; uint64_t iOldIndex = m_iNextIndex; ++m_iNextIndex; // Temporary marker // Read metatable if(!readStackObject()) return false; lua_getfield(L, -1, "__depersist_size"); if(!lua_isnumber(L, -1)) { setError("Userdata missing __depersist_size metafield"); return false; } lua_newuserdata(L, (size_t)lua_tonumber(L, -1)); lua_replace(L, -2); // Replace marker with userdata uint64_t iNewIndex = m_iNextIndex; m_iNextIndex = iOldIndex; saveStackObject(); m_iNextIndex = iNewIndex; // Perform immediate initialisation lua_getfield(L, -2, "__pre_depersist"); if(lua_isnil(L, -1)) lua_pop(L, 1); else { // Set metatable now, as pre-depersister may expect it // NB: Setting metatable if there isn't a pre-depersister // is not a good idea, as if there is an error while the // environment table is being de-persisted, then the __gc // handler of the userdata will eventually be called with // the userdata's contents still being uninitialised. lua_pushvalue(L, -3); lua_setmetatable(L, -3); bHasSetMetatable = true; lua_pushvalue(L, -2); lua_call(L, 1, 0); } // Read environment if(!readStackObject()) return false; lua_setfenv(L, -2); // Set metatable and read the raw data if(!bHasSetMetatable) { lua_pushvalue(L, -2); lua_setmetatable(L, -2); } lua_getfield(L, -2, "__depersist"); if(lua_isnil(L, -1)) lua_pop(L, 1); else { lua_pushvalue(L, -2); lua_rawgeti(L, 1, -3); lua_call(L, 2, 1); if(lua_toboolean(L, -1) != 0) { lua_pop(L, 1); lua_rawgeti(L, 1, -3); lua_getmetatable(L, -1); lua_replace(L, -2); lua_pushvalue(L, -2); lua_rawseti(L, -2, (int)lua_objlen(L, -2) + 1); } lua_pop(L, 1); } lua_replace(L, -2); uint64_t iSyncMarker; if(!readVUInt(iSyncMarker)) return false; if(iSyncMarker != 0x42) { setError("sync fail"); return false; } break; } case PERSIST_TINTEGER: { uint16_t iValue; if(!readVUInt(iValue)) return false; lua_pushinteger(L, iValue); break; } default: lua_pushliteral(L, "Unable to depersist values of type \'"); if(iType <= LUA_TTHREAD) lua_pushstring(L, lua_typename(L, iType)); else { switch(iType) { case PERSIST_TPERMANENT: lua_pushliteral(L, "permanent"); break; case PERSIST_TTRUE: lua_pushliteral(L, "boolean-true"); break; case PERSIST_TTABLE_WITH_META: lua_pushliteral(L, "table-with-metatable"); break; case PERSIST_TINTEGER: lua_pushliteral(L, "integer"); break; case PERSIST_TPROTOTYPE: lua_pushliteral(L, "prototype"); break; case PERSIST_TRESERVED1: lua_pushliteral(L, "reserved1"); break; case PERSIST_TRESERVED2: lua_pushliteral(L, "reserved2"); break; } } lua_pushliteral(L, "\'"); lua_concat(L, 3); setError(lua_tostring(L, -1)); lua_pop(L, 1); return false; } } return true; }
apr_status_t LuaAction::run(ActionCtx *actionCtx) const { RUM_PTRC_ACTION(actionCtx->reqCtx()->pool(), "LuaAction::run(ActionCtx *actionCtx), " "actionCtx: " << (void *)actionCtx); RUM_LOG_ACTION(actionCtx->reqCtx()->logger(), APLOG_DEBUG, "LuaAction: executing chunk"); int lStatus; apr_status_t aStatus; ReqCtx *reqCtx = actionCtx->reqCtx(); lua_State *L = reqCtx->luaState(); if (L == 0) { RUM_LOG_ACTION(actionCtx->reqCtx()->logger(), APLOG_ERR, "aborting Lua action due to errors"); return APR_EGENERAL; } lua_pop(L, lua_gettop(L)); // if custom error handler is defined, push it onto the stack, // otherwise use debug.traceback if (reqCtx->config().errHandlerChunk()) { const Blob *chunk = reqCtx->config().errHandlerChunk(); lStatus = luaL_loadbuffer(L, static_cast<const char *>(chunk->data()), chunk->size(), "<ErrorHandler>"); if (lStatus) { const char *msg = lua_tostring(L, -1); RUM_LOG_ACTION(actionCtx->reqCtx()->logger(), APLOG_ERR, "failed to load ErrorHandler Lua chunk: " << msg); return APR_EGENERAL; } } else { // push debug.traceback onto stack lua_getglobal(L, "debug"); lua_getfield(L, -1, "traceback"); lua_remove(L, -2); } // create Lua sandbox environment which inherits from main environment lua_newtable(L); lua_newtable(L); lua_pushliteral(L, "__index"); lua_pushvalue(L, LUA_GLOBALSINDEX); lua_settable(L, -3); lua_setmetatable(L, -2); int envTableIdx = lua_gettop(L); // make sure scripts can't access real global _G lua_pushliteral(L, "_G"); lua_pushvalue(L, -2); lua_settable(L, -3); // add sandbox env to registry so that interactive_lua() can access it lua_pushlightuserdata(L, sandboxEnvRegKey()); lua_pushvalue(L, envTableIdx); lua_settable(L, LUA_REGISTRYINDEX); // create "rum" table in sandbox environment lua_pushvalue(L, envTableIdx); lua_newtable(L); lua_pushvalue(L, -1); int tos = lua_gettop(L); aStatus = setRumFields(L, actionCtx); if (aStatus != APR_SUCCESS) { RUM_LOG_ACTION(actionCtx->reqCtx()->logger(), APLOG_ERR, "aborting Lua action due to errors"); return APR_EGENERAL; } lua_pop(L, lua_gettop(L) - tos); lua_setfield(L, -3, "rum"); tos = lua_gettop(L); // the "rum" table is now at the top of the stack // have the global "rum" proxy table inherit from the real // "rum" table in the sandbox environment we just created lua_getglobal(L, "rum"); lua_getmetatable(L, -1); lua_pushvalue(L, -3); lua_setfield(L, -2, "__index"); lua_pop(L, 2); // load and run CommonPreAction Lua chunks in sandbox StaticStrBuffer<32> nameBuf; nameBuf << "ruleIdx:" << actionCtx->ruleIdx(); apr_ssize_t i; apr_ssize_t numCPA = reqCtx->config().commonPreActions().size(); for (i = 0; i < numCPA; i++) { const Blob *chunk = reqCtx->config().commonPreActions()[i]; lStatus = luaL_loadbuffer(L, static_cast<const char *>(chunk->data()), chunk->size(), nameBuf.asStr()); if (lStatus) { const char *msg = lua_tostring(L, -1); RUM_LOG_ACTION(actionCtx->reqCtx()->logger(), APLOG_ERR, "failed to load CommonPreAction Lua chunk: " << msg); return APR_EGENERAL; } lua_pushvalue(L, envTableIdx); lua_setfenv(L, -2); lStatus = lua_pcall(L, 0, 0, 1); if (lStatus) { const char *msg = lua_tostring(L, -1); RUM_LOG_ACTION(actionCtx->reqCtx()->logger(), APLOG_ERR, "failed to execute CommonPreAction Lua chunk: " << msg); return APR_EGENERAL; } } // load and run Lua chunk in same sandbox as CommonPreAction lStatus = luaL_loadbuffer(L, static_cast<const char *>(chunk_->data()), chunk_->size(), nameBuf.asStr()); if (lStatus) { const char *msg = lua_tostring(L, -1); RUM_LOG_ACTION(actionCtx->reqCtx()->logger(), APLOG_ERR, "failed to load Lua chunk: " << msg); return APR_EGENERAL; } lua_pushvalue(L, envTableIdx); lua_setfenv(L, -2); lStatus = lua_pcall(L, 0, 1, 1); if (lStatus) { const char *msg = lua_tostring(L, -1); RUM_LOG_ACTION(actionCtx->reqCtx()->logger(), APLOG_ERR, "failed to execute Lua chunk: " << msg); return APR_EGENERAL; } // process optionally returned value aStatus = RUM_DEFAULT; if (lua_type(L, -1) == LUA_TNUMBER) { aStatus = static_cast<apr_status_t>(lua_tointeger(L, -1)); RUM_LOG_ACTION(actionCtx->reqCtx()->logger(), APLOG_INFO, "integer return code from action: " << aStatus); if ((aStatus != RUM_OK) && (aStatus != RUM_DELAYED_OK) && (aStatus != RUM_RELOOKUP) && (aStatus != RUM_DECLINED)) { RUM_LOG_ACTION(actionCtx->reqCtx()->logger(), APLOG_ERR, "invalid return code from action: " << aStatus); return APR_EGENERAL; } } else if (lua_type(L, -1) == LUA_TNIL) { RUM_LOG_ACTION(actionCtx->reqCtx()->logger(), APLOG_INFO, "nil return code from action"); } else { RUM_LOG_ACTION(actionCtx->reqCtx()->logger(), APLOG_ERR, "invalid non-integer return code from action"); return APR_EGENERAL; } lua_pop(L, 1); #if 0 //bgt -- eliminate in favor of return codes // check status flags if (actionCtx->lastAction()) { aStatus = RUM_LAST_ACTION; } else if (actionCtx->relookup()) { aStatus = RUM_RELOOKUP; } #endif return aStatus; }
/** * Set environment table for the given code closure. * * Before: * | code closure | <- top * | ... | * * After: * | code closure | <- top * | ... | * */ static void ngx_http_lua_set_by_lua_env(lua_State *L, ngx_http_request_t *r, size_t nargs, ngx_http_variable_value_t *args) { /* set nginx request pointer to current lua thread's globals table */ lua_pushlightuserdata(L, r); lua_setglobal(L, GLOBALS_SYMBOL_REQUEST); /** * we want to create empty environment for current script * * setmetatable({}, {__index = _G}) * * if a function or symbol is not defined in our env, __index will lookup * in the global env. * * all variables created in the script-env will be thrown away at the end * of the script run. * */ lua_newtable(L); /* new empty environment aka {} */ /* override 'print' function */ lua_pushcfunction(L, ngx_http_lua_print); lua_setfield(L, -2, "print"); /* {{{ initialize ngx.* namespace */ lua_newtable(L); /* ngx.* */ lua_newtable(L); /* .arg table aka {} */ lua_newtable(L); /* the metatable for new param table */ lua_pushinteger(L, nargs); /* 1st upvalue: argument number */ lua_pushlightuserdata(L, args); /* 2nd upvalue: pointer to arguments */ lua_pushcclosure(L, ngx_http_lua_param_get, 2); /* binding upvalues to __index meta-method closure */ lua_setfield(L, -2, "__index"); lua_setmetatable(L, -2); /* tie the metatable to param table */ lua_setfield(L, -2, "arg"); /* set ngx.arg table */ /* {{{ register reference maps */ lua_newtable(L); /* ngx.var */ lua_newtable(L); /* metatable for ngx.var */ lua_pushcfunction(L, ngx_http_lua_var_get); lua_setfield(L, -2, "__index"); lua_pushcfunction(L, ngx_http_lua_var_set); lua_setfield(L, -2, "__newindex"); lua_setmetatable(L, -2); lua_setfield(L, -2, "var"); /* }}} */ #if (NGX_PCRE) /* {{{ ngx.re table */ lua_newtable(L); /* .re */ lua_pushcfunction(L, ngx_http_lua_ngx_re_match); lua_setfield(L, -2, "match"); lua_pushcfunction(L, ngx_http_lua_ngx_re_gmatch); lua_setfield(L, -2, "gmatch"); lua_pushcfunction(L, ngx_http_lua_ngx_re_sub); lua_setfield(L, -2, "sub"); lua_pushcfunction(L, ngx_http_lua_ngx_re_gsub); lua_setfield(L, -2, "gsub"); lua_setfield(L, -2, "re"); /* }}} */ #endif /* NGX_PCRE */ lua_pushcfunction(L, ngx_http_lua_ngx_escape_uri); lua_setfield(L, -2, "escape_uri"); lua_pushcfunction(L, ngx_http_lua_ngx_unescape_uri); lua_setfield(L, -2, "unescape_uri"); lua_pushcfunction(L, ngx_http_lua_ngx_quote_sql_str); lua_setfield(L, -2, "quote_sql_str"); lua_pushcfunction(L, ngx_http_lua_ngx_decode_base64); lua_setfield(L, -2, "decode_base64"); lua_pushcfunction(L, ngx_http_lua_ngx_encode_base64); lua_setfield(L, -2, "encode_base64"); lua_pushcfunction(L, ngx_http_lua_ngx_md5_bin); lua_setfield(L, -2, "md5_bin"); lua_pushcfunction(L, ngx_http_lua_ngx_md5); lua_setfield(L, -2, "md5"); lua_pushcfunction(L, ngx_http_lua_ngx_time); lua_setfield(L, -2, "get_now_ts"); /* deprecated */ lua_pushcfunction(L, ngx_http_lua_ngx_utctime); lua_setfield(L, -2, "utctime"); lua_pushcfunction(L, ngx_http_lua_ngx_localtime); lua_setfield(L, -2, "get_now"); /* deprecated */ lua_pushcfunction(L, ngx_http_lua_ngx_time); lua_setfield(L, -2, "time"); lua_pushcfunction(L, ngx_http_lua_ngx_localtime); lua_setfield(L, -2, "localtime"); lua_pushcfunction(L, ngx_http_lua_ngx_today); lua_setfield(L, -2, "get_today"); /* deprecated */ lua_pushcfunction(L, ngx_http_lua_ngx_today); lua_setfield(L, -2, "today"); lua_pushcfunction(L, ngx_http_lua_ngx_http_time); lua_setfield(L, -2, "http_time"); lua_pushcfunction(L, ngx_http_lua_ngx_parse_http_time); lua_setfield(L, -2, "parse_http_time"); lua_pushcfunction(L, ngx_http_lua_ngx_cookie_time); lua_setfield(L, -2, "cookie_time"); lua_pushcfunction(L, ngx_http_lua_ngx_log); lua_setfield(L, -2, "log"); ngx_http_lua_inject_log_consts(L); /* ngx. getter and setter */ lua_createtable(L, 0, 2); /* metatable for .ngx */ lua_pushcfunction(L, ngx_http_lua_ngx_get); lua_setfield(L, -2, "__index"); lua_pushcfunction(L, ngx_http_lua_ngx_set); lua_setfield(L, -2, "__newindex"); lua_setmetatable(L, -2); lua_setfield(L, -2, "ngx"); /* }}} */ /* {{{ make new env inheriting main thread's globals table */ lua_newtable(L); /* the metatable for the new env */ lua_pushvalue(L, LUA_GLOBALSINDEX); lua_setfield(L, -2, "__index"); lua_setmetatable(L, -2); /* setmetatable({}, {__index = _G}) */ /* }}} */ lua_setfenv(L, -2); /* set new running env for the code closure */ }
ngx_int_t ngx_http_lua_content_by_chunk(lua_State *L, ngx_http_request_t *r) { int cc_ref; lua_State *cc; ngx_http_lua_ctx_t *ctx; ngx_http_cleanup_t *cln; dd("content by chunk"); ctx = ngx_http_get_module_ctx(r, ngx_http_lua_module); if (ctx == NULL) { ctx = ngx_pcalloc(r->pool, sizeof(ngx_http_lua_ctx_t)); if (ctx == NULL) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } dd("setting new ctx, ctx = %p", ctx); ctx->cc_ref = LUA_NOREF; ctx->ctx_ref = LUA_NOREF; ngx_http_set_ctx(r, ctx, ngx_http_lua_module); } else { dd("reset ctx"); ngx_http_lua_reset_ctx(r, L, ctx); } ctx->entered_content_phase = 1; /* {{{ new coroutine to handle request */ cc = ngx_http_lua_new_thread(r, L, &cc_ref); if (cc == NULL) { ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "(lua-content-by-chunk) failed to create new coroutine " "to handle request"); return NGX_HTTP_INTERNAL_SERVER_ERROR; } /* move code closure to new coroutine */ lua_xmove(L, cc, 1); /* set closure's env table to new coroutine's globals table */ lua_pushvalue(cc, LUA_GLOBALSINDEX); lua_setfenv(cc, -2); /* save reference of code to ease forcing stopping */ lua_pushvalue(cc, -1); lua_setglobal(cc, GLOBALS_SYMBOL_RUNCODE); /* save nginx request in coroutine globals table */ lua_pushlightuserdata(cc, r); lua_setglobal(cc, GLOBALS_SYMBOL_REQUEST); /* }}} */ ctx->cc = cc; ctx->cc_ref = cc_ref; /* {{{ register request cleanup hooks */ if (ctx->cleanup == NULL) { cln = ngx_http_cleanup_add(r, 0); if (cln == NULL) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } cln->handler = ngx_http_lua_request_cleanup; cln->data = r; ctx->cleanup = &cln->handler; } /* }}} */ return ngx_http_lua_run_thread(L, r, ctx, 0); }
bool CLuaVMClass::loadFromPackage(weak_ptr<CPackage> package) { _package = package; shared_ptr<CPackage> locked = package.lock(); if ( locked == nullptr ) return false; shared_ptr<CLuaVM> host = getLuaHost().lock(); lua_State *L = host->getState(); _functions.clear(); CCodeAsset* luaMain = castAsset<CCodeAsset>( locked->findAssetByName("main.code") ); if ( luaMain == nullptr ) { log(LOG_ERROR, "Failed to load 'main.code'"); return false; } if (luaL_loadbuffer(L, luaMain->getCodeBuffer(), luaMain->getCodeLength(), *luaMain->getName())) { std::cout << "Lua: " << *luaMain->getName() << " : " << lua_tostring(L, -1) << std::endl; lua_pop(L, 1); return false; } lua_newtable(L); lua_pushlightuserdata(L, this); lua_setfield(L, -2, "__klass"); lua_newtable(L); _locals = makeShared<LuaVMReference>(getLuaHost(), -1); lua_setfield(L, -2, "__locals"); lua_newtable(L); lua_pushcclosure(L, CLuaVMClass::metaTopLevelGet, 0); lua_setfield(L, -2, "__index"); lua_pushcclosure(L, CLuaVMClass::metaTopLevelSet, 0); lua_setfield(L, -2, "__newindex"); lua_setmetatable(L, -2); lua_setfenv(L, -2); if (lua_pcall(L, 0, 0, 0)) { std::cout << "Lua: " << lua_tostring(L, -1) << std::endl; lua_pop(L, 1); return false; } for ( uint32 i=0; i<locked->getNumAssets(); ++i ) { CCodeAsset* lib = castAsset<CCodeAsset>( locked->getAsset(i) ); if ( lib && lib != luaMain ) { if (luaL_loadbuffer(L, lib->getCodeBuffer(), lib->getCodeLength(), *lib->getName())) { std::cout << "Lua: " << *lib->getName() << " : " << lua_tostring(L, -1) << std::endl; lua_pop(L, 1); } else { if (lua_pcall(L, 0, 0, 0)) { std::cout << "Lua: " << lua_tostring(L, -1) << std::endl; lua_pop(L, 1); } } } } return true; }
void SavedVariables::Load(lua_State *L){ auto FilePath = boostfs::absolute(FileName, SavedVariablesFolderPath); //just silently return if nothing has been saved before. The container table should have default values set in it by the owner if(!boostfs::exists(FilePath)){ return; } int ContainerIndex = LUA_GLOBALSINDEX; //add these 2 early to the stack so we don't have to deal with fun shifting stack indexs if(ContainerTable.is_valid()) { ContainerTable.push(L); ContainerIndex = lua_gettop(L); } lua_newtable(L); int EnvTable = lua_gettop(L); //adapted from http://danwellman.com/vws.html if(LuaModule::LoadLuaFile(L,FilePath, "") == 0){ //Set the chunk's environment to a table //import the constructors for Vector and Angles lua_getfield(L, LUA_GLOBALSINDEX, "Vector"); lua_setfield(L, EnvTable, "Vector"); lua_getfield(L, LUA_GLOBALSINDEX, "Angles"); lua_setfield(L, EnvTable, "Angles"); lua_getfield(L, LUA_GLOBALSINDEX, "Color"); lua_setfield(L, EnvTable, "Color"); lua_pushvalue(L, EnvTable); if (!lua_setfenv(L, -2)){ assert(false && "Chunk must be loaded"); } //Push the chunk to the top, required by pcall lua_pushvalue(L, EnvTable+1); //Remove the old chunk lua_remove(L, EnvTable+1); //Call the chunk, it then inserts any globals into the environment table if (lua_pcall(L, 0, 0, 0) == 0){ for (auto it = VariableNames.begin(), end = VariableNames.end(); it != end; ++it){ const char* FieldName = it->c_str(); lua_getfield(L, EnvTable, FieldName); if (lua_isnil(L, -1)){ lua_pop(L, 1); }else{ lua_setfield(L, ContainerIndex, FieldName); } } if(ContainerTable.is_valid()) lua_pop(L, 1); //Pop environment table lua_pop(L, 1); return; } } //we got an error while either parsing the saved variables file or when running it an error string should of been pushed onto the stack size_t len = 0; const char* s = lua_tolstring(L, -1, &len); if(s != NULL){ throw exception(s); }else{ throw std::runtime_error(string("Unknown error while loading saved variables from ")+FileName.string()); } }
// Initializes uv_process_t and starts the process. int luv_spawn(lua_State* L) { int before = lua_gettop(L); uv_pipe_t* stdin_stream = (uv_pipe_t*)luv_checkudata(L, 1, "pipe"); uv_pipe_t* stdout_stream = (uv_pipe_t*)luv_checkudata(L, 2, "pipe"); uv_pipe_t* stderr_stream = (uv_pipe_t*)luv_checkudata(L, 3, "pipe"); const char* command = luaL_checkstring(L, 4); luaL_checktype(L, 5, LUA_TTABLE); // args luaL_checktype(L, 6, LUA_TTABLE); // options // Parse the args array size_t argc = lua_objlen(L, 5) + 1; char** args = malloc(argc + 1); args[0] = (char*)command; int i; for (i = 1; i < argc; i++) { lua_rawgeti(L, 5, i); args[i] = (char*)lua_tostring(L, -1); lua_pop(L, 1); } args[argc] = NULL; // Get the cwd lua_getfield(L, 6, "cwd"); char* cwd = (char*)lua_tostring(L, -1); lua_pop(L, 1); // Get the env lua_getfield(L, 6, "env"); char** env = NULL; if (lua_type(L, -1) == LUA_TTABLE) { argc = lua_objlen(L, -1); env = malloc(argc + 1); for (i = 0; i < argc; i++) { lua_rawgeti(L, -1, i + 1); env[i] = (char*)lua_tostring(L, -1); lua_pop(L, 1); } env[argc] = NULL; } lua_pop(L, 1); uv_process_options_t options; options.exit_cb = luv_process_on_exit; options.file = command; options.args = args; options.env = env; options.cwd = cwd; options.stdin_stream = stdin_stream; options.stdout_stream = stdout_stream; options.stderr_stream = stderr_stream; // Create the userdata uv_process_t* handle = (uv_process_t*)lua_newuserdata(L, sizeof(uv_process_t)); int r = uv_spawn(uv_default_loop(), handle, options); free(args); if (env) free(env); if (r) { uv_err_t err = uv_last_error(uv_default_loop()); return luaL_error(L, "spawn: %s", uv_strerror(err)); } // Set metatable for type luaL_getmetatable(L, "luv_process"); lua_setmetatable(L, -2); // Create a local environment for storing stuff lua_newtable(L); lua_setfenv (L, -2); // Store a reference to the userdata in the handle luv_ref_t* ref = (luv_ref_t*)malloc(sizeof(luv_ref_t)); ref->L = L; lua_pushvalue(L, -1); // duplicate so we can _ref it ref->r = luaL_ref(L, LUA_REGISTRYINDEX); handle->data = ref; assert(lua_gettop(L) == before + 1); // return the userdata return 1; }
static int js_generator(lua_State *L) { yajl_print_t print = NULL; void * ctx = NULL; yajl_gen* handle; luaL_checktype(L, 1, LUA_TTABLE); /* {args}, ?, tbl */ lua_newtable(L); /* Validate and save in fenv so it isn't gc'ed: */ lua_getfield(L, 1, "printer"); if ( ! lua_isnil(L, -1) ) { js_printer_ctx* print_ctx; luaL_checktype(L, -1, LUA_TFUNCTION); lua_pushvalue(L, -1); /* {args}, ?, tbl, printer, printer */ lua_setfield(L, -3, "printer"); print_ctx = (js_printer_ctx*) lua_newuserdata(L, sizeof(js_printer_ctx)); /* {args}, ?, tbl, printer, printer_ctx */ lua_setfield(L, -3, "printer_ctx"); /* {args}, ?, tbl, printer */ lua_getfield(L, LUA_REGISTRYINDEX, "yajl.refs"); /* {args}, ?, tbl, printer, refs */ lua_insert(L, -2); /* {args}, ?, tbl, refs, printer */ print_ctx->printer_ref = luaL_ref(L, -2); print_ctx->L = L; print = &js_printer; ctx = print_ctx; } lua_pop(L, 1); /* {args}, ?, tbl */ /* Sucks that yajl's generator doesn't keep track of this for me (this is a stack of strings "array" and "object" so I can keep track of what to "close"): */ lua_newtable(L); lua_setfield(L, -2, "stack"); /* {args}, ?, tbl */ handle = (yajl_gen*)lua_newuserdata(L, sizeof(yajl_gen)); *handle = yajl_gen_alloc(NULL); /* {args}, ?, tbl, ud */ if ( print ) { yajl_gen_config(*handle, yajl_gen_print_callback, print, ctx); } /* Get the indent and save so it isn't gc'ed: */ lua_getfield(L, 1, "indent"); if ( ! lua_isnil(L, -1) ) { yajl_gen_config(*handle, yajl_gen_beautify, 1); yajl_gen_config(*handle, yajl_gen_indent_string, lua_tostring(L, -1)); lua_setfield(L, -3, "indent"); } else { lua_pop(L, 1); } /* {args}, ?, tbl, ud */ /* {args}, ?, tbl, ud, meta */ luaL_getmetatable(L, "yajl.generator.meta"); lua_setmetatable(L, -2); /* {args}, ?, tbl, ud */ lua_insert(L, -2); /* {args}, ?, ud, tbl */ lua_setfenv(L, -2); return 1; }
static handler_t magnet_attract(server *srv, connection *con, plugin_data *p, buffer *name) { lua_State *L; int lua_return_value = -1; /* get the script-context */ L = script_cache_get_script(srv, con, p->cache, name); if (lua_isstring(L, -1)) { log_error_write(srv, __FILE__, __LINE__, "sbss", "loading script", name, "failed:", lua_tostring(L, -1)); lua_pop(L, 1); assert(lua_gettop(L) == 0); /* only the function should be on the stack */ con->http_status = 500; con->mode = DIRECT; return HANDLER_FINISHED; } lua_pushstring(L, "lighty.srv"); lua_pushlightuserdata(L, srv); lua_settable(L, LUA_REGISTRYINDEX); /* registery[<id>] = srv */ lua_pushstring(L, "lighty.con"); lua_pushlightuserdata(L, con); lua_settable(L, LUA_REGISTRYINDEX); /* registery[<id>] = con */ lua_atpanic(L, magnet_atpanic); /** * we want to create empty environment for our script * * setmetatable({}, {__index = _G}) * * if a function, symbol is not defined in our env, __index will lookup * in the global env. * * all variables created in the script-env will be thrown * away at the end of the script run. */ lua_newtable(L); /* my empty environment aka {} (sp += 1) */ /* we have to overwrite the print function */ lua_pushcfunction(L, magnet_print); /* (sp += 1) */ lua_setfield(L, -2, "print"); /* -1 is the env we want to set(sp -= 1) */ /** * lighty.request[] has the HTTP-request headers * lighty.content[] is a table of string/file * lighty.header[] is a array to set response headers */ lua_newtable(L); /* lighty.* (sp += 1) */ lua_newtable(L); /* {} (sp += 1) */ lua_newtable(L); /* the meta-table for the request-table (sp += 1) */ lua_pushcfunction(L, magnet_reqhdr_get); /* (sp += 1) */ lua_setfield(L, -2, "__index"); /* (sp -= 1) */ lua_setmetatable(L, -2); /* tie the metatable to request (sp -= 1) */ lua_setfield(L, -2, "request"); /* content = {} (sp -= 1) */ lua_newtable(L); /* {} (sp += 1) */ lua_newtable(L); /* the meta-table for the request-table (sp += 1) */ lua_pushcfunction(L, magnet_env_get); /* (sp += 1) */ lua_setfield(L, -2, "__index"); /* (sp -= 1) */ lua_pushcfunction(L, magnet_env_set); /* (sp += 1) */ lua_setfield(L, -2, "__newindex"); /* (sp -= 1) */ lua_setmetatable(L, -2); /* tie the metatable to request (sp -= 1) */ lua_setfield(L, -2, "env"); /* content = {} (sp -= 1) */ lua_newtable(L); /* {} (sp += 1) */ lua_newtable(L); /* the meta-table for the request-table (sp += 1) */ lua_pushcfunction(L, magnet_status_get); /* (sp += 1) */ lua_setfield(L, -2, "__index"); /* (sp -= 1) */ lua_pushcfunction(L, magnet_status_set); /* (sp += 1) */ lua_setfield(L, -2, "__newindex"); /* (sp -= 1) */ lua_setmetatable(L, -2); /* tie the metatable to request (sp -= 1) */ lua_setfield(L, -2, "status"); /* content = {} (sp -= 1) */ /* add empty 'content' and 'header' tables */ lua_newtable(L); /* {} (sp += 1) */ lua_setfield(L, -2, "content"); /* content = {} (sp -= 1) */ lua_newtable(L); /* {} (sp += 1) */ lua_setfield(L, -2, "header"); /* header = {} (sp -= 1) */ lua_pushinteger(L, MAGNET_RESTART_REQUEST); lua_setfield(L, -2, "RESTART_REQUEST"); lua_pushcfunction(L, magnet_stat); /* (sp += 1) */ lua_setfield(L, -2, "stat"); /* -1 is the env we want to set (sp -= 1) */ lua_setfield(L, -2, "lighty"); /* lighty.* (sp -= 1) */ lua_newtable(L); /* the meta-table for the new env (sp += 1) */ lua_pushvalue(L, LUA_GLOBALSINDEX); /* (sp += 1) */ lua_setfield(L, -2, "__index"); /* { __index = _G } (sp -= 1) */ lua_setmetatable(L, -2); /* setmetatable({}, {__index = _G}) (sp -= 1) */ lua_setfenv(L, -2); /* on the stack should be a modified env (sp -= 1) */ if (lua_pcall(L, 0, 1, 0)) { log_error_write(srv, __FILE__, __LINE__, "ss", "lua_pcall():", lua_tostring(L, -1)); lua_pop(L, 1); /* remove the error-msg and the function copy from the stack */ assert(lua_gettop(L) == 1); /* only the function should be on the stack */ con->http_status = 500; con->mode = DIRECT; return HANDLER_FINISHED; } /* we should have the function-copy and the return value on the stack */ assert(lua_gettop(L) == 2); if (lua_isnumber(L, -1)) { /* if the ret-value is a number, take it */ lua_return_value = (int)lua_tonumber(L, -1); } lua_pop(L, 1); /* pop the ret-value */ magnet_copy_response_header(srv, con, p, L); if (lua_return_value > 99) { con->http_status = lua_return_value; con->file_finished = 1; /* try { ...*/ if (0 == setjmp(exceptionjmp)) { magnet_attach_content(srv, con, p, L); if (!chunkqueue_is_empty(con->write_queue)) { con->mode = p->id; } } else { /* } catch () { */ con->http_status = 500; con->mode = DIRECT; } assert(lua_gettop(L) == 1); /* only the function should be on the stack */ /* we are finished */ return HANDLER_FINISHED; } else if (MAGNET_RESTART_REQUEST == lua_return_value) { assert(lua_gettop(L) == 1); /* only the function should be on the stack */ return HANDLER_COMEBACK; } else { assert(lua_gettop(L) == 1); /* only the function should be on the stack */ return HANDLER_GO_ON; } }
TOLUA_API void tolua_pushusertype (lua_State* L, void* value, const char* type) { if (value == NULL) lua_pushnil(L); else { luaL_getmetatable(L, type); lua_pushstring(L,"tolua_ubox"); lua_rawget(L,-2); /* stack: mt ubox */ if (lua_isnil(L, -1)) { lua_pop(L, 1); lua_pushstring(L, "tolua_ubox"); lua_rawget(L, LUA_REGISTRYINDEX); }; lua_pushlightuserdata(L,value); lua_rawget(L,-2); /* stack: mt ubox ubox[u] */ if (lua_isnil(L,-1)) { lua_pop(L,1); /* stack: mt ubox */ lua_pushlightuserdata(L,value); *(void**)lua_newuserdata(L,sizeof(void *)) = value; /* stack: mt ubox u newud */ lua_pushvalue(L,-1); /* stack: mt ubox u newud newud */ lua_insert(L,-4); /* stack: mt newud ubox u newud */ lua_rawset(L,-3); /* stack: mt newud ubox */ lua_pop(L,1); /* stack: mt newud */ /*luaL_getmetatable(L,type);*/ lua_pushvalue(L, -2); /* stack: mt newud mt */ lua_setmetatable(L,-2); /* stack: mt newud */ #ifdef LUA_VERSION_NUM lua_pushvalue(L, TOLUA_NOPEER); lua_setfenv(L, -2); #endif } else { /* check the need of updating the metatable to a more specialized class */ lua_insert(L,-2); /* stack: mt ubox[u] ubox */ lua_pop(L,1); /* stack: mt ubox[u] */ lua_pushstring(L,"tolua_super"); lua_rawget(L,LUA_REGISTRYINDEX); /* stack: mt ubox[u] super */ lua_getmetatable(L,-2); /* stack: mt ubox[u] super mt */ lua_rawget(L,-2); /* stack: mt ubox[u] super super[mt] */ if (lua_istable(L,-1)) { lua_pushstring(L,type); /* stack: mt ubox[u] super super[mt] type */ lua_rawget(L,-2); /* stack: mt ubox[u] super super[mt] flag */ if (lua_toboolean(L,-1) == 1) /* if true */ { lua_pop(L,3); /* mt ubox[u]*/ lua_remove(L, -2); return; } } /* type represents a more specilized type */ /*luaL_getmetatable(L,type); // stack: mt ubox[u] super super[mt] flag mt */ lua_pushvalue(L, -5); /* stack: mt ubox[u] super super[mt] flag mt */ lua_setmetatable(L,-5); /* stack: mt ubox[u] super super[mt] flag */ lua_pop(L,3); /* stack: mt ubox[u] */ } lua_remove(L, -2); /* stack: ubox[u]*/ } }
static int ngx_http_lua_ngx_timer_at(lua_State *L) { int nargs, co_ref; u_char *p; lua_State *mt; /* the main thread */ lua_State *co; ngx_msec_t delay; ngx_event_t *ev; ngx_http_request_t *r; ngx_connection_t *saved_c = NULL; #if 0 ngx_http_connection_t *hc; #endif ngx_http_lua_timer_ctx_t *tctx; ngx_http_lua_main_conf_t *lmcf; #if 0 ngx_http_core_main_conf_t *cmcf; #endif nargs = lua_gettop(L); if (nargs < 2) { return luaL_error(L, "expecting at least 2 arguments but got %d", nargs); } delay = (ngx_msec_t) (luaL_checknumber(L, 1) * 1000); luaL_argcheck(L, lua_isfunction(L, 2) && !lua_iscfunction(L, 2), 2, "Lua function expected"); r = ngx_http_lua_get_req(L); if (r == NULL) { return luaL_error(L, "no request"); } if (ngx_exiting) { lua_pushnil(L); lua_pushliteral(L, "process exiting"); return 2; } lmcf = ngx_http_get_module_main_conf(r, ngx_http_lua_module); if (lmcf->pending_timers >= lmcf->max_pending_timers) { lua_pushnil(L); lua_pushliteral(L, "too many pending timers"); return 2; } if (lmcf->watcher == NULL) { /* create the watcher fake connection */ ngx_log_debug0(NGX_LOG_DEBUG_HTTP, ngx_cycle->log, 0, "lua creating fake watcher connection"); if (ngx_cycle->files) { saved_c = ngx_cycle->files[0]; } lmcf->watcher = ngx_get_connection(0, ngx_cycle->log); if (ngx_cycle->files) { ngx_cycle->files[0] = saved_c; } if (lmcf->watcher == NULL) { return luaL_error(L, "no memory"); } lmcf->watcher->fd = -2; /* to work around the -1 check in ngx_worker_process_cycle */ lmcf->watcher->idle = 1; lmcf->watcher->read->handler = ngx_http_lua_abort_pending_timers; lmcf->watcher->data = lmcf; } mt = lmcf->lua; co = lua_newthread(mt); /* L stack: time func [args] thread */ ngx_http_lua_probe_user_coroutine_create(r, L, co); lua_createtable(co, 0, 0); /* the new global table */ /* co stack: global_tb */ lua_createtable(co, 0, 1); /* the metatable */ lua_pushvalue(co, LUA_GLOBALSINDEX); lua_setfield(co, -2, "__index"); lua_setmetatable(co, -2); /* co stack: global_tb */ lua_replace(co, LUA_GLOBALSINDEX); /* co stack: <empty> */ dd("stack top: %d", lua_gettop(L)); lua_xmove(mt, L, 1); /* move coroutine from main thread to L */ /* L stack: time func [args] thread */ /* mt stack: empty */ lua_pushvalue(L, 2); /* copy entry function to top of L*/ /* L stack: time func [args] thread func */ lua_xmove(L, co, 1); /* move entry function from L to co */ /* L stack: time func [args] thread */ /* co stack: func */ lua_pushvalue(co, LUA_GLOBALSINDEX); lua_setfenv(co, -2); /* co stack: func */ lua_pushlightuserdata(L, &ngx_http_lua_coroutines_key); lua_rawget(L, LUA_REGISTRYINDEX); /* L stack: time func [args] thread corountines */ lua_pushvalue(L, -2); /* L stack: time func [args] thread coroutines thread */ co_ref = luaL_ref(L, -2); lua_pop(L, 1); /* L stack: time func [args] thread */ if (nargs > 2) { lua_pop(L, 1); /* L stack: time func [args] */ lua_xmove(L, co, nargs - 2); /* L stack: time func */ /* co stack: func [args] */ } p = ngx_alloc(sizeof(ngx_event_t) + sizeof(ngx_http_lua_timer_ctx_t), r->connection->log); if (p == NULL) { lua_pushlightuserdata(L, &ngx_http_lua_coroutines_key); lua_rawget(L, LUA_REGISTRYINDEX); luaL_unref(L, -1, co_ref); return luaL_error(L, "no memory"); } ev = (ngx_event_t *) p; ngx_memzero(ev, sizeof(ngx_event_t)); p += sizeof(ngx_event_t); tctx = (ngx_http_lua_timer_ctx_t *) p; tctx->premature = 0; tctx->co_ref = co_ref; tctx->co = co; tctx->main_conf = r->main_conf; tctx->srv_conf = r->srv_conf; tctx->loc_conf = r->loc_conf; tctx->lmcf = lmcf; ev->handler = ngx_http_lua_timer_handler; ev->data = tctx; ev->log = ngx_cycle->log; lmcf->pending_timers++; ngx_add_timer(ev, delay); lua_pushinteger(L, 1); return 1; }
static void commit_lua_upload(indigo_cxn_id_t cxn_id, of_object_t *msg) { uint16_t flags; of_bsn_lua_upload_flags_get(msg, &flags); /* TODO use stronger hash function */ uint32_t new_checksum = murmur_hash(xbuf_data(&upload_chunks), xbuf_length(&upload_chunks), 0); if (!(flags & OFP_BSN_LUA_UPLOAD_FORCE) && checksum == new_checksum) { AIM_LOG_VERBOSE("Skipping Lua commit, checksums match"); goto cleanup; } checksum = 0; reset_lua(); uint32_t offset = 0; while (offset < xbuf_length(&upload_chunks)) { struct upload_chunk *chunk = xbuf_data(&upload_chunks) + offset; offset += sizeof(*chunk) + chunk->size; AIM_LOG_VERBOSE("Loading Lua chunk %s, %u bytes", chunk->filename, chunk->size); char name[64]; snprintf(name, sizeof(name), "=%s", chunk->filename); if (luaL_loadbuffer(lua, chunk->data, chunk->size, name) != 0) { AIM_LOG_ERROR("Failed to load code: %s", lua_tostring(lua, -1)); indigo_cxn_send_error_reply( cxn_id, msg, OF_ERROR_TYPE_BAD_REQUEST, OF_REQUEST_FAILED_EPERM); goto cleanup; } /* Set the environment of the new chunk to the sandbox */ lua_getglobal(lua, "sandbox"); lua_setfenv(lua, -2); if (lua_pcall(lua, 0, 1, 0) != 0) { AIM_LOG_ERROR("Failed to execute code %s: %s", chunk->filename, lua_tostring(lua, -1)); indigo_cxn_send_error_reply( cxn_id, msg, OF_ERROR_TYPE_BAD_REQUEST, OF_REQUEST_FAILED_EPERM); goto cleanup; } /* Save the return value in the "modules" table, used by require */ char *module_name = aim_strdup(chunk->filename); char *dot = strrchr(module_name, '.'); if (dot) *dot = 0; /* strip file extension */ lua_getglobal(lua, "modules"); lua_pushstring(lua, module_name); lua_pushvalue(lua, -3); /* return value from pcall */ lua_rawset(lua, -3); /* modules[filename] = return_value */ lua_pop(lua, 2); /* pop modules and return value */ free(module_name); } checksum = new_checksum; cleanup: cleanup_lua_upload(); return; }
JNIEXPORT jint JNICALL Java_m_lua_Lua_setFEnv (JNIEnv* env, jobject thiz, jlong nativeObj, jint idx) { pushJNIEnv(env, nativeObj); return (jint) lua_setfenv((lua_State*) nativeObj, idx); }
int LuaParser::Include(lua_State* L) { if (currentParser == NULL) { luaL_error(L, "invalid call to Include() after execution"); } // filename [, fenv] const string filename = luaL_checkstring(L, 1); if (!LuaIO::IsSimplePath(filename)) { luaL_error(L, "bad pathname"); } string modes = luaL_optstring(L, 3, currentParser->accessModes.c_str()); modes = CFileHandler::AllowModes(modes, currentParser->accessModes); CFileHandler fh(filename, modes); if (!fh.FileExists()) { char buf[1024]; SNPRINTF(buf, sizeof(buf), "Include() file missing '%s'\n", filename.c_str()); lua_pushstring(L, buf); lua_error(L); } string code; if (!fh.LoadStringData(code)) { char buf[1024]; SNPRINTF(buf, sizeof(buf), "Include() could not load '%s'\n", filename.c_str()); lua_pushstring(L, buf); lua_error(L); } int error = luaL_loadbuffer(L, code.c_str(), code.size(), filename.c_str()); if (error != 0) { char buf[1024]; SNPRINTF(buf, sizeof(buf), "error = %i, %s, %s\n", error, filename.c_str(), lua_tostring(L, -1)); lua_pushstring(L, buf); lua_error(L); } // set the chunk's fenv to the current fenv, or a user table if (lua_istable(L, 2)) { lua_pushvalue(L, 2); // user fenv } else { LuaUtils::PushCurrentFuncEnv(L, __FUNCTION__); } // set the include fenv to the current function's fenv if (lua_setfenv(L, -2) == 0) { luaL_error(L, "Include(): error with setfenv"); } const int paramTop = lua_gettop(L) - 1; error = lua_pcall(L, 0, LUA_MULTRET, 0); if (error != 0) { char buf[1024]; SNPRINTF(buf, sizeof(buf), "error = %i, %s, %s\n", error, filename.c_str(), lua_tostring(L, -1)); lua_pushstring(L, buf); lua_error(L); } currentParser->accessedFiles.insert(StringToLower(filename)); return lua_gettop(L) - paramTop; }
/* ** copy 'ktable' of element 'idx' to new tree (on top of stack) */ static void copyktable (lua_State *L, int idx) { lua_getfenv(L, idx); lua_setfenv(L, -2); }
TOLUA_API int toluafix_remove_ccobject_by_refid(lua_State* L, int refid) { void* ptr = NULL; const char* type = NULL; void** ud = NULL; if (refid == 0) return -1; // get ptr from tolua_refid_ptr_mapping lua_pushstring(L, TOLUA_REFID_PTR_MAPPING); lua_rawget(L, LUA_REGISTRYINDEX); /* stack: refid_ptr */ lua_pushinteger(L, refid); /* stack: refid_ptr refid */ lua_rawget(L, -2); /* stack: refid_ptr ptr */ ptr = lua_touserdata(L, -1); lua_pop(L, 1); /* stack: refid_ptr */ if (ptr == NULL) { lua_pop(L, 1); // Lua stack has closed, C++ object not in Lua. // printf("[LUA ERROR] remove CCObject with NULL ptr, refid: %d\n", refid); return -2; } // remove ptr from tolua_refid_ptr_mapping lua_pushinteger(L, refid); /* stack: refid_ptr refid */ lua_pushnil(L); /* stack: refid_ptr refid nil */ lua_rawset(L, -3); /* delete refid_ptr[refid], stack: refid_ptr */ lua_pop(L, 1); /* stack: - */ // get type from tolua_refid_type_mapping lua_pushstring(L, TOLUA_REFID_TYPE_MAPPING); lua_rawget(L, LUA_REGISTRYINDEX); /* stack: refid_type */ lua_pushinteger(L, refid); /* stack: refid_type refid */ lua_rawget(L, -2); /* stack: refid_type type */ if (lua_isnil(L, -1)) { lua_pop(L, 2); printf("[LUA ERROR] remove CCObject with NULL type, refid: %d, ptr: %p\n", refid, ptr); return -1; } type = lua_tostring(L, -1); lua_pop(L, 1); /* stack: refid_type */ // remove type from tolua_refid_type_mapping lua_pushinteger(L, refid); /* stack: refid_type refid */ lua_pushnil(L); /* stack: refid_type refid nil */ lua_rawset(L, -3); /* delete refid_type[refid], stack: refid_type */ lua_pop(L, 1); /* stack: - */ // get ubox luaL_getmetatable(L, type); /* stack: mt */ lua_pushstring(L, "tolua_ubox"); /* stack: mt key */ lua_rawget(L, -2); /* stack: mt ubox */ if (lua_isnil(L, -1)) { // use global ubox lua_pop(L, 1); /* stack: mt */ lua_pushstring(L, "tolua_ubox"); /* stack: mt key */ lua_rawget(L, LUA_REGISTRYINDEX); /* stack: mt ubox */ }; // cleanup root tolua_remove_value_from_root(L, ptr); lua_pushlightuserdata(L, ptr); /* stack: mt ubox ptr */ lua_rawget(L,-2); /* stack: mt ubox ud */ if (lua_isnil(L, -1)) { // Lua object has released (GC), C++ object not in ubox. //printf("[LUA ERROR] remove CCObject with NULL ubox, refid: %d, ptr: %x, type: %s\n", refid, (int)ptr, type); lua_pop(L, 3); return -3; } // cleanup peertable lua_pushvalue(L, LUA_REGISTRYINDEX); lua_setfenv(L, -2); ud = (void**)lua_touserdata(L, -1); lua_pop(L, 1); /* stack: mt ubox */ if (ud == NULL) { printf("[LUA ERROR] remove CCObject with NULL userdata, refid: %d, ptr: %p, type: %s\n", refid, ptr, type); lua_pop(L, 2); return -1; } // clean userdata *ud = NULL; lua_pushlightuserdata(L, ptr); /* stack: mt ubox ptr */ lua_pushnil(L); /* stack: mt ubox ptr nil */ lua_rawset(L, -3); /* ubox[ptr] = nil, stack: mt ubox */ lua_pop(L, 2); //printf("[LUA] remove CCObject, refid: %d, ptr: %x, type: %s\n", refid, (int)ptr, type); return 0; }
static ngx_int_t ngx_http_lua_rewrite_by_chunk(lua_State *L, ngx_http_request_t *r) { int co_ref; lua_State *co; ngx_int_t rc; ngx_connection_t *c; ngx_http_lua_ctx_t *ctx; ngx_http_cleanup_t *cln; ngx_http_lua_loc_conf_t *llcf; /* {{{ new coroutine to handle request */ co = ngx_http_lua_new_thread(r, L, &co_ref); if (co == NULL) { ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "lua: failed to create new coroutine to handle request"); return NGX_HTTP_INTERNAL_SERVER_ERROR; } /* move code closure to new coroutine */ lua_xmove(L, co, 1); /* set closure's env table to new coroutine's globals table */ lua_pushvalue(co, LUA_GLOBALSINDEX); lua_setfenv(co, -2); /* save nginx request in coroutine globals table */ lua_pushlightuserdata(co, &ngx_http_lua_request_key); lua_pushlightuserdata(co, r); lua_rawset(co, LUA_GLOBALSINDEX); /* }}} */ /* {{{ initialize request context */ ctx = ngx_http_get_module_ctx(r, ngx_http_lua_module); dd("ctx = %p", ctx); if (ctx == NULL) { return NGX_ERROR; } ngx_http_lua_reset_ctx(r, L, ctx); ctx->entered_rewrite_phase = 1; ctx->cur_co_ctx = &ctx->entry_co_ctx; ctx->cur_co_ctx->co = co; ctx->cur_co_ctx->co_ref = co_ref; /* }}} */ /* {{{ register request cleanup hooks */ if (ctx->cleanup == NULL) { cln = ngx_http_cleanup_add(r, 0); if (cln == NULL) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } cln->handler = ngx_http_lua_request_cleanup; cln->data = r; ctx->cleanup = &cln->handler; } /* }}} */ ctx->context = NGX_HTTP_LUA_CONTEXT_REWRITE; llcf = ngx_http_get_module_loc_conf(r, ngx_http_lua_module); if (llcf->check_client_abort) { r->read_event_handler = ngx_http_lua_rd_check_broken_connection; } else { r->read_event_handler = ngx_http_block_reading; } rc = ngx_http_lua_run_thread(L, r, ctx, 0); if (rc == NGX_ERROR || rc > NGX_OK) { return rc; } c = r->connection; if (rc == NGX_AGAIN) { rc = ngx_http_lua_run_posted_threads(c, L, r, ctx); if (rc == NGX_OK) { return NGX_DECLINED; } return rc; } if (rc == NGX_DONE) { ngx_http_finalize_request(r, NGX_DONE); rc = ngx_http_lua_run_posted_threads(c, L, r, ctx); if (rc == NGX_OK) { return NGX_DECLINED; } return rc; } return NGX_DECLINED; }
static int new_check (lua_State *L) { int ret = 0; libuv_check_t *check = NULL; uv_check_t *uvcheck = NULL; libuv_loop_t *loop = NULL; /* [ userdata ] */ /* DUMP_STACK(L); */ TRACE("arguments: L = %p\n", L); assert(L != NULL); /* get first argument */ loop = (libuv_loop_t *)lua_touserdata(L, 1); /* [userdata ] */ if (loop == NULL) { /* TODO: error */ return 0; } TRACE("get libuv_loop_t (%p)\n", loop); assert(loop->uvloop != NULL); lua_pop(L, 1); /* [ ] */ assert(lua_gettop(L) == 0); /* create libuv_check_t */ check = (libuv_check_t *)lua_newuserdata(L, sizeof(libuv_check_t)); /* [ userdata ] */ if (check == NULL) { /* TODO: error */ return 0; } TRACE("create libuv_check_t (%p)\n", check); assert(check != NULL); /* create uv_check_t */ uvcheck = (uv_check_t *)malloc(sizeof(uv_check_t)); if (uvcheck == NULL) { /* TODO: error */ return 0; } TRACE("create uv_check_t (%p)\n", uvcheck); assert(uvcheck != NULL); /* libuv_check_t settings */ check->uvcheck = uvcheck; check->L = L; check->ref = LUA_NOREF; /* set envriment table to userdata */ lua_newtable(L); /* [ userdata, table ] */ lua_setfenv(L, -2); /* [ userdata ] */ assert(lua_gettop(L) == 1); /* set metatable */ luaL_getmetatable(L, CHECK_T); /* [ userdata, metatable ] */ lua_setmetatable(L, -2); /* [ userdata ] */ TRACE("set metatable to userdata\n"); /* initialize check */ ret = uv_check_init(loop->uvloop, check->uvcheck); if (ret) { /* TODO: error */ return 0; } TRACE("uv_check_init: ret = %d\n", ret); /* return userdata */ return 1; }