From a9dc10f1439263882976e3db9db9349281a21b42 Mon Sep 17 00:00:00 2001 From: Aleteoryx Date: Mon, 2 Sep 2024 15:46:30 -0400 Subject: [PATCH] socket listener done --- socket.nelua | 160 ++++++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 134 insertions(+), 26 deletions(-) diff --git a/socket.nelua b/socket.nelua index cb9e67d..58e89cc 100644 --- a/socket.nelua +++ b/socket.nelua @@ -4,6 +4,8 @@ but for now it's a standalone function. ]] +-- ## pragmas.nogc = true + -- c imports ## cinclude '' local AF_INET: cint @@ -15,12 +17,15 @@ local SOCK_STREAM: cint -- local SOCK_RAW: cint local MSG_DONTWAIT: cint +local MSG_PEEK: cint local function c_socket(domain: cint, type: cint, protocol: cint): cint end local function c_accept(fd: cint, address: pointer, address_len: *cint): cint end local function c_listen(fd: cint, backlog: cint): cint end local function c_send(fd: cint, buf: *[0]byte, len: usize, flags: cint): isize end +local function c_recv(fd: cint, buf: *[0]byte, len: usize, flags: cint): isize end + ## cinclude '' local function c_inet_pton(af: cint, src: cstring , dst: pointer): cint end @@ -65,10 +70,12 @@ local function c_close(fd: cint): cint end -- end c imports require 'string' +require 'hashmap' +require 'stringbuilder' require 'coroutine' require 'math' require 'C.stdio' -require 'allocators.pool' +require 'allocators.default' local function fakeuse(...: varargs) end @@ -86,20 +93,106 @@ local function die_errno(cond: boolean, msg: string): void end local handler_req = @enum{ - init = 0, + close = 0, read_line, - write, - close + write } local handler_state = @record{ fd: cint, co: coroutine, - last_req: handler_req + last_req: handler_req, + buf: stringbuilder } -function handler_state:step(epfd: cint, state: *handler_state): (boolean) - return false +function handler_state:step(epfd: cint, key: uint32): (boolean) + local should_call = false + switch self.last_req do + case handler_req.write then fallthrough + case handler_req.close then + should_call = true + case handler_req.read_line then + local maxread = 4096 + local buf: [maxread]byte = {} + local len = c_recv(self.fd, &buf, maxread, MSG_PEEK) + if len == -1 then + local errmsg = "Internal error, please try again later.\n" + C.perror("Error reading for handler") + c_send(self.fd, errmsg.data, errmsg.size, 0) + c_epoll_ctl(epfd, EPOLL_CTL_DEL, self.fd, nilptr) + c_close(self.fd) + return false + end + local lf_idx = -1 + for i=0,= 1024 then -- drop connections if allocation fails local errmsg = "The server is overloaded, please try again later.\n" c_send(fd, errmsg.data, errmsg.size, 0) c_close(fd) continue end - state.fd = fd - state.co = coroutine.create(handler) - state.last_req = handler_req.init - local ok, events = state:step() + + local key: uint32 = math.random(0_u32, (@uint32)(2^32-1)) + + local state: handler_state = { + fd = fd, + co = coroutine.create(handler), + last_req = handler_req.close + } + + local fd_event: epoll_event = { data = { u32 = key } } + c_epoll_ctl(epfd, EPOLL_CTL_ADD, fd, &fd_event) + + local ok = state:step(epfd, key) if ok then - local fd_event: epoll_event = { - events = events, - data = { ptr = (@pointer)(state) } - } - c_epoll_ctl(epfd, EPOLL_CTL_ADD, fd, &fd_event) + handlers[key] = state else + c_epoll_ctl(epfd, EPOLL_CTL_DEL, fd, nilptr) local errmsg = "Internal error, please try again later.\n" c_send(fd, errmsg.data, errmsg.size, 0) c_close(fd) - alloc:delete() end else - print("TODO") + if not handlers[events[i].data.u32]:step(epfd, events[i].data.u32) then + handlers:remove(events[i].data.u32) + end end end end @@ -183,8 +280,19 @@ local function listen_tcp(address: string, handler: function(): void): void ]] ]==] die_errno(c_err == -1, "couldn't bind TCP socket") + defer c_close(fd) end + listen_sock(fd, handler) end end -listen_tcp("127.0.0.1:1900", function() end) +listen_tcp("127.0.0.1:1901", function() + local line: string + repeat + coroutine.yield(handler_req.read_line) + coroutine.running():pop(&line) + coroutine.running():push(line.."\n") + coroutine.yield(handler_req.write) + until line == "bye" + coroutine.yield(handler_req.close) +end) -- 2.43.4