tcp.zig (3676B)
1 const std = @import("std"); 2 3 pub const Error = error{ 4 InvalidKind, 5 ExpectedBind, 6 } || std.Io.Reader.Error || std.Io.Writer.Error || std.mem.Allocator.Error; 7 8 pub const PacketKind = enum(u8) { 9 Bind, 10 Request, 11 Read, 12 Write, 13 Disconnect, 14 Print, 15 }; 16 pub const Packet = union(PacketKind) { 17 pub const ConnectionId = u16; 18 19 Bind: struct { port: u16, ttl: u32 }, 20 Request: struct { id: ConnectionId, ip: u32 }, 21 Read: struct { id: ConnectionId, length: u16 }, 22 Write: struct { id: ConnectionId, length: u16, data: []const u8 }, 23 Disconnect: ConnectionId, 24 // Still print while going through UART 25 Print: struct { length: u16, data: []const u8 }, 26 }; 27 28 fn get(comptime T: type, r: *std.Io.Reader) !T { 29 var buffer: [@sizeOf(T)]u8 = undefined; 30 try r.readSliceAll(&buffer); 31 return std.mem.readInt(T, &buffer, .little); 32 } 33 34 fn put(w: *std.Io.Writer, v: anytype) !void { 35 const T = @TypeOf(v); 36 var buffer: [@sizeOf(T)]u8 = undefined; 37 std.mem.writeInt(T, &buffer, v, .little); 38 39 try w.writeAll(&buffer); 40 try w.flush(); 41 } 42 43 pub fn receive(r: *std.Io.Reader, allocator: std.mem.Allocator) Error!Packet { 44 const kind_raw = try get(u8, r); 45 if (kind_raw > @intFromEnum(PacketKind.Print)) return Error.InvalidKind; 46 const kind: PacketKind = @enumFromInt(kind_raw); 47 48 switch (kind) { 49 .Bind => { 50 const port = try get(u16, r); 51 const ttl = try get(u32, r); 52 53 return Packet{ .Bind = .{ 54 .port = port, 55 .ttl = ttl, 56 } }; 57 }, 58 .Request => { 59 const id = try get(Packet.ConnectionId, r); 60 const ip = try get(u32, r); 61 62 return Packet{ .Request = .{ .id = id, .ip = ip } }; 63 }, 64 .Read => { 65 const id = try get(Packet.ConnectionId, r); 66 const length = try get(u16, r); 67 68 return Packet{ .Read = .{ 69 .id = id, 70 .length = length, 71 } }; 72 }, 73 .Write => { 74 const id = try get(Packet.ConnectionId, r); 75 const length = try get(u16, r); 76 const buffer = try allocator.alloc(u8, length); 77 78 try r.readSliceAll(buffer); 79 80 return Packet{ .Write = .{ 81 .id = id, 82 .length = length, 83 .data = buffer, 84 } }; 85 }, 86 .Disconnect => { 87 return Packet{ .Disconnect = try get(Packet.ConnectionId, r) }; 88 }, 89 .Print => { 90 const length = try get(u16, r); 91 const buffer = try allocator.alloc(u8, length); 92 93 try r.readSliceAll(buffer); 94 return Packet{ .Print = .{ 95 .length = length, 96 .data = buffer, 97 } }; 98 }, 99 } 100 } 101 102 pub fn send(w: *std.Io.Writer, packet: Packet) Error!void { 103 try put(w, @intFromEnum(packet)); 104 105 switch (packet) { 106 .Bind => |*bind| { 107 try put(w, bind.port); 108 try put(w, bind.ttl); 109 }, 110 .Request => |*request| { 111 try put(w, request.id); 112 try put(w, request.ip); 113 }, 114 .Disconnect => |id| { 115 try put(w, id); 116 }, 117 .Read => |*read| { 118 try put(w, read.id); 119 try put(w, read.length); 120 }, 121 .Write => |*write| { 122 try put(w, write.id); 123 try put(w, write.length); 124 125 try w.writeAll(write.data); 126 try w.flush(); 127 }, 128 .Print => |*print| { 129 try put(w, print.length); 130 try w.writeAll(print.data); 131 try w.flush(); 132 }, 133 } 134 }