commit b4d7e9ad22203a5a49cae9cb97835d24cff585bd
parent 5999ce9e450115ea21d5bb3ea54771b2dab704eb
Author: Yersa Nordman <yersa@finwo.nl>
Date: Thu, 27 Jul 2023 21:44:39 +0200
Actually accepting connections now
Diffstat:
| M | src/fnet.c | | | 171 | ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++----------- |
| M | src/fnet.h | | | 17 | +++++++++++------ |
| M | test.c | | | 14 | +++++++------- |
3 files changed, 166 insertions(+), 36 deletions(-)
diff --git a/src/fnet.c b/src/fnet.c
@@ -6,6 +6,8 @@ extern "C" {
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
+#include <unistd.h>
+#include <sys/time.h>
#include <fcntl.h>
#include <sys/types.h>
@@ -27,12 +29,33 @@ struct fnet_internal_t {
int nfds;
FNET_FLAG flags;
FNET_CALLBACK(onConnect);
- FNET_CALLBACK_VA(onData, struct buf *data);
+ FNET_CALLBACK(onData);
FNET_CALLBACK(onClose);
};
struct fnet_internal_t *connections = NULL;
+int setkeepalive(int fd) {
+ if (setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, &(int){1}, sizeof(int))) {
+ return -1;
+ }
+#if defined(__linux__)
+ // tcp_keepalive_time
+ if (setsockopt(fd, IPPROTO_TCP, TCP_KEEPIDLE, &(int){600}, sizeof(int))) {
+ return -1;
+ }
+ // tcp_keepalive_intvl
+ if (setsockopt(fd, IPPROTO_TCP, TCP_KEEPINTVL, &(int){60}, sizeof(int))) {
+ return -1;
+ }
+ // tcp_keepalive_probes
+ if (setsockopt(fd, IPPROTO_TCP, TCP_KEEPCNT, &(int){6}, sizeof(int))) {
+ return -1;
+ }
+#endif
+ return 0;
+}
+
int settcpnodelay(int fd) {
return setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &(int){1}, sizeof(int));
}
@@ -43,6 +66,36 @@ int setnonblock(int fd) {
return fcntl(fd, F_SETFL, flags | O_NONBLOCK);
}
+int64_t _fnet_now() {
+ struct timeval tv;
+ gettimeofday(&tv, NULL);
+ return (tv.tv_sec * ((int64_t)1000000)) + tv.tv_usec;
+}
+
+// CAUTION: assumes options have been vetted
+struct fnet_internal_t * _fnet_init(const struct fnet_options_t *options) {
+ // 1-to-1 copy, don't touch the options
+ struct fnet_internal_t *conn = malloc(sizeof(struct fnet_internal_t));
+ conn->ext.proto = options->proto;
+ conn->ext.status = FNET_STATUS_INITIALIZING;
+ conn->ext.udata = options->udata;
+ conn->flags = options->flags;
+ conn->onConnect = options->onConnect;
+ conn->onData = options->onData;
+ conn->onClose = options->onClose;
+ conn->nfds = 0;
+ conn->fds = NULL;
+
+ // Aanndd add to the connection tracking list
+ conn->next = connections;
+ if (connections) connections->prev = conn;
+ connections = conn;
+
+ // Done
+ return conn;
+}
+
+
struct fnet_t * fnet_listen(const char *address, uint16_t port, const struct fnet_options_t *options) {
struct fnet_internal_t *conn;
@@ -72,21 +125,7 @@ struct fnet_t * fnet_listen(const char *address, uint16_t port, const struct fne
}
// 1-to-1 copy, don't touch the options
- conn = malloc(sizeof(struct fnet_internal_t));
- conn->ext.proto = options->proto;
- conn->ext.status = FNET_STATUS_INITIALIZING;
- conn->ext.udata = options->udata;
- conn->flags = options->flags;
- conn->onConnect = options->onConnect;
- conn->onData = options->onData;
- conn->onClose = options->onClose;
- conn->nfds = 0;
- conn->fds = NULL;
-
- // Aanndd add to the connection tracking list
- conn->next = connections;
- if (connections) connections->prev = conn;
- connections = conn;
+ conn = _fnet_init(options);
/* struct sockaddr_in servaddr; */
struct addrinfo hints = {}, *addrs;
@@ -166,7 +205,8 @@ struct fnet_t * fnet_listen(const char *address, uint16_t port, const struct fne
}
freeaddrinfo(addrs);
- return conn;
+ conn->ext.status = FNET_STATUS_LISTENING;
+ return (struct fnet_t *)conn;
}
struct fnet_t * fnet_connect(const char *address, uint16_t port, const struct fnet_options_t *options) {
@@ -201,6 +241,11 @@ struct fnet_t * fnet_connect(const char *address, uint16_t port, const struct fn
FNET_RETURNCODE fnet_process(const struct fnet_t *connection) {
struct fnet_internal_t *conn = (struct fnet_internal_t *)connection;
+ struct fnet_internal_t *nconn = NULL;
+ int i;
+ FNET_SOCKET nfd;
+ struct sockaddr_storage addr;
+ socklen_t addrlen = sizeof(addr);
// Checking arguments are given
if (!conn) {
@@ -208,10 +253,74 @@ FNET_RETURNCODE fnet_process(const struct fnet_t *connection) {
return FNET_RETURNCODE_MISSING_ARGUMENT;
}
- return FNET_RETURNCODE_OK;
-}
+ // No processing to be done here
+ if (conn->ext.status == FNET_STATUS_INITIALIZING) return FNET_RETURNCODE_OK;
+ if (conn->ext.status & FNET_STATUS_ERROR ) return FNET_RETURNCODE_OK;
+ if (conn->ext.status & FNET_STATUS_CLOSED ) return FNET_RETURNCODE_OK;
+
+ /* // Handle client still connecting */
+ /* if (conn->ext.status & FNET_STATUS_CONNECTING) { */
+ /* // TODO: handle client connecting */
+ /* return FNET_RETURNCODE_NOT_IMPLEMENTED; */
+ /* } */
+
+ /* if (conn->ext.status & FNET_STATUS_CONNECTED) { */
+ /* // TODO: handle client connection */
+ /* return FNET_RETURNCODE_NOT_IMPLEMENTED; */
+ /* } */
+
+ if (conn->ext.status & FNET_STATUS_LISTENING) {
+ for ( i = 0 ; i < conn->nfds ; i++ ) {
+ nfd = accept(conn->fds[i], (struct sockaddr *)&addr, &addrlen);
+
+ if (nfd < 0) {
+ if (
+ (errno == EAGAIN) ||
+ (errno == EWOULDBLOCK)
+ ) {
+ // Simply no connections to accept
+ continue;
+ }
+ // Indicate the errno is set
+ return FNET_RETURNCODE_ERRNO;
+ }
+
+ // Make this one non-blocking and stay alive
+ if (setnonblock(nfd) < 0) return FNET_RETURNCODE_ERROR;
+ if (setkeepalive(nfd) < 0) return FNET_RETURNCODE_ERROR;
+
+ // Create new fnet_t instance
+ // _init already tracks the connection
+ nconn = _fnet_init(&((struct fnet_options_t){
+ .proto = conn->ext.proto,
+ .flags = conn->flags & (~FNET_FLAG_RECONNECT),
+ .onConnect = NULL,
+ .onData = NULL,
+ .onClose = NULL,
+ .udata = NULL,
+ }));
+
+ nconn->fds = malloc(sizeof(FNET_SOCKET));
+ nconn->fds[0] = nfd;
+ nconn->nfds = 1;
+ nconn->ext.status = FNET_STATUS_CONNECTED;
+
+ if (conn->onConnect) {
+ conn->onConnect(&((struct fnet_ev){
+ .connection = (struct fnet_t *)nconn,
+ .type = FNET_EVENT_CONNECT,
+ .buffer = NULL,
+ .udata = conn->ext.udata,
+ }));
+ }
+ }
+ // TODO: handle client connection
+ return FNET_RETURNCODE_OK;
+ }
+ return FNET_RETURNCODE_OK;
+}
FNET_RETURNCODE fnet_write(const struct fnet_t *connection, struct buf *buf) {
struct fnet_internal_t *conn = (struct fnet_internal_t *)connection;
@@ -238,6 +347,10 @@ FNET_RETURNCODE fnet_close(const struct fnet_t *connection) {
return FNET_RETURNCODE_MISSING_ARGUMENT;
}
+ // TODO: actually close the connection
+ // TODO: call onclose
+ // TODO: call free
+
return FNET_RETURNCODE_OK;
}
@@ -251,8 +364,8 @@ FNET_RETURNCODE fnet_free(struct fnet_t *connection) {
}
// Remove ourselves from the linked list
- if (conn->next) conn->next->prev = conn->prev;
- if (conn->prev) conn->prev->next = conn->next;
+ if (conn->next) ((struct fnet_internal_t *)(conn->next))->prev = conn->prev;
+ if (conn->prev) ((struct fnet_internal_t *)(conn->prev))->next = conn->next;
if (conn == connections) connections = conn->next;
// TODO: check if the connections are closed?
@@ -268,7 +381,7 @@ FNET_RETURNCODE fnet_step() {
struct fnet_internal_t *conn = connections;
FNET_RETURNCODE ret;
while(conn) {
- ret = fnet_process(conn);
+ ret = fnet_process((struct fnet_t *)conn);
if (ret < 0) return ret;
conn = conn->next;
}
@@ -277,11 +390,23 @@ FNET_RETURNCODE fnet_step() {
FNET_RETURNCODE fnet_main() {
FNET_RETURNCODE ret;
+ int64_t ttime = _fnet_now();
+ int64_t tdiff;
+
while(1) {
// TODO: handle kill signal?
// TODO: dynamic sleep to have 10ms - 100ms tick?
- ret = fnet_step();
+ ret = fnet_step();
if (ret) return ret;
+
+ // Sleep 10ms to lower cpu consumption
+ ttime = ttime + 10000;
+ tdiff = ttime - _fnet_now();
+ if (tdiff <= 0) {
+ ttime = 10 + ttime - tdiff;
+ tdiff = 10;
+ }
+ usleep(tdiff);
}
// TODO: is this really ok?
diff --git a/src/fnet.h b/src/fnet.h
@@ -17,14 +17,19 @@ extern "C" {
#define FNET_RETURNCODE int
#define FNET_RETURNCODE_OK 0
-#define FNET_RETURNCODE_MISSING_ARGUMENT 1
+#define FNET_RETURNCODE_ERROR -1
+#define FNET_RETURNCODE_MISSING_ARGUMENT -2
+#define FNET_RETURNCODE_NOT_IMPLEMENTED -3
+#define FNET_RETURNCODE_ERRNO -4
#define FNET_STATUS uint8_t
-#define FNET_STATUS_INITIALIZING 0
-#define FNET_STATUS_CONNECTING 1 // Client-only status
-#define FNET_STATUS_READY 2 // Client = connected, server = listening
-#define FNET_STATUS_ERROR 4
-#define FNET_STATUS_CLOSED 8
+#define FNET_STATUS_INITIALIZING 0
+#define FNET_STATUS_CONNECTING 1 // Client-only status
+#define FNET_STATUS_CONNECTED 2 // Client ready
+#define FNET_STATUS_LISTENING 4 // Listen ready
+#define FNET_STATUS_READY 6 // Any ready
+#define FNET_STATUS_ERROR 8
+#define FNET_STATUS_CLOSED 16
#define FNET_EVENT int
#define FNET_EVENT_CONNECT 1
diff --git a/test.c b/test.c
@@ -4,22 +4,22 @@
#include "fnet.h"
+void onConnect(struct fnet_ev *ev) {
+ printf("Connection!!\n");
+}
+
int main() {
const struct fnet_options_t opts = {
.proto = FNET_PROTO_TCP,
.flags = 0,
- .onConnect = NULL,
+ .onConnect = onConnect,
.onData = NULL,
.onClose = NULL,
.udata = NULL,
};
- struct fnet_t *conn = fnet_listen("::", 1337, &opts);
-
- printf("p: %p\n", conn);
-
- sleep(3600);
-
+ struct fnet_t *conn = fnet_listen("0.0.0.0", 1337, &opts);
+ fnet_main();
return 42;
}