request handling almost done (timing is missing)

This commit is contained in:
overflowerror 2019-03-05 15:05:55 +01:00
parent 16a8e6c9a5
commit 553d40d1aa
7 changed files with 253 additions and 9 deletions

View file

@ -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 $@ $<

7
src/error.c Normal file
View file

@ -0,0 +1,7 @@
#include "error.h"
void status500(struct request request, struct response response) {
}

8
src/error.h Normal file
View file

@ -0,0 +1,8 @@
#ifndef ERROR_H
#define ERROR_H
#include "misc.h"
handler_t status500;
#endif

32
src/misc.c Normal file
View file

@ -0,0 +1,32 @@
#include <unistd.h>
#include <stdlib.h>
#include <pthread.h>
#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;
}

View file

@ -1,7 +1,7 @@
#ifndef MISC_H
#define MISC_H
#include "headers.h"
#include <pthread.h>
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

View file

@ -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]);

View file

@ -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 {