diff options
-rw-r--r-- | makefile | 2 | ||||
-rw-r--r-- | network.c | 6 | ||||
-rw-r--r-- | plugin.c | 109 | ||||
-rw-r--r-- | plugin.h | 2 | ||||
-rw-r--r-- | websocket.c | 3 | ||||
-rw-r--r-- | websocksy.c | 9 | ||||
-rw-r--r-- | websocksy.h | 2 |
7 files changed, 117 insertions, 16 deletions
@@ -1,7 +1,7 @@ PLUGINPATH=plugins/ CFLAGS=-g -Wall -Wpedantic -DPLUGINS=\"$(PLUGINPATH)\" -LDLIBS=-lnettle +LDLIBS=-lnettle -ldl OBJECTS=builtins.o network.o websocket.o plugin.o @@ -127,13 +127,13 @@ int network_socket_unix(char* path, int socktype, int listener){ if(listener){ unlink(path); if(bind(fd, (struct sockaddr*) &addr, sizeof(addr))){ - fprintf(stderr, "Failed to bind: %s\n", strerror(errno)); + fprintf(stderr, "Failed to bind %s: %s\n", path, strerror(errno)); close(fd); return -1; } if(listen(fd, SOMAXCONN)){ - fprintf(stderr, "Failed to listen: %s\n", strerror(errno)); + fprintf(stderr, "Failed to listen on %s: %s\n", path, strerror(errno)); close(fd); return -1; } @@ -143,7 +143,7 @@ int network_socket_unix(char* path, int socktype, int listener){ //connect clients if(connect(fd, (struct sockaddr*) &addr, sizeof(addr))){ - fprintf(stderr, "Failed to connect: %s\n", strerror(errno)); + fprintf(stderr, "Failed to connect to %s: %s\n", path, strerror(errno)); close(fd); return -1; } @@ -1,20 +1,112 @@ #include <string.h> #include <stdio.h> +#include <sys/types.h> +#include <dirent.h> +#include <errno.h> +#include <dlfcn.h> #include "websocksy.h" #include "plugin.h" +//cheap out because i dont want the overhead of allocating here +#define MAX_PLUGIN_PATH 4096 + static size_t framing_functions = 0; static ws_framing* framing_function = NULL; static char** framing_function_name = NULL; +static size_t attached_libraries = 0; +static void** attached_library = NULL; + +static void* plugin_attach(char* path){ + void* module = dlopen(path, RTLD_LAZY); + + if(!module){ + fprintf(stderr, "Failed to load module %s\n", dlerror()); + return NULL; + } + + attached_library = realloc(attached_library, (attached_libraries + 1) * sizeof(void*)); + if(!attached_library){ + fprintf(stderr, "Failed to allocate memory\n"); + dlclose(module); + return NULL; + } + + attached_library[attached_libraries] = module; + attached_libraries++; + + return module; +} + int plugin_framing_load(char* path){ - //TODO load plugins + DIR* directory = opendir(path); + struct dirent* file = NULL; + char plugin_path[MAX_PLUGIN_PATH] = ""; + size_t path_len; + + if(strlen(path) >= sizeof(plugin_path) - 20){ + fprintf(stderr, "Plugin path length exceeds limit\n"); + return 1; + } + + strncpy(plugin_path, path, sizeof(plugin_path) - 2); + if(path[strlen(path) - 1] != '/'){ + plugin_path[strlen(path)] = '/'; + plugin_path[strlen(path) + 1] = 0; + } + path_len = strlen(plugin_path); + + if(!directory){ + fprintf(stderr, "Failed to open directory %s: %s\n", path, strerror(errno)); + return 0; + } + + for(file = readdir(directory); file; file = readdir(directory)){ + //skip backends + if(!strncmp(file->d_name, "backend_", 8)){ + continue; + } + //skip file not ending in .so + if(strlen(file->d_name) < 4 || strcmp(file->d_name + strlen(file->d_name) - 3, ".so")){ + continue; + } + strncpy(plugin_path + path_len, file->d_name, sizeof(plugin_path) - path_len - 2); + if(!plugin_attach(plugin_path)){ + return 1; + } + } + + closedir(directory); return 0; } -int plugin_backend_load(char* backend_requested, ws_backend* backend){ - //TODO load backend +int plugin_backend_load(char* path, char* backend_requested, ws_backend* backend){ + char plugin_path[MAX_PLUGIN_PATH] = ""; + void* handle = NULL; + + if(strlen(path) >= sizeof(plugin_path) - 30){ + fprintf(stderr, "Plugin path length exceeds limit\n"); + return 1; + } + + snprintf(plugin_path, sizeof(plugin_path), "%s%sbackend_%s.so", path, (path[strlen(path) - 1] == '/') ? "" : "/", backend_requested); + + handle = plugin_attach(plugin_path); + if(!handle){ + return 1; + } + + //read backend functions into the structure + backend->init = (ws_backend_init) dlsym(handle, "init"); + backend->config = (ws_backend_configure) dlsym(handle, "configure"); + backend->query = (ws_backend_query) dlsym(handle, "query"); + backend->cleanup = (ws_backend_cleanup) dlsym(handle, "cleanup"); + + if(!backend->init || !backend->query){ + fprintf(stderr, "Backend module %s is missing required symbols\n", plugin_path); + return 1; + } return 0; } @@ -63,8 +155,8 @@ ws_framing plugin_framing(char* name){ void plugin_cleanup(){ size_t u; - //TODO dlclose all plugins - + + //free allocated buffers for(u = 0; u < framing_functions; u++){ free(framing_function_name[u]); } @@ -74,4 +166,11 @@ void plugin_cleanup(){ framing_function_name = 0; framing_function = NULL; framing_functions = 0; + + //dlclose all plugins + for(u = 0; u < attached_libraries; u++){ + dlclose(attached_library[u]); + } + free(attached_library); + attached_libraries = 0; } @@ -1,6 +1,6 @@ /* Shared object handling */ int plugin_framing_load(char* path); -int plugin_backend_load(char* backend_requested, ws_backend* backend); +int plugin_backend_load(char* path, char* backend_requested, ws_backend* backend); /* Framing function registry */ int plugin_register_framing(char* name, ws_framing func); diff --git a/websocket.c b/websocket.c index ab33a88..fe4a39a 100644 --- a/websocket.c +++ b/websocket.c @@ -66,8 +66,9 @@ int ws_close(websocket* ws, ws_close_reason code, char* reason){ for(p = 0; p < ws->protocols; p++){ free(ws->protocol[p]); } - ws->protocols = 0; + free(ws->protocol); ws->protocol = NULL; + ws->protocols = 0; ws->read_buffer_offset = 0; ws->peer_buffer_offset = 0; diff --git a/websocksy.c b/websocksy.c index 1bd1abf..f625174 100644 --- a/websocksy.c +++ b/websocksy.c @@ -21,7 +21,8 @@ /* TODO * - TLS - * - framing function discovery / registry + * - plugin loading + * - config file * - WS p2p */ @@ -111,8 +112,8 @@ static peer_transport client_detect_transport(char* host){ memmove(host, host + 9, strlen(host) - 8); return peer_fifo_rx; } - else if(!strncmp(host, "unix://", 8)){ - memmove(host, host + 8, strlen(host) - 7); + else if(!strncmp(host, "unix://", 7)){ + memmove(host, host + 7, strlen(host) - 6); return peer_unix_stream; } else if(!strncmp(host, "unix-dgram://", 13)){ @@ -213,7 +214,7 @@ static int args_parse(int argc, char** argv){ config.backend.cleanup(); } //load the backend plugin - if(plugin_backend_load(argv[u + 1], &(config.backend))){ + if(plugin_backend_load(PLUGINS, argv[u + 1], &(config.backend))){ return 1; } if(config.backend.init() != WEBSOCKSY_API_VERSION){ diff --git a/websocksy.h b/websocksy.h index 8b85719..39ce9c7 100644 --- a/websocksy.h +++ b/websocksy.h @@ -153,7 +153,7 @@ typedef struct /*_web_socket*/ { * sheer guesses). * * Backends are supplied as shared objects exporting the following symbols: - * * `init`: Optional, initialize any storage or connections required + * * `init`: Required, initialize any storage or connections required * * `configure`: Optional, configure the backend * * `query`: Required, find a peer for the given parameters * * `cleanup`: Optional, Release any acquired resources prior to shutdown |