Author: Pedro Lucas Porcellis <porcellis@eletrotupi.com>
all: drop socket.ha
cmd/beterrabad/socket.ha | 258 ------------------------------------------
diff --git a/cmd/beterrabad/socket.ha b/cmd/beterrabad/socket.ha deleted file mode 100644 index bcb845a6b769b001c303b294d167e0feebcd87f9..0000000000000000000000000000000000000000 --- a/cmd/beterrabad/socket.ha +++ /dev/null @@ -1,258 +0,0 @@ -use bytes; -use bufio; -use dirs; -use encoding::utf8; -use errors; -use fmt; -use fs; -use io; -use log; -use net::unix; -use net; -use os; -use path; -use beterraba; -use strings; -use unix::poll::{event}; -use unix::poll; -use unix::signal; - -def CLIENT_MAXBUF: size = 16777216; // 16 MiB -// TODO: Might not even use this, as a client will connect and then drop -def MAX_CLIENTS: size = 256; -def POLLFD_RESERVED: size = 2; - -type servererror = !(io::error | fs::error); - -type server = struct { - sock: net::socket, - signalfd: io::file, - pollfd: []poll::pollfd, - clients: []client, - disconnected: bool, // XXX: Bit of a hack here - terminate: bool, -}; - -fn bind( - signalfd: io::file, -) server = { - const statedir = match (dirs::runtime()) { - case let err: fs::error => - fmt::fatalf("Unable to initialize socket: {}", fs::strerror(err)); - case let dir: str => - yield dir; - }; - - let buf = path::init(); - path::set(&buf, statedir, "beterrabad")!; - const sockpath = path::string(&buf); - const sock = match (unix::listen(sockpath, net::sockflags::NOCLOEXEC)) { - case let l: net::socket => - yield l; - case let err: net::error => - log::fatal(net::strerror(err)); - }; - os::chmod(sockpath, 0o700)!; - - let pollfd = alloc([poll::pollfd { - fd = sock, - events = event::POLLIN, - ... - }, poll::pollfd { - fd = signalfd, - events = event::POLLIN, - ... - }]); - - return server { - sock = sock, - signalfd = signalfd, - pollfd = pollfd, - ... - }; -}; - -fn shutdown(serv: *server) void = { - for (let i = 0z; i < len(serv.clients); i += 1) { - io::close(serv.clients[i].sock)!; - free(serv.clients[i].rbuf); - free(serv.clients[i].wbuf); - }; - free(serv.clients); - free(serv.pollfd); - - let buf = path::init(); - path::set(&buf, dirs::runtime()!, "beterrabad")!; - os::remove(path::string(&buf))!; - - net::close(serv.sock)!; -}; - -fn dispatch(serv: *server) bool = { - if (serv.terminate) { - return false; - }; - - match (poll::poll(serv.pollfd, poll::INDEF)) { - case uint => - if (serv.pollfd[0].revents & event::POLLIN != 0) { - accept(serv); - }; - if (serv.pollfd[1].revents & event::POLLIN != 0) { - signal::read(serv.signalfd)!; - return false; - }; - for (let i = POLLFD_RESERVED; i < len(serv.pollfd); i += 1) { - dispatch_client(serv, &serv.clients[i - POLLFD_RESERVED]); - if (serv.disconnected) { - // Restart loop on client disconnect - serv.disconnected = false; - i = POLLFD_RESERVED; - }; - }; - case errors::interrupted => - yield; - case let err: errors::error => - log::fatal("poll:", errors::strerror(err)); - }; - - return true; -}; - -fn accept(serv: *server) void = { - // TODO: O_NONBLOCK - const sock = match (net::accept(serv.sock)) { - case let sock: net::socket => - yield sock; - case let err: net::error => - log::fatal(net::strerror(err)); - }; - if (len(serv.clients) >= MAX_CLIENTS) { - log::println("Max clients exceeded; dropping client"); - io::close(sock)!; - return; - }; - - append(serv.pollfd, poll::pollfd { - fd = sock, - events = event::POLLIN | event::POLLHUP, - ... - }); - const pollfd = &serv.pollfd[len(serv.pollfd) - 1]; - append(serv.clients, client { - server = serv, - sock = sock, - pollfd = pollfd, - ... - }); -}; - -fn dispatch_client(serv: *server, client: *client) void = { - const pollfd = client.pollfd; - if (pollfd.revents & event::POLLERR != 0) { - disconnect(client); - return; - }; - if (pollfd.revents & event::POLLHUP != 0) { - disconnect(client); - return; - }; - if (pollfd.revents & event::POLLIN != 0) { - client_readable(serv, client); - }; - if (pollfd.revents & event::POLLOUT != 0) { - client_writable(serv, client); - }; -}; - -fn client_readable(serv: *server, client: *client) void = { - let buf: [os::BUFSIZ]u8 = [0...]; - const z = match (io::read(client.sock, buf)) { - case let z: size => - yield z; - case io::EOF => - disconnect(client); - return; - case let err: io::error => - disconnect(client); - return; - }; - append(client.rbuf, buf[..z]...); - if (len(client.rbuf) >= CLIENT_MAXBUF) { - disconnect_error(client, "error Buffer exceeded\n"); - return; - }; - - for (true) { - let i = match (bytes::index(client.rbuf, '\n')) { - case let i: size => - yield i; - case void => - return; - }; - - const line = match (strings::try_fromutf8(client.rbuf[..i])) { - case let s: str => - yield s; - case utf8::invalid => - disconnect_error(client, "error Invalid UTF-8\n"); - return; - }; - defer delete(client.rbuf[..i+1]); - match (exec(serv, client, line)) { - case let err: servererror => - log::printfln("Error processing user command: {}", - strerror(err)); - case void => - yield; - }; - if (serv.disconnected) { - break; - }; - }; -}; - -fn client_writable(serv: *server, client: *client) void = { - const z = match (io::write(client.sock, client.wbuf)) { - case let z: size => - yield z; - case errors::again => - return; - case let err: io::error => - disconnect(client); - return; - }; - delete(client.wbuf[..z]); - if (len(client.wbuf) != 0) { - return; - }; - - switch (client.state) { - case state::WRITE => - client.state = state::READ; - client.pollfd.events = event::POLLIN | event::POLLHUP; - case state::WRITE_ERROR => - disconnect(client); - case => abort(); - }; -}; - -fn exec(serv: *server, client: *client, line: str) (servererror | void) = { - log::printfln("Received {}", line); - - let buf = bufio::dynamic(io::mode::WRITE); - - switch (line) { - case "start test" => - start_service("test"); - case "ping" => - fmt::fprintf(&buf, "pong\n")?; - }; - - fmt::fprintln(&buf, "end")?; - writebuf(client, bufio::buffer(&buf)); -}; - -fn strerror(err: servererror) str = { - return "Error"; -};