aboutsummaryrefslogtreecommitdiffstats
path: root/src/main.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/main.c')
-rw-r--r--src/main.c129
1 files changed, 79 insertions, 50 deletions
diff --git a/src/main.c b/src/main.c
index 36df30a..431a9a7 100644
--- a/src/main.c
+++ b/src/main.c
@@ -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;
}