Skip to content

Commit 92a291b

Browse files
committed
Implement plugin loading
1 parent e16f061 commit 92a291b

File tree

7 files changed

+117
-16
lines changed

7 files changed

+117
-16
lines changed

makefile

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
PLUGINPATH=plugins/
22

33
CFLAGS=-g -Wall -Wpedantic -DPLUGINS=\"$(PLUGINPATH)\"
4-
LDLIBS=-lnettle
4+
LDLIBS=-lnettle -ldl
55

66
OBJECTS=builtins.o network.o websocket.o plugin.o
77

network.c

+3-3
Original file line numberDiff line numberDiff line change
@@ -127,13 +127,13 @@ int network_socket_unix(char* path, int socktype, int listener){
127127
if(listener){
128128
unlink(path);
129129
if(bind(fd, (struct sockaddr*) &addr, sizeof(addr))){
130-
fprintf(stderr, "Failed to bind: %s\n", strerror(errno));
130+
fprintf(stderr, "Failed to bind %s: %s\n", path, strerror(errno));
131131
close(fd);
132132
return -1;
133133
}
134134

135135
if(listen(fd, SOMAXCONN)){
136-
fprintf(stderr, "Failed to listen: %s\n", strerror(errno));
136+
fprintf(stderr, "Failed to listen on %s: %s\n", path, strerror(errno));
137137
close(fd);
138138
return -1;
139139
}
@@ -143,7 +143,7 @@ int network_socket_unix(char* path, int socktype, int listener){
143143

144144
//connect clients
145145
if(connect(fd, (struct sockaddr*) &addr, sizeof(addr))){
146-
fprintf(stderr, "Failed to connect: %s\n", strerror(errno));
146+
fprintf(stderr, "Failed to connect to %s: %s\n", path, strerror(errno));
147147
close(fd);
148148
return -1;
149149
}

plugin.c

+104-5
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,112 @@
11
#include <string.h>
22
#include <stdio.h>
3+
#include <sys/types.h>
4+
#include <dirent.h>
5+
#include <errno.h>
6+
#include <dlfcn.h>
37

48
#include "websocksy.h"
59
#include "plugin.h"
610

11+
//cheap out because i dont want the overhead of allocating here
12+
#define MAX_PLUGIN_PATH 4096
13+
714
static size_t framing_functions = 0;
815
static ws_framing* framing_function = NULL;
916
static char** framing_function_name = NULL;
1017

18+
static size_t attached_libraries = 0;
19+
static void** attached_library = NULL;
20+
21+
static void* plugin_attach(char* path){
22+
void* module = dlopen(path, RTLD_LAZY);
23+
24+
if(!module){
25+
fprintf(stderr, "Failed to load module %s\n", dlerror());
26+
return NULL;
27+
}
28+
29+
attached_library = realloc(attached_library, (attached_libraries + 1) * sizeof(void*));
30+
if(!attached_library){
31+
fprintf(stderr, "Failed to allocate memory\n");
32+
dlclose(module);
33+
return NULL;
34+
}
35+
36+
attached_library[attached_libraries] = module;
37+
attached_libraries++;
38+
39+
return module;
40+
}
41+
1142
int plugin_framing_load(char* path){
12-
//TODO load plugins
43+
DIR* directory = opendir(path);
44+
struct dirent* file = NULL;
45+
char plugin_path[MAX_PLUGIN_PATH] = "";
46+
size_t path_len;
47+
48+
if(strlen(path) >= sizeof(plugin_path) - 20){
49+
fprintf(stderr, "Plugin path length exceeds limit\n");
50+
return 1;
51+
}
52+
53+
strncpy(plugin_path, path, sizeof(plugin_path) - 2);
54+
if(path[strlen(path) - 1] != '/'){
55+
plugin_path[strlen(path)] = '/';
56+
plugin_path[strlen(path) + 1] = 0;
57+
}
58+
path_len = strlen(plugin_path);
59+
60+
if(!directory){
61+
fprintf(stderr, "Failed to open directory %s: %s\n", path, strerror(errno));
62+
return 0;
63+
}
64+
65+
for(file = readdir(directory); file; file = readdir(directory)){
66+
//skip backends
67+
if(!strncmp(file->d_name, "backend_", 8)){
68+
continue;
69+
}
70+
//skip file not ending in .so
71+
if(strlen(file->d_name) < 4 || strcmp(file->d_name + strlen(file->d_name) - 3, ".so")){
72+
continue;
73+
}
74+
strncpy(plugin_path + path_len, file->d_name, sizeof(plugin_path) - path_len - 2);
75+
if(!plugin_attach(plugin_path)){
76+
return 1;
77+
}
78+
}
79+
80+
closedir(directory);
1381
return 0;
1482
}
1583

16-
int plugin_backend_load(char* backend_requested, ws_backend* backend){
17-
//TODO load backend
84+
int plugin_backend_load(char* path, char* backend_requested, ws_backend* backend){
85+
char plugin_path[MAX_PLUGIN_PATH] = "";
86+
void* handle = NULL;
87+
88+
if(strlen(path) >= sizeof(plugin_path) - 30){
89+
fprintf(stderr, "Plugin path length exceeds limit\n");
90+
return 1;
91+
}
92+
93+
snprintf(plugin_path, sizeof(plugin_path), "%s%sbackend_%s.so", path, (path[strlen(path) - 1] == '/') ? "" : "/", backend_requested);
94+
95+
handle = plugin_attach(plugin_path);
96+
if(!handle){
97+
return 1;
98+
}
99+
100+
//read backend functions into the structure
101+
backend->init = (ws_backend_init) dlsym(handle, "init");
102+
backend->config = (ws_backend_configure) dlsym(handle, "configure");
103+
backend->query = (ws_backend_query) dlsym(handle, "query");
104+
backend->cleanup = (ws_backend_cleanup) dlsym(handle, "cleanup");
105+
106+
if(!backend->init || !backend->query){
107+
fprintf(stderr, "Backend module %s is missing required symbols\n", plugin_path);
108+
return 1;
109+
}
18110
return 0;
19111
}
20112

@@ -63,8 +155,8 @@ ws_framing plugin_framing(char* name){
63155

64156
void plugin_cleanup(){
65157
size_t u;
66-
//TODO dlclose all plugins
67-
158+
159+
//free allocated buffers
68160
for(u = 0; u < framing_functions; u++){
69161
free(framing_function_name[u]);
70162
}
@@ -74,4 +166,11 @@ void plugin_cleanup(){
74166
framing_function_name = 0;
75167
framing_function = NULL;
76168
framing_functions = 0;
169+
170+
//dlclose all plugins
171+
for(u = 0; u < attached_libraries; u++){
172+
dlclose(attached_library[u]);
173+
}
174+
free(attached_library);
175+
attached_libraries = 0;
77176
}

plugin.h

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
/* Shared object handling */
22
int plugin_framing_load(char* path);
3-
int plugin_backend_load(char* backend_requested, ws_backend* backend);
3+
int plugin_backend_load(char* path, char* backend_requested, ws_backend* backend);
44

55
/* Framing function registry */
66
int plugin_register_framing(char* name, ws_framing func);

websocket.c

+2-1
Original file line numberDiff line numberDiff line change
@@ -66,8 +66,9 @@ int ws_close(websocket* ws, ws_close_reason code, char* reason){
6666
for(p = 0; p < ws->protocols; p++){
6767
free(ws->protocol[p]);
6868
}
69-
ws->protocols = 0;
69+
free(ws->protocol);
7070
ws->protocol = NULL;
71+
ws->protocols = 0;
7172

7273
ws->read_buffer_offset = 0;
7374
ws->peer_buffer_offset = 0;

websocksy.c

+5-4
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,8 @@
2121

2222
/* TODO
2323
* - TLS
24-
* - framing function discovery / registry
24+
* - plugin loading
25+
* - config file
2526
* - WS p2p
2627
*/
2728

@@ -111,8 +112,8 @@ static peer_transport client_detect_transport(char* host){
111112
memmove(host, host + 9, strlen(host) - 8);
112113
return peer_fifo_rx;
113114
}
114-
else if(!strncmp(host, "unix://", 8)){
115-
memmove(host, host + 8, strlen(host) - 7);
115+
else if(!strncmp(host, "unix://", 7)){
116+
memmove(host, host + 7, strlen(host) - 6);
116117
return peer_unix_stream;
117118
}
118119
else if(!strncmp(host, "unix-dgram://", 13)){
@@ -213,7 +214,7 @@ static int args_parse(int argc, char** argv){
213214
config.backend.cleanup();
214215
}
215216
//load the backend plugin
216-
if(plugin_backend_load(argv[u + 1], &(config.backend))){
217+
if(plugin_backend_load(PLUGINS, argv[u + 1], &(config.backend))){
217218
return 1;
218219
}
219220
if(config.backend.init() != WEBSOCKSY_API_VERSION){

websocksy.h

+1-1
Original file line numberDiff line numberDiff line change
@@ -153,7 +153,7 @@ typedef struct /*_web_socket*/ {
153153
* sheer guesses).
154154
*
155155
* Backends are supplied as shared objects exporting the following symbols:
156-
* * `init`: Optional, initialize any storage or connections required
156+
* * `init`: Required, initialize any storage or connections required
157157
* * `configure`: Optional, configure the backend
158158
* * `query`: Required, find a peer for the given parameters
159159
* * `cleanup`: Optional, Release any acquired resources prior to shutdown

0 commit comments

Comments
 (0)