From 7c5f8c9f30125c073307691c67f09a9d07396843 Mon Sep 17 00:00:00 2001 From: "Gu://em_" Date: Fri, 12 Jun 2026 15:50:01 +0200 Subject: [PATCH] Fixed packet deserialization and tests and made improvements to code readability --- src/packet.zig | 199 ++++++++++++++++++++++++++----------------------- 1 file changed, 107 insertions(+), 92 deletions(-) diff --git a/src/packet.zig b/src/packet.zig index bf0b90b..7589890 100644 --- a/src/packet.zig +++ b/src/packet.zig @@ -1,15 +1,6 @@ -///////////////// Imports -// - -const std = @import("std"); - ///////////////// Constants // -const expect = std.testing.expect; -const memeql = std.mem.eql; -const asBytes = std.mem.asBytes; - const MAX_DATA_SIZE = 465; const ADDRESS_SIZE = 16; @@ -17,90 +8,117 @@ const ADDRESS_SIZE = 16; // const IfacFlag = enum(u1) { - open = 0, // Packet for publically accessible interface - authenticated = 1, // Interface authentication is included in packet + open = 0, // Packet for publically accessible interface + authenticated = 1, // Interface authentication is included in packet }; const HeaderType = enum(u1) { - type1 = 0, // One address field - type2 = 1, // Two address fields + type1 = 0, // One address field + type2 = 1, // Two address fields }; -const ContextFlag = enum(u1) { // Meaning depends on packet context +const ContextFlag = enum(u1) { + // Meaning depends on packet context unset = 0, - set = 1, + set = 1, +}; +const PropagationType = enum(u1) { + broadcast = 0, + transport = 1 }; -const PropagationType = enum(u1) { broadcast = 0, transport = 1 }; const DestinationType = enum(u2) { single = 0b0, - group = 0b01, - plain = 0b10, - link = 0b11, + group = 0b01, + plain = 0b10, + link = 0b11, }; const PacketType = enum(u2) { - data = 0b0, - announce = 0b01, + data = 0b0, + announce = 0b01, link_request = 0b10, - proof = 0b11, + proof = 0b11, }; const PacketContext = enum(u8) { - none = 0x00, // Generic data packet - resource = 0x01, // Packet is part of a resource - resource_adv = 0x02, // Packet is a resource advertisement - resource_req = 0x03, // Packet is a resource part request - resource_hmu = 0x04, // Packet is a resource hashmap update - resource_prf = 0x05, // Packet is a resource proof - resource_icl = 0x06, // Packet is a resource initiator cancel message - resource_rcl = 0x07, // Packet is a resource receiver cancel message - cache_request = 0x08, // Packet is a cache request - request = 0x09, // Packet is a request - response = 0x0A, // Packet is a response to a request - path_response = 0x0B, // Packet is a response to a path request - command = 0x0C, // Packet is a command - command_status = 0x0D, // Packet is a status of an executed command - channel = 0x0E, // Packet contains link channel data - keepalive = 0xFA, // Packet is a keepalive packet - linkidentify = 0xFB, // Packet is a link peer identification proof - linkclose = 0xFC, // Packet is a link close message - linkproof = 0xFD, // Packet is a link packet proof - lrrtt = 0xFE, // Packet is a link request round-trip time measurement - lrproof = 0xFF, // Packet is a link request proof + none = 0x00, // Generic data packet + resource = 0x01, // Packet is part of a resource + resource_adv = 0x02, // Packet is a resource advertisement + resource_req = 0x03, // Packet is a resource part request + resource_hmu = 0x04, // Packet is a resource hashmap update + resource_prf = 0x05, // Packet is a resource proof + resource_icl = 0x06, // Packet is a resource initiator cancel message + resource_rcl = 0x07, // Packet is a resource receiver cancel message + cache_request = 0x08, // Packet is a cache request + request = 0x09, // Packet is a request + response = 0x0A, // Packet is a response to a request + path_response = 0x0B, // Packet is a response to a path request + command = 0x0C, // Packet is a command + command_status = 0x0D, // Packet is a status of an executed command + channel = 0x0E, // Packet contains link channel data + keepalive = 0xFA, // Packet is a keepalive packet + linkidentify = 0xFB, // Packet is a link peer identification proof + linkclose = 0xFC, // Packet is a link close message + linkproof = 0xFD, // Packet is a link packet proof + lrrtt = 0xFE, // Packet is a link request round-trip time measurement + lrproof = 0xFF, // Packet is a link request proof }; ///////////////// Structs // const PacketHeader = packed struct { - ifac: IfacFlag, - header: HeaderType, - context: ContextFlag, + ifac: IfacFlag, + header: HeaderType, + context: ContextFlag, propagation: PropagationType, destination: DestinationType, - packet: PacketType, - hops: u8, + packet: PacketType, + hops: u8, }; const Packet = struct { - header: PacketHeader, + header: PacketHeader, address1: [ADDRESS_SIZE]u8, address2: [ADDRESS_SIZE]u8, - context: PacketContext, - data: []const u8, + context: PacketContext, + data: []u8, }; ///////////////// Functions // +//////// Helper functions +// + +// Copies serialized data (as a byte array) into any structure type +fn copyToPacket(dst: anytype, src: []const u8, offset: usize, count: usize) !usize { + if (count == 0) return 0; + if (src.len < offset + count) return error.BufferTooShort; + + + const dst_ptr: []u8 = @ptrCast(dst); + if (dst_ptr.len != count) return error.MismatchedLengths; + + + @memcpy(dst_ptr, src[offset .. offset + count]); + + return offset + count; +} + +// Returns the size of the packet in bytes +fn getPacketSize(data_size: usize, has_two_addresses: bool) usize { + var res = @sizeOf(PacketHeader) + ADDRESS_SIZE + @sizeOf(PacketContext) + data_size; + if (has_two_addresses) res += ADDRESS_SIZE; + return res; +} + +//////// Public functions +// + pub fn serializePacket(packet: Packet, output_buffer: []u8) !usize { const has_two_addresses = packet.header.header == HeaderType.type2; - // Compute size of final packet (in bytes) - var target_size: u16 = @sizeOf(Packet); - if (!has_two_addresses) { - target_size -= packet.address2.len; - } - // TODO check data len + const target_size = getPacketSize(packet.data.len, has_two_addresses); if (output_buffer.len < target_size) { return error.BufferTooShort; @@ -132,17 +150,6 @@ pub fn serializePacket(packet: Packet, output_buffer: []u8) !usize { return offset; } -fn copyToPacket(dst: anytype, src: []const u8, offset: usize, count: usize) !usize { - if (src.len < offset + count) { - return error.BufferTooShort; - } - - const dst_ptr: []u8 = @ptrCast(dst); - @memcpy(dst_ptr, src[offset .. offset + count]); - - return offset + count; -} - // Reads the message buffer and builds the corresponding packet struct inside dest_packet pub fn deserializePacket(message_buffer: []u8, dest_packet: *Packet) !void { var offset: usize = 0; @@ -154,14 +161,18 @@ pub fn deserializePacket(message_buffer: []u8, dest_packet: *Packet) !void { offset = try copyToPacket(&dest_packet.address2, message_buffer, offset, ADDRESS_SIZE); } offset = try copyToPacket(&dest_packet.context, message_buffer, offset, @sizeOf(PacketContext)); - // TODO compute data length - const data_len = 0; - offset = try copyToPacket(&dest_packet.data, message_buffer, offset, data_len); + offset = try copyToPacket(dest_packet.data, message_buffer, offset, message_buffer.len - offset); } ///////////////// Tests // +const std = @import("std"); + +const expect = std.testing.expect; +const memeql = std.mem.eql; +const asBytes = std.mem.asBytes; + //////// Helper functions // @@ -170,11 +181,8 @@ fn testPacketSerialization(packet: Packet) !void { const buf_size = comptime @sizeOf(Packet) + MAX_DATA_SIZE; var buf: [buf_size]u8 = undefined; const res: usize = try serializePacket(packet, &buf); - var expected_res: usize = @sizeOf(PacketHeader) + packet.address1.len + @sizeOf(PacketContext) + packet.data.len; const has_second_address = packet.header.header == HeaderType.type2; - if (has_second_address) { - expected_res += packet.address2.len; - } + const expected_res: usize = getPacketSize(packet.data.len, has_second_address); try expect(res == expected_res); @@ -186,6 +194,11 @@ fn testPacketSerialization(packet: Packet) !void { try expect(memeql(u8, buf[offset .. offset + packet.address1.len], asBytes(&packet.address1))); offset += packet.address1.len; + if (has_second_address) { + try expect(memeql(u8, buf[offset .. offset + packet.address2.len], asBytes(&packet.address2))); + offset += packet.address2.len; + } + try expect(memeql(u8, buf[offset .. offset + @sizeOf(PacketContext)], asBytes(&packet.context))); offset += @sizeOf(PacketContext); @@ -194,20 +207,20 @@ fn testPacketSerialization(packet: Packet) !void { } fn headersEql(h1: *const PacketHeader, h2: *const PacketHeader) bool { - return h1.ifac == h2.ifac - and h1.header == h2.header - and h1.context == h2.context + return h1.ifac == h2.ifac + and h1.header == h2.header + and h1.context == h2.context and h1.propagation == h2.propagation and h1.destination == h2.destination - and h1.packet == h2.packet - and h1.hops == h2.hops; + and h1.packet == h2.packet + and h1.hops == h2.hops; } fn packetsEql(p1: *const Packet, p2: *const Packet) bool { return headersEql(&p1.header, &p2.header) and memeql(u8, &p1.address1, &p2.address1) and memeql(u8, &p1.address2, &p2.address2) - and p1.context == p2.context + and p1.context == p2.context and p1.data.len == p2.data.len and memeql(u8, p1.data, p2.data); } @@ -231,9 +244,9 @@ test "Basic serialization: header type 1, max data size" { }; const data_size = MAX_DATA_SIZE; - const data: [data_size]u8 = undefined; + var data: [data_size]u8 = undefined; - const packet: Packet = .{ // + const packet: Packet = .{ .header = header, .address1 = undefined, .address2 = undefined, @@ -256,9 +269,9 @@ test "Basic serialization: header type 2, max data size" { }; const data_size = MAX_DATA_SIZE; - const data: [data_size]u8 = undefined; + var data: [data_size]u8 = undefined; - const packet: Packet = .{ // + const packet: Packet = .{ .header = header, .address1 = undefined, .address2 = undefined, @@ -281,9 +294,9 @@ test "Basic serialization: header type 1, medium data size" { }; const data_size = MAX_DATA_SIZE / 2 + 3; - const data: [data_size]u8 = undefined; + var data: [data_size]u8 = undefined; - const packet: Packet = .{ // + const packet: Packet = .{ .header = header, .address1 = undefined, .address2 = undefined, @@ -306,9 +319,9 @@ test "Basic serialization: header type 2, medium data size" { }; const data_size = MAX_DATA_SIZE / 2 + 3; - const data: [data_size]u8 = undefined; + var data: [data_size]u8 = undefined; - const packet: Packet = .{ // + const packet: Packet = .{ .header = header, .address1 = undefined, .address2 = undefined, @@ -331,9 +344,9 @@ test "Serialize / Deserialize Packet: Header type2, Medium data size" { }; const data_size = MAX_DATA_SIZE / 2 + 3; - const data: [data_size]u8 = undefined; + var data: [data_size]u8 = undefined; - const packet: Packet = .{ // + const packet: Packet = .{ .header = header, .address1 = undefined, .address2 = undefined, @@ -341,9 +354,11 @@ test "Serialize / Deserialize Packet: Header type2, Medium data size" { .data = &data, }; - const buf_size = comptime @sizeOf(Packet) + MAX_DATA_SIZE; + const buf_size = comptime @sizeOf(PacketHeader) + 2*ADDRESS_SIZE + @sizeOf(PacketContext) + data_size; var buf: [buf_size]u8 = undefined; var res_packet: Packet = undefined; + var res_data: [data_size]u8 = undefined; + res_packet.data = &res_data; _ = try serializePacket(packet, &buf); try deserializePacket(&buf, &res_packet);