this repo has no description

BytePacketBuffer read api

altagos.dev 326d319f ef43edf7

verified
+149 -11
-1
src/main.zig
··· 3 3 4 4 pub fn main() !void { 5 5 std.debug.print("All your {s} are belong to us.\n", .{"codebase"}); 6 - try aether.advancedPrint(); 7 6 } 8 7 9 8 test "simple test" {
+149 -10
src/root.zig
··· 1 1 const std = @import("std"); 2 2 3 - pub fn advancedPrint() !void { 4 - const stdout_file = std.io.getStdOut().writer(); 5 - var bw = std.io.bufferedWriter(stdout_file); 6 - const stdout = bw.writer(); 3 + pub const BytePacketBuffer = struct { 4 + buf: [512]u8 = undefined, 5 + pos: usize = 0, 6 + 7 + /// Change the buffer position forward a specific number of steps 8 + pub fn step(self: *BytePacketBuffer, pos: usize) void { 9 + self.pos += pos; 10 + } 11 + 12 + /// Chanke the buffer position 13 + pub fn seek(self: *BytePacketBuffer, pos: usize) void { 14 + self.pos = pos; 15 + } 16 + 17 + /// Read a single byte and move the position one step forward 18 + pub fn read(self: *BytePacketBuffer) error{EndOfBuffer}!u8 { 19 + if (self.pos >= comptime self.buf.len) return error.EndOfBuffer; 20 + const res = self.buf[self.pos]; 21 + self.pos += 1; 22 + return res; 23 + } 24 + 25 + /// Get a single byte without changing the buffer position 26 + pub fn get(self: *const BytePacketBuffer, pos: usize) error{EndOfBuffer}!u8 { 27 + if (pos >= comptime self.buf.len) return error.EndOfBuffer; 28 + return self.buf[pos]; 29 + } 30 + 31 + /// Get a range of bytes 32 + pub fn get_range(self: *const BytePacketBuffer, start: usize, len: usize) error{EndOfBuffer}![]const u8 { 33 + if (start + len >= comptime self.buf.len) return error.EndOfBuffer; 34 + return self.buf[start .. start + len]; 35 + } 36 + 37 + /// Read two bytes, stepping two steps forward 38 + pub fn read_u16(self: *BytePacketBuffer) error{EndOfBuffer}!u16 { 39 + return (@as(u16, try self.read()) << 8) | 40 + @as(u16, try self.read()); 41 + } 42 + 43 + /// Read two bytes, stepping two steps forward 44 + pub fn read_u32(self: *BytePacketBuffer) error{EndOfBuffer}!u32 { 45 + return @as(u32, try self.read()) << 24 | 46 + (@as(u32, try self.read()) << 16) | 47 + (@as(u32, try self.read()) << 8) | 48 + (@as(u32, try self.read())); 49 + } 50 + 51 + /// Read a qname 52 + /// 53 + /// The tricky part: Reading domain names, taking labels into consideration. 54 + /// Will take something like [3]www[6]google[3]com and append 55 + /// www.google.com to outstr. 56 + pub fn read_qname(self: *BytePacketBuffer, outstr: []u8) !void { 57 + // We might encounter jumps, therefore we need to keep thrack of our position locally 58 + var pos = self.pos; 59 + var out_pos: usize = 0; 60 + 61 + // track whether or nor we've jumped 62 + var jumped = false; 63 + const max_jumps: usize = 5; 64 + var jumps_performed: usize = 0; 65 + 66 + var delim: ?[]const u8 = null; 67 + while (true) { 68 + if (jumps_performed > max_jumps) return error.JumpLimitExceeded; 69 + 70 + // Each label starts with a length byte 71 + const len = try self.get(pos); 72 + 73 + // If len has the two most signigicant bit set, it represents a jump to some other 74 + // offset in the packet: 75 + if ((len & 0xC0) == 0xC0) { 76 + // Update the buffer position to a point past the current label 77 + if (!jumped) self.seek(2); 78 + 79 + // Read another byte, calculate offset and performe the jump by updating our 80 + // local position variable 81 + const b2 = @as(u16, try self.get(pos + 1)); 82 + const offset = ((@as(u16, len) ^ 0xC0) << 8) | b2; 83 + pos = @as(usize, offset); 7 84 8 - try stdout.print("Run `zig build test` to run the tests.\n", .{}); 85 + // Indicate that a jump was performed 86 + jumped = true; 87 + jumps_performed += 1; 88 + 89 + continue; 90 + } else { 91 + // Move a single byte forward to move path the length 92 + pos += 1; 93 + 94 + // Domain names are terminated by an empty label of length 0, so if the length 95 + // is zero we're done 96 + if (len == 0) break; 97 + 98 + if (delim) |del| { 99 + @memcpy(outstr[out_pos .. out_pos + del.len], del); 100 + out_pos += del.len; 101 + } 102 + 103 + @memcpy(outstr[out_pos .. out_pos + len], try self.get_range(pos, len)); 104 + delim = "."; 105 + 106 + pos += len; 107 + out_pos += len; 108 + } 109 + } 110 + 111 + if (!jumped) self.seek(1); 112 + } 113 + }; 114 + 115 + test "BytePacketBuffer.read" { 116 + const testing = std.testing; 117 + var buf = BytePacketBuffer{}; 118 + buf.buf[0] = 0x1; 119 + try testing.expectEqual(0x1, try buf.read()); 120 + } 9 121 10 - try bw.flush(); // Don't forget to flush! 122 + test "BytePacketBuffer.read_u16" { 123 + const testing = std.testing; 124 + var buf = BytePacketBuffer{}; 125 + buf.buf[0] = 0x1; 126 + buf.buf[1] = 0x1; 127 + try testing.expectEqual(0x101, try buf.read_u16()); 11 128 } 12 129 13 - pub fn add(a: i32, b: i32) i32 { 14 - return a + b; 130 + test "BytePacketBuffer.read_u32" { 131 + const testing = std.testing; 132 + var buf = BytePacketBuffer{}; 133 + buf.buf[0] = 0x1; 134 + buf.buf[1] = 0x1; 135 + buf.buf[2] = 0x1; 136 + buf.buf[3] = 0x1; 137 + try testing.expectEqual(0x1010101, try buf.read_u32()); 15 138 } 16 139 17 - test "basic add functionality" { 18 - try std.testing.expect(add(3, 7) == 10); 140 + test "BytePacketBuffer.read_qname" { 141 + const testing = std.testing; 142 + const allocator = testing.allocator; 143 + 144 + const input = [_]u8{ 0x06, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x03, 0x63, 0x6f, 0x6d, 0x00 }; 145 + var buf = BytePacketBuffer{}; 146 + 147 + for (input, 0..) |char, idx| { 148 + buf.buf[idx] = char; 149 + } 150 + 151 + const expected = "google.com"; 152 + const outstr = try allocator.alloc(u8, expected.len); 153 + defer allocator.free(outstr); 154 + 155 + try buf.read_qname(outstr); 156 + 157 + try testing.expectEqualStrings(expected, outstr); 19 158 }