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 (5439B)



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