/* stdlib */ #include #include #include #include /* unix */ #include #include /* dynamic */ #include #include /* my libs */ #include #define COMMON_IMPLEMENTATION #include #ifndef DEFAULT_ENDPOINTS_PATH # define DEFAULT_ENDPOINTS_PATH "./endpoints.so" #endif #ifndef DEFAULT_DATABASE_PATH # define DEFAULT_DATABASE_PATH "./jals.db" #endif struct connarg { void* dylib; query_func query; void (*constructor)(const char*); void (*destructor)(void); } arg = {NULL, NULL, NULL, NULL}; 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(arg->dylib, url); struct MHD_Response *res; int status = MHD_HTTP_OK; const char *response; char *newurl; if (strcasecmp(method, "GET")) { status = MHD_HTTP_METHOD_NOT_ALLOWED; res = MHD_create_response_from_buffer(18, "Method not allowed", MHD_RESPMEM_PERSISTENT); } else if (handler != NULL) { /* endpoint access */ LINFOF("Accessed endpoint at url %s", url); res = handler(connection, &status); } else if ((newurl = arg->query(url + 1)) != NULL) { LINFOF("Redirect from %s to %s", url, newurl); response = "Recirecting..."; 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); } else { /* error */ LINFOF("Failed access to endpoint\t%s", url); const char* error = "\"resource does not exist\""; res = MHD_create_response_from_buffer(strlen(error), (void*)error, MHD_RESPMEM_PERSISTENT); status = MHD_HTTP_NOT_FOUND; } 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; } 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(); if (arg.destructor) arg.destructor(); dlclose(arg.dylib); MHD_stop_daemon(daemon); return 0; }