sylveos

Toy Operating System
Log | Files | Refs

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 }