/* * Copyright (c) 2013 Joris Vink * * 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 #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "spdy.h" #include "kore.h" static void *mod_handle = NULL; static char *mod_name = NULL; static time_t mod_last_mtime = 0; struct module_domain { char *domain; TAILQ_HEAD(, kore_module_handle) handlers; TAILQ_ENTRY(module_domain) list; }; static TAILQ_HEAD(, module_domain) domains; static struct module_domain *kore_module_domain_lookup(char *); void kore_module_load(char *module_name) { struct stat st; kore_log("kore_module_load(%s)", module_name); if (mod_handle != NULL) fatal("site module already loaded, skipping %s", module_name); if (stat(module_name, &st) == -1) fatal("stat(%s): %s", module_name, errno_s); mod_last_mtime = st.st_mtime; mod_handle = dlopen(module_name, RTLD_NOW); if (mod_handle == NULL) fatal("%s", dlerror()); TAILQ_INIT(&domains); mod_name = kore_strdup(module_name); } void kore_module_reload(void) { struct module_domain *dom; struct kore_module_handle *hdlr; if (dlclose(mod_handle)) fatal("cannot close existing module: %s", dlerror()); mod_handle = dlopen(mod_name, RTLD_NOW); if (mod_handle == NULL) fatal("kore_module_reload(): %s", dlerror()); TAILQ_FOREACH(dom, &domains, list) { TAILQ_FOREACH(hdlr, &(dom->handlers), list) { hdlr->addr = dlsym(mod_handle, hdlr->func); if (hdlr->func == NULL) fatal("no function '%s' found", hdlr->func); } } kore_log("reloaded '%s' module", mod_name); } int kore_module_loaded(void) { return (mod_handle != NULL ? KORE_RESULT_OK : KORE_RESULT_ERROR); } int kore_module_domain_new(char *domain) { struct module_domain *dom; if (kore_module_domain_lookup(domain) != NULL) return (KORE_RESULT_ERROR); dom = (struct module_domain *)kore_malloc(sizeof(*dom)); dom->domain = kore_strdup(domain); TAILQ_INIT(&(dom->handlers)); TAILQ_INSERT_TAIL(&domains, dom, list); return (KORE_RESULT_OK); } int kore_module_handler_new(char *path, char *domain, char *func, int type) { void *addr; struct module_domain *dom; struct kore_module_handle *hdlr; kore_log("kore_module_handler_new(%s, %s, %s, %d)", path, domain, func, type); addr = dlsym(mod_handle, func); if (addr == NULL) { kore_log("function '%s' not found", func); return (KORE_RESULT_ERROR); } if ((dom = kore_module_domain_lookup(domain)) == NULL) return (KORE_RESULT_ERROR); hdlr = (struct kore_module_handle *)kore_malloc(sizeof(*hdlr)); hdlr->addr = addr; hdlr->type = type; hdlr->path = kore_strdup(path); hdlr->func = kore_strdup(func); if (hdlr->type == HANDLER_TYPE_DYNAMIC) { if (regcomp(&(hdlr->rctx), hdlr->path, REG_NOSUB)) { free(hdlr->func); free(hdlr->path); free(hdlr); kore_log("regcomp() on %s failed", path); return (KORE_RESULT_ERROR); } } TAILQ_INSERT_TAIL(&(dom->handlers), hdlr, list); return (KORE_RESULT_OK); } void * kore_module_handler_find(char *domain, char *path) { struct module_domain *dom; struct kore_module_handle *hdlr; if ((dom = kore_module_domain_lookup(domain)) == NULL) return (NULL); TAILQ_FOREACH(hdlr, &(dom->handlers), list) { if (hdlr->type == HANDLER_TYPE_STATIC) { if (!strcmp(hdlr->path, path)) return (hdlr->addr); } else { if (!regexec(&(hdlr->rctx), path, 0, NULL, 0)) return (hdlr->addr); } } return (NULL); } static struct module_domain * kore_module_domain_lookup(char *domain) { struct module_domain *dom; TAILQ_FOREACH(dom, &domains, list) { if (!strcmp(dom->domain, domain)) return (dom); } return (NULL); }