diff options
Diffstat (limited to 'src/main.c')
-rw-r--r-- | src/main.c | 129 |
1 files changed, 79 insertions, 50 deletions
@@ -1,78 +1,62 @@ +/* stdlib */ +#include <errno.h> #include <stdio.h> #include <stdlib.h> #include <string.h> +/* unix */ #include <dlfcn.h> - +#include <signal.h> +/* dynamic */ #include <microhttpd.h> #include <sqlite3.h> - +/* my libs */ #include <log.h> #define COMMON_IMPLEMENTATION #include <common.h> -/* sqlite leastunused implementation */ -struct slidid { sqlite3_int64 il, in, res; }; -void step_leastunused(sqlite3_context* ctx, int argc, sqlite3_value** argv) { - struct slidid *idx = sqlite3_aggregate_context(ctx, sizeof *idx); - if (idx->res) return; - idx->in = sqlite3_value_int64(argv[0]); - if (idx->il + 1 != idx->in) idx->res = idx->il + 1; - idx->il = idx->in; -} -void final_leastunused(sqlite3_context* ctx) { - struct slidid *idx = sqlite3_aggregate_context(ctx, 0); - sqlite3_result_int(ctx, idx->res); -} +#ifndef DEFAULT_ENDPOINTS_PATH +# define DEFAULT_ENDPOINTS_PATH "./endpoints.so" +#endif +#ifndef DEFAULT_DATABASE_PATH +# define DEFAULT_DATABASE_PATH "./jals.db" +#endif -sqlite3 *sqlite_init(const char *db) { - sqlite3 *ret; - sqlite3_open_v2(db, &ret, SQLITE_OPEN_CREATE | SQLITE_OPEN_READWRITE, NULL); - if (ret == NULL) LCRIT(1, "could not open sqlite3 database"); - sqlite3_create_function(ret, "leastunused", 1, SQLITE_UTF8, NULL, NULL, step_leastunused, final_leastunused); - return ret; -} +struct connarg { + void* dylib; + query_func query; + void (*constructor)(const char*); + void (*destructor)(void); +} arg = {NULL, NULL, NULL, NULL}; -enum MHD_Result process_connection(void *dylib, struct MHD_Connection *connection, const char *url, +volatile char reload_library = 0; + +enum MHD_Result process_connection(void *cls, struct MHD_Connection *connection, const char *url, const char *method, const char *version, const char *upload_data, size_t *upload_data_size, void **req_cls) { LDEBUGF("\nurl: %s\nmethod:%s\nversion:%s\nupload_data:%s\nsize:%zu\n", url, method, version, upload_data, *upload_data_size); + struct connarg *arg = cls; /* Load function with the name of the url from shared library */ - endpoint handler = dlsym(dylib, url); - query_func query = dlsym(dylib, "db_get_url"); + endpoint handler = dlsym(arg->dylib, url); struct MHD_Response *res; int status = MHD_HTTP_OK; const char *response; char *newurl; - if (query == NULL) { - response = "<!DOCTYPE html><html><body>Temporary server error: could not open database</body></html>"; - res = MHD_create_response_from_buffer(strlen(response), (void*)response, MHD_RESPMEM_PERSISTENT); - status = MHD_HTTP_INTERNAL_SERVER_ERROR; - goto response; - } if (strcasecmp(method, "GET")) { status = MHD_HTTP_METHOD_NOT_ALLOWED; res = MHD_create_response_from_buffer(18, "Method not allowed", MHD_RESPMEM_PERSISTENT); - goto response; - } - if (handler != NULL) { + } else if (handler != NULL) { /* endpoint access */ LINFOF("Accessed endpoint at url %s", url); res = handler(connection, &status); - } else if ((newurl = query(url)) != NULL) { + } else if ((newurl = arg->query(url + 1)) != NULL) { LINFOF("Redirect from %s to %s", url, newurl); - /* if (newurl == NULL) { */ - /* free(newurl); */ - /* response = "<!DOCTYPE html><html><body>Page does not exist</body></html>"; */ - /* res = MHD_create_response_from_buffer(strlen(response), (void*)response, MHD_RESPMEM_PERSISTENT); */ - /* status = MHD_HTTP_NOT_FOUND; */ - /* goto response; */ - /* } */ response = "<!DOCTYPE html><html><body>Recirecting...</body></html>"; res = MHD_create_response_from_buffer(strlen(response), (void*)response, MHD_RESPMEM_PERSISTENT); MHD_add_response_header(res, "Location", newurl); status = MHD_HTTP_FOUND; + free(newurl); } else if ((res = get_from_file(url + 1)) != NULL) { /* fallback file access */ LINFOF("Accessed file at url %s", url); @@ -83,22 +67,67 @@ enum MHD_Result process_connection(void *dylib, struct MHD_Connection *connectio res = MHD_create_response_from_buffer(strlen(error), (void*)error, MHD_RESPMEM_PERSISTENT); status = MHD_HTTP_NOT_FOUND; } -response: MHD_queue_response(connection, status, res); MHD_destroy_response(res); return MHD_YES; } +/* Because calling dlclose and dlopen from here is undefined */ +void sigusr1_handler(int i) { + reload_library = 1; +} -int main(int argc, char *argv[]){ - void* dylib = dlopen("./endpoints.so", RTLD_NOW); - if (!dylib) LCRITF(1, "Could not open dynamic library: %s\n", dlerror()); - struct MHD_Daemon *daemon = MHD_start_daemon(MHD_USE_POLL | MHD_USE_INTERNAL_POLLING_THREAD, 8080, NULL, NULL, process_connection, dylib, MHD_OPTION_END); - if (daemon == NULL) LCRITV(1, "could not initialize daemon"); +void reload_dylib(const char *so_path, const char *db_path) { + LINFOF("Reloading dymanic library: %s", so_path); + if (arg.destructor) arg.destructor(); + if (arg.dylib != NULL) dlclose(arg.dylib); + arg.dylib = dlopen(so_path, RTLD_LAZY); + if (!arg.dylib) LCRITVF(1, "Could not open dynamic library: %s\n", dlerror()); + arg.query = dlsym(arg.dylib, "db_get_url"); + if (!arg.query) LCRITVF(1, "Could not load `db_get_url` from shared library: %s", dlerror()); + arg.constructor = dlsym(arg.dylib, "sqlite_init"); + if (!arg.constructor) LCRITVF(1, "Could not load `sqlite_init` from shared library: %s", dlerror()); + arg.constructor(db_path); + arg.destructor = dlsym(arg.dylib, "sqlite_deinit"); + if (!arg.destructor) LCRITVF(1, "Could not load `sqlite_deinit` from shared library: %s", dlerror()); +} + +struct MHD_Daemon *init(sigset_t *sigset, const char *dlpath, const char *dbpath) { + sigset_t newmask; + errno = 0; + reload_dylib(dlpath, dbpath); + sigemptyset(&newmask); + sigaddset(&newmask, SIGUSR1); + + struct sigaction handler = {.sa_handler = sigusr1_handler}; + if (sigaction(SIGUSR1, &handler, NULL) < 0) LFAILV("Setting signal handler for SIGUSR1"); + + sigset_t oldmask; + pthread_sigmask(SIG_BLOCK, &newmask, sigset); /* To prevent MHD from recieving the signal */ + struct MHD_Daemon *daemon = MHD_start_daemon(MHD_USE_ERROR_LOG | MHD_USE_POLL | MHD_USE_INTERNAL_POLLING_THREAD, 8080, NULL, NULL, process_connection, &arg, MHD_OPTION_END); + pthread_sigmask(SIG_UNBLOCK, &newmask, NULL); + + if (daemon == NULL) LFAILV("could not initialize daemon"); + + return daemon; +} + +int main(int argc, char *argv[]) { + sigset_t sig; + const char *dlpath = DEFAULT_ENDPOINTS_PATH; + const char *dbpath = DEFAULT_DATABASE_PATH; + struct MHD_Daemon *daemon = init(&sig, dlpath, dbpath); + /* while (reload_library == 0) { */ + /* sigsuspend(&sig); */ + /* if (reload_library == 1) { */ + /* reload_dylib(dlpath, dbpath); */ + /* reload_library = 0; */ + /* } */ + /* } */ getchar(); - - dlclose(dylib); + if (arg.destructor) arg.destructor(); + dlclose(arg.dylib); MHD_stop_daemon(daemon); return 0; } |