mirror of
https://github.com/sigmasternchen/CFloor
synced 2025-03-15 20:28:56 +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
|
CC = gcc
|
||||||
CFLAGS = -std=c99 -Wall -D_POSIX_C_SOURCE=199506L
|
CFLAGS = -std=c99 -Wall -D_POSIX_C_SOURCE=201112L
|
||||||
LD = gcc
|
LD = gcc
|
||||||
LDFLAGS = -lpthread -lrt
|
LDFLAGS = -lpthread -lrt
|
||||||
|
|
||||||
|
@ -7,16 +7,21 @@ BIN_NAME = cfloor
|
||||||
|
|
||||||
all: $(BIN_NAME)
|
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
|
test: obj/test.o obj/networking.o obj/linked.o obj/logging.o obj/signals.o
|
||||||
$(LD) $(LDFLAGS) -o $@ $^
|
$(LD) $(LDFLAGS) -o $@ $^
|
||||||
|
|
||||||
valgrind: CFLAGS += -static -g
|
valgrind: CFLAGS += -static -g
|
||||||
valgrind: clean test
|
valgrind: clean test
|
||||||
valgrind --leak-check=yes ./test
|
valgrind --leak-check=yes ./test
|
||||||
|
|
||||||
obj/test.o: src/networking.h src/linked.h src/logging.h src/signals.h
|
obj/main.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
|
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/linked.o: src/linked.h
|
||||||
obj/loggin.o: src/logging.h
|
obj/logging.o: src/logging.h
|
||||||
obj/signals.o: src/signals.h
|
obj/signals.o: src/signals.h
|
||||||
|
|
||||||
obj/%.o: src/%.c obj
|
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) {
|
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 <stdbool.h>
|
||||||
#include <stdlib.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 "networking.h"
|
||||||
|
#include "linked.h"
|
||||||
|
#include "logging.h"
|
||||||
|
#include "signals.h"
|
||||||
|
|
||||||
struct networkingConfig networkingConfig;
|
struct networkingConfig networkingConfig;
|
||||||
|
|
||||||
struct connection connections[MAX_CONNECTIONS];
|
linkedList_t connectionList;
|
||||||
|
|
||||||
static inline struct connection emptyConnection() {
|
void cleanup() {
|
||||||
return (struct connection) {
|
signal_block_all();
|
||||||
.used = false,
|
|
||||||
.connectionState = CLOSED,
|
link_t* link = linked_first(&connectionList);
|
||||||
.metaData = {
|
|
||||||
|
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,
|
.path = NULL,
|
||||||
.queryString = NULL
|
.queryString = NULL
|
||||||
},
|
};
|
||||||
.headers = {
|
connection->headers = (struct headers) {
|
||||||
.number = 0,
|
.number = 0,
|
||||||
.headers = NULL
|
.headers = NULL
|
||||||
},
|
};
|
||||||
.currentHeaderLength = 0,
|
connection->currentHeaderLength = 0;
|
||||||
.fd = -1,
|
connection->currentHeader = NULL;
|
||||||
/*
|
connection->handler = NULL;
|
||||||
* ignored:
|
updateTiming(connection, false);
|
||||||
* .metaData.method
|
|
||||||
* .metaData.httpVersion
|
linked_push(&connectionList, connection);
|
||||||
* .currentHeader
|
}
|
||||||
* .timing.*
|
|
||||||
*/
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void initNetworking(struct networkingConfig _networkingConfig) {
|
void initNetworking(struct networkingConfig _networkingConfig) {
|
||||||
networkingConfig = _networkingConfig;
|
networkingConfig = _networkingConfig;
|
||||||
|
|
||||||
for (int i = 0; i < MAX_CONNECTIONS; i++) {
|
connectionList = linked_create();
|
||||||
connections[i] = emptyConnection();
|
|
||||||
|
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 <stdbool.h>
|
||||||
#include <sys/time.h>
|
#include <sys/time.h>
|
||||||
|
#include <pthread.h>
|
||||||
|
|
||||||
|
#include <sys/socket.h>
|
||||||
|
#include <netinet/in.h>
|
||||||
|
|
||||||
#include "headers.h"
|
#include "headers.h"
|
||||||
#include "misc.h"
|
#include "misc.h"
|
||||||
|
|
||||||
#define MAX_CONNECTIONS (512)
|
#define NR_CONNECTION_STATE (5)
|
||||||
|
|
||||||
#define NR_CONNECTION_STATE (6)
|
|
||||||
enum connectionState {
|
enum connectionState {
|
||||||
ESTABLISHED = 0,
|
OPENED = 0,
|
||||||
HEADERS_COMPLETE = 1,
|
PROCESSING = 1,
|
||||||
DATA_COMPLETE = 2,
|
ABORTED = 2,
|
||||||
PROCESSING = 3,
|
CLOSED = 3,
|
||||||
ABORTED = 4,
|
FREED = 4
|
||||||
CLOSED = 5,
|
|
||||||
FREED = 6
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct timing {
|
struct timing {
|
||||||
struct timeval states[NR_CONNECTION_STATE];
|
struct timespec states[NR_CONNECTION_STATE];
|
||||||
struct timeval lastUpdate;
|
struct timespec lastUpdate;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct connection {
|
struct bind_private {
|
||||||
bool used;
|
pthread_t threadId;
|
||||||
enum connectionState connectionState;
|
int socketFd;
|
||||||
struct metaData metaData;
|
|
||||||
struct headers headers;
|
|
||||||
size_t currentHeaderLength;
|
|
||||||
char* currentHeader;
|
|
||||||
int fd;
|
|
||||||
struct timing timing;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef handler_t (*handlerGetter_t)(struct metaData metaData, const char* host);
|
|
||||||
|
|
||||||
struct bind {
|
struct bind {
|
||||||
const char* address;
|
const char* address;
|
||||||
const char* port;
|
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 {
|
struct binds {
|
||||||
|
@ -51,10 +60,15 @@ struct binds {
|
||||||
struct networkingConfig {
|
struct networkingConfig {
|
||||||
struct binds binds;
|
struct binds binds;
|
||||||
long connectionTimeout;
|
long connectionTimeout;
|
||||||
|
long maxConnections;
|
||||||
struct headers defaultResponse;
|
struct headers defaultResponse;
|
||||||
handlerGetter_t getHandler;
|
handlerGetter_t getHandler;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#define CLEANUP_INTERVAl (1000)
|
||||||
|
|
||||||
|
#define LISTEN_BACKLOG (1024)
|
||||||
|
|
||||||
void initNetworking(struct networkingConfig networkingConfig);
|
void initNetworking(struct networkingConfig networkingConfig);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
Loading…
Reference in a new issue