summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authortomsmeding <tom.smeding@gmail.com>2016-12-25 22:55:21 +0100
committertomsmeding <tom.smeding@gmail.com>2016-12-25 22:56:13 +0100
commited2b3a38ec05c566c645dc2aabfd513edff8d63b (patch)
tree388cf0c5d6a425f5d7f86783e0c67e930f94c6a4
parent70431dcb67e33bd466d03fb41e5a90ba301127a4 (diff)
Plugins
-rw-r--r--.gitignore1
-rw-r--r--Makefile8
-rw-r--r--main.c76
-rw-r--r--plugin.h18
-rw-r--r--plugins/Makefile39
-rw-r--r--plugins/echoback/echoback.c25
-rw-r--r--util.c4
-rw-r--r--util.h4
8 files changed, 160 insertions, 15 deletions
diff --git a/.gitignore b/.gitignore
index 7304726..ffa1d4b 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,3 +1,4 @@
cserver
*.o
*.dSYM
+*.dylib
diff --git a/Makefile b/Makefile
index 1583287..078b0a0 100644
--- a/Makefile
+++ b/Makefile
@@ -7,12 +7,18 @@ else
endif
BIN = cserver
+PLUGINDIR = plugins
+
+PLUGINS = $(patsubst $(PLUGINDIR)/%,%,$(shell find $(PLUGINDIR)/ -maxdepth 1 -type d))
+
.PHONY: all clean remake
all: $(BIN)
+ for pl in $(PLUGINS); do make -C $(PLUGINDIR) $@ PLUGINNAME=$$pl; done
clean:
rm -rf $(BIN) *.o *.dSYM
+ for pl in $(PLUGINS); do make -C $(PLUGINDIR) $@ PLUGINNAME=$$pl; done
remake: clean all
@@ -20,5 +26,5 @@ remake: clean all
$(BIN): $(patsubst %.c,%.o,$(wildcard *.c))
$(CC) -o $@ $^
-%.o: %.cpp $(wildcard *.h)
+%.o: %.c $(wildcard $(dir %.o)*.h)
$(CC) $(CFLAGS) -c -o $@ $<
diff --git a/main.c b/main.c
index 60b9584..52d10bd 100644
--- a/main.c
+++ b/main.c
@@ -7,9 +7,11 @@
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
+#include <dlfcn.h>
#include <errno.h>
#include "http.h"
#include "memory.h"
+#include "plugin.h"
#include "util.h"
@@ -37,27 +39,81 @@ static void signal_handler(int sig){
}
+typedef struct Plugin{
+ char *name;
+ Handler handler;
+ struct Plugin *next;
+} Plugin;
+
+Plugin *pluginlist=NULL,*pluginlist_last=NULL;
+
+static void plugin_register_callback(const char *name,Handler handler){
+ if(pluginlist==NULL){
+ pluginlist=pluginlist_last=malloc(1,Plugin);
+ pluginlist->name=copy_str(name);
+ pluginlist->handler=handler;
+ pluginlist->next=NULL;
+ } else {
+ Plugin *newplugin=malloc(1,Plugin);
+ newplugin->name=copy_str(name);
+ newplugin->handler=handler;
+ newplugin->next=NULL;
+ pluginlist_last->next=newplugin;
+ pluginlist_last=newplugin;
+ }
+ printf("Registered plugin '%s' (handler %p)\n",name,handler);
+}
+
+typedef void (*register_function)(register_callback_t callback);
+
+static void load_plugin(const char *name){
+ void *lib=dlopen(name,RTLD_NOW|RTLD_LOCAL);
+ if(lib==NULL){
+ fprintf(stderr,"dlopen(%s): %s\n",name,dlerror());
+ exit(1);
+ }
+ register_function regfunc=(register_function)dlsym(lib,"plugin_register_yourself");
+ if(regfunc==NULL){
+ fprintf(stderr,"Cannot find plugin_register_yourself symbol in library '%s'\n",name);
+ exit(1);
+ }
+ regfunc(&plugin_register_callback);
+}
+
+
static void connection_handler(int sock){
Headers *headers=http_get_headers(sock);
if(headers==NULL){
return;
}
- sendall(sock,"HTTP/1.1 200 OK\r\n"
- "Content-Type: text/plain; charset=UTF-8\r\n"
- "Server: cserver\r\n"
- "\r\n",-1);
+ for(Plugin *pl=pluginlist;pl!=NULL;pl=pl->next){
+ switch(pl->handler(sock,headers)){
+ case HR_HANDLED:
+ printf("Request handled by %s\n",pl->name);
+ break;
+
+ case HR_NEXT:
+ continue;
- sendallf(sock,"Method: %s\n",headers->method);
- sendallf(sock,"URL: %s\n",headers->url);
- sendallf(sock,"Version: %s\n",headers->version);
- for(int i=0;i<headers->nheaders;i++){
- sendallf(sock,"Header '%s': '%s'\n",headers->headers[i][0],headers->headers[i][1]);
+ case HR_ERROR:
+ printf("Request handler '%s' threw error\n",pl->name);
+ break;
+ }
+ break;
}
}
-int main(void){
+int main(int argc,char **argv){
+ if(argc==1){
+ printf("Loading no plugin files\n");
+ } else {
+ for(int i=1;i<argc;i++){
+ load_plugin(argv[i]);
+ }
+ }
+
int sock=socket(PF_INET,SOCK_STREAM,0);
if(sock<0){
perror("socket");
diff --git a/plugin.h b/plugin.h
new file mode 100644
index 0000000..d3e8b36
--- /dev/null
+++ b/plugin.h
@@ -0,0 +1,18 @@
+#pragma once
+
+#include "http.h"
+
+
+typedef enum Handler_ret_t{
+ HR_HANDLED,
+ HR_NEXT,
+ HR_ERROR,
+} Handler_ret_t;
+
+typedef Handler_ret_t (*Handler)(int sock,Headers *headers);
+
+typedef void (*register_callback_t)(const char *name,Handler handler);
+
+// Override this in the plugin; it will be called from the main application.
+// It should call the callback with the plugin's handler.
+void plugin_register_yourself(register_callback_t callback);
diff --git a/plugins/Makefile b/plugins/Makefile
new file mode 100644
index 0000000..145500c
--- /dev/null
+++ b/plugins/Makefile
@@ -0,0 +1,39 @@
+CC = gcc
+CFLAGS = -Wall -Wextra -std=c11 -fwrapv -I..
+ifneq ($(DEBUG),)
+ CFLAGS += -g
+else
+ CFLAGS += -O2
+endif
+
+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:
+ 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 ../*.o ../*.h)
+ $(CC) $(SO_FLAGS) -o $@ $(filter %.o,$^)
diff --git a/plugins/echoback/echoback.c b/plugins/echoback/echoback.c
new file mode 100644
index 0000000..af94cbf
--- /dev/null
+++ b/plugins/echoback/echoback.c
@@ -0,0 +1,25 @@
+#include <stdio.h>
+#include "plugin.h"
+#include "util.h"
+
+
+static Handler_ret_t connection_handler(int sock,Headers *headers){
+ sendall(sock,"HTTP/1.1 200 OK\r\n"
+ "Content-Type: text/plain; charset=UTF-8\r\n"
+ "Server: cserver\r\n"
+ "\r\n",-1);
+
+ sendallf(sock,"Method: %s\n",headers->method);
+ sendallf(sock,"URL: %s\n",headers->url);
+ sendallf(sock,"Version: %s\n",headers->version);
+ sendall(sock,"\n",1);
+ for(int i=0;i<headers->nheaders;i++){
+ sendallf(sock,"Header '%s': '%s'\n",headers->headers[i][0],headers->headers[i][1]);
+ }
+
+ return HR_HANDLED;
+}
+
+void plugin_register_yourself(register_callback_t callback){
+ callback("echoback",&connection_handler);
+}
diff --git a/util.c b/util.c
index 9d9c5d3..5116347 100644
--- a/util.c
+++ b/util.c
@@ -10,14 +10,14 @@
#include "util.h"
-char* copy_buf(char *buf,int len){
+char* copy_buf(const char *buf,int len){
char *dst=malloc(len+1,char);
memcpy(dst,buf,len);
dst[len]='\0';
return dst;
}
-char* copy_str(char *str){
+char* copy_str(const char *str){
return copy_buf(str,strlen(str));
}
diff --git a/util.h b/util.h
index 5831b95..1124982 100644
--- a/util.h
+++ b/util.h
@@ -1,8 +1,8 @@
#pragma once
-char* copy_buf(char *buf,int len);
-char* copy_str(char *str);
+char* copy_buf(const char *buf,int len);
+char* copy_str(const char *str);
void str_toupper(char *str);