mirror of
https://github.com/sigmasternchen/CFloor
synced 2025-03-15 04:18:55 +00:00
request handling almost done (timing is missing)
This commit is contained in:
parent
16a8e6c9a5
commit
553d40d1aa
7 changed files with 253 additions and 9 deletions
5
Makefile
5
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 $@ $<
|
||||
|
|
7
src/error.c
Normal file
7
src/error.c
Normal file
|
@ -0,0 +1,7 @@
|
|||
|
||||
|
||||
#include "error.h"
|
||||
|
||||
void status500(struct request request, struct response response) {
|
||||
|
||||
}
|
8
src/error.h
Normal file
8
src/error.h
Normal file
|
@ -0,0 +1,8 @@
|
|||
#ifndef ERROR_H
|
||||
#define ERROR_H
|
||||
|
||||
#include "misc.h"
|
||||
|
||||
handler_t status500;
|
||||
|
||||
#endif
|
32
src/misc.c
Normal file
32
src/misc.c
Normal 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;
|
||||
}
|
19
src/misc.h
19
src/misc.h
|
@ -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
|
||||
|
|
179
src/networking.c
179
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]);
|
||||
|
|
|
@ -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 {
|
||||
|
|
Loading…
Reference in a new issue