summaryrefslogtreecommitdiff
path: root/include/net/conn.hpp
diff options
context:
space:
mode:
authorhovertank3d <[email protected]>2025-11-13 23:02:56 +0100
committerhovertank3d <[email protected]>2025-11-13 23:06:37 +0100
commita5b377745116de2b269cdfc5b90f08f46d0432d2 (patch)
tree7aea9482dadc4d66df17907282f2359c54c9df0d /include/net/conn.hpp
downloadogurec-a5b377745116de2b269cdfc5b90f08f46d0432d2.tar.gz
ogurec-a5b377745116de2b269cdfc5b90f08f46d0432d2.zip
initial commit
Diffstat (limited to 'include/net/conn.hpp')
-rw-r--r--include/net/conn.hpp188
1 files changed, 188 insertions, 0 deletions
diff --git a/include/net/conn.hpp b/include/net/conn.hpp
new file mode 100644
index 0000000..b69dac6
--- /dev/null
+++ b/include/net/conn.hpp
@@ -0,0 +1,188 @@
+#pragma once
+
+#include <cstdint>
+#include <functional>
+#include <map>
+#include <netinet/in.h>
+#include <span>
+#include <vector>
+
+#include "net/packet.hpp"
+
+namespace net {
+class conn {
+ int sock_fd;
+
+ sockaddr_in conn_addr;
+ socklen_t conn_addr_size;
+
+ using handler_list = std::vector<std::function<bool(std::span<uint8_t>)>>;
+ std::array<handler_list, 256> handlers;
+ std::map<uint16_t, handler_list> netmodule_handlers;
+
+private:
+ packet::packet_header read_header()
+ {
+ uint16_t packet_size;
+ uint8_t id;
+
+ recv(packet_size);
+ recv(id);
+
+ return { id, packet_size - 3};
+ }
+
+public:
+ conn(int sock_fd, sockaddr_in conn_addr, socklen_t conn_addr_size)
+ : sock_fd(sock_fd)
+ , conn_addr(conn_addr)
+ , conn_addr_size(conn_addr_size)
+ {
+ }
+
+ ~conn()
+ {
+ close(sock_fd);
+ }
+
+ ssize_t send(std::span<uint8_t> data)
+ {
+ auto bytes = ::send(sock_fd, data.data(), data.size_bytes(), 0);
+ if (bytes < 0) {
+ throw std::runtime_error(strerror(errno));
+ }
+ return bytes;
+ }
+
+ template <std::integral T>
+ ssize_t send(T t)
+ {
+ t = to_little(t);
+ auto bytes = ::send(sock_fd, &t, sizeof(T), 0);
+ if (bytes < 0) {
+ throw std::runtime_error(strerror(errno));
+ }
+ return bytes;
+ }
+
+ ssize_t recv(std::span<uint8_t> data)
+ {
+ if (data.size_bytes() == 0) {
+ return 0;
+ }
+
+ auto bytes = ::recv(sock_fd, data.data(), data.size_bytes(), 0);
+ if (bytes <= 0) {
+ throw std::runtime_error(strerror(errno));
+ }
+ return bytes;
+ }
+
+ template <std::integral T>
+ ssize_t recv(T& t)
+ {
+ auto bytes = ::recv(sock_fd, &t, sizeof(T), 0);
+ if (bytes <= 0) {
+ throw std::runtime_error(strerror(errno));
+ }
+ t = to_little(t);
+ if (bytes != sizeof(T)) {
+ throw std::runtime_error(strerror(errno));
+ }
+ return bytes;
+ }
+
+ template <packet::packet T>
+ void expect_packet(T& t)
+ {
+ auto [id, len] = read_header();
+ assert(id == T::packet_id);
+
+ if(len > 0) {
+ std::vector<uint8_t> payload(len);
+ recv(payload);
+ decode_packet(payload, t);
+ }
+ }
+
+ template <packet::packet P, typename H>
+ void reg_handler(H h) {
+ handlers[P::packet_id].push_back([this, h](std::span<uint8_t> payload) {
+ P t;
+ if (payload.size() > 0) {
+ packet::decode_packet(payload, t);
+ }
+ return h(t);
+ });
+ }
+
+ template <packet::netmodule P, typename H>
+ void reg_handler(H h) {
+ netmodule_handlers[P::module_id].push_back([this, h](std::span<uint8_t> payload) {
+ P t;
+ if (payload.size() > 0) {
+ packet::decode_packet(payload, t);
+ }
+ return h(t);
+ });
+ }
+
+ template <packet::packet T>
+ void send_packet(T p)
+ {
+ auto payload = encode_packet(p);
+
+ send(int16_t(payload.size() + 3));
+ send(T::packet_id);
+ if (payload.size() > 0) {
+ send(payload);
+ }
+ }
+
+ bool handle_netmodule(std::span<uint8_t> payload) {
+ uint16_t id;
+ std::memcpy(&id, payload.data(), sizeof(id));
+ id = to_little(id);
+
+ if (netmodule_handlers[id].size() <= 0) {
+ // currently i won't bother implementing netmodules
+ // FIXME: return false
+ return true;
+ }
+
+ for (auto &h : handlers[id]) {
+ if (h(payload.subspan(2)) == true) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ bool handle() {
+ auto [id, len] = read_header();
+ if (id == 0) {
+ return false;
+ }
+
+ std::vector<uint8_t> payload(len);
+ recv(payload);
+
+ //got netmodule
+ if (id == 82) {
+ return handle_netmodule(payload);
+ }
+
+ if (handlers[id].size() <= 0) {
+ return false;
+ }
+
+ for (auto &h : handlers[id]) {
+ if (h(payload) == true) {
+ break;
+ }
+ }
+ return true;
+ }
+
+};
+} \ No newline at end of file