diff options
-rw-r--r-- | .gitignore | 1 | ||||
-rw-r--r-- | Makefile | 8 | ||||
-rw-r--r-- | main.c | 76 | ||||
-rw-r--r-- | plugin.h | 18 | ||||
-rw-r--r-- | plugins/Makefile | 39 | ||||
-rw-r--r-- | plugins/echoback/echoback.c | 25 | ||||
-rw-r--r-- | util.c | 4 | ||||
-rw-r--r-- | util.h | 4 |
8 files changed, 160 insertions, 15 deletions
@@ -1,3 +1,4 @@ cserver *.o *.dSYM +*.dylib @@ -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 $@ $< @@ -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); +} @@ -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)); } @@ -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); |