2013-05-01 16:03:48 +02:00
|
|
|
/*
|
2018-01-20 22:51:06 +01:00
|
|
|
* Copyright (c) 2013-2018 Joris Vink <joris@coders.se>
|
2013-05-01 16:03:48 +02:00
|
|
|
*
|
|
|
|
* 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/stat.h>
|
|
|
|
|
|
|
|
#include <dlfcn.h>
|
|
|
|
|
|
|
|
#include "kore.h"
|
|
|
|
|
2017-01-12 23:38:51 +01:00
|
|
|
#if !defined(KORE_NO_HTTP)
|
|
|
|
#include "http.h"
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#if defined(KORE_USE_PYTHON)
|
|
|
|
#include "python_api.h"
|
|
|
|
#endif
|
|
|
|
|
2013-12-15 01:11:56 +01:00
|
|
|
static TAILQ_HEAD(, kore_module) modules;
|
2013-09-02 08:52:16 +02:00
|
|
|
|
2017-01-12 23:38:51 +01:00
|
|
|
static void native_free(struct kore_module *);
|
2018-02-14 13:48:49 +01:00
|
|
|
static void native_load(struct kore_module *);
|
2017-01-12 23:38:51 +01:00
|
|
|
static void native_reload(struct kore_module *);
|
|
|
|
static void *native_getsym(struct kore_module *, const char *);
|
|
|
|
|
|
|
|
struct kore_module_functions kore_native_module = {
|
|
|
|
.free = native_free,
|
|
|
|
.load = native_load,
|
|
|
|
.getsym = native_getsym,
|
|
|
|
.reload = native_reload,
|
|
|
|
};
|
|
|
|
|
2013-12-15 01:11:56 +01:00
|
|
|
void
|
|
|
|
kore_module_init(void)
|
|
|
|
{
|
|
|
|
TAILQ_INIT(&modules);
|
|
|
|
}
|
2013-05-01 16:03:48 +02:00
|
|
|
|
2016-06-08 13:55:14 +02:00
|
|
|
void
|
|
|
|
kore_module_cleanup(void)
|
|
|
|
{
|
|
|
|
struct kore_module *module, *next;
|
|
|
|
|
2017-02-07 22:44:20 +01:00
|
|
|
for (module = TAILQ_FIRST(&modules); module != NULL; module = next) {
|
|
|
|
next = TAILQ_NEXT(module, list);
|
2016-06-08 13:55:14 +02:00
|
|
|
TAILQ_REMOVE(&modules, module, list);
|
2017-01-12 23:38:51 +01:00
|
|
|
module->fun->free(module);
|
2016-06-08 13:55:14 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-10-16 13:16:36 +02:00
|
|
|
struct kore_module *
|
2017-01-12 23:38:51 +01:00
|
|
|
kore_module_load(const char *path, const char *onload, int type)
|
2013-05-01 16:03:48 +02:00
|
|
|
{
|
|
|
|
struct stat st;
|
2013-12-15 01:11:56 +01:00
|
|
|
struct kore_module *module;
|
2013-05-01 16:03:48 +02:00
|
|
|
|
2013-12-15 01:11:56 +01:00
|
|
|
kore_debug("kore_module_load(%s, %s)", path, onload);
|
2013-05-01 16:03:48 +02:00
|
|
|
|
2016-07-06 16:16:15 +02:00
|
|
|
module = kore_malloc(sizeof(struct kore_module));
|
|
|
|
module->ocb = NULL;
|
2017-01-12 23:38:51 +01:00
|
|
|
module->type = type;
|
|
|
|
module->onload = NULL;
|
|
|
|
module->handle = NULL;
|
2016-07-06 16:16:15 +02:00
|
|
|
|
2017-01-26 13:13:23 +01:00
|
|
|
if (path != NULL) {
|
|
|
|
if (stat(path, &st) == -1)
|
|
|
|
fatal("stat(%s): %s", path, errno_s);
|
2013-05-01 16:03:48 +02:00
|
|
|
|
2017-01-26 13:13:23 +01:00
|
|
|
module->path = kore_strdup(path);
|
|
|
|
module->mtime = st.st_mtime;
|
|
|
|
} else {
|
|
|
|
module->path = NULL;
|
|
|
|
module->mtime = 0;
|
|
|
|
}
|
2013-05-01 16:03:48 +02:00
|
|
|
|
2017-01-12 23:38:51 +01:00
|
|
|
switch (module->type) {
|
|
|
|
case KORE_MODULE_NATIVE:
|
|
|
|
module->fun = &kore_native_module;
|
|
|
|
module->runtime = &kore_native_runtime;
|
|
|
|
break;
|
|
|
|
#if defined(KORE_USE_PYTHON)
|
|
|
|
case KORE_MODULE_PYTHON:
|
|
|
|
module->fun = &kore_python_module;
|
|
|
|
module->runtime = &kore_python_runtime;
|
|
|
|
break;
|
|
|
|
#endif
|
|
|
|
default:
|
|
|
|
fatal("kore_module_load: unknown type %d", type);
|
2013-05-30 21:26:39 +02:00
|
|
|
}
|
2013-09-02 08:52:16 +02:00
|
|
|
|
2018-02-14 13:48:49 +01:00
|
|
|
module->fun->load(module);
|
2013-12-15 01:11:56 +01:00
|
|
|
TAILQ_INSERT_TAIL(&modules, module, list);
|
2017-01-12 23:38:51 +01:00
|
|
|
|
|
|
|
if (onload != NULL) {
|
2017-08-30 15:11:07 +02:00
|
|
|
module->onload = kore_strdup(onload);
|
2017-01-12 23:38:51 +01:00
|
|
|
module->ocb = kore_malloc(sizeof(*module->ocb));
|
|
|
|
module->ocb->runtime = module->runtime;
|
|
|
|
module->ocb->addr = module->fun->getsym(module, onload);
|
|
|
|
|
|
|
|
if (module->ocb->addr == NULL) {
|
|
|
|
fatal("%s: onload '%s' not present",
|
|
|
|
module->path, onload);
|
|
|
|
}
|
|
|
|
}
|
2018-10-16 13:16:36 +02:00
|
|
|
|
|
|
|
return (module);
|
2013-05-03 00:04:06 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2014-06-29 21:15:23 +02:00
|
|
|
kore_module_onload(void)
|
|
|
|
{
|
|
|
|
struct kore_module *module;
|
|
|
|
|
|
|
|
TAILQ_FOREACH(module, &modules, list) {
|
2017-01-26 13:13:23 +01:00
|
|
|
if (module->path == NULL || module->ocb == NULL)
|
2014-06-29 21:15:23 +02:00
|
|
|
continue;
|
|
|
|
|
2017-01-12 23:38:51 +01:00
|
|
|
kore_runtime_onload(module->ocb, KORE_MODULE_LOAD);
|
2014-06-29 21:15:23 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
kore_module_reload(int cbs)
|
2013-05-03 00:04:06 +02:00
|
|
|
{
|
2013-12-15 01:11:56 +01:00
|
|
|
struct stat st;
|
2017-01-12 23:38:51 +01:00
|
|
|
int ret;
|
2018-07-17 14:28:43 +02:00
|
|
|
#if !defined(KORE_NO_HTTP)
|
2017-08-31 17:11:24 +02:00
|
|
|
struct kore_domain *dom;
|
|
|
|
struct kore_module_handle *hdlr;
|
2018-07-17 14:28:43 +02:00
|
|
|
#endif
|
2013-12-15 01:11:56 +01:00
|
|
|
struct kore_module *module;
|
2013-05-03 00:04:06 +02:00
|
|
|
|
2013-12-15 01:11:56 +01:00
|
|
|
TAILQ_FOREACH(module, &modules, list) {
|
2017-01-26 13:13:23 +01:00
|
|
|
if (module->path == NULL)
|
|
|
|
continue;
|
|
|
|
|
2013-12-15 01:11:56 +01:00
|
|
|
if (stat(module->path, &st) == -1) {
|
|
|
|
kore_log(LOG_NOTICE, "stat(%s): %s, skipping reload",
|
|
|
|
module->path, errno_s);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2017-02-22 21:48:06 +01:00
|
|
|
if (module->mtime == st.st_mtime)
|
2013-12-15 01:11:56 +01:00
|
|
|
continue;
|
|
|
|
|
2015-05-07 13:03:10 +02:00
|
|
|
if (module->ocb != NULL && cbs == 1) {
|
2017-01-12 23:38:51 +01:00
|
|
|
ret = kore_runtime_onload(module->ocb,
|
|
|
|
KORE_MODULE_UNLOAD);
|
|
|
|
if (ret == KORE_RESULT_ERROR) {
|
2015-05-07 13:03:10 +02:00
|
|
|
kore_log(LOG_NOTICE,
|
2017-02-22 21:48:06 +01:00
|
|
|
"%s forced no reloaded", module->path);
|
2015-05-07 13:03:10 +02:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
}
|
2013-12-21 13:37:34 +01:00
|
|
|
|
2013-12-15 01:11:56 +01:00
|
|
|
module->mtime = st.st_mtime;
|
2017-01-12 23:38:51 +01:00
|
|
|
module->fun->reload(module);
|
2013-12-15 01:11:56 +01:00
|
|
|
|
|
|
|
if (module->onload != NULL) {
|
2017-01-12 23:38:51 +01:00
|
|
|
kore_free(module->ocb);
|
|
|
|
module->ocb = kore_malloc(sizeof(*module->ocb));
|
|
|
|
module->ocb->runtime = module->runtime;
|
|
|
|
module->ocb->addr =
|
|
|
|
module->fun->getsym(module, module->onload);
|
|
|
|
if (module->ocb->addr == NULL) {
|
2013-12-15 01:11:56 +01:00
|
|
|
fatal("%s: onload '%s' not present",
|
|
|
|
module->path, module->onload);
|
|
|
|
}
|
|
|
|
}
|
2013-05-03 00:04:06 +02:00
|
|
|
|
2017-01-12 23:38:51 +01:00
|
|
|
if (module->ocb != NULL && cbs == 1)
|
|
|
|
kore_runtime_onload(module->ocb, KORE_MODULE_LOAD);
|
|
|
|
|
2013-12-15 01:11:56 +01:00
|
|
|
kore_log(LOG_NOTICE, "reloaded '%s' module", module->path);
|
|
|
|
}
|
|
|
|
|
2018-07-17 14:28:43 +02:00
|
|
|
#if !defined(KORE_NO_HTTP)
|
2017-08-31 17:11:24 +02:00
|
|
|
TAILQ_FOREACH(dom, &domains, list) {
|
|
|
|
TAILQ_FOREACH(hdlr, &(dom->handlers), list) {
|
|
|
|
kore_free(hdlr->rcall);
|
|
|
|
hdlr->rcall = kore_runtime_getcall(hdlr->func);
|
|
|
|
if (hdlr->rcall == NULL)
|
|
|
|
fatal("no function '%s' found", hdlr->func);
|
|
|
|
hdlr->errors = 0;
|
|
|
|
}
|
|
|
|
}
|
2018-07-17 14:28:43 +02:00
|
|
|
#endif
|
2017-08-31 17:11:24 +02:00
|
|
|
|
|
|
|
#if !defined(KORE_NO_HTTP)
|
|
|
|
kore_validator_reload();
|
|
|
|
#endif
|
2013-05-01 16:03:48 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
kore_module_loaded(void)
|
|
|
|
{
|
2013-12-15 01:11:56 +01:00
|
|
|
if (TAILQ_EMPTY(&modules))
|
|
|
|
return (0);
|
|
|
|
|
|
|
|
return (1);
|
2013-05-01 16:03:48 +02:00
|
|
|
}
|
|
|
|
|
2015-11-27 16:22:50 +01:00
|
|
|
#if !defined(KORE_NO_HTTP)
|
2013-05-01 16:03:48 +02:00
|
|
|
int
|
2014-08-04 12:40:21 +02:00
|
|
|
kore_module_handler_new(const char *path, const char *domain,
|
|
|
|
const char *func, const char *auth, int type)
|
2013-05-01 16:03:48 +02:00
|
|
|
{
|
2014-01-22 22:55:10 +01:00
|
|
|
struct kore_auth *ap;
|
2013-06-24 11:32:45 +02:00
|
|
|
struct kore_domain *dom;
|
2013-05-01 16:03:48 +02:00
|
|
|
struct kore_module_handle *hdlr;
|
|
|
|
|
2014-01-22 22:55:10 +01:00
|
|
|
kore_debug("kore_module_handler_new(%s, %s, %s, %s, %d)", path,
|
|
|
|
domain, func, auth, type);
|
2013-05-01 16:03:48 +02:00
|
|
|
|
2013-06-24 11:32:45 +02:00
|
|
|
if ((dom = kore_domain_lookup(domain)) == NULL)
|
2013-05-29 14:29:46 +02:00
|
|
|
return (KORE_RESULT_ERROR);
|
2013-05-02 13:30:13 +02:00
|
|
|
|
2014-01-22 22:55:10 +01:00
|
|
|
if (auth != NULL) {
|
|
|
|
if ((ap = kore_auth_lookup(auth)) == NULL)
|
|
|
|
fatal("no authentication block '%s' found", auth);
|
|
|
|
} else {
|
|
|
|
ap = NULL;
|
|
|
|
}
|
|
|
|
|
2013-07-13 21:08:55 +02:00
|
|
|
hdlr = kore_malloc(sizeof(*hdlr));
|
2014-01-22 22:55:10 +01:00
|
|
|
hdlr->auth = ap;
|
2014-07-30 09:11:21 +02:00
|
|
|
hdlr->dom = dom;
|
2013-07-07 14:48:32 +02:00
|
|
|
hdlr->errors = 0;
|
2013-05-01 16:03:48 +02:00
|
|
|
hdlr->type = type;
|
2013-05-29 14:29:46 +02:00
|
|
|
hdlr->path = kore_strdup(path);
|
2013-05-03 00:04:06 +02:00
|
|
|
hdlr->func = kore_strdup(func);
|
2018-07-17 14:23:57 +02:00
|
|
|
hdlr->methods = HTTP_METHOD_ALL;
|
2013-05-01 16:03:48 +02:00
|
|
|
|
2017-01-12 23:38:51 +01:00
|
|
|
TAILQ_INIT(&(hdlr->params));
|
|
|
|
|
|
|
|
if ((hdlr->rcall = kore_runtime_getcall(func)) == NULL) {
|
|
|
|
kore_module_handler_free(hdlr);
|
|
|
|
kore_log(LOG_ERR, "function '%s' not found", func);
|
|
|
|
return (KORE_RESULT_ERROR);
|
|
|
|
}
|
|
|
|
|
2013-05-29 14:29:46 +02:00
|
|
|
if (hdlr->type == HANDLER_TYPE_DYNAMIC) {
|
2013-12-11 19:13:50 +01:00
|
|
|
if (regcomp(&(hdlr->rctx), hdlr->path,
|
|
|
|
REG_EXTENDED | REG_NOSUB)) {
|
2016-02-01 12:30:20 +01:00
|
|
|
kore_module_handler_free(hdlr);
|
2013-06-04 16:30:53 +02:00
|
|
|
kore_debug("regcomp() on %s failed", path);
|
2013-05-29 14:29:46 +02:00
|
|
|
return (KORE_RESULT_ERROR);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
TAILQ_INSERT_TAIL(&(dom->handlers), hdlr, list);
|
2013-05-01 16:03:48 +02:00
|
|
|
return (KORE_RESULT_OK);
|
|
|
|
}
|
|
|
|
|
2016-02-01 12:30:20 +01:00
|
|
|
void
|
|
|
|
kore_module_handler_free(struct kore_module_handle *hdlr)
|
|
|
|
{
|
|
|
|
struct kore_handler_params *param;
|
|
|
|
|
2016-02-01 20:02:02 +01:00
|
|
|
if (hdlr == NULL)
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (hdlr->func != NULL)
|
2016-07-12 13:54:14 +02:00
|
|
|
kore_free(hdlr->func);
|
2016-02-01 20:02:02 +01:00
|
|
|
if (hdlr->path != NULL)
|
2016-07-12 13:54:14 +02:00
|
|
|
kore_free(hdlr->path);
|
2016-02-01 20:02:02 +01:00
|
|
|
if (hdlr->type == HANDLER_TYPE_DYNAMIC)
|
2016-02-01 12:30:20 +01:00
|
|
|
regfree(&(hdlr->rctx));
|
|
|
|
|
2016-02-01 20:02:02 +01:00
|
|
|
/* Drop all validators associated with this handler */
|
|
|
|
while ((param = TAILQ_FIRST(&(hdlr->params))) != NULL) {
|
|
|
|
TAILQ_REMOVE(&(hdlr->params), param, list);
|
2017-02-07 22:44:20 +01:00
|
|
|
if (param->name != NULL)
|
|
|
|
kore_free(param->name);
|
2016-07-12 13:54:14 +02:00
|
|
|
kore_free(param);
|
2016-02-01 12:30:20 +01:00
|
|
|
}
|
2016-02-01 20:02:02 +01:00
|
|
|
|
2016-07-12 13:54:14 +02:00
|
|
|
kore_free(hdlr);
|
2016-02-01 12:30:20 +01:00
|
|
|
}
|
|
|
|
|
2013-07-07 14:48:32 +02:00
|
|
|
struct kore_module_handle *
|
2014-08-04 12:40:21 +02:00
|
|
|
kore_module_handler_find(const char *domain, const char *path)
|
2013-05-01 16:03:48 +02:00
|
|
|
{
|
2013-06-24 11:32:45 +02:00
|
|
|
struct kore_domain *dom;
|
2013-05-01 16:11:10 +02:00
|
|
|
struct kore_module_handle *hdlr;
|
2013-05-02 13:30:13 +02:00
|
|
|
|
2013-06-24 11:32:45 +02:00
|
|
|
if ((dom = kore_domain_lookup(domain)) == NULL)
|
2013-05-29 14:29:46 +02:00
|
|
|
return (NULL);
|
2013-05-01 16:11:10 +02:00
|
|
|
|
2013-05-29 14:29:46 +02:00
|
|
|
TAILQ_FOREACH(hdlr, &(dom->handlers), list) {
|
2013-05-29 13:33:32 +02:00
|
|
|
if (hdlr->type == HANDLER_TYPE_STATIC) {
|
2013-05-29 14:29:46 +02:00
|
|
|
if (!strcmp(hdlr->path, path))
|
2013-07-07 14:48:32 +02:00
|
|
|
return (hdlr);
|
2013-05-29 13:33:32 +02:00
|
|
|
} else {
|
2013-05-29 14:29:46 +02:00
|
|
|
if (!regexec(&(hdlr->rctx), path, 0, NULL, 0))
|
2013-07-07 14:48:32 +02:00
|
|
|
return (hdlr);
|
2013-05-29 13:33:32 +02:00
|
|
|
}
|
2013-05-01 16:11:10 +02:00
|
|
|
}
|
|
|
|
|
2013-05-01 16:03:48 +02:00
|
|
|
return (NULL);
|
|
|
|
}
|
2015-11-27 16:22:50 +01:00
|
|
|
#endif /* !KORE_NO_HTTP */
|
|
|
|
|
2013-11-09 16:21:52 +01:00
|
|
|
void *
|
2017-01-12 23:38:51 +01:00
|
|
|
kore_module_getsym(const char *symbol, struct kore_runtime **runtime)
|
2013-11-09 16:21:52 +01:00
|
|
|
{
|
2013-12-15 01:11:56 +01:00
|
|
|
void *ptr;
|
|
|
|
struct kore_module *module;
|
|
|
|
|
2017-01-12 23:38:51 +01:00
|
|
|
if (runtime != NULL)
|
|
|
|
*runtime = NULL;
|
|
|
|
|
2013-12-15 01:11:56 +01:00
|
|
|
TAILQ_FOREACH(module, &modules, list) {
|
2017-01-12 23:38:51 +01:00
|
|
|
ptr = module->fun->getsym(module, symbol);
|
|
|
|
if (ptr != NULL) {
|
|
|
|
if (runtime != NULL)
|
|
|
|
*runtime = module->runtime;
|
2013-12-15 01:11:56 +01:00
|
|
|
return (ptr);
|
2017-01-12 23:38:51 +01:00
|
|
|
}
|
2013-12-15 01:11:56 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
return (NULL);
|
2013-11-09 16:21:52 +01:00
|
|
|
}
|
2017-01-12 23:38:51 +01:00
|
|
|
|
|
|
|
static void *
|
|
|
|
native_getsym(struct kore_module *module, const char *symbol)
|
|
|
|
{
|
|
|
|
return (dlsym(module->handle, symbol));
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
native_free(struct kore_module *module)
|
|
|
|
{
|
|
|
|
kore_free(module->path);
|
|
|
|
(void)dlclose(module->handle);
|
|
|
|
kore_free(module);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
native_reload(struct kore_module *module)
|
|
|
|
{
|
|
|
|
if (dlclose(module->handle))
|
|
|
|
fatal("cannot close existing module: %s", dlerror());
|
2018-02-14 13:48:49 +01:00
|
|
|
module->fun->load(module);
|
2017-01-12 23:38:51 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2018-02-14 13:48:49 +01:00
|
|
|
native_load(struct kore_module *module)
|
2017-01-12 23:38:51 +01:00
|
|
|
{
|
|
|
|
module->handle = dlopen(module->path, RTLD_NOW | RTLD_GLOBAL);
|
|
|
|
if (module->handle == NULL)
|
|
|
|
fatal("%s: %s", module->path, dlerror());
|
|
|
|
}
|