feat(lnm): start of event loop
ci/woodpecker/push/build Pipeline was successful
Details
ci/woodpecker/push/build Pipeline was successful
Details
parent
20b6b593eb
commit
8a3be2b07c
|
@ -20,6 +20,8 @@
|
||||||
typedef enum {
|
typedef enum {
|
||||||
lnm_err_ok = 0,
|
lnm_err_ok = 0,
|
||||||
lnm_err_failed_alloc,
|
lnm_err_failed_alloc,
|
||||||
|
lnm_err_failed_network,
|
||||||
|
lnm_err_failed_poll,
|
||||||
} lnm_err;
|
} lnm_err;
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -1,11 +1,13 @@
|
||||||
#ifndef LNM_LOOP
|
#ifndef LNM_LOOP
|
||||||
#define LNM_LOOP
|
#define LNM_LOOP
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
|
||||||
#include "lnm/common.h"
|
#include "lnm/common.h"
|
||||||
|
|
||||||
#define LNM_LOOP_BUF_SIZE 4096
|
#define LNM_LOOP_BUF_SIZE 4096
|
||||||
|
#define LNM_LOOP_INITIAL_CONNS 16
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
lnm_loop_state_req = 0,
|
lnm_loop_state_req = 0,
|
||||||
|
@ -33,10 +35,17 @@ typedef struct {
|
||||||
struct {
|
struct {
|
||||||
lnm_loop_conn **arr;
|
lnm_loop_conn **arr;
|
||||||
size_t len;
|
size_t len;
|
||||||
|
size_t open;
|
||||||
} conns;
|
} conns;
|
||||||
void *gctx;
|
void *gctx;
|
||||||
lnm_err (*ctx_init)(void **out, void *gctx);
|
lnm_err (*ctx_init)(void **out, void *gctx);
|
||||||
void (*ctx_free)(void *ctx);
|
void (*ctx_free)(void *ctx);
|
||||||
} lnm_loop;
|
} lnm_loop;
|
||||||
|
|
||||||
|
lnm_err lnm_loop_init(lnm_loop **out, void *gctx,
|
||||||
|
lnm_err (*ctx_init)(void **out, void *gctx),
|
||||||
|
void (*ctx_free)(void *ctx));
|
||||||
|
|
||||||
|
lnm_err lnm_loop_run(lnm_loop *l, uint16_t port);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -3,3 +3,5 @@
|
||||||
lnm_err lnm_loop_conn_init(lnm_loop_conn **out, lnm_loop *l);
|
lnm_err lnm_loop_conn_init(lnm_loop_conn **out, lnm_loop *l);
|
||||||
|
|
||||||
void lnm_loop_conn_free(lnm_loop *l, lnm_loop_conn *conn);
|
void lnm_loop_conn_free(lnm_loop *l, lnm_loop_conn *conn);
|
||||||
|
|
||||||
|
lnm_err lnm_loop_accept(lnm_loop *l);
|
||||||
|
|
|
@ -1 +1,134 @@
|
||||||
#include "lnm/loop.h"
|
#include <netinet/in.h>
|
||||||
|
#include <poll.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
#include "lnm/common.h"
|
||||||
|
#include "lnm/loop_internal.h"
|
||||||
|
|
||||||
|
lnm_err lnm_loop_init(lnm_loop **out, void *gctx,
|
||||||
|
lnm_err (*ctx_init)(void **out, void *gctx),
|
||||||
|
void (*ctx_free)(void *ctx)) {
|
||||||
|
lnm_loop *l = calloc(1, sizeof(lnm_loop));
|
||||||
|
|
||||||
|
if (l == NULL) {
|
||||||
|
return lnm_err_failed_alloc;
|
||||||
|
}
|
||||||
|
|
||||||
|
l->gctx = gctx;
|
||||||
|
l->ctx_init = ctx_init;
|
||||||
|
l->ctx_free = ctx_free;
|
||||||
|
|
||||||
|
*out = l;
|
||||||
|
|
||||||
|
return lnm_err_ok;
|
||||||
|
}
|
||||||
|
|
||||||
|
lnm_err lnm_loop_run(lnm_loop *l, uint16_t port) {
|
||||||
|
int listen_fd = socket(AF_INET, SOCK_STREAM | SOCK_NONBLOCK, 0);
|
||||||
|
|
||||||
|
if (listen_fd < 0) {
|
||||||
|
return lnm_err_failed_network;
|
||||||
|
}
|
||||||
|
|
||||||
|
int val = 1;
|
||||||
|
int res = setsockopt(listen_fd, SOL_SOCKET, SO_REUSEADDR, &val, sizeof(int));
|
||||||
|
|
||||||
|
if (res < 0) {
|
||||||
|
return lnm_err_failed_network;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct sockaddr_in addr = {.sin_family = AF_INET,
|
||||||
|
.sin_port = ntohs(port),
|
||||||
|
.sin_addr.s_addr = ntohl(0)};
|
||||||
|
|
||||||
|
res = bind(listen_fd, (const struct sockaddr *)&addr, sizeof(addr));
|
||||||
|
|
||||||
|
if (res < 0) {
|
||||||
|
return lnm_err_failed_network;
|
||||||
|
}
|
||||||
|
|
||||||
|
res = listen(listen_fd, SOMAXCONN);
|
||||||
|
|
||||||
|
if (res < 0) {
|
||||||
|
return lnm_err_failed_network;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct pollfd *poll_args =
|
||||||
|
malloc((LNM_LOOP_INITIAL_CONNS + 1) * sizeof(struct pollfd));
|
||||||
|
size_t poll_args_cap = LNM_LOOP_INITIAL_CONNS + 1;
|
||||||
|
|
||||||
|
if (poll_args == NULL) {
|
||||||
|
return lnm_err_failed_alloc;
|
||||||
|
}
|
||||||
|
|
||||||
|
// First argument is listening socket
|
||||||
|
poll_args[0].fd = listen_fd;
|
||||||
|
poll_args[0].events = POLLIN;
|
||||||
|
|
||||||
|
while (1) {
|
||||||
|
size_t poll_args_len = 1;
|
||||||
|
|
||||||
|
// Add all open connections to the poll command
|
||||||
|
for (size_t i = 0; i < l->conns.len && poll_args_len <= l->conns.open;
|
||||||
|
i++) {
|
||||||
|
lnm_loop_conn *conn = l->conns.arr[i];
|
||||||
|
|
||||||
|
if (conn == NULL) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
poll_args[poll_args_len].fd = conn->fd;
|
||||||
|
poll_args[poll_args_len].events =
|
||||||
|
((conn->state == lnm_loop_state_req) ? POLLIN : POLLOUT) | POLLERR;
|
||||||
|
|
||||||
|
poll_args_len++;
|
||||||
|
}
|
||||||
|
|
||||||
|
int polled = poll(poll_args, poll_args_len, -1);
|
||||||
|
|
||||||
|
if (polled < 0) {
|
||||||
|
return lnm_err_failed_poll;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (poll_args[0].revents) {
|
||||||
|
lnm_loop_accept(l);
|
||||||
|
polled--;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (size_t i = 1; i < poll_args_len && polled > 0; i++) {
|
||||||
|
if (poll_args[i].revents) {
|
||||||
|
lnm_loop_conn *conn = l->conns.arr[poll_args[i].fd];
|
||||||
|
|
||||||
|
// TODO actual IO
|
||||||
|
|
||||||
|
if (conn->state == lnm_loop_state_end) {
|
||||||
|
l->conns.arr[conn->fd] = NULL;
|
||||||
|
close(conn->fd);
|
||||||
|
|
||||||
|
l->conns.open--;
|
||||||
|
lnm_loop_conn_free(l, conn);
|
||||||
|
}
|
||||||
|
|
||||||
|
polled--;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (poll_args_cap < l->conns.open + 1) {
|
||||||
|
struct pollfd *buf = malloc((l->conns.open + 1) * sizeof(struct pollfd));
|
||||||
|
|
||||||
|
if (buf == NULL) {
|
||||||
|
return lnm_err_failed_alloc;
|
||||||
|
}
|
||||||
|
|
||||||
|
buf[0].fd = listen_fd;
|
||||||
|
buf[0].events = POLLIN;
|
||||||
|
|
||||||
|
free(poll_args);
|
||||||
|
poll_args = buf;
|
||||||
|
|
||||||
|
poll_args_cap = l->conns.open + 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return lnm_err_ok;
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue