mirror of
https://github.com/sigmasternchen/CFloor
synced 2025-03-15 04:18:55 +00:00
big chunk of networking done
This commit is contained in:
parent
fa9cc3b8cc
commit
654227d1c2
4 changed files with 279 additions and 52 deletions
13
Makefile
13
Makefile
|
@ -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
|
||||
|
|
33
src/main.c
33
src/main.c
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
225
src/networking.c
225
src/networking.c
|
@ -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() {
|
||||
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in a new issue