kore

An easy to use, scalable and secure web application framework for writing web APIs in C.
Commits | Files | Refs | README | LICENSE | git clone https://git.kore.io/kore.git

module.c (5495B)



      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 static TAILQ_HEAD(, kore_module)	modules;
     33 
     34 static void	native_free(struct kore_module *);
     35 static void	native_load(struct kore_module *);
     36 static void	native_reload(struct kore_module *);
     37 static void	*native_getsym(struct kore_module *, const char *);
     38 
     39 struct kore_module_functions kore_native_module = {
     40 	.free = native_free,
     41 	.load = native_load,
     42 	.getsym = native_getsym,
     43 	.reload = native_reload,
     44 };
     45 
     46 void
     47 kore_module_init(void)
     48 {
     49 	TAILQ_INIT(&modules);
     50 }
     51 
     52 void
     53 kore_module_cleanup(void)
     54 {
     55 	struct kore_module	*module, *next;
     56 
     57 	for (module = TAILQ_FIRST(&modules); module != NULL; module = next) {
     58 		next = TAILQ_NEXT(module, list);
     59 		TAILQ_REMOVE(&modules, module, list);
     60 		module->fun->free(module);
     61 	}
     62 }
     63 
     64 struct kore_module *
     65 kore_module_load(const char *path, const char *onload, int type)
     66 {
     67 	struct stat		st;
     68 	struct kore_module	*module;
     69 
     70 	kore_debug("kore_module_load(%s, %s)", path, onload);
     71 
     72 	module = kore_malloc(sizeof(struct kore_module));
     73 	module->ocb = NULL;
     74 	module->type = type;
     75 	module->onload = NULL;
     76 	module->handle = NULL;
     77 
     78 	if (path != NULL) {
     79 		if (stat(path, &st) == -1)
     80 			fatal("stat(%s): %s", path, errno_s);
     81 
     82 		module->path = kore_strdup(path);
     83 	} else {
     84 		module->path = NULL;
     85 	}
     86 
     87 	switch (module->type) {
     88 	case KORE_MODULE_NATIVE:
     89 		module->fun = &kore_native_module;
     90 		module->runtime = &kore_native_runtime;
     91 		break;
     92 #if defined(KORE_USE_PYTHON)
     93 	case KORE_MODULE_PYTHON:
     94 		module->fun = &kore_python_module;
     95 		module->runtime = &kore_python_runtime;
     96 		break;
     97 #endif
     98 	default:
     99 		fatal("kore_module_load: unknown type %d", type);
    100 	}
    101 
    102 	module->fun->load(module);
    103 	TAILQ_INSERT_TAIL(&modules, module, list);
    104 
    105 	if (onload != NULL) {
    106 		module->onload = kore_strdup(onload);
    107 		module->ocb = kore_malloc(sizeof(*module->ocb));
    108 		module->ocb->runtime = module->runtime;
    109 		module->ocb->addr = module->fun->getsym(module, onload);
    110 
    111 		if (module->ocb->addr == NULL) {
    112 			fatal("%s: onload '%s' not present",
    113 			    module->path, onload);
    114 		}
    115 	}
    116 
    117 	return (module);
    118 }
    119 
    120 void
    121 kore_module_onload(void)
    122 {
    123 	struct kore_module	*module;
    124 
    125 	TAILQ_FOREACH(module, &modules, list) {
    126 		if (module->path == NULL || module->ocb == NULL)
    127 			continue;
    128 
    129 		kore_runtime_onload(module->ocb, KORE_MODULE_LOAD);
    130 	}
    131 }
    132 
    133 void
    134 kore_module_reload(int cbs)
    135 {
    136 	struct stat			st;
    137 	int				ret;
    138 	struct kore_module		*module;
    139 
    140 	TAILQ_FOREACH(module, &modules, list) {
    141 		if (module->path == NULL)
    142 			continue;
    143 
    144 		if (stat(module->path, &st) == -1) {
    145 			kore_log(LOG_NOTICE, "stat(%s): %s, skipping reload",
    146 			    module->path, errno_s);
    147 			continue;
    148 		}
    149 
    150 		if (module->ocb != NULL && cbs == 1) {
    151 			ret = kore_runtime_onload(module->ocb,
    152 			    KORE_MODULE_UNLOAD);
    153 			if (ret == KORE_RESULT_ERROR) {
    154 				kore_log(LOG_NOTICE,
    155 				    "%s forced no reloaded", module->path);
    156 				continue;
    157 			}
    158 		}
    159 
    160 		module->fun->reload(module);
    161 
    162 		if (module->onload != NULL) {
    163 			kore_free(module->ocb);
    164 			module->ocb = kore_malloc(sizeof(*module->ocb));
    165 			module->ocb->runtime = module->runtime;
    166 			module->ocb->addr =
    167 			    module->fun->getsym(module, module->onload);
    168 			if (module->ocb->addr == NULL) {
    169 				fatal("%s: onload '%s' not present",
    170 				    module->path, module->onload);
    171 			}
    172 		}
    173 
    174 		if (module->ocb != NULL && cbs == 1)
    175 			kore_runtime_onload(module->ocb, KORE_MODULE_LOAD);
    176 
    177 		kore_log(LOG_NOTICE, "reloaded '%s' module", module->path);
    178 	}
    179 
    180 #if !defined(KORE_NO_HTTP)
    181 	kore_route_reload();
    182 	kore_validator_reload();
    183 #endif
    184 }
    185 
    186 int
    187 kore_module_loaded(void)
    188 {
    189 	if (TAILQ_EMPTY(&modules))
    190 		return (0);
    191 
    192 	return (1);
    193 }
    194 
    195 void *
    196 kore_module_getsym(const char *symbol, struct kore_runtime **runtime)
    197 {
    198 	void			*ptr;
    199 	struct kore_module	*module;
    200 
    201 	if (runtime != NULL)
    202 		*runtime = NULL;
    203 
    204 	TAILQ_FOREACH(module, &modules, list) {
    205 		ptr = module->fun->getsym(module, symbol);
    206 		if (ptr != NULL) {
    207 			if (runtime != NULL)
    208 				*runtime = module->runtime;
    209 			return (ptr);
    210 		}
    211 	}
    212 
    213 	return (NULL);
    214 }
    215 
    216 static void *
    217 native_getsym(struct kore_module *module, const char *symbol)
    218 {
    219 	return (dlsym(module->handle, symbol));
    220 }
    221 
    222 static void
    223 native_free(struct kore_module *module)
    224 {
    225 	kore_free(module->path);
    226 	(void)dlclose(module->handle);
    227 	kore_free(module);
    228 }
    229 
    230 static void
    231 native_reload(struct kore_module *module)
    232 {
    233 	if (dlclose(module->handle))
    234 		fatal("cannot close existing module: %s", dlerror());
    235 	module->fun->load(module);
    236 }
    237 
    238 static void
    239 native_load(struct kore_module *module)
    240 {
    241 	module->handle = dlopen(module->path, RTLD_NOW | RTLD_GLOBAL);
    242 	if (module->handle == NULL)
    243 		fatal("%s: %s", module->path, dlerror());
    244 }