This commit is contained in:
Theis Pieter Hollebeek 2026-03-25 12:39:19 +01:00
parent d311a20c53
commit 3646c5bf90
5 changed files with 107 additions and 18 deletions

View File

@ -1,3 +1,5 @@
#include "tcp.hpp"
#include <print>
#include <stdio.h> #include <stdio.h>
#include <sys/select.h> #include <sys/select.h>
#include <sys/socket.h> #include <sys/socket.h>
@ -7,6 +9,15 @@
int main(void) int main(void)
{ {
printf("hello\n"); auto x = mst::TcpListener::bind("0.0.0.0", PORT);
if (!x) {
std::println("{}", x.error());
return 1;
}
std::println("starting");
auto listener = x.value();
{
auto x = listener.loop();
}
return 0; return 0;
} }

0
backend/src/server.cpp Normal file
View File

1
backend/src/server.hpp Normal file
View File

@ -0,0 +1 @@
#pragma once

View File

@ -1,5 +1,6 @@
#include "tcp.h" #include "tcp.h"
#include <arpa/inet.h> #include <arpa/inet.h>
#include <cstdlib>
#include <errno.h> #include <errno.h>
#include <expected> #include <expected>
#include <format> #include <format>
@ -15,6 +16,29 @@
#include <unistd.h> #include <unistd.h>
namespace mst { namespace mst {
auto event::make_listener_event(int fd) -> Event*
{
auto ev = (Event*)malloc(sizeof(Event));
ev->variant = Listener;
ev->data.listener_fd = fd;
return ev;
}
auto event::make_connection_event(TcpConnection connection) -> Event*
{
auto ev = (Event*)malloc(sizeof(Event));
auto ptr = (TcpConnection*)std::malloc(sizeof(TcpConnection));
*ptr = connection;
ev->variant = Connection;
ev->data.connection = ptr;
return ev;
}
auto errno_shim(std::string_view message) -> std::string auto errno_shim(std::string_view message) -> std::string
{ {
auto x = strerror(errno); auto x = strerror(errno);
@ -62,24 +86,61 @@ auto TcpListener::bind(const std::string& host, uint16_t port)
return std::unexpected(errno_shim("could not listen")); return std::unexpected(errno_shim("could not listen"));
} }
auto epoll_fd = ::epoll_create(0); auto epoll_fd = ::epoll_create1(0);
auto events_accepted = epoll_event { .events = EPOLLIN, .data = { } }; auto context = event::make_listener_event(socket_fd);
if (::epoll_ctl(epoll_fd, EPOLL_CTL_ADD, socket_fd, &events_accepted) < 0) {
auto event = epoll_event { .events = EPOLLIN, .data = { .ptr = context } };
if (::epoll_ctl(epoll_fd, EPOLL_CTL_ADD, socket_fd, &event) < 0) {
return std::unexpected(errno_shim("could not connect to epoll")); return std::unexpected(errno_shim("could not connect to epoll"));
} }
return TcpListener(socket_fd, epoll_fd, address); return TcpListener(epoll_fd, address);
} }
auto TcpListener::accept() -> Result<TcpConnection> auto TcpListener::start() -> Result<void>
{ {
epoll_event events[128] = { };
while (true) {
auto events_len = ::epoll_wait(this->epoll_fd, events, 128, -1);
if (events_len < 0) {
return std::unexpected(errno_shim("could not poll"));
}
for (int i = 0; i < events_len; ++i) {
auto event = (event::Event*)events[i].data.ptr;
switch (event->variant) {
case event::Listener: {
socklen_t size = sizeof(address); socklen_t size = sizeof(address);
int socket = ::accept(this->listener_fd, (struct sockaddr*)&address, &size); int client = ::accept(
if (socket < 0) { events[0].data.fd, (struct sockaddr*)&address, &size);
if (client < 0) {
return std::unexpected(errno_shim("could not accept")); return std::unexpected(errno_shim("could not accept"));
} }
return TcpConnection(*this, socket);
auto context = event::make_connection_event(
TcpConnection(*this, client));
auto poll_event = epoll_event { .events = EPOLLIN,
.data = { .ptr = context } };
if (::epoll_ctl(
epoll_fd, EPOLL_CTL_ADD, client, &poll_event)
< 0) {
return std::unexpected(
errno_shim("could not add connection to epoll"));
}
break;
}
case event::Connection: {
event->data.connection.wake();
break;
}
}
}
}
} }
} }

View File

@ -4,11 +4,29 @@
#include <expected> #include <expected>
#include <netinet/in.h> #include <netinet/in.h>
#include <string> #include <string>
#include <vector> #include <unistd.h>
namespace mst { namespace mst {
template <typename T> using Result = std::expected<T, std::string>; template <typename T> using Result = std::expected<T, std::string>;
class TcpConnection;
namespace event {
enum Variant { Listener, Connection };
typedef union {
int listener_fd;
TcpConnection* connection;
} Data;
struct Event {
Variant variant;
Data data;
};
auto make_listener_event(int fd) -> Event*;
auto make_connection_event(TcpConnection connection) -> Event*;
}
class TcpListener; class TcpListener;
class TcpConnection { class TcpConnection {
@ -20,6 +38,7 @@ public:
private: private:
int fd; int fd;
event::Event event;
}; };
class TcpListener { class TcpListener {
@ -27,16 +46,13 @@ class TcpListener {
public: public:
static auto bind(const std::string& host, uint16_t port) static auto bind(const std::string& host, uint16_t port)
-> Result<TcpListener>; -> Result<TcpListener>;
auto accept() -> Result<TcpConnection>; auto start() -> Result<void>;
private: private:
TcpListener(int listener_fd, int epoll_fd, sockaddr_in address) TcpListener(int epoll_fd, sockaddr_in address)
: listener_fd(listener_fd) : epoll_fd(epoll_fd)
, epoll_fd(epoll_fd)
, address(address) { }; , address(address) { };
int listener_fd;
int epoll_fd; int epoll_fd;
sockaddr_in address; sockaddr_in address;
std::vector<int> epoll_fds;
}; };
} }