aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorubq323 <ubq323@ubq323.website>2024-04-13 00:49:14 +0100
committerubq323 <ubq323@ubq323.website>2024-04-13 00:49:14 +0100
commitbf03e2a0d86a4b5202a72aa66da5dc0e2c0b412b (patch)
treeda47f07c9f3c7946044153f21b7d4bcf991ea1bf
parent0eeff114b44ccdd6bc430bc5f9583e2a3eea9823 (diff)
multiple packet types. code quality is declining steadily
-rw-r--r--client/main.ha13
-rw-r--r--drawing/op.ha8
-rw-r--r--packet_reader/packet_reader.ha66
-rw-r--r--server/main.ha68
4 files changed, 112 insertions, 43 deletions
diff --git a/client/main.ha b/client/main.ha
index fa63004..242a101 100644
--- a/client/main.ha
+++ b/client/main.ha
@@ -87,16 +87,21 @@ export fn main() void = {
case void => yield;
case let op: drawing::op =>
drawing::perform(pictures, op);
- drawing::send_op(conn, op)!;
+ packet_reader::send(conn, op: packet_reader::packet_drawop)!;
};
const n = poll::poll(pollfd, poll::NONBLOCK)!;
if (n > 0) {
fmt::println("data available")!;
packet_reader::read(&packet_reader, conn)!;
- for (const packet_bytes => packet_reader::next(&packet_reader)) {
- const op = drawing::deser_op(packet_bytes);
- drawing::perform(pictures, op);
+ for (const packet => packet_reader::next(&packet_reader)!) {
+ match (packet) {
+ case let op: packet_reader::packet_drawop =>
+ const opc = op as drawing::op_circle;
+ drawing::perform(pictures, opc);
+ case =>
+ abort("other packet not supported yet");
+ };
};
};
diff --git a/drawing/op.ha b/drawing/op.ha
index deda81c..acbca29 100644
--- a/drawing/op.ha
+++ b/drawing/op.ha
@@ -7,13 +7,13 @@ export type op_other = void;
export type op = (op_circle| op_other);
-
-export fn send_op(file: io::handle, op: op) (void | io::error) = {
- static let buf: [8]u8 = [0...];
+// return value must be freed... for now. ehh
+export fn ser_op(op: op) []u8 = {
const opc = op as op_circle;
+ let buf: []u8 = alloc([0...],8);
endian::leputu32(buf[0..4], opc.0: u32);
endian::leputu32(buf[4..8], opc.1: u32);
- io::writeall(file, buf)?;
+ return buf;
};
export fn deser_op(bytes: []u8) op = {
diff --git a/packet_reader/packet_reader.ha b/packet_reader/packet_reader.ha
index 43b85d1..9cae444 100644
--- a/packet_reader/packet_reader.ha
+++ b/packet_reader/packet_reader.ha
@@ -1,24 +1,33 @@
use io;
use fmt;
+use endian;
+use drawing;
-export type packet = []u8;
-def PCKSZ: size = 8;
+export type error = !str;
export type packet_reader = struct {
- buf: [256]u8,
+ buf: []u8,
good: []u8,
};
export fn new() packet_reader = {
let pr = packet_reader {
- buf = [0...],
+ buf = alloc([0...],512*512*4*2), // ehhh
...
};
pr.good = pr.buf[0..0];
return pr;
+};
+export type packet_type = enum u8 {
+ DRAW_OP,
+ SEND_CHUNK,
};
+export type packet_drawop = drawing::op;
+export type packet_sendchunk = []u32;
+export type packet = (packet_drawop | packet_sendchunk);
+
// call when input is ready. could block otherwise
export fn read(pr: *packet_reader, sock: io::handle) (void | io::error | io::EOF) = {
const remaining_amt = len(pr.good);
@@ -39,14 +48,53 @@ export fn read(pr: *packet_reader, sock: io::handle) (void | io::error | io::EOF
fmt::printfln("now {} bytes in buffer",total_amt)!;
};
+// packet format:
+// u32 size
+// u32 type
+// [size-8]u8 data...
+// size includes size of header (size and type fields)
-export fn next(pr: *packet_reader) (packet | done) = {
+export fn next(pr: *packet_reader) (packet | done | error) = {
// either parse a full packet out of the front of good,
// move good along that many bytes,
// and return the packet,
// or, ascertain there is no full packet, and return done
- if (len(pr.good) < PCKSZ) return done;
- const packet_bytes = pr.good[..PCKSZ];
- pr.good = pr.good[PCKSZ..];
- return packet_bytes;
+ if (len(pr.good) < size(u32)) return done;
+ const packet_len = endian::legetu32(pr.good[0..4]);
+ if (packet_len < 8) return "packet size field too small": error;
+ if (len(pr.good) < packet_len) return done;
+
+ const packet_bytes = pr.good[..packet_len];
+ pr.good = pr.good[packet_len..];
+
+ const ty = endian::legetu32(packet_bytes[4..8]): packet_type;
+ switch (ty) {
+ case packet_type::DRAW_OP =>
+ const op = drawing::deser_op(packet_bytes[8..]);
+ return op: packet_drawop;
+ case packet_type::SEND_CHUNK =>
+ // in an ideal world we would need no copies
+ const totally_necessary_copy = alloc(packet_bytes[8..]...);
+ return totally_necessary_copy: packet_sendchunk;
+ };
+};
+
+export fn send_raw(sock: io::file, ty: packet_type, data: []u8) (void | io::error) = {
+ // ehh
+ const header: [8]u8 = [0...];
+ endian::leputu32(header[0..4], 8u32 + len(data):u32);
+ endian::leputu32(header[4..8], ty);
+ io::writeall(sock, header)?;
+ io::writeall(sock, data)?;
+};
+
+export fn send(sock: io::file, packet: packet) (void | io::error) = {
+ match (packet) {
+ case let op: packet_drawop =>
+ const ser_op = drawing::ser_op(op);
+ defer free(ser_op);
+ send_raw(sock, packet_type::DRAW_OP, ser_op)?;
+ case let chunkdata: packet_sendchunk =>
+ abort("not implemented sendchunk yet");
+ };
};
diff --git a/server/main.ha b/server/main.ha
index abcb0fe..9f21932 100644
--- a/server/main.ha
+++ b/server/main.ha
@@ -45,7 +45,7 @@ export fn main() void = {
loop(listener, pictures);
};
-def save_interval = 5 * time::SECOND;
+def save_interval = 20 * time::SECOND;
fn save_world(pictures: []drawing::picture) void = {
fmt::printfln("saving world!")!;
@@ -59,13 +59,20 @@ fn save_world(pictures: []drawing::picture) void = {
fmt::printfln("\t. {}",filename)!;
io::close(file)!;
};
+
const header = fmt::asprintf("P6\n{} {}\n{}\n", pic.w, pic.h, 255);
defer free(header);
io::writeall(file, strings::toutf8(header))!;
+
+ let buf: []u8 = alloc([0...],3*pic.w*pic.h);
+ defer free(buf);
for (let i = 0z; i < pic.w * pic.h; i += 1) {
const px = pic.d[i];
- io::writeall(file, [(px&0xff): u8, ((px>>8)&0xff): u8, ((px>>16)&0xff): u8])!;
+ buf[3*i ] = ((px>>16)&0xff): u8;
+ buf[3*i+1] = ((px>>8) &0xff): u8;
+ buf[3*i+2] = ((px) &0xff): u8;
};
+ io::writeall(file, buf)!;
};
};
@@ -81,6 +88,7 @@ fn loop(listener: net::socket, pictures: []drawing::picture) void = {
let now = time::now(time::clock::MONOTONIC);
let next = time::add(now, save_interval);
+ save_world(pictures);
for (true) {
fmt::println("poll.")!;
@@ -104,36 +112,44 @@ fn loop(listener: net::socket, pictures: []drawing::picture) void = {
append(packet_readers, packet_reader::new());
fmt::printfln("there are now {},{} conns.",len(pollfds),len(packet_readers))!;
};
- for (let i = 1z; i < len(pollfds); i += 1) {
- if (0 != pollfds[i].revents & poll::event::POLLIN) {
- match (packet_reader::read(&packet_readers[i-1], pollfds[i].fd)) {
+ for (let connidx = 1z; connidx < len(pollfds); connidx += 1) {
+ if (0 != pollfds[connidx].revents & poll::event::POLLIN) {
+ match (packet_reader::read(&packet_readers[connidx-1], pollfds[connidx].fd)) {
case void =>
- let j = 1;
- for (const packet_bytes => packet_reader::next(&packet_readers[i-1])) {
- fmt::printf("#{}:{} got {:2}",i,j,len(packet_bytes))!;
- j += 1;
- for (let byte .. packet_bytes) fmt::printf(" {:x}",byte)!;
- const op = drawing::deser_op(packet_bytes) as drawing::op_circle;
- drawing::perform(pictures, op);
- fmt::printfln("\t({:+6},{:+6})",op.0,op.1)!;
- for (let k = 1z; k < len(pollfds); k += 1) {
- if (k == i) continue;
- fmt::printfln("\t -> #{}",k)!;
- io::writeall(pollfds[k].fd, packet_bytes)!;
- };
+ for (const packet => packet_reader::next(&packet_readers[connidx-1])!) {
+ handle_packet(pictures, pollfds, packet, connidx);
};
case let err: io::error =>
- fmt::printfln("#{} error: {}",i,io::strerror(err))!;
- delete(pollfds[i]);
- delete(packet_readers[i-1]);
- i -= 1;
+ fmt::printfln("#{} error: {}",connidx,io::strerror(err))!;
+ delete(pollfds[connidx]);
+ delete(packet_readers[connidx-1]);
+ connidx -= 1;
case io::EOF =>
- fmt::printfln("#{} disconnect",i)!;
- delete(pollfds[i]);
- delete(packet_readers[i-1]);
- i -= 1;
+ fmt::printfln("#{} disconnect",connidx)!;
+ delete(pollfds[connidx]);
+ delete(packet_readers[connidx-1]);
+ connidx -= 1;
};
};
};
};
};
+
+// ehh, really need a struct to put pollfds, pictures, connections... in
+fn handle_packet(pictures: []drawing::picture, pollfds: []poll::pollfd, packet: packet_reader::packet, connidx: size) void = {
+ match (packet) {
+ case let op: packet_reader::packet_drawop =>
+ const opc = op as drawing::op_circle;
+ fmt::printfln("#{}: drawop ({:+6},{:+6})",connidx,opc.0,opc.1)!;
+ drawing::perform(pictures, opc);
+ for (let otheridx = 1z; otheridx < len(pollfds); otheridx += 1) {
+ if (otheridx == connidx) continue;
+ fmt::printfln("\t -> #{}",otheridx)!;
+ // ehhh shouldn't reserialize for each other thing
+ packet_reader::send(pollfds[otheridx].fd, packet)!;
+ };
+ case =>
+ abort("other packets not supported yet");
+ };
+};
+