From 24de2cd600a4e108c24f6f77a5a4d30111fd9918 Mon Sep 17 00:00:00 2001 From: tomsmeding Date: Tue, 9 May 2017 22:39:16 +0200 Subject: server: Add plugin framework --- Makefile | 10 +++++-- main.c | 26 +++++------------ plugin.c | 79 ++++++++++++++++++++++++++++++++++++++++++++++++++ plugin.h | 7 +++++ plugin_client_header.h | 26 +++++++++++++++++ plugins/Makefile | 34 ++++++++++++++++++++++ plugins/log/main.c | 11 +++++++ 7 files changed, 172 insertions(+), 21 deletions(-) create mode 100644 plugin.c create mode 100644 plugin.h create mode 100644 plugin_client_header.h create mode 100644 plugins/Makefile create mode 100644 plugins/log/main.c diff --git a/Makefile b/Makefile index 8922662..307fbfa 100644 --- a/Makefile +++ b/Makefile @@ -1,9 +1,13 @@ CC = gcc -CFLAGS = -Wall -Wextra -std=c11 -g -fwrapv -LDFLAGS = -lsqlite3 +CFLAGS = -Wall -Wextra -std=c11 -g -fwrapv -D_BSD_SOURCE +LDFLAGS = -lsqlite3 -ldl TARGETS = tomsg_server +PLUGINDIR = plugins + +PLUGINS = $(patsubst $(PLUGINDIR)/%,%,$(shell find $(PLUGINDIR)/ -maxdepth 1 -type d)) + .PHONY: all clean remake # Clear all implicit suffix rules @@ -13,9 +17,11 @@ TARGETS = tomsg_server .SECONDARY: all: $(TARGETS) + for pl in $(PLUGINS); do make --no-print-directory -C $(PLUGINDIR) $@ PLUGINNAME=$$pl; done clean: rm -f $(TARGETS) *.o *.sql.h + for pl in $(PLUGINS); do make --no-print-directory -C $(PLUGINDIR) $@ PLUGINNAME=$$pl; done remake: clean $(MAKE) all diff --git a/main.c b/main.c index a754f02..5028190 100644 --- a/main.c +++ b/main.c @@ -13,6 +13,7 @@ #include "db.h" #include "event.h" #include "net.h" +#include "plugin.h" #include "runloop.h" #include "user_data.h" @@ -146,34 +147,21 @@ void srandomdev(void){ } #endif -__attribute__((unused)) -static void dummy_event_handler(const struct event_item *event){ - switch(event->type){ - case EVENT_MESSAGE: - debug("event: <%s>@%s: %s",event->user,event->room,event->message); - break; - - case EVENT_ONLINE: - debug("event: <%s> online=%" PRIi64,event->user,event->num); - break; +int main(int argc,char **argv){ + srandomdev(); - case EVENT_JOIN: - debug("event: <%s> joins %s",event->user,event->room); - break; + plugin_init(); + for(int i=1;i +#include +#include +#include "event.h" +#include "global.h" +#include "plugin.h" +#include "plugin_client_header.h" + + +struct plugin_data{ + void *handle; + plugin_event_func_t *callback; +}; + +static i64 num_plugins=0; +static i64 plugins_cap=8; +static struct plugin_data *plugins_list=NULL; + + +static void consume_event(const struct event_item *event){ + struct plugin_event pe; + switch(event->type){ + case EVENT_MESSAGE: pe.type=PLUGIN_EVENT_MESSAGE; break; + case EVENT_ONLINE: pe.type=PLUGIN_EVENT_ONLINE; break; + case EVENT_JOIN: pe.type=PLUGIN_EVENT_JOIN; break; + default: + die("Unknown event type %d in plugin.c:consume_event",event->type); + } + pe.timestamp=event->timestamp; + pe.message=event->message; + pe.user=event->user; + pe.room=event->room; + pe.num=event->num; + + for(i64 i=0;ihandle=dlopen(fname,RTLD_NOW|RTLD_LOCAL); + if(data->handle==NULL){ + die("Error loading plugin '%s': %s",fname,dlerror()); + } + + plugin_event_func_t* (*init_func)(void)=NULL; + dlerror(); + *(void**)&init_func=dlsym(data->handle,"plugin_init_func"); + char *err=dlerror(); + if(err!=NULL){ + die("Error reading symbol 'plugin_init_func' from plugin '%s'",fname); + } + if(init_func==NULL){ + die("Plugin '%s' exports NULL init function",fname); + } + + data->callback=init_func(); + if(data->callback==NULL){ + die("Init function of plugin '%s' returned NULL",fname); + } + + printf("Loaded plugin '%s'\n",fname); +} diff --git a/plugin.h b/plugin.h new file mode 100644 index 0000000..de235c9 --- /dev/null +++ b/plugin.h @@ -0,0 +1,7 @@ +#pragma once + + +void plugin_init(void); + +// Pass path to a shared object file / dynamic library +void plugin_register(const char *fname); diff --git a/plugin_client_header.h b/plugin_client_header.h new file mode 100644 index 0000000..4428b3c --- /dev/null +++ b/plugin_client_header.h @@ -0,0 +1,26 @@ +#pragma once + +#include + + +enum plugin_event_type{ + PLUGIN_EVENT_MESSAGE, // message, user, room + PLUGIN_EVENT_ONLINE, // user, num + PLUGIN_EVENT_JOIN, // user, room +}; + +struct plugin_event{ + enum plugin_event_type type; + int64_t timestamp; // always set + char *message,*user,*room; + int64_t num; +}; + + +typedef void plugin_event_func_t(const struct plugin_event *event); + + +// All plugins should export a function of type plugin_init_func_t with +// name "plugin_init_func" that returns a pointer to a function that +// receives all events. +plugin_event_func_t* plugin_init_func(void); diff --git a/plugins/Makefile b/plugins/Makefile new file mode 100644 index 0000000..0824f2e --- /dev/null +++ b/plugins/Makefile @@ -0,0 +1,34 @@ +CC = gcc +CFLAGS = -Wall -Wextra -std=c11 -g -fwrapv -I.. -fPIC + +ifeq ($(shell uname),Darwin) + SO_EXT = dylib + SO_FLAGS = -dynamiclib +else + SO_EXT = so + SO_FLAGS = -shared +endif +SO_FLAGS += -fPIC + +TARGET = $(PLUGINNAME)/$(PLUGINNAME).$(SO_EXT) + + +.PHONY: all clean remake warning + +all: warning $(TARGET) + +clean: warning + rm -rf $(TARGET) $(PLUGINNAME)/*.{o,dSYM} + +remake: clean all + +warning: +ifndef PLUGINNAME + $(error "PLUGINNAME not set! Please run root Makefile instead.") +endif + + +.SECONDARY: + +$(PLUGINNAME)/%.$(SO_EXT): $(patsubst %.c,%.o,$(wildcard $(PLUGINNAME)/*.c)) $(wildcard ../*.h) + $(CC) $(SO_FLAGS) -o $@ $(filter %.o,$^) diff --git a/plugins/log/main.c b/plugins/log/main.c new file mode 100644 index 0000000..b931d12 --- /dev/null +++ b/plugins/log/main.c @@ -0,0 +1,11 @@ +#include +#include "plugin_client_header.h" + + +static void eventfunc(const struct plugin_event *event){ + printf("type = %d\n",event->type); +} + +plugin_event_func_t* plugin_init_func(void){ + return eventfunc; +} -- cgit v1.2.3-70-g09d2