From aed37425605d73ac22ec1f8c3145486d0ec79bb3 Mon Sep 17 00:00:00 2001 From: cbdev Date: Thu, 8 Jun 2017 02:33:18 +0200 Subject: Move to dynamically loading backends --- .gitignore | 1 + artnet.c | 2 +- artnet.h | 2 +- makefile | 22 ++++++++---- midi.c | 2 +- midi.h | 2 +- midimonster.c | 13 +++---- plugin.c | 110 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ plugin.h | 3 ++ 9 files changed, 139 insertions(+), 18 deletions(-) create mode 100644 plugin.c create mode 100644 plugin.h diff --git a/.gitignore b/.gitignore index 36d8a83..3afd872 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ midimonster *.swp *.o +*.so diff --git a/artnet.c b/artnet.c index 599a6c4..3c76f21 100644 --- a/artnet.c +++ b/artnet.c @@ -88,7 +88,7 @@ static int artnet_parse_addr(char* host, char* port, struct sockaddr_storage* ad return 0; } -int artnet_init(){ +int init(){ backend artnet = { .name = BACKEND_NAME, .conf = artnet_configure, diff --git a/artnet.h b/artnet.h index dc90e19..0d61627 100644 --- a/artnet.h +++ b/artnet.h @@ -7,7 +7,7 @@ * destination per instance */ -int artnet_init(); +int init(); static int artnet_configure(char* option, char* value); static int artnet_configure_instance(instance* instance, char* option, char* value); static instance* artnet_instance(); diff --git a/makefile b/makefile index ec5238e..6819f7f 100644 --- a/makefile +++ b/makefile @@ -1,16 +1,26 @@ -LDLIBS = -lasound -CFLAGS = -g -Wall +.PHONY: clean +BACKENDS = artnet.so midi.so osc.so +OBJS = config.o backend.o plugin.o +PLUGINDIR = "\"./\"" -BACKENDS = artnet.o midi.o osc.o -OBJS = config.o backend.o $(BACKENDS) +LDLIBS = -lasound -ldl +CFLAGS ?= -g -Wall -midimonster: midimonster.h $(OBJS) +midimonster: CFLAGS += -rdynamic -DPLUGINS=$(PLUGINDIR) +%.so: CFLAGS += -fPIC +%.so: LDFLAGS += -shared + +%.so :: %.c %.h + $(CC) $(CFLAGS) $< -o $@ $(LDFLAGS) -all: midimonster +all: midimonster $(BACKENDS) + +midimonster: midimonster.h $(OBJS) clean: $(RM) midimonster $(RM) $(OBJS) + $(RM) $(BACKENDS) run: valgrind --leak-check=full --show-leak-kinds=all ./midimonster diff --git a/midi.c b/midi.c index 9235c89..f5666ba 100644 --- a/midi.c +++ b/midi.c @@ -28,7 +28,7 @@ enum /*_midi_channel_type*/ { sysmsg }; -int midi_init(){ +int init(){ backend midi = { .name = BACKEND_NAME, .conf = midi_configure, diff --git a/midi.h b/midi.h index 185176b..556706f 100644 --- a/midi.h +++ b/midi.h @@ -1,6 +1,6 @@ #include "midimonster.h" -int midi_init(); +int init(); static int midi_configure(char* option, char* value); static int midi_configure_instance(instance* instance, char* option, char* value); static instance* midi_instance(); diff --git a/midimonster.c b/midimonster.c index b1c14e2..03b2699 100644 --- a/midimonster.c +++ b/midimonster.c @@ -6,11 +6,7 @@ #include "midimonster.h" #include "config.h" #include "backend.h" - -//temporary prototypes -int artnet_init(); -int midi_init(); -int osc_init(); +#include "plugin.h" static size_t mappings = 0; static channel_mapping* map = NULL; @@ -196,7 +192,7 @@ int main(int argc, char** argv){ fd_set all_fds, read_fds; struct timeval tv; size_t u, n; - managed_fd* signaled_fds; + managed_fd* signaled_fds = NULL; int rv = EXIT_FAILURE, error, maxfd = -1; char* cfg_file = DEFAULT_CFG; if(argc > 1){ @@ -204,8 +200,7 @@ int main(int argc, char** argv){ } //initialize backends - //TODO replace this with loading shared objects - if(artnet_init() || midi_init() /* || osc_init()*/){ + if(plugins_load(PLUGINS)){ fprintf(stderr, "Failed to initialize a backend\n"); goto bail; } @@ -218,6 +213,7 @@ int main(int argc, char** argv){ instances_free(); map_free(); fds_free(); + plugins_close(); return usage(argv[0]); } @@ -291,6 +287,7 @@ bail: map_free(); fds_free(); event_free(); + plugins_close(); return rv; } diff --git a/plugin.c b/plugin.c new file mode 100644 index 0000000..561e131 --- /dev/null +++ b/plugin.c @@ -0,0 +1,110 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include "plugin.h" + +size_t plugins = 0; +void** plugin_handle = NULL; + +static int plugin_attach(char* path, char* file){ + plugin_init init = NULL; + void* handle = NULL; + + char* lib = calloc(strlen(path) + strlen(file) + 1, sizeof(char)); + if(!lib){ + fprintf(stderr, "Failed to allocate memory\n"); + return 1; + } + + snprintf(lib, strlen(path) + strlen(file) + 1, "%s%s", path, file); + + handle = dlopen(lib, RTLD_NOW); + if(!handle){ + fprintf(stderr, "Failed to load plugin %s: %s\n", lib, dlerror()); + free(lib); + return 0; + } + + init = dlsym(handle, "init"); + if(init){ + if(init()){ + fprintf(stderr, "Plugin %s failed to initialize\n", lib); + dlclose(handle); + free(lib); + return 1; + } + } + else{ + return 0; + } + + plugin_handle = realloc(plugin_handle, (plugins + 1) * sizeof(void*)); + if(!plugin_handle){ + fprintf(stderr, "Failed to allocate memory\n"); + dlclose(handle); + free(lib); + return 1; + } + + plugin_handle[plugins] = handle; + plugins++; + + return 0; +} + +int plugins_load(char* path){ + int rv = -1; + + struct dirent* entry; + struct stat file_stat; + DIR* directory = opendir(path); + if(!directory){ + fprintf(stderr, "Failed to open plugin search path %s: %s\n", path, strerror(errno)); + return 1; + } + + for(entry = readdir(directory); entry; entry = readdir(directory)){ + if(fstatat(dirfd(directory), entry->d_name, &file_stat, 0) < 0){ + fprintf(stderr, "Failed to stat %s: %s\n", entry->d_name, strerror(errno)); + continue; + } + + if(!S_ISREG(file_stat.st_mode)){ + continue; + } + + if(!(file_stat.st_mode & S_IXUSR)){ + continue; + } + + if(plugin_attach(path, entry->d_name)){ + goto load_done; + } + } + rv = 0; + +load_done: + if(closedir(directory) < 0){ + fprintf(stderr, "Failed to close plugin directory %s: %s\n", path, strerror(errno)); + return -1; + } + return rv; +} + +int plugins_close(){ + size_t u; + for(u = 0; u < plugins; u++){ + if(dlclose(plugin_handle[u])){ + fprintf(stderr, "Failed to unload plugin: %s\n", dlerror()); + } + } + + free(plugin_handle); + plugins = 0; + return 0; +} diff --git a/plugin.h b/plugin.h new file mode 100644 index 0000000..64c557f --- /dev/null +++ b/plugin.h @@ -0,0 +1,3 @@ +typedef int (*plugin_init)(); +int plugins_load(char* dir); +int plugins_close(); -- cgit v1.2.3