diff --git a/Makefile b/Makefile index 84b1bb4..101dd75 100644 --- a/Makefile +++ b/Makefile @@ -7,10 +7,10 @@ BIN_NAME = cfloor all: $(BIN_NAME) -$(BIN_NAME): obj/main.o obj/networking.o obj/linked.o obj/logging.o obj/signals.o obj/headers.o +$(BIN_NAME): obj/main.o obj/networking.o obj/linked.o obj/logging.o obj/signals.o obj/headers.o obj/misc.o $(LD) $(LDFLAGS) -o $@ $^ -test: obj/test.o obj/networking.o obj/linked.o obj/logging.o obj/signals.o obj/headers.o +test: obj/test.o obj/networking.o obj/linked.o obj/logging.o obj/signals.o obj/headers.o obj/misc.o $(LD) $(LDFLAGS) -o $@ $^ valgrind: CFLAGS += -static -g @@ -24,6 +24,7 @@ obj/linked.o: src/linked.h obj/logging.o: src/logging.h obj/signals.o: src/signals.h obj/headers.o: src/headers.h src/misc.h +obj/misc.o: src/misc.h obj/%.o: src/%.c obj $(CC) $(CFLAGS) -c -o $@ $< diff --git a/src/error.c b/src/error.c new file mode 100644 index 0000000..64ff8da --- /dev/null +++ b/src/error.c @@ -0,0 +1,7 @@ + + +#include "error.h" + +void status500(struct request request, struct response response) { + +} diff --git a/src/error.h b/src/error.h new file mode 100644 index 0000000..9cb1856 --- /dev/null +++ b/src/error.h @@ -0,0 +1,8 @@ +#ifndef ERROR_H +#define ERROR_H + +#include "misc.h" + +handler_t status500; + +#endif diff --git a/src/misc.c b/src/misc.c new file mode 100644 index 0000000..d260593 --- /dev/null +++ b/src/misc.c @@ -0,0 +1,32 @@ +#include +#include + +#include + +#include "misc.h" + +int startCopyThread(int from, int to, pthread_t* thread) { + struct fileCopy* files = malloc(sizeof(struct fileCopy)); + if (files < 0) + return -1; + + files->readFd = from; + files->writeFd = to; + + return pthread_create(thread, NULL, &fileCopyThread, files); +} + +void* fileCopyThread(void* data) { + struct fileCopy* files = (struct fileCopy*) data; + char* c; + + while(read(files->readFd, &c, 1) > 0) + write(files->writeFd, &c, 1); + + close(files->readFd); + close(files->writeFd); + + free(files); + + return NULL; +} diff --git a/src/misc.h b/src/misc.h index 583e995..4c6e0e8 100644 --- a/src/misc.h +++ b/src/misc.h @@ -1,7 +1,7 @@ #ifndef MISC_H #define MISC_H -#include "headers.h" +#include enum method { GET, POST, PUT @@ -18,6 +18,12 @@ struct metaData { char* queryString; }; +/* + * recursive headers. + * I don't know how to fix this a better way. + */ +#include "headers.h" + struct request { struct metaData metaData; struct headers* headers; @@ -26,9 +32,18 @@ struct request { }; struct response { - int (*sendHeader)(int statusCode, struct headers headers); + int (*sendHeader)(int statusCode, struct headers headers, struct request* request); }; typedef void (*handler_t)(struct request request, struct response response); + + +struct fileCopy { + int readFd; + int writeFd; +}; +int startCopyThread(int from, int to, pthread_t* thread); +void* fileCopyThread(void* data); + #endif diff --git a/src/networking.c b/src/networking.c index f51062d..e36ba57 100644 --- a/src/networking.c +++ b/src/networking.c @@ -15,6 +15,7 @@ #include "linked.h" #include "logging.h" #include "signals.h" +#include "error.h" struct networkingConfig networkingConfig; @@ -157,13 +158,164 @@ int dumpHeaderBuffer(char* buffer, size_t size, struct connection* connection) { return 0; } +int sendHeader(int statusCode, struct headers headers, struct request* request) { + struct connection* connection = (struct connection*) request->_private; -void requestHandlerThread(struct connection* connection) { + // send statusCode and headers + + return connection->threads.responseFd; +} + +static inline void stopThread(pthread_t self, pthread_t thread, bool force) { + if (pthread_equal(self, thread)) + return; + + if (force) + pthread_cancel(thread); + else + pthread_join(thread, NULL); +} + +void safeEndConnection(struct connection* connection, bool force) { + pthread_t self = pthread_self(); + + stopThread(self, connection->threads.request, true); + stopThread(self, connection->threads.response, force); + stopThread(self, connection->threads.helper[0], force); + stopThread(self, connection->threads.helper[1], force); + + connection->inUse--; +} + +/* + * This thread calls the handler. + */ +void* responseThread(void* data) { + struct connection* connection = (struct connection*) data; + + connection->threads.handler((struct request) { + .metaData = connection->metaData, + .headers = &(connection->headers), + .fd = connection->threads.requestFd, + ._private = connection + }, (struct response) { + .sendHeader = sendHeader + }); + + close(connection->threads.requestFd); + close(connection->threads._requestFd); + close(connection->threads.responseFd); + close(connection->threads._responseFd); + + safeEndConnection(connection, false); + + return NULL; +} + +/* + * This thread handles finding a handler and handles pipes + */ +void* requestThread(void* data) { + struct connection* connection = (struct connection*) data; + + signal_block_all(); + + handler_t handler = networkingConfig.getHandler(connection->metaData, headers_get(&(connection->headers), "Host"), connection->bind); + + if (handler == NULL) { + handler = status500; + } + + connection->threads.handler = handler; + + int pipefd[2]; + if (pipe(&(pipefd[0])) < 0) { + error("networking: Couldn't create reponse pipe: %s", strerror(errno)); + warn("Aborting request."); + connection->state = ABORTED; + connection->inUse--; + return NULL; + } + + int request = pipefd[1]; + connection->threads._requestFd = request; + connection->threads.requestFd = pipefd[0]; + if (pipe(&(pipefd[0])) < 0) { + close(request); + close(connection->threads.requestFd); + + error("networking: Couldn't create reponse pipe: %s", strerror(errno)); + warn("Aborting request."); + connection->state = ABORTED; + connection->inUse--; + return NULL; + } + + int response = pipefd[0]; + connection->threads._responseFd = response; + connection->threads.responseFd = pipefd[1]; + + if (startCopyThread(connection->fd, request, &(connection->threads.helper[0])) < 0) { + close(request); + close(connection->threads.requestFd); + close(response); + close(connection->threads.responseFd); + + error("networking: Couldn't start helper thread."); + warn("networking: Aborting request."); + connection->state = ABORTED; + connection->inUse--; + return NULL; + } + if (startCopyThread(response, connection->fd, &(connection->threads.helper[1])) < 0) { + close(request); + close(connection->threads.requestFd); + close(response); + close(connection->threads.responseFd); + + error("networking: Couldn't start helper thread."); + warn("networking: Aborting request."); + connection->state = ABORTED; + connection->inUse--; + return NULL; + } + + if (pthread_create(&(connection->threads.response), NULL, &responseThread, connection) < 0) { + close(request); + close(connection->threads.requestFd); + close(response); + close(connection->threads.responseFd); + + error("networking: Couldn't start response thread."); + warn("networking: Aborting request."); + connection->state = ABORTED; + connection->inUse--; + return NULL; + } + + // timeout + + close(request); + close(connection->threads.requestFd); + close(response); + close(connection->threads.responseFd); + + safeEndConnection(connection, true); + + return NULL; } void startRequestHandler(struct connection* connection) { connection->inUse++; + + if (pthread_create(&(connection->threads.request), NULL, &requestThread, connection) != 0) { + error("networking: Couldn't start request thread."); + warn("networking: Aborting request."); + connection->state = ABORTED; + connection->inUse--; + return; + } } #define BUFFER_LENGTH (64) @@ -206,12 +358,12 @@ void dataHandler(int signo) { tmp = headers_metadata(&(connection->metaData), connection->currentHeader); if (tmp == HEADERS_ALLOC_ERROR) { error("networking: couldn't allocate memory for meta data: %s", strerror(errno)); - error("networking: aborting request"); + warn("networking: aborting request"); dropConnection = true; break; } else if (tmp == HEADERS_PARSE_ERROR) { error("networking: error while reading header line"); - error("networking: aborting request"); + warn("networking: aborting request"); dropConnection = true; break; } @@ -225,12 +377,12 @@ void dataHandler(int signo) { break; } else if (tmp == HEADERS_ALLOC_ERROR) { error("networking: couldn't allocate memory for header: %s", strerror(errno)); - error("networking: aborting request"); + warn("networking: aborting request"); dropConnection = true; break; } else if (tmp == HEADERS_PARSE_ERROR) { error("networking: failed to parse headers"); - error("networking: aborting request"); + warn("networking: aborting request"); dropConnection = true; break; @@ -403,6 +555,22 @@ void* listenThread(void* _bind) { .number = 0, .headers = NULL }; + connection->threads = (struct threads) { + /* + * This is really hacky. pthread_t is no(t always an) integer. + * TODO: better solution + */ + .request = 0, + .response = 0, + .handler = NULL, + .requestFd = -1, + .responseFd = -1, + ._requestFd = -1, + ._responseFd = -1 + }; + // TODO see above + connection->threads.helper[0] = 0; + connection->threads.helper[1] = 0; connection->currentHeaderLength = 0; connection->currentHeader = NULL; connection->inUse = 0; @@ -439,6 +607,7 @@ void initNetworking(struct networkingConfig _networkingConfig) { } signal_block(SIGIO); + signal_block(SIGALRM); for(int i = 0; i < networkingConfig.binds.number; i++) { struct bind* bind = &(networkingConfig.binds.binds[i]); diff --git a/src/networking.h b/src/networking.h index cccb02c..435acd2 100644 --- a/src/networking.h +++ b/src/networking.h @@ -40,6 +40,17 @@ struct bind { typedef handler_t (*handlerGetter_t)(struct metaData metaData, const char* host, struct bind* bind); +struct threads { + pthread_t request; + pthread_t response; + pthread_t helper[2]; + handler_t handler; + int requestFd; + int responseFd; + int _requestFd; + int _responseFd; +}; + struct connection { enum connectionState state; struct sockaddr_in client; @@ -51,6 +62,7 @@ struct connection { size_t currentHeaderLength; char* currentHeader; struct timing timing; + struct threads threads; }; struct binds {