Fixed packet deserialization and tests and made improvements to code readability

This commit is contained in:
Gu://em_ 2026-06-12 15:50:01 +02:00
parent ee3cba3cab
commit 7c5f8c9f30

View file

@ -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);