diff options
| -rw-r--r-- | Makefile | 10 | ||||
| -rw-r--r-- | main.c | 26 | ||||
| -rw-r--r-- | plugin.c | 79 | ||||
| -rw-r--r-- | plugin.h | 7 | ||||
| -rw-r--r-- | plugin_client_header.h | 26 | ||||
| -rw-r--r-- | plugins/Makefile | 34 | ||||
| -rw-r--r-- | plugins/log/main.c | 11 | 
7 files changed, 172 insertions, 21 deletions
| @@ -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 @@ -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<argc;i++){ +		plugin_register(argv[i]);  	} -} - -int main(void){ -	srandomdev(); +	if(argc<=1)printf("Loaded no plugins\n");  	db_init();  	int sock=create_server_socket();  	printf("Listening on port %d\n",PORT); -	// event_register(dummy_event_handler);  	runloop_set_timeout(60*1000000,timeout_callback);  	runloop_add_fd(sock,server_socket_callback,false);  	runloop_run();  	printf("Runloop empty, shutting down\n"); -	// event_unregister(dummy_event_handler);  	db_close();  } diff --git a/plugin.c b/plugin.c new file mode 100644 index 0000000..14dce01 --- /dev/null +++ b/plugin.c @@ -0,0 +1,79 @@ +#include <stdio.h> +#include <string.h> +#include <dlfcn.h> +#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;i<num_plugins;i++){ +		plugins_list[i].callback(&pe); +	} +} + + +void plugin_init(void){ +	if(plugins_list!=NULL)return; +	plugins_list=malloc(plugins_cap,struct plugin_data); +	memset(plugins_list,0,num_plugins*sizeof(struct plugin_data)); + +	event_register(consume_event); +} + +void plugin_register(const char *fname){ +	if(num_plugins==plugins_cap){ +		plugins_cap*=2; +		plugins_list=realloc(plugins_list,plugins_cap,struct plugin_data); +	} + +	struct plugin_data *data=plugins_list+num_plugins; +	num_plugins++; +	data->handle=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 <stdint.h> + + +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 <stdio.h> +#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; +} | 
