aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--.gitignore1
-rw-r--r--artnet.c2
-rw-r--r--artnet.h2
-rw-r--r--makefile22
-rw-r--r--midi.c2
-rw-r--r--midi.h2
-rw-r--r--midimonster.c13
-rw-r--r--plugin.c110
-rw-r--r--plugin.h3
9 files changed, 139 insertions, 18 deletions
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 <stdio.h>
+#include <string.h>
+#include <dlfcn.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <dirent.h>
+#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();