kore

Kore is a web application platform for writing scalable, concurrent web based processes in C or Python.
Commits | Files | Refs | README | LICENSE | git clone https://git.kore.io/kore.git

commit 4718bae098d4cb9bbba6893c3b408c1feef37560
parent 2f5d274059dcb6a55b4c5b7014b7064ffe31f716
Author: Joris Vink <joris@coders.se>
Date:   Sat, 21 Jan 2023 23:41:35 +0100

Initial lua runtime.

Works enough so one can do basic configuration and handle HTTP.

Diffstat:
Makefile | 10++++++++++
include/kore/kore.h | 11+++++------
include/kore/lua_api.h | 30++++++++++++++++++++++++++++++
include/kore/lua_methods.h | 49+++++++++++++++++++++++++++++++++++++++++++++++++
src/config.c | 10+++-------
src/kore.c | 30+++++++++++++++++++++++-------
src/lua.c | 626+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
src/module.c | 10++++++++++
src/pool.c | 1-
src/runtime.c | 7+++++++
10 files changed, 763 insertions(+), 21 deletions(-)

diff --git a/Makefile b/Makefile @@ -117,6 +117,16 @@ ifneq ("$(PYTHON)", "") FEATURES_INC+=$(KORE_PYTHON_INC) endif +ifneq ("$(LUA)", "") + S_SRC+=src/lua.c + KORE_LUA_LIB?=$(shell pkg-config --libs lua) + KORE_LUA_INC?=$(shell pkg-config --cflags lua) + LDFLAGS+=$(KORE_LUA_LIB) + CFLAGS+=$(KORE_LUA_INC) -DKORE_USE_LUA + FEATURES+=-DKORE_USE_LUA + FEATURES_INC+=$(KORE_LUA_INC) +endif + OSNAME=$(shell uname -s | sed -e 's/[-_].*//g' | tr A-Z a-z) ifeq ("$(OSNAME)", "freebsd") KORE_CURL_LIB=-L/usr/local/lib -lcurl diff --git a/include/kore/kore.h b/include/kore/kore.h @@ -274,6 +274,7 @@ extern struct connection_list disconnected; #define KORE_RUNTIME_NATIVE 0 #define KORE_RUNTIME_PYTHON 1 +#define KORE_RUNTIME_LUA 2 struct kore_runtime { int type; @@ -413,8 +414,9 @@ struct kore_auth { #define KORE_MODULE_LOAD 1 #define KORE_MODULE_UNLOAD 2 -#define KORE_MODULE_NATIVE 0 -#define KORE_MODULE_PYTHON 1 +#define KORE_MODULE_NATIVE KORE_RUNTIME_NATIVE +#define KORE_MODULE_PYTHON KORE_RUNTIME_PYTHON +#define KORE_MODULE_LUA KORE_RUNTIME_LUA struct kore_module; @@ -894,13 +896,10 @@ const char *kore_connection_ip(struct connection *); void kore_log_init(void); void kore_log_file(const char *); -#if defined(KORE_USE_PYTHON) -int kore_configure_setting(const char *, char *); -#endif - /* config.c */ void kore_parse_config(void); void kore_parse_config_file(FILE *); +int kore_configure_setting(const char *, char *); /* mem.c */ void *kore_malloc(size_t); diff --git a/include/kore/lua_api.h b/include/kore/lua_api.h @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2023 Joris Vink <joris@coders.se> + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef __H_LUA_API_H +#define __H_LUA_API_H + +#include <lua.h> +#include <lualib.h> +#include <lauxlib.h> + +void kore_lua_init(void); +void kore_lua_cleanup(void); + +extern struct kore_module_functions kore_lua_module; +extern struct kore_runtime kore_lua_runtime; + +#endif diff --git a/include/kore/lua_methods.h b/include/kore/lua_methods.h @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2023 Joris Vink <joris@coders.se> + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef __H_LUA_METHODS_H +#define __H_LUA_METHODS_H + +static int lua_http_request_gc(lua_State *); +static int lua_http_request_index(lua_State *); + +static int lua_http_response(lua_State *); +static int lua_http_request_header(lua_State *); +static int lua_http_response_header(lua_State *); + +static const luaL_Reg lua_http_request_meta[] = { + { "__gc", lua_http_request_gc }, + { "__index", lua_http_request_index }, + { NULL, NULL }, +}; + +static const luaL_Reg lua_http_request_methods[] = { + { "response", lua_http_response }, + { "request_header", lua_http_request_header }, + { "response_header", lua_http_response_header }, + { NULL, NULL }, +}; + +static int lua_kore_config(lua_State *); +static int lua_kore_server(lua_State *); + +static const luaL_Reg lua_kore_functions[] = { + { "config", lua_kore_config }, + { "server", lua_kore_server }, + { NULL, NULL }, +}; + +#endif diff --git a/src/config.c b/src/config.c @@ -93,6 +93,7 @@ static int configure_socket_backlog(char *); static int configure_privsep_skip(char *); static int configure_privsep_root(char *); static int configure_privsep_runas(char *); +static int configure_deployment(char *); #if defined(KORE_USE_PLATFORM_PLEDGE) static int configure_add_pledge(char *); @@ -157,7 +158,6 @@ static int configure_task_threads(char *); #endif #if defined(KORE_USE_PYTHON) -static int configure_deployment(char *); static int configure_python_path(char *); static int configure_python_import(char *); #endif @@ -240,6 +240,7 @@ static struct { { "tls_cipher", configure_tls_cipher }, { "tls_dhparam", configure_tls_dhparam }, { "rand_file", configure_rand_file }, + { "deployment", configure_deployment }, #if defined(KORE_USE_ACME) { "acme_email", configure_acme_email }, { "acme_provider", configure_acme_provider }, @@ -269,9 +270,6 @@ static struct { { "websocket_maxframe", configure_websocket_maxframe }, { "websocket_timeout", configure_websocket_timeout }, #endif -#if defined(KORE_USE_PYTHON) - { "deployment", configure_deployment }, -#endif #if defined(KORE_USE_PGSQL) { "pgsql_conn_max", configure_pgsql_conn_max }, { "pgsql_queue_limit", configure_pgsql_queue_limit }, @@ -524,7 +522,6 @@ kore_parse_config_file(FILE *fp) } } -#if defined(KORE_USE_PYTHON) int kore_configure_setting(const char *name, char *value) { @@ -544,7 +541,6 @@ kore_configure_setting(const char *name, char *value) kore_log(LOG_NOTICE, "ignoring unknown kore.config.%s setting", name); return (KORE_RESULT_OK); } -#endif static void configure_check_var(char **var, const char *other, const char *logmsg) @@ -2015,7 +2011,6 @@ configure_task_threads(char *option) } #endif -#if defined(KORE_USE_PYTHON) static int configure_deployment(char *value) { @@ -2040,6 +2035,7 @@ configure_deployment(char *value) return (KORE_RESULT_OK); } +#if defined(KORE_USE_PYTHON) static int configure_python_path(char *path) { diff --git a/src/kore.c b/src/kore.c @@ -46,6 +46,10 @@ #include "python_api.h" #endif +#if defined(KORE_USE_LUA) +#include "lua_api.h" +#endif + #if defined(KORE_USE_ACME) #include "acme.h" #endif @@ -97,11 +101,11 @@ static const char *parent_daemonized_hook = KORE_DAEMONIZED_HOOK; static void usage(void) { -#if defined(KORE_USE_PYTHON) - printf("Usage: %s [options] [app | app.py]\n", __progname); -#else - printf("Usage: %s [options]\n", __progname); -#endif + if (kore_runtime_count() > 0) { + printf("Usage: %s [options] [app | script]\n", __progname); + } else { + printf("Usage: %s [options]\n", __progname); + } printf("\n"); printf("Command-line options:\n"); @@ -151,6 +155,10 @@ version(void) #if defined(KORE_USE_PYTHON) printf("python-%s ", PY_VERSION); #endif +#if defined(KORE_USE_LUA) + printf("lua-%s.%s.%s ", + LUA_VERSION_MAJOR, LUA_VERSION_MINOR, LUA_VERSION_RELEASE); +#endif #if defined(KORE_USE_ACME) printf("acme "); #endif @@ -234,8 +242,8 @@ main(int argc, char *argv[]) kore_domain_init(); kore_module_init(); -#if !defined(KORE_SINGLE_BINARY) && !defined(KORE_USE_PYTHON) - if (config_file == NULL) +#if !defined(KORE_SINGLE_BINARY) + if (kore_runtime_count() == 0 && config_file == NULL) usage(); #endif kore_module_load(NULL, NULL, KORE_MODULE_NATIVE); @@ -244,6 +252,10 @@ main(int argc, char *argv[]) kore_python_init(); #endif +#if defined(KORE_USE_LUA) + kore_lua_init(); +#endif + #if !defined(KORE_SINGLE_BINARY) if (kore_runtime_count() > 0 && rarg0 != NULL) kore_runtime_resolve(rarg0, &st); @@ -294,6 +306,10 @@ main(int argc, char *argv[]) kore_python_cleanup(); #endif +#if defined(KORE_USE_LUA) + kore_lua_cleanup(); +#endif + kore_mem_cleanup(); return (kore_quit); diff --git a/src/lua.c b/src/lua.c @@ -0,0 +1,626 @@ +/* + * Copyright (c) 2023 Joris Vink <joris@coders.se> + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include <sys/types.h> + +#include "kore.h" + +#if !defined(KORE_NO_HTTP) +#include "http.h" +#endif + +#include "lua_api.h" +#include "lua_methods.h" + +struct lua_http_request { + struct http_request *req; +}; + +struct lua_symbol { + lua_State *L; + int ref; + LIST_ENTRY(lua_symbol) list; +}; + +struct lua_module { + lua_State *L; + LIST_HEAD(, lua_symbol) symbols; +}; + +static int lua_runtime_resolve(const char *, const struct stat *); +static int lua_runtime_http_request(void *, struct http_request *); +static void lua_runtime_http_request_free(void *, struct http_request *); +static void lua_runtime_http_body_chunk(void *, struct http_request *, + const void *, size_t); +static int lua_runtime_validator(void *, struct http_request *, + const void *); +static void lua_runtime_wsmessage(void *, struct connection *, + u_int8_t, const void *, size_t); +static void lua_runtime_execute(void *); +static int lua_runtime_onload(void *, int); +static void lua_runtime_signal(void *, int); +static void lua_runtime_configure(void *, int, char **); +static void lua_runtime_connect(void *, struct connection *); + +static void lua_module_load(struct kore_module *); +static void lua_module_free(struct kore_module *); +static void lua_module_reload(struct kore_module *); +static void *lua_module_getsym(struct kore_module *, const char *); + +static void *lua_mem_alloc(void *, void *, size_t, size_t); + +static int lua_kore_module_init(lua_State *); +static void lua_symbol_resolve(struct lua_symbol *, lua_State **); + +static int lua_argument_get_bool(lua_State *, const char *); +static const char *lua_argument_get_string(lua_State *, const char *); +//static int lua_argument_get_integer(lua_State *, const char *, +// lua_Integer *); + +struct kore_module_functions kore_lua_module = { + .free = lua_module_free, + .load = lua_module_load, + .getsym = lua_module_getsym, + .reload = lua_module_reload +}; + +struct kore_runtime kore_lua_runtime = { + KORE_RUNTIME_LUA, + .resolve = lua_runtime_resolve, + .http_request = lua_runtime_http_request, + .http_body_chunk = lua_runtime_http_body_chunk, + .http_request_free = lua_runtime_http_request_free, + .validator = lua_runtime_validator, + .wsconnect = lua_runtime_connect, + .wsmessage = lua_runtime_wsmessage, + .wsdisconnect = lua_runtime_connect, + .onload = lua_runtime_onload, + .signal = lua_runtime_signal, + .connect = lua_runtime_connect, + .execute = lua_runtime_execute, + .configure = lua_runtime_configure, +}; + +#define LUA_CONSTANT(x) { #x, x } + +static struct { + const char *symbol; + int value; +} lua_integers[] = { + LUA_CONSTANT(LOG_ERR), + LUA_CONSTANT(LOG_INFO), + LUA_CONSTANT(LOG_NOTICE), + LUA_CONSTANT(HTTP_METHOD_GET), + LUA_CONSTANT(HTTP_METHOD_PUT), + LUA_CONSTANT(HTTP_METHOD_POST), + LUA_CONSTANT(HTTP_METHOD_HEAD), + LUA_CONSTANT(HTTP_METHOD_PATCH), + LUA_CONSTANT(HTTP_METHOD_DELETE), + LUA_CONSTANT(HTTP_METHOD_OPTIONS), + { NULL, -1 }, +}; + +void +kore_lua_init(void) +{ + if (!kore_configure_setting("deployment", "dev")) + fatal("failed to set initial deployment to dev"); +} + +void +kore_lua_cleanup(void) +{ +} + +static void * +lua_mem_alloc(void *uptr, void *ptr, size_t osize, size_t nsize) +{ + if (nsize == 0) { + kore_free(ptr); + return (NULL); + } + + return (kore_realloc(ptr, nsize)); +} + +static void +lua_symbol_resolve(struct lua_symbol *sym, lua_State **L) +{ + lua_rawgeti(sym->L, LUA_REGISTRYINDEX, sym->ref); + *L = sym->L; +} + +#if 0 +static int +lua_argument_get_integer(lua_State *L, const char *field, lua_Integer *ret) +{ + int type; + + lua_pushstring(L, field); + type = lua_gettable(L, -2); + + if (type == LUA_TNIL) { + lua_pop(L, 1); + return (KORE_RESULT_ERROR); + } + + luaL_argcheck(L, type == LUA_TNUMBER, 0, field); + + *ret = lua_tointeger(L, -1); + lua_pop(L, 1); + + return (KORE_RESULT_OK); +} +#endif + +static int +lua_argument_get_bool(lua_State *L, const char *field) +{ + int ret; + + lua_pushstring(L, field); + ret = lua_gettable(L, -2); + + if (ret == LUA_TNIL) { + lua_pop(L, 1); + return (0); + } + + luaL_argcheck(L, ret == LUA_TBOOLEAN, 0, field); + + ret = lua_toboolean(L, -1); + lua_pop(L, 1); + + return (ret); +} + +static const char * +lua_argument_get_string(lua_State *L, const char *field) +{ + const char *v; + int type; + + lua_pushstring(L, field); + type = lua_gettable(L, -2); + + if (type == LUA_TNIL) { + lua_pop(L, 1); + return (NULL); + } + + luaL_argcheck(L, type == LUA_TSTRING, 0, field); + + v = lua_tostring(L, -1); + lua_pop(L, 1); + + return (v); +} + +static int +lua_kore_module_init(lua_State *L) +{ + int i; + + luaL_newlib(L, lua_kore_functions); + + for (i = 0; lua_integers[i].symbol != NULL; i++) { + lua_pushstring(L, lua_integers[i].symbol); + lua_pushnumber(L, lua_integers[i].value); + lua_settable(L, -3); + } + + return (1); +} + +static void +lua_module_free(struct kore_module *module) +{ + struct lua_symbol *sym; + struct lua_module *lua; + + lua = module->handle; + + while ((sym = LIST_FIRST(&lua->symbols)) != NULL) { + LIST_REMOVE(sym, list); + kore_free(sym); + } + + kore_free(lua); +} + +static void +lua_module_reload(struct kore_module *module) +{ + lua_module_free(module); + lua_module_load(module); +} + +static void +lua_module_load(struct kore_module *module) +{ + struct lua_module *lua; + + lua = kore_calloc(1, sizeof(*lua)); + LIST_INIT(&lua->symbols); + + if ((lua->L = lua_newstate(lua_mem_alloc, NULL)) == NULL) + fatal("luaL_newstate"); + + luaL_openlibs(lua->L); + + luaL_requiref(lua->L, "kore", lua_kore_module_init, 1); + lua_pop(lua->L, 1); + + luaL_newmetatable(lua->L, "http_request"); + luaL_setfuncs(lua->L, lua_http_request_meta, 0); + lua_pop(lua->L, 1); + + lua_pushliteral(lua->L, "http_request_methods"); + luaL_newlib(lua->L, lua_http_request_methods); + lua_settable(lua->L, LUA_REGISTRYINDEX); + + luaL_newlib(lua->L, lua_http_request_methods); + lua_pop(lua->L, 1); + + if (luaL_loadfile(lua->L, module->path) != LUA_OK) { + fatal("%s: failed to import module (%s)", module->path, + lua_tostring(lua->L, -1)); + } + + if (lua_pcall(lua->L, 0, 0, 0) != LUA_OK) { + fatal("%s: failed to import module (%s)", module->path, + lua_tostring(lua->L, -1)); + } + + module->handle = lua; +} + +static void * +lua_module_getsym(struct kore_module *module, const char *symbol) +{ + int ref; + struct lua_module *lua; + struct lua_symbol *sym; + + lua = module->handle; + + if (lua_getglobal(lua->L, symbol) != LUA_TFUNCTION) + return (NULL); + + if ((ref = luaL_ref(lua->L, LUA_REGISTRYINDEX)) == LUA_REFNIL) + return (NULL); + + sym = kore_calloc(1, sizeof(*sym)); + + sym->ref = ref; + sym->L = lua->L; + + LIST_INSERT_HEAD(&lua->symbols, sym, list); + + return (sym); +} + +static int +lua_runtime_resolve(const char *module, const struct stat *st) +{ + const char *ext; + + if (!S_ISREG(st->st_mode)) + return (KORE_RESULT_ERROR); + + ext = strrchr(module, '.'); + + if (ext == NULL || strcasecmp(ext, ".lua")) + return (KORE_RESULT_ERROR); + + kore_module_load(module, NULL, KORE_MODULE_LUA); + + return (KORE_RESULT_OK); +} + +static int +lua_runtime_http_request(void *addr, struct http_request *req) +{ + lua_State *L; + struct lua_http_request *lreq; + + lua_symbol_resolve(addr, &L); + + lreq = lua_newuserdata(L, sizeof(*lreq)); + luaL_setmetatable(L, "http_request"); + + lreq->req = req; + + if (lua_pcall(L, 1, 0, 0)) { + kore_log(LOG_NOTICE, "%s: failed to call handler: %s", __func__, + lua_tostring(L, -1)); + http_response(req, 500, NULL, 0); + return (KORE_RESULT_OK); + } + + return (KORE_RESULT_OK); +} + +static void +lua_runtime_http_request_free(void *addr, struct http_request *req) +{ + fatal("%s: not yet implemented", __func__); +} + +static void +lua_runtime_http_body_chunk(void *addr, struct http_request *req, + const void *data, size_t len) +{ + fatal("%s: not yet implemented", __func__); +} + +static int +lua_runtime_validator(void *addr, struct http_request *req, const void *data) +{ + fatal("%s: not yet implemented", __func__); + + return (KORE_RESULT_ERROR); +} + +static void +lua_runtime_wsmessage(void *addr, struct connection *c, u_int8_t op, + const void *data, size_t len) +{ + fatal("%s: not yet implemented", __func__); +} + +static void +lua_runtime_execute(void *addr) +{ + lua_State *L; + + lua_symbol_resolve(addr, &L); + + if (lua_pcall(L, 0, 0, 0)) { + fatal("failed to execute function: %s", + lua_tostring(L, -1)); + } +} + +static void +lua_runtime_configure(void *addr, int argc, char **argv) +{ + lua_State *L; + int idx; + + lua_symbol_resolve(addr, &L); + + lua_pushinteger(L, argc); + lua_newtable(L); + + for (idx = 0; idx < argc; idx++) { + lua_pushstring(L, argv[idx]); + lua_rawseti(L, -2, idx); + } + + if (lua_pcall(L, 2, 0, 0)) { + fatal("failed to configure your application (%s)", + lua_tostring(L, -1)); + } +} + +static int +lua_runtime_onload(void *addr, int action) +{ + fatal("%s: not yet implemented", __func__); + + return (KORE_RESULT_ERROR); +} + +static void +lua_runtime_connect(void *addr, struct connection *c) +{ + fatal("%s: not yet implemented", __func__); +} + +static void +lua_runtime_signal(void *addr, int sig) +{ + fatal("%s: not yet implemented", __func__); +} + +static int +lua_kore_config(lua_State *L) +{ + char *v; + const char *opt, *val; + + lua_pushnil(L); + + while (lua_next(L, -2) != 0) { + if (!lua_isstring(L, -2)) + fatal("kore.config: keyword not a string"); + + opt = lua_tostring(L, -2); + + if (lua_isinteger(L, -1)) { + lua_pushvalue(L, -1); + val = lua_tostring(L, -1); + lua_pop(L, 1); + } else if (lua_isstring(L, -1)) { + val = lua_tostring(L, -1); + } else { + fatal("kore.config: value not a string or integer"); + } + + v = kore_strdup(val); + + if (!kore_configure_setting(opt, v)) { + kore_free(v); + luaL_error(L, "kore.config: cannot be set at runtime"); + lua_pop(L, 1); + return (0); + } + + kore_free(v); + lua_pop(L, 1); + } + + return (0); +} + +static int +lua_kore_server(lua_State *L) +{ + struct kore_server *srv; + const char *name, *ip, *port; + + if ((name = lua_argument_get_string(L, "name")) == NULL) + name = "default"; + + if ((ip = lua_argument_get_string(L, "ip")) == NULL) { + luaL_error(L, "kore.server: missing ip keyword"); + return (0); + } + + if ((port = lua_argument_get_string(L, "port")) == NULL) { + luaL_error(L, "kore.server: missing port keyword"); + return (0); + } + + if ((srv = kore_server_lookup(name)) != NULL) { + luaL_error(L, "kore.server: server '%s' exists", name); + return (0); + } + + srv = kore_server_create(name); + srv->tls = lua_argument_get_bool(L, "tls"); + + if (srv->tls && !kore_tls_supported()) { + kore_server_free(srv); + luaL_error(L, "kore.server: TLS not supported"); + return (0); + } + + if (!kore_server_bind(srv, ip, port, NULL)) { + kore_server_free(srv); + luaL_error(L, "kore.server: failed to bind %s:%s", ip, port); + return (0); + } + + kore_server_finalize(srv); + + return (0); +} + +static int +lua_http_request_gc(lua_State *L) +{ + struct lua_http_request *lreq; + + lreq = luaL_checkudata(L, 1, "http_request"); + kore_free(lreq); + + return (0); +} + +static int +lua_http_request_index(lua_State *L) +{ + struct lua_http_request *lreq; + const char *field; + + lreq = luaL_checkudata(L, 1, "http_request"); + field = luaL_checkstring(L, 2); + + lua_getfield(L, LUA_REGISTRYINDEX, "http_request_methods"); + lua_getfield(L, -1, field); + + if (!lua_isnil(L, -1)) + return (1); + + lua_pop(L, 2); + + if (!strcmp(field, "path")) { + lua_pushstring(L, lreq->req->path); + return (1); + } else if (!strcmp(field, "host")) { + lua_pushstring(L, lreq->req->host); + return (1); + } else if (!strcmp(field, "agent")) { + lua_pushstring(L, lreq->req->agent); + return (1); + } else if (!strcmp(field, "referer")) { + lua_pushstring(L, lreq->req->referer); + return (1); + } else if (!strcmp(field, "method")) { + lua_pushinteger(L, lreq->req->method); + return (1); + } + + return (0); +} + +static int +lua_http_response_header(lua_State *L) +{ + struct lua_http_request *lreq; + const char *header, *value; + + lreq = luaL_checkudata(L, 1, "http_request"); + header = luaL_checkstring(L, 2); + value = luaL_checkstring(L, 3); + + http_response_header(lreq->req, header, value); + + return (0); +} + +static int +lua_http_request_header(lua_State *L) +{ + struct lua_http_request *lreq; + const char *header, *value; + + lreq = luaL_checkudata(L, 1, "http_request"); + header = luaL_checkstring(L, 2); + + if (!http_request_header(lreq->req, header, &value)) { + lua_pushnil(L); + } else { + lua_pushstring(L, value); + } + + return (1); +} + +static int +lua_http_response(lua_State *L) +{ + size_t len; + struct lua_http_request *lreq; + const void *data; + int status; + + lreq = luaL_checkudata(L, 1, "http_request"); + status = luaL_checkinteger(L, 2); + + if (lua_isnil(L, 3)) { + len = 0; + data = NULL; + } else { + data = luaL_checklstring(L, 3, &len); + } + + http_response(lreq->req, status, data, len); + + return (0); +} diff --git a/src/module.c b/src/module.c @@ -29,6 +29,10 @@ #include "python_api.h" #endif +#if defined(KORE_USE_LUA) +#include "lua_api.h" +#endif + static TAILQ_HEAD(, kore_module) modules; static void native_free(struct kore_module *); @@ -93,6 +97,12 @@ kore_module_load(const char *path, const char *onload, int type) module->runtime = &kore_python_runtime; break; #endif +#if defined(KORE_USE_LUA) + case KORE_MODULE_LUA: + module->fun = &kore_lua_module; + module->runtime = &kore_lua_runtime; + break; +#endif default: fatal("kore_module_load: unknown type %d", type); } diff --git a/src/pool.c b/src/pool.c @@ -206,7 +206,6 @@ kore_pool_put(struct kore_pool *pool, void *ptr) pool_mark_entry_none(pool, entry); pool->freelist = entry; - #if defined(KORE_USE_TASKS) pool_unlock(pool); #endif diff --git a/src/runtime.c b/src/runtime.c @@ -27,6 +27,10 @@ #include "python_api.h" #endif +#if defined(KORE_USE_LUA) +#include "lua_api.h" +#endif + static void native_runtime_execute(void *); static int native_runtime_onload(void *, int); static void native_runtime_signal(void *, int); @@ -66,6 +70,9 @@ static struct kore_runtime *runtimes[] = { #if defined(KORE_USE_PYTHON) &kore_python_runtime, #endif +#if defined(KORE_USE_LUA) + &kore_lua_runtime, +#endif NULL };