big chunk of networking done

This commit is contained in:
overflowerror 2019-03-03 23:08:51 +01:00
parent fa9cc3b8cc
commit 654227d1c2
4 changed files with 279 additions and 52 deletions

View file

@ -1,5 +1,5 @@
CC = gcc
CFLAGS = -std=c99 -Wall -D_POSIX_C_SOURCE=199506L
CFLAGS = -std=c99 -Wall -D_POSIX_C_SOURCE=201112L
LD = gcc
LDFLAGS = -lpthread -lrt
@ -7,16 +7,21 @@ BIN_NAME = cfloor
all: $(BIN_NAME)
$(BIN_NAME): obj/main.o obj/networking.o obj/linked.o obj/logging.o obj/signals.o
$(LD) $(LDFLAGS) -o $@ $^
test: obj/test.o obj/networking.o obj/linked.o obj/logging.o obj/signals.o
$(LD) $(LDFLAGS) -o $@ $^
valgrind: CFLAGS += -static -g
valgrind: clean test
valgrind --leak-check=yes ./test
obj/test.o: src/networking.h src/linked.h src/logging.h src/signals.h
obj/networking.o: src/networking.h src/headers.h src/linked.h
obj/main.o: src/networking.h src/linked.h src/logging.h src/signals.h src/misc.h
obj/test.o: src/networking.h src/linked.h src/logging.h src/signals.h src/misc.h
obj/networking.o: src/networking.h src/headers.h src/linked.h src/logging.h src/signals.h
obj/linked.o: src/linked.h
obj/loggin.o: src/logging.h
obj/logging.o: src/logging.h
obj/signals.o: src/signals.h
obj/%.o: src/%.c obj

View file

@ -1,7 +1,40 @@
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include "networking.h"
#include "logging.h"
handler_t handlerGetter(struct metaData metaData, const char* host, struct bind* bind) {
return NULL;
}
int main(int argc, char** argv) {
setLogging(stderr, INFO, true);
setCriticalHandler(NULL);
struct networkingConfig config = {
.maxConnections = 1024,
.connectionTimeout = 30000,
.binds = {
.number = 1,
.binds = (struct bind[]) {
{
.address = "0.0.0.0",
.port = "1337"
}
}
},
.defaultResponse = {
.number = 0
},
.getHandler = &handlerGetter
};
initNetworking(config);
while(true) {
sleep(0xffff);
}
}

View file

@ -1,44 +1,219 @@
#include <stdbool.h>
#include <stdlib.h>
#include <string.h>
#include <pthread.h>
#include <unistd.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include "networking.h"
#include "linked.h"
#include "logging.h"
#include "signals.h"
struct networkingConfig networkingConfig;
struct connection connections[MAX_CONNECTIONS];
linkedList_t connectionList;
static inline struct connection emptyConnection() {
return (struct connection) {
.used = false,
.connectionState = CLOSED,
.metaData = {
void cleanup() {
signal_block_all();
link_t* link = linked_first(&connectionList);
int length = 0;
int unlinked = 0;
while(link != NULL) {
length++;
struct connection* connection = link->data;
switch(connection->state) {
case OPENED:
break;
default:
unlinked++;
linked_unlink(link);
}
link = linked_next(link);
}
info("cleanup: %d/%d unlinked", length, unlinked);
}
pthread_t dataThreadId;
void dataHandler(int signo) {
info("data handler got called.");
}
void* dataThread(void* ignore) {
signal_block_all();
signal_allow(SIGIO);
signal_setup(SIGIO, &dataHandler);
while(true) {
sleep(0xffff);
}
}
void updateTiming(struct connection* connection, bool stateChange) {
struct timespec time;
// no need to check result; none of the errors can happen
clock_gettime(CLOCK_REALTIME, &time);
connection->timing.lastUpdate = time;
if (stateChange)
connection->timing.states[connection->state] = time;
}
void* listenThread(void* _bind) {
signal_block_all();
struct bind* bindObj = (struct bind*) _bind;
info("networking: Starting to listen on %s:%s", bindObj->address, bindObj->port);
struct addrinfo hints;
struct addrinfo* result;
struct addrinfo* rp;
memset(&hints, 0, sizeof(struct addrinfo));
hints.ai_family = AF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;
hints.ai_flags = AI_PASSIVE;
hints.ai_protocol = 0;
hints.ai_canonname = NULL;
hints.ai_addr = NULL;
hints.ai_next = NULL;
int tmp;
tmp = getaddrinfo(bindObj->address, bindObj->port, &hints, &result);
if (tmp < 0) {
error("networking: networking: could't get addrinfo: %s", gai_strerror(tmp));
warn("networking: Not listening on %s:%s", bindObj->address == NULL ? "0.0.0.0" : bindObj->address, bindObj->port);
return NULL;
}
for (rp = result; rp != NULL; rp = rp->ai_next) {
tmp = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol);
if (tmp == -1)
continue;
bindObj->_private.socketFd = tmp;
if (bind(tmp, rp->ai_addr, rp->ai_addrlen) == 0)
break;
close(tmp);
}
if (rp == NULL) {
error("networking: Could not bind.");
warn("networking: Not listening on %s:%s", bindObj->address == NULL ? "0.0.0.0" : bindObj->address, bindObj->port);
return NULL;
}
if (listen(tmp, LISTEN_BACKLOG) < 0) {
error("networking: Could not listen.");
warn("networking: Not listening on %s:%s", bindObj->address == NULL ? "0.0.0.0" : bindObj->address, bindObj->port);
return NULL;
}
freeaddrinfo(result);
while(true) {
struct sockaddr_in client;
socklen_t clientSize = sizeof (struct sockaddr_in);
tmp = accept(bindObj->_private.socketFd, (struct sockaddr *) &client, &clientSize);
if (tmp < 0) {
switch(errno) {
case ENETDOWN:
case EPROTO:
case ENOPROTOOPT:
case EHOSTDOWN:
case ENONET:
case EHOSTUNREACH:
case EOPNOTSUPP:
case ENETUNREACH:
case EAGAIN:
case ECONNABORTED:
case EINTR:
// retry
break;
default:
error("networking: Could not accept connection: %s", strerror(errno));
warn("networking: Not listening on %s:%s", bindObj->address == NULL ? "0.0.0.0" : bindObj->address, bindObj->port);
return NULL;
}
continue;
}
struct connection* connection = malloc(sizeof (struct connection));
if (connection == NULL) {
error("networking: Couldn't allocate connection objekt: %s", strerror(errno));
continue;
}
connection->state = OPENED;
connection->client = client;
connection->bind = bindObj;
connection->fd = tmp;
connection->metaData = (struct metaData) {
.path = NULL,
.queryString = NULL
},
.headers = {
};
connection->headers = (struct headers) {
.number = 0,
.headers = NULL
},
.currentHeaderLength = 0,
.fd = -1,
/*
* ignored:
* .metaData.method
* .metaData.httpVersion
* .currentHeader
* .timing.*
*/
};
};
connection->currentHeaderLength = 0;
connection->currentHeader = NULL;
connection->handler = NULL;
updateTiming(connection, false);
linked_push(&connectionList, connection);
}
}
void initNetworking(struct networkingConfig _networkingConfig) {
networkingConfig = _networkingConfig;
for (int i = 0; i < MAX_CONNECTIONS; i++) {
connections[i] = emptyConnection();
connectionList = linked_create();
timer_t timer = timer_createThreadTimer(&cleanup);
if (timer == NULL) {
critical("networking: Couldn't create cleaup timer.");
return;
}
if (timer_startInterval(timer, CLEANUP_INTERVAl) < 0) {
critical("networking: Couldn't start cleaup timer.");
return;
}
if (pthread_create(&dataThreadId, NULL, &dataThread, NULL) != 0) {
critical("networking: Couldn't start data thread.");
return;
}
signal_block(SIGIO);
for(int i = 0; i < networkingConfig.binds.number; i++) {
struct bind bind = networkingConfig.binds.binds[i];
if (pthread_create(&(bind._private.threadId), NULL, &listenThread, &bind) != 0) {
critical("networking: Couldn't start data thread.");
return;
}
}
}
void newConnection() {
}

View file

@ -3,44 +3,53 @@
#include <stdbool.h>
#include <sys/time.h>
#include <pthread.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include "headers.h"
#include "misc.h"
#define MAX_CONNECTIONS (512)
#define NR_CONNECTION_STATE (6)
#define NR_CONNECTION_STATE (5)
enum connectionState {
ESTABLISHED = 0,
HEADERS_COMPLETE = 1,
DATA_COMPLETE = 2,
PROCESSING = 3,
ABORTED = 4,
CLOSED = 5,
FREED = 6
OPENED = 0,
PROCESSING = 1,
ABORTED = 2,
CLOSED = 3,
FREED = 4
};
struct timing {
struct timeval states[NR_CONNECTION_STATE];
struct timeval lastUpdate;
struct timespec states[NR_CONNECTION_STATE];
struct timespec lastUpdate;
};
struct connection {
bool used;
enum connectionState connectionState;
struct metaData metaData;
struct headers headers;
size_t currentHeaderLength;
char* currentHeader;
int fd;
struct timing timing;
struct bind_private {
pthread_t threadId;
int socketFd;
};
typedef handler_t (*handlerGetter_t)(struct metaData metaData, const char* host);
struct bind {
const char* address;
const char* port;
bool tls;
struct bind_private _private;
};
typedef handler_t (*handlerGetter_t)(struct metaData metaData, const char* host, struct bind* bind);
struct connection {
enum connectionState state;
struct sockaddr_in client;
struct bind* bind;
int fd;
struct metaData metaData;
struct headers headers;
size_t currentHeaderLength;
char* currentHeader;
handler_t handler;
struct timing timing;
};
struct binds {
@ -51,10 +60,15 @@ struct binds {
struct networkingConfig {
struct binds binds;
long connectionTimeout;
long maxConnections;
struct headers defaultResponse;
handlerGetter_t getHandler;
};
#define CLEANUP_INTERVAl (1000)
#define LISTEN_BACKLOG (1024)
void initNetworking(struct networkingConfig networkingConfig);
#endif