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

module.c (5632B)



      1 /*
      2  * Copyright (c) 2013-2022 Joris Vink <joris@coders.se>
      3  *
      4  * Permission to use, copy, modify, and distribute this software for any
      5  * purpose with or without fee is hereby granted, provided that the above
      6  * copyright notice and this permission notice appear in all copies.
      7  *
      8  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
      9  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
     10  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
     11  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
     12  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
     13  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
     14  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
     15  */
     16 
     17 #include <sys/types.h>
     18 #include <sys/stat.h>
     19 
     20 #include <dlfcn.h>
     21 
     22 #include "kore.h"
     23 
     24 #if !defined(KORE_NO_HTTP)
     25 #include "http.h"
     26 #endif
     27 
     28 #if defined(KORE_USE_PYTHON)
     29 #include "python_api.h"
     30 #endif
     31 
     32 #if defined(KORE_USE_LUA)
     33 #include "lua_api.h"
     34 #endif
     35 
     36 static TAILQ_HEAD(, kore_module)	modules;
     37 
     38 static void	native_free(struct kore_module *);
     39 static void	native_load(struct kore_module *);
     40 static void	native_reload(struct kore_module *);
     41 static void	*native_getsym(struct kore_module *, const char *);
     42 
     43 struct kore_module_functions kore_native_module = {
     44 	.free = native_free,
     45 	.load = native_load,
     46 	.getsym = native_getsym,
     47 	.reload = native_reload,
     48 };
     49 
     50 void
     51 kore_module_init(void)
     52 {
     53 	TAILQ_INIT(&modules);
     54 }
     55 
     56 void
     57 kore_module_cleanup(void)
     58 {
     59 	struct kore_module	*module, *next;
     60 
     61 	for (module = TAILQ_FIRST(&modules); module != NULL; module = next) {
     62 		next = TAILQ_NEXT(module, list);
     63 		TAILQ_REMOVE(&modules, module, list);
     64 		module->fun->free(module);
     65 	}
     66 }
     67 
     68 struct kore_module *
     69 kore_module_load(const char *path, const char *onload, int type)
     70 {
     71 	struct stat		st;
     72 	struct kore_module	*module;
     73 
     74 	module = kore_malloc(sizeof(struct kore_module));
     75 	module->ocb = NULL;
     76 	module->type = type;
     77 	module->onload = NULL;
     78 	module->handle = NULL;
     79 
     80 	if (path != NULL) {
     81 		if (stat(path, &st) == -1)
     82 			fatal("stat(%s): %s", path, errno_s);
     83 
     84 		module->path = kore_strdup(path);
     85 	} else {
     86 		module->path = NULL;
     87 	}
     88 
     89 	switch (module->type) {
     90 	case KORE_MODULE_NATIVE:
     91 		module->fun = &kore_native_module;
     92 		module->runtime = &kore_native_runtime;
     93 		break;
     94 #if defined(KORE_USE_PYTHON)
     95 	case KORE_MODULE_PYTHON:
     96 		module->fun = &kore_python_module;
     97 		module->runtime = &kore_python_runtime;
     98 		break;
     99 #endif
    100 #if defined(KORE_USE_LUA)
    101 	case KORE_MODULE_LUA:
    102 		module->fun = &kore_lua_module;
    103 		module->runtime = &kore_lua_runtime;
    104 		break;
    105 #endif
    106 	default:
    107 		fatal("kore_module_load: unknown type %d", type);
    108 	}
    109 
    110 	module->fun->load(module);
    111 	TAILQ_INSERT_TAIL(&modules, module, list);
    112 
    113 	if (onload != NULL) {
    114 		module->onload = kore_strdup(onload);
    115 		module->ocb = kore_malloc(sizeof(*module->ocb));
    116 		module->ocb->runtime = module->runtime;
    117 		module->ocb->addr = module->fun->getsym(module, onload);
    118 
    119 		if (module->ocb->addr == NULL) {
    120 			fatal("%s: onload '%s' not present",
    121 			    module->path, onload);
    122 		}
    123 	}
    124 
    125 	return (module);
    126 }
    127 
    128 void
    129 kore_module_onload(void)
    130 {
    131 	struct kore_module	*module;
    132 
    133 	TAILQ_FOREACH(module, &modules, list) {
    134 		if (module->path == NULL || module->ocb == NULL)
    135 			continue;
    136 
    137 		kore_runtime_onload(module->ocb, KORE_MODULE_LOAD);
    138 	}
    139 }
    140 
    141 void
    142 kore_module_reload(int cbs)
    143 {
    144 	struct stat			st;
    145 	int				ret;
    146 	struct kore_module		*module;
    147 
    148 	TAILQ_FOREACH(module, &modules, list) {
    149 		if (module->path == NULL)
    150 			continue;
    151 
    152 		if (stat(module->path, &st) == -1) {
    153 			kore_log(LOG_NOTICE, "stat(%s): %s, skipping reload",
    154 			    module->path, errno_s);
    155 			continue;
    156 		}
    157 
    158 		if (module->ocb != NULL && cbs == 1) {
    159 			ret = kore_runtime_onload(module->ocb,
    160 			    KORE_MODULE_UNLOAD);
    161 			if (ret == KORE_RESULT_ERROR) {
    162 				kore_log(LOG_NOTICE,
    163 				    "%s forced no reloaded", module->path);
    164 				continue;
    165 			}
    166 		}
    167 
    168 		module->fun->reload(module);
    169 
    170 		if (module->onload != NULL) {
    171 			kore_free(module->ocb);
    172 			module->ocb = kore_malloc(sizeof(*module->ocb));
    173 			module->ocb->runtime = module->runtime;
    174 			module->ocb->addr =
    175 			    module->fun->getsym(module, module->onload);
    176 			if (module->ocb->addr == NULL) {
    177 				fatal("%s: onload '%s' not present",
    178 				    module->path, module->onload);
    179 			}
    180 		}
    181 
    182 		if (module->ocb != NULL && cbs == 1)
    183 			kore_runtime_onload(module->ocb, KORE_MODULE_LOAD);
    184 
    185 		kore_log(LOG_NOTICE, "reloaded '%s' module", module->path);
    186 	}
    187 
    188 #if !defined(KORE_NO_HTTP)
    189 	kore_route_reload();
    190 	kore_validator_reload();
    191 #endif
    192 }
    193 
    194 int
    195 kore_module_loaded(void)
    196 {
    197 	if (TAILQ_EMPTY(&modules))
    198 		return (0);
    199 
    200 	return (1);
    201 }
    202 
    203 void *
    204 kore_module_getsym(const char *symbol, struct kore_runtime **runtime)
    205 {
    206 	void			*ptr;
    207 	struct kore_module	*module;
    208 
    209 	if (runtime != NULL)
    210 		*runtime = NULL;
    211 
    212 	TAILQ_FOREACH(module, &modules, list) {
    213 		ptr = module->fun->getsym(module, symbol);
    214 		if (ptr != NULL) {
    215 			if (runtime != NULL)
    216 				*runtime = module->runtime;
    217 			return (ptr);
    218 		}
    219 	}
    220 
    221 	return (NULL);
    222 }
    223 
    224 static void *
    225 native_getsym(struct kore_module *module, const char *symbol)
    226 {
    227 	return (dlsym(module->handle, symbol));
    228 }
    229 
    230 static void
    231 native_free(struct kore_module *module)
    232 {
    233 	kore_free(module->path);
    234 	(void)dlclose(module->handle);
    235 	kore_free(module);
    236 }
    237 
    238 static void
    239 native_reload(struct kore_module *module)
    240 {
    241 	if (dlclose(module->handle))
    242 		fatal("cannot close existing module: %s", dlerror());
    243 	module->fun->load(module);
    244 }
    245 
    246 static void
    247 native_load(struct kore_module *module)
    248 {
    249 	module->handle = dlopen(module->path, RTLD_NOW | RTLD_GLOBAL);
    250 	if (module->handle == NULL)
    251 		fatal("%s: %s", module->path, dlerror());
    252 }