|
@@ -4,10 +4,13 @@
|
|
|
|
|
|
#if !defined(_WIN32)
|
|
#if !defined(_WIN32)
|
|
#include <dlfcn.h>
|
|
#include <dlfcn.h>
|
|
|
|
+#include <sys/mman.h>
|
|
#endif
|
|
#endif
|
|
|
|
+
|
|
#include "civetweb_lua.h"
|
|
#include "civetweb_lua.h"
|
|
#include "civetweb_private_lua.h"
|
|
#include "civetweb_private_lua.h"
|
|
|
|
|
|
|
|
+
|
|
#if defined(_WIN32)
|
|
#if defined(_WIN32)
|
|
static void *
|
|
static void *
|
|
mmap(void *addr, int64_t len, int prot, int flags, int fd, int offset)
|
|
mmap(void *addr, int64_t len, int prot, int flags, int fd, int offset)
|
|
@@ -32,6 +35,7 @@ mmap(void *addr, int64_t len, int prot, int flags, int fd, int offset)
|
|
return p;
|
|
return p;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+
|
|
static void
|
|
static void
|
|
munmap(void *addr, int64_t length)
|
|
munmap(void *addr, int64_t length)
|
|
{
|
|
{
|
|
@@ -41,19 +45,21 @@ munmap(void *addr, int64_t length)
|
|
UnmapViewOfFile(addr);
|
|
UnmapViewOfFile(addr);
|
|
}
|
|
}
|
|
|
|
|
|
-#define MAP_FAILED (NULL)
|
|
|
|
|
|
+
|
|
#define MAP_PRIVATE (0)
|
|
#define MAP_PRIVATE (0)
|
|
#define PROT_READ (0)
|
|
#define PROT_READ (0)
|
|
-#else
|
|
|
|
-#include <sys/mman.h>
|
|
|
|
#endif
|
|
#endif
|
|
|
|
|
|
|
|
+
|
|
static const char *const LUASOCKET = "luasocket";
|
|
static const char *const LUASOCKET = "luasocket";
|
|
static const char lua_regkey_ctx = 1;
|
|
static const char lua_regkey_ctx = 1;
|
|
static const char lua_regkey_connlist = 2;
|
|
static const char lua_regkey_connlist = 2;
|
|
static const char lua_regkey_lsp_include_history = 3;
|
|
static const char lua_regkey_lsp_include_history = 3;
|
|
|
|
+static const char lua_regkey_environment_type = 4;
|
|
|
|
+static const char lua_regkey_dtor = 5;
|
|
static const char *const LUABACKGROUNDPARAMS = "mg";
|
|
static const char *const LUABACKGROUNDPARAMS = "mg";
|
|
|
|
|
|
|
|
+
|
|
/* Limit nesting depth of mg.include.
|
|
/* Limit nesting depth of mg.include.
|
|
* This takes a lot of stack (~10 kB per recursion),
|
|
* This takes a lot of stack (~10 kB per recursion),
|
|
* so do not use a too high limit. */
|
|
* so do not use a too high limit. */
|
|
@@ -82,6 +88,7 @@ reg_lstring(struct lua_State *L,
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+
|
|
static void
|
|
static void
|
|
reg_llstring(struct lua_State *L,
|
|
reg_llstring(struct lua_State *L,
|
|
const void *buffer1,
|
|
const void *buffer1,
|
|
@@ -96,9 +103,11 @@ reg_llstring(struct lua_State *L,
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+
|
|
#define reg_string(L, name, val) \
|
|
#define reg_string(L, name, val) \
|
|
reg_lstring(L, name, val, val ? strlen(val) : 0)
|
|
reg_lstring(L, name, val, val ? strlen(val) : 0)
|
|
|
|
|
|
|
|
+
|
|
static void
|
|
static void
|
|
reg_int(struct lua_State *L, const char *name, int val)
|
|
reg_int(struct lua_State *L, const char *name, int val)
|
|
{
|
|
{
|
|
@@ -109,6 +118,7 @@ reg_int(struct lua_State *L, const char *name, int val)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+
|
|
static void
|
|
static void
|
|
reg_boolean(struct lua_State *L, const char *name, int val)
|
|
reg_boolean(struct lua_State *L, const char *name, int val)
|
|
{
|
|
{
|
|
@@ -119,6 +129,7 @@ reg_boolean(struct lua_State *L, const char *name, int val)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+
|
|
static void
|
|
static void
|
|
reg_conn_function(struct lua_State *L,
|
|
reg_conn_function(struct lua_State *L,
|
|
const char *name,
|
|
const char *name,
|
|
@@ -133,6 +144,7 @@ reg_conn_function(struct lua_State *L,
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+
|
|
static void
|
|
static void
|
|
reg_function(struct lua_State *L, const char *name, lua_CFunction func)
|
|
reg_function(struct lua_State *L, const char *name, lua_CFunction func)
|
|
{
|
|
{
|
|
@@ -143,6 +155,7 @@ reg_function(struct lua_State *L, const char *name, lua_CFunction func)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+
|
|
static void
|
|
static void
|
|
lua_cry(struct mg_connection *conn,
|
|
lua_cry(struct mg_connection *conn,
|
|
int err,
|
|
int err,
|
|
@@ -200,6 +213,7 @@ lua_cry(struct mg_connection *conn,
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+
|
|
static int
|
|
static int
|
|
lsp_sock_close(lua_State *L)
|
|
lsp_sock_close(lua_State *L)
|
|
{
|
|
{
|
|
@@ -221,6 +235,7 @@ lsp_sock_close(lua_State *L)
|
|
return 0;
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+
|
|
static int
|
|
static int
|
|
lsp_sock_recv(lua_State *L)
|
|
lsp_sock_recv(lua_State *L)
|
|
{
|
|
{
|
|
@@ -248,6 +263,7 @@ lsp_sock_recv(lua_State *L)
|
|
return 1;
|
|
return 1;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+
|
|
static int
|
|
static int
|
|
lsp_sock_send(lua_State *L)
|
|
lsp_sock_send(lua_State *L)
|
|
{
|
|
{
|
|
@@ -279,6 +295,7 @@ lsp_sock_send(lua_State *L)
|
|
return 1;
|
|
return 1;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+
|
|
static int
|
|
static int
|
|
lsp_sock_gc(lua_State *L)
|
|
lsp_sock_gc(lua_State *L)
|
|
{
|
|
{
|
|
@@ -301,6 +318,7 @@ lsp_sock_gc(lua_State *L)
|
|
return 0;
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+
|
|
/* Methods and meta-methods supported by the object returned by connect.
|
|
/* Methods and meta-methods supported by the object returned by connect.
|
|
* For meta-methods, see http://lua-users.org/wiki/MetatableEvents */
|
|
* For meta-methods, see http://lua-users.org/wiki/MetatableEvents */
|
|
static const struct luaL_Reg luasocket_methods[] = {{"close", lsp_sock_close},
|
|
static const struct luaL_Reg luasocket_methods[] = {{"close", lsp_sock_close},
|
|
@@ -309,6 +327,7 @@ static const struct luaL_Reg luasocket_methods[] = {{"close", lsp_sock_close},
|
|
{"__gc", lsp_sock_gc},
|
|
{"__gc", lsp_sock_gc},
|
|
{NULL, NULL}};
|
|
{NULL, NULL}};
|
|
|
|
|
|
|
|
+
|
|
static int
|
|
static int
|
|
lsp_connect(lua_State *L)
|
|
lsp_connect(lua_State *L)
|
|
{
|
|
{
|
|
@@ -345,6 +364,7 @@ lsp_connect(lua_State *L)
|
|
return 1;
|
|
return 1;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+
|
|
static int
|
|
static int
|
|
lsp_error(lua_State *L)
|
|
lsp_error(lua_State *L)
|
|
{
|
|
{
|
|
@@ -356,6 +376,7 @@ lsp_error(lua_State *L)
|
|
return 0;
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+
|
|
/* Silently stop processing chunks. */
|
|
/* Silently stop processing chunks. */
|
|
static void
|
|
static void
|
|
lsp_abort(lua_State *L)
|
|
lsp_abort(lua_State *L)
|
|
@@ -1732,6 +1753,7 @@ lsp_get_option(lua_State *L)
|
|
return luaL_error(L, "invalid get_option() call");
|
|
return luaL_error(L, "invalid get_option() call");
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+
|
|
static int s_lua_traceLevel = 1;
|
|
static int s_lua_traceLevel = 1;
|
|
static FILE *s_lua_traceFile = NULL;
|
|
static FILE *s_lua_traceFile = NULL;
|
|
static pthread_mutex_t s_lua_traceMutex;
|
|
static pthread_mutex_t s_lua_traceMutex;
|
|
@@ -1964,70 +1986,111 @@ lwebsock_write(lua_State *L)
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
-struct laction_arg {
|
|
|
|
- lua_State *state;
|
|
|
|
|
|
+struct laction_string_arg {
|
|
|
|
+ lua_State *L;
|
|
const char *script;
|
|
const char *script;
|
|
pthread_mutex_t *pmutex;
|
|
pthread_mutex_t *pmutex;
|
|
char txt[1];
|
|
char txt[1];
|
|
};
|
|
};
|
|
|
|
|
|
|
|
+struct laction_funcref_arg {
|
|
|
|
+ lua_State *L;
|
|
|
|
+ const char *script;
|
|
|
|
+ pthread_mutex_t *pmutex;
|
|
|
|
+ int funcref;
|
|
|
|
+};
|
|
|
|
+
|
|
|
|
|
|
static int
|
|
static int
|
|
-lua_action(struct laction_arg *arg)
|
|
|
|
|
|
+lua_action_string(struct laction_string_arg *arg)
|
|
{
|
|
{
|
|
int err, ok;
|
|
int err, ok;
|
|
struct mg_context *ctx;
|
|
struct mg_context *ctx;
|
|
|
|
|
|
(void)pthread_mutex_lock(arg->pmutex);
|
|
(void)pthread_mutex_lock(arg->pmutex);
|
|
|
|
|
|
- lua_pushlightuserdata(arg->state, (void *)&lua_regkey_ctx);
|
|
|
|
- lua_gettable(arg->state, LUA_REGISTRYINDEX);
|
|
|
|
- ctx = (struct mg_context *)lua_touserdata(arg->state, -1);
|
|
|
|
- lua_pop(arg->state, 1);
|
|
|
|
|
|
+ lua_pushlightuserdata(arg->L, (void *)&lua_regkey_ctx);
|
|
|
|
+ lua_gettable(arg->L, LUA_REGISTRYINDEX);
|
|
|
|
+ ctx = (struct mg_context *)lua_touserdata(arg->L, -1);
|
|
|
|
+ lua_pop(arg->L, 1);
|
|
|
|
|
|
- err = luaL_loadstring(arg->state, arg->txt);
|
|
|
|
|
|
+ err = luaL_loadstring(arg->L, arg->txt);
|
|
if (err != 0) {
|
|
if (err != 0) {
|
|
struct mg_connection fc;
|
|
struct mg_connection fc;
|
|
- lua_cry(
|
|
|
|
- fake_connection(&fc, ctx), err, arg->state, arg->script, "timer");
|
|
|
|
|
|
+ lua_cry(fake_connection(&fc, ctx), err, arg->L, arg->script, "timer");
|
|
(void)pthread_mutex_unlock(arg->pmutex);
|
|
(void)pthread_mutex_unlock(arg->pmutex);
|
|
- mg_free(arg);
|
|
|
|
return 0;
|
|
return 0;
|
|
}
|
|
}
|
|
- err = lua_pcall(arg->state, 0, 1, 0);
|
|
|
|
|
|
+ err = lua_pcall(arg->L, 0, 1, 0);
|
|
if (err != 0) {
|
|
if (err != 0) {
|
|
struct mg_connection fc;
|
|
struct mg_connection fc;
|
|
- lua_cry(
|
|
|
|
- fake_connection(&fc, ctx), err, arg->state, arg->script, "timer");
|
|
|
|
|
|
+ lua_cry(fake_connection(&fc, ctx), err, arg->L, arg->script, "timer");
|
|
(void)pthread_mutex_unlock(arg->pmutex);
|
|
(void)pthread_mutex_unlock(arg->pmutex);
|
|
- mg_free(arg);
|
|
|
|
return 0;
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
|
|
- ok = lua_type(arg->state, -1);
|
|
|
|
- if (lua_isboolean(arg->state, -1)) {
|
|
|
|
- ok = lua_toboolean(arg->state, -1);
|
|
|
|
|
|
+ ok = lua_type(arg->L, -1);
|
|
|
|
+ if (lua_isboolean(arg->L, -1)) {
|
|
|
|
+ ok = lua_toboolean(arg->L, -1);
|
|
} else {
|
|
} else {
|
|
ok = 0;
|
|
ok = 0;
|
|
}
|
|
}
|
|
- lua_pop(arg->state, 1);
|
|
|
|
|
|
+ lua_pop(arg->L, 1);
|
|
|
|
|
|
(void)pthread_mutex_unlock(arg->pmutex);
|
|
(void)pthread_mutex_unlock(arg->pmutex);
|
|
|
|
|
|
- if (!ok) {
|
|
|
|
- mg_free(arg);
|
|
|
|
- }
|
|
|
|
return ok;
|
|
return ok;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
static int
|
|
static int
|
|
-lua_action_free(struct laction_arg *arg)
|
|
|
|
|
|
+lua_action_funcref(struct laction_funcref_arg *arg)
|
|
{
|
|
{
|
|
- if (lua_action(arg)) {
|
|
|
|
- mg_free(arg);
|
|
|
|
|
|
+ int err, ok;
|
|
|
|
+ struct mg_context *ctx;
|
|
|
|
+
|
|
|
|
+ (void)pthread_mutex_lock(arg->pmutex);
|
|
|
|
+
|
|
|
|
+ lua_pushlightuserdata(arg->L, (void *)&lua_regkey_ctx);
|
|
|
|
+ lua_gettable(arg->L, LUA_REGISTRYINDEX);
|
|
|
|
+ ctx = (struct mg_context *)lua_touserdata(arg->L, -1);
|
|
|
|
+ lua_pop(arg->L, 1);
|
|
|
|
+
|
|
|
|
+ lua_rawgeti(arg->L, LUA_REGISTRYINDEX, arg->funcref);
|
|
|
|
+ err = lua_pcall(arg->L, 0, 1, 0);
|
|
|
|
+ if (err != 0) {
|
|
|
|
+ struct mg_connection fc;
|
|
|
|
+ lua_cry(fake_connection(&fc, ctx), err, arg->L, arg->script, "timer");
|
|
|
|
+ (void)pthread_mutex_unlock(arg->pmutex);
|
|
|
|
+ return 0;
|
|
}
|
|
}
|
|
- return 0;
|
|
|
|
|
|
+
|
|
|
|
+ ok = lua_type(arg->L, -1);
|
|
|
|
+ if (lua_isboolean(arg->L, -1)) {
|
|
|
|
+ ok = lua_toboolean(arg->L, -1);
|
|
|
|
+ } else {
|
|
|
|
+ ok = 0;
|
|
|
|
+ }
|
|
|
|
+ lua_pop(arg->L, 1);
|
|
|
|
+
|
|
|
|
+ (void)pthread_mutex_unlock(arg->pmutex);
|
|
|
|
+
|
|
|
|
+ return ok;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+static void
|
|
|
|
+lua_action_string_cancel(struct laction_string_arg *arg)
|
|
|
|
+{
|
|
|
|
+ mg_free(arg);
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+static void
|
|
|
|
+lua_action_funcref_cancel(struct laction_funcref_arg *arg)
|
|
|
|
+{
|
|
|
|
+ luaL_unref(arg->L, LUA_REGISTRYINDEX, arg->funcref);
|
|
|
|
+ mg_free(arg);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
@@ -2037,12 +2100,9 @@ lwebsocket_set_timer(lua_State *L, int is_periodic)
|
|
#if defined(USE_TIMERS) && defined(USE_WEBSOCKET)
|
|
#if defined(USE_TIMERS) && defined(USE_WEBSOCKET)
|
|
int num_args = lua_gettop(L);
|
|
int num_args = lua_gettop(L);
|
|
struct lua_websock_data *ws;
|
|
struct lua_websock_data *ws;
|
|
- int type1, type2, ok = 0;
|
|
|
|
- double timediff;
|
|
|
|
|
|
+ int type1, type2, type3, ok = 0;
|
|
|
|
+ double delay, interval;
|
|
struct mg_context *ctx;
|
|
struct mg_context *ctx;
|
|
- struct laction_arg *arg;
|
|
|
|
- const char *txt;
|
|
|
|
- size_t txt_len;
|
|
|
|
|
|
|
|
lua_pushlightuserdata(L, (void *)&lua_regkey_ctx);
|
|
lua_pushlightuserdata(L, (void *)&lua_regkey_ctx);
|
|
lua_gettable(L, LUA_REGISTRYINDEX);
|
|
lua_gettable(L, LUA_REGISTRYINDEX);
|
|
@@ -2059,36 +2119,108 @@ lwebsocket_set_timer(lua_State *L, int is_periodic)
|
|
|
|
|
|
type1 = lua_type(L, 1);
|
|
type1 = lua_type(L, 1);
|
|
type2 = lua_type(L, 2);
|
|
type2 = lua_type(L, 2);
|
|
|
|
+ type3 = lua_type(L, 3);
|
|
|
|
+
|
|
|
|
+ /* Must have at least two arguments, ant the first one has to be some text
|
|
|
|
+ */
|
|
|
|
+ if ((num_args < 2) || (num_args > 3)) {
|
|
|
|
+ return luaL_error(L, "invalid arguments for set_timer/interval() call");
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ /* Second argument is the delay (and interval) */
|
|
|
|
+ if (type2 != LUA_TNUMBER) {
|
|
|
|
+ return luaL_error(L, "invalid arguments for set_timer/interval() call");
|
|
|
|
+ }
|
|
|
|
+ delay = (double)lua_tonumber(L, 2);
|
|
|
|
+ interval = (is_periodic ? delay : 0.0);
|
|
|
|
+
|
|
|
|
+ /* Third argument (optional) could be an interval */
|
|
|
|
+ if (num_args > 2) {
|
|
|
|
+ if (is_periodic || (type3 != LUA_TNUMBER)) {
|
|
|
|
+ return luaL_error(
|
|
|
|
+ L, "invalid arguments for set_timer/interval() call");
|
|
|
|
+ }
|
|
|
|
+ interval = (double)lua_tonumber(L, 3);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ /* Check numbers */
|
|
|
|
+ if ((delay < 0.0) || (interval < 0.0)) {
|
|
|
|
+ return luaL_error(L, "invalid arguments for set_timer/interval() call");
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ /* First value specifies the action */
|
|
|
|
+ if (type1 == LUA_TSTRING) {
|
|
|
|
+
|
|
|
|
+ /* Action could be passed as a string value */
|
|
|
|
+ struct laction_string_arg *arg;
|
|
|
|
+ const char *action_txt;
|
|
|
|
+ size_t action_txt_len;
|
|
|
|
+
|
|
|
|
+ action_txt = lua_tostring(L, 1);
|
|
|
|
+ if ((action_txt == NULL) || (action_txt[0] == 0)) {
|
|
|
|
+ return luaL_error(
|
|
|
|
+ L, "invalid arguments for set_timer/interval() call");
|
|
|
|
+ }
|
|
|
|
+ action_txt_len = strlen(action_txt);
|
|
|
|
|
|
- if (type1 == LUA_TSTRING && type2 == LUA_TNUMBER && num_args == 2) {
|
|
|
|
- timediff = (double)lua_tonumber(L, 2);
|
|
|
|
- txt = lua_tostring(L, 1);
|
|
|
|
- txt_len = strlen(txt);
|
|
|
|
- arg = (struct laction_arg *)mg_malloc_ctx(sizeof(struct laction_arg)
|
|
|
|
- + txt_len + 10,
|
|
|
|
- ctx);
|
|
|
|
|
|
+ /* Create timer data structure and schedule timer */
|
|
|
|
+ arg = (struct laction_string_arg *)mg_malloc_ctx(
|
|
|
|
+ sizeof(struct laction_string_arg) + action_txt_len + 10, ctx);
|
|
if (!arg) {
|
|
if (!arg) {
|
|
return luaL_error(L, "out of memory");
|
|
return luaL_error(L, "out of memory");
|
|
}
|
|
}
|
|
|
|
|
|
- arg->state = L;
|
|
|
|
|
|
+ /* Argument for timer */
|
|
|
|
+ arg->L = L;
|
|
arg->script = ws->script;
|
|
arg->script = ws->script;
|
|
arg->pmutex = &(ws->ws_mutex);
|
|
arg->pmutex = &(ws->ws_mutex);
|
|
memcpy(arg->txt, "return(", 7);
|
|
memcpy(arg->txt, "return(", 7);
|
|
- memcpy(arg->txt + 7, txt, txt_len);
|
|
|
|
- arg->txt[txt_len + 7] = ')';
|
|
|
|
- arg->txt[txt_len + 8] = 0;
|
|
|
|
- ok =
|
|
|
|
- (0
|
|
|
|
- == timer_add(ctx,
|
|
|
|
- timediff,
|
|
|
|
- is_periodic,
|
|
|
|
- 1,
|
|
|
|
- (taction)(is_periodic ? lua_action : lua_action_free),
|
|
|
|
- (void *)arg));
|
|
|
|
- } else if (type1 == LUA_TFUNCTION && type2 == LUA_TNUMBER) {
|
|
|
|
- /* TODO (mid): not implemented yet */
|
|
|
|
- return luaL_error(L, "invalid arguments for set_timer/interval() call");
|
|
|
|
|
|
+ memcpy(arg->txt + 7, action_txt, action_txt_len);
|
|
|
|
+ arg->txt[action_txt_len + 7] = ')';
|
|
|
|
+ arg->txt[action_txt_len + 8] = 0;
|
|
|
|
+ if (0
|
|
|
|
+ == timer_add(ctx,
|
|
|
|
+ delay,
|
|
|
|
+ interval,
|
|
|
|
+ 1,
|
|
|
|
+ (taction)lua_action_string,
|
|
|
|
+ (void *)arg,
|
|
|
|
+ (tcancelaction)lua_action_string_cancel)) {
|
|
|
|
+ /* Timer added successfully */
|
|
|
|
+ ok = 1;
|
|
|
|
+ }
|
|
|
|
+ } else if (type1 == LUA_TFUNCTION) {
|
|
|
|
+
|
|
|
|
+ /* Action could be passed as a function */
|
|
|
|
+ int funcref;
|
|
|
|
+ struct laction_funcref_arg *arg;
|
|
|
|
+
|
|
|
|
+ lua_pushvalue(L, 1);
|
|
|
|
+ funcref = luaL_ref(L, LUA_REGISTRYINDEX);
|
|
|
|
+
|
|
|
|
+ /* Create timer data structure and schedule timer */
|
|
|
|
+ arg = (struct laction_funcref_arg *)
|
|
|
|
+ mg_malloc_ctx(sizeof(struct laction_funcref_arg), ctx);
|
|
|
|
+ if (!arg) {
|
|
|
|
+ return luaL_error(L, "out of memory");
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ /* Argument for timer */
|
|
|
|
+ arg->L = L;
|
|
|
|
+ arg->script = ws->script;
|
|
|
|
+ arg->pmutex = &(ws->ws_mutex);
|
|
|
|
+ arg->funcref = funcref;
|
|
|
|
+ if (0
|
|
|
|
+ == timer_add(ctx,
|
|
|
|
+ delay,
|
|
|
|
+ interval,
|
|
|
|
+ 1,
|
|
|
|
+ (taction)lua_action_funcref,
|
|
|
|
+ (void *)arg,
|
|
|
|
+ (tcancelaction)lua_action_funcref_cancel)) {
|
|
|
|
+ /* Timer added successfully */
|
|
|
|
+ ok = 1;
|
|
|
|
+ }
|
|
} else {
|
|
} else {
|
|
return luaL_error(L, "invalid arguments for set_timer/interval() call");
|
|
return luaL_error(L, "invalid arguments for set_timer/interval() call");
|
|
}
|
|
}
|
|
@@ -2330,6 +2462,65 @@ civetweb_open_lua_libs(lua_State *L)
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
+/* garbage collect "mg"
|
|
|
|
+ * this indicates when a Lua state is closed
|
|
|
|
+ */
|
|
|
|
+static int
|
|
|
|
+lsp_mg_gc(lua_State *L)
|
|
|
|
+{
|
|
|
|
+ unsigned context_flags;
|
|
|
|
+ struct mg_context *ctx;
|
|
|
|
+ struct mg_connection *conn =
|
|
|
|
+ (struct mg_connection *)lua_touserdata(L, lua_upvalueindex(1));
|
|
|
|
+
|
|
|
|
+ lua_pushlightuserdata(L, (void *)&lua_regkey_ctx);
|
|
|
|
+ lua_gettable(L, LUA_REGISTRYINDEX);
|
|
|
|
+ ctx = (struct mg_context *)lua_touserdata(L, -1);
|
|
|
|
+
|
|
|
|
+ lua_pushlightuserdata(L, (void *)&lua_regkey_environment_type);
|
|
|
|
+ lua_gettable(L, LUA_REGISTRYINDEX);
|
|
|
|
+ context_flags = lua_tounsigned(L, -1);
|
|
|
|
+
|
|
|
|
+ if (ctx != NULL) {
|
|
|
|
+ if (ctx->callbacks.exit_lua != NULL) {
|
|
|
|
+ ctx->callbacks.exit_lua(conn, L, context_flags);
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ return 0;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+static void
|
|
|
|
+reg_gc(lua_State *L, void *conn)
|
|
|
|
+{
|
|
|
|
+ /* Key element */
|
|
|
|
+ lua_pushlightuserdata(L, (void *)&lua_regkey_dtor);
|
|
|
|
+
|
|
|
|
+ /* Value element */
|
|
|
|
+ lua_newuserdata(L, 0);
|
|
|
|
+
|
|
|
|
+ /* Prepare metatable for value element */
|
|
|
|
+ lua_newtable(L);
|
|
|
|
+
|
|
|
|
+ /* Add garbage collector key to metatable */
|
|
|
|
+ lua_pushliteral(L, "__gc");
|
|
|
|
+
|
|
|
|
+ /* Add garbage collector function with one upvalue (conn) */
|
|
|
|
+ lua_pushlightuserdata(L, conn);
|
|
|
|
+ lua_pushcclosure(L, lsp_mg_gc, 1);
|
|
|
|
+
|
|
|
|
+ /* Set __gc = function lsp_mg_gc in metatable */
|
|
|
|
+ lua_rawset(L, -3);
|
|
|
|
+
|
|
|
|
+ /* Set metatable for "value element" */
|
|
|
|
+ lua_setmetatable(L, -2);
|
|
|
|
+
|
|
|
|
+ /* Add key (lightuserdata) = value (userdata with metatable) */
|
|
|
|
+ lua_settable(L, LUA_REGISTRYINDEX);
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+
|
|
static void
|
|
static void
|
|
prepare_lua_environment(struct mg_context *ctx,
|
|
prepare_lua_environment(struct mg_context *ctx,
|
|
struct mg_connection *conn,
|
|
struct mg_connection *conn,
|
|
@@ -2341,6 +2532,8 @@ prepare_lua_environment(struct mg_context *ctx,
|
|
const char *preload_file_name = NULL;
|
|
const char *preload_file_name = NULL;
|
|
const char *debug_params = NULL;
|
|
const char *debug_params = NULL;
|
|
|
|
|
|
|
|
+ unsigned lua_context_flags = (unsigned)lua_env_type;
|
|
|
|
+
|
|
civetweb_open_lua_libs(L);
|
|
civetweb_open_lua_libs(L);
|
|
|
|
|
|
#if defined(MG_EXPERIMENTAL_INTERFACES)
|
|
#if defined(MG_EXPERIMENTAL_INTERFACES)
|
|
@@ -2375,6 +2568,12 @@ prepare_lua_environment(struct mg_context *ctx,
|
|
lua_pushlightuserdata(L, (void *)ws_conn_list);
|
|
lua_pushlightuserdata(L, (void *)ws_conn_list);
|
|
lua_settable(L, LUA_REGISTRYINDEX);
|
|
lua_settable(L, LUA_REGISTRYINDEX);
|
|
}
|
|
}
|
|
|
|
+ lua_pushlightuserdata(L, (void *)&lua_regkey_environment_type);
|
|
|
|
+ lua_pushunsigned(L, (unsigned)lua_context_flags);
|
|
|
|
+ lua_settable(L, LUA_REGISTRYINDEX);
|
|
|
|
+
|
|
|
|
+ /* State close function */
|
|
|
|
+ reg_gc(L, conn);
|
|
|
|
|
|
/* Lua server pages store the depth of mg.include, in order
|
|
/* Lua server pages store the depth of mg.include, in order
|
|
* to detect recursions and prevent stack overflows. */
|
|
* to detect recursions and prevent stack overflows. */
|
|
@@ -2504,7 +2703,7 @@ prepare_lua_environment(struct mg_context *ctx,
|
|
/* Call user init function */
|
|
/* Call user init function */
|
|
if (ctx != NULL) {
|
|
if (ctx != NULL) {
|
|
if (ctx->callbacks.init_lua != NULL) {
|
|
if (ctx->callbacks.init_lua != NULL) {
|
|
- ctx->callbacks.init_lua(conn, L);
|
|
|
|
|
|
+ ctx->callbacks.init_lua(conn, L, lua_context_flags);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
@@ -2608,7 +2807,6 @@ handle_lsp_request(struct mg_connection *conn,
|
|
lua_State *L = NULL;
|
|
lua_State *L = NULL;
|
|
struct lsp_include_history *include_history;
|
|
struct lsp_include_history *include_history;
|
|
int error = 1;
|
|
int error = 1;
|
|
- void *file_in_memory; /* TODO(low): remove when removing "file in memory" */
|
|
|
|
int (*run_lsp)(struct mg_connection *,
|
|
int (*run_lsp)(struct mg_connection *,
|
|
const char *,
|
|
const char *,
|
|
const char *,
|
|
const char *,
|
|
@@ -2633,23 +2831,14 @@ handle_lsp_request(struct mg_connection *conn,
|
|
goto cleanup_handle_lsp_request;
|
|
goto cleanup_handle_lsp_request;
|
|
}
|
|
}
|
|
|
|
|
|
-#if defined(MG_USE_OPEN_FILE)
|
|
|
|
- /* The "file in memory" feature is going to be removed. For details see
|
|
|
|
- * https://groups.google.com/forum/#!topic/civetweb/h9HT4CmeYqI */
|
|
|
|
- file_in_memory = filep->access.membuf;
|
|
|
|
-#else
|
|
|
|
- file_in_memory = NULL;
|
|
|
|
-#endif
|
|
|
|
-
|
|
|
|
/* Map file in memory (size is known). */
|
|
/* Map file in memory (size is known). */
|
|
- if (file_in_memory == NULL
|
|
|
|
- && (p = mmap(NULL,
|
|
|
|
- (size_t)filep->stat.size,
|
|
|
|
- PROT_READ,
|
|
|
|
- MAP_PRIVATE,
|
|
|
|
- fileno(filep->access.fp),
|
|
|
|
- 0))
|
|
|
|
- == MAP_FAILED) {
|
|
|
|
|
|
+ if ((p = mmap(NULL,
|
|
|
|
+ (size_t)filep->stat.size,
|
|
|
|
+ PROT_READ,
|
|
|
|
+ MAP_PRIVATE,
|
|
|
|
+ fileno(filep->access.fp),
|
|
|
|
+ 0))
|
|
|
|
+ == NULL) {
|
|
|
|
|
|
/* File was not already in memory, and mmap failed now.
|
|
/* File was not already in memory, and mmap failed now.
|
|
* Since wi have no data, show an error. */
|
|
* Since wi have no data, show an error. */
|
|
@@ -2673,9 +2862,8 @@ handle_lsp_request(struct mg_connection *conn,
|
|
goto cleanup_handle_lsp_request;
|
|
goto cleanup_handle_lsp_request;
|
|
}
|
|
}
|
|
|
|
|
|
- /* File content is now memory mapped. Get mapping address */
|
|
|
|
- addr = (file_in_memory == NULL) ? (const char *)p
|
|
|
|
- : (const char *)file_in_memory;
|
|
|
|
|
|
+ /* File content is now memory mapped. Get mapping address. */
|
|
|
|
+ addr = (const char *)p;
|
|
|
|
|
|
/* Get a Lua state */
|
|
/* Get a Lua state */
|
|
if (ls != NULL) {
|
|
if (ls != NULL) {
|
|
@@ -2966,6 +3154,7 @@ lua_websocket_close(struct mg_connection *conn, void *ws_arg)
|
|
&(conn->dom_ctx->shared_lua_websockets);
|
|
&(conn->dom_ctx->shared_lua_websockets);
|
|
int err = 0;
|
|
int err = 0;
|
|
unsigned i;
|
|
unsigned i;
|
|
|
|
+ int delete_state = 0;
|
|
|
|
|
|
DEBUG_ASSERT(ws != NULL);
|
|
DEBUG_ASSERT(ws != NULL);
|
|
DEBUG_ASSERT(ws->state != NULL);
|
|
DEBUG_ASSERT(ws->state != NULL);
|
|
@@ -2985,13 +3174,33 @@ lua_websocket_close(struct mg_connection *conn, void *ws_arg)
|
|
for (i = 0; i < ws->references; i++) {
|
|
for (i = 0; i < ws->references; i++) {
|
|
if (ws->conn[i] == conn) {
|
|
if (ws->conn[i] == conn) {
|
|
ws->references--;
|
|
ws->references--;
|
|
|
|
+ if (ws->references == 0) {
|
|
|
|
+ delete_state = 1;
|
|
|
|
+ break;
|
|
|
|
+ }
|
|
ws->conn[i] = ws->conn[ws->references];
|
|
ws->conn[i] = ws->conn[ws->references];
|
|
}
|
|
}
|
|
}
|
|
}
|
|
/* TODO: Delete lua_websock_data and remove it from the websocket list.
|
|
/* TODO: Delete lua_websock_data and remove it from the websocket list.
|
|
This must only be done, when all connections are closed, and all
|
|
This must only be done, when all connections are closed, and all
|
|
asynchronous operations and timers are completed/expired. */
|
|
asynchronous operations and timers are completed/expired. */
|
|
- (void)shared_websock_list; /* shared_websock_list unused (see open TODO) */
|
|
|
|
|
|
+ if (delete_state) {
|
|
|
|
+ /* lock list (mg_context global) */
|
|
|
|
+ mg_lock_context(conn->phys_ctx);
|
|
|
|
+ while (*shared_websock_list) {
|
|
|
|
+ /* find ws in list */
|
|
|
|
+ if (0 == strcmp(ws->script, (*shared_websock_list)->ws.script)) {
|
|
|
|
+ break;
|
|
|
|
+ }
|
|
|
|
+ shared_websock_list = &((*shared_websock_list)->next);
|
|
|
|
+ }
|
|
|
|
+ if (*shared_websock_list != NULL) {
|
|
|
|
+ /* TODO: If we close the state here, timers must be stopped first */
|
|
|
|
+ /* lua_close(ws->state); <-- other thread will crash, if there are
|
|
|
|
+ * still active timers */
|
|
|
|
+ }
|
|
|
|
+ mg_unlock_context(conn->phys_ctx);
|
|
|
|
+ }
|
|
|
|
|
|
(void)pthread_mutex_unlock(&(ws->ws_mutex));
|
|
(void)pthread_mutex_unlock(&(ws->ws_mutex));
|
|
}
|
|
}
|
|
@@ -3062,6 +3271,38 @@ mg_prepare_lua_context_script(const char *file_name,
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
+static void
|
|
|
|
+lua_ctx_init(struct mg_context *ctx)
|
|
|
|
+{
|
|
|
|
+#if defined(USE_WEBSOCKET)
|
|
|
|
+ ctx->dd.shared_lua_websockets = NULL;
|
|
|
|
+#endif
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+static void
|
|
|
|
+lua_ctx_exit(struct mg_context *ctx)
|
|
|
|
+{
|
|
|
|
+#if defined(USE_WEBSOCKET)
|
|
|
|
+ struct mg_shared_lua_websocket_list **shared_websock_list =
|
|
|
|
+ &(ctx->dd.shared_lua_websockets);
|
|
|
|
+ struct mg_shared_lua_websocket_list *next;
|
|
|
|
+
|
|
|
|
+ mg_lock_context(ctx);
|
|
|
|
+ while (*shared_websock_list) {
|
|
|
|
+ lua_close((*shared_websock_list)->ws.state);
|
|
|
|
+ mg_free((*shared_websock_list)->ws.script);
|
|
|
|
+
|
|
|
|
+ /* Save "next" pointer before freeing list element */
|
|
|
|
+ next = ((*shared_websock_list)->next);
|
|
|
|
+ mg_free(*shared_websock_list);
|
|
|
|
+ shared_websock_list = &next;
|
|
|
|
+ }
|
|
|
|
+ mg_unlock_context(ctx);
|
|
|
|
+#endif
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+
|
|
int
|
|
int
|
|
run_lua(const char *file_name)
|
|
run_lua(const char *file_name)
|
|
{
|
|
{
|