aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--makefile2
-rw-r--r--network.c6
-rw-r--r--plugin.c109
-rw-r--r--plugin.h2
-rw-r--r--websocket.c3
-rw-r--r--websocksy.c9
-rw-r--r--websocksy.h2
7 files changed, 117 insertions, 16 deletions
diff --git a/makefile b/makefile
index eb7a579..9ed6711 100644
--- a/makefile
+++ b/makefile
@@ -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
diff --git a/network.c b/network.c
index 34baf8a..b866b9f 100644
--- a/network.c
+++ b/network.c
@@ -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;
}
diff --git a/plugin.c b/plugin.c
index 87c9bde..30c5775 100644
--- a/plugin.c
+++ b/plugin.c
@@ -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;
}
diff --git a/plugin.h b/plugin.h
index f7dcd11..91689ee 100644
--- a/plugin.h
+++ b/plugin.h
@@ -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