From 5e22c2b2ef325c843e36bfa67db3b5434069d56f Mon Sep 17 00:00:00 2001 From: Robby Zambito Date: Tue, 29 Apr 2025 08:29:15 -0400 Subject: --- src/message.zig | 120 +++++++++++++++++++++++++++++++++++++++----------------- 1 file changed, 85 insertions(+), 35 deletions(-) diff --git a/src/message.zig b/src/message.zig index 0b07603..ae3507e 100644 --- a/src/message.zig +++ b/src/message.zig @@ -26,6 +26,7 @@ pub const ConnectionOptions = packed struct(u8) { pub const Error = error{ NotImplementedSaprusType, UnknownSaprusType, + InvalidMessage, }; // ZERO COPY STUFF @@ -35,19 +36,10 @@ pub const ZeroCopyMessage = packed struct { dest: @Vector(4, u8), payload: void, - pub fn getPayload(self: *align(1) Relay) []u8 { - // const vself: *void = @ptrCast(self); - // var parent: *align(1) ZeroCopyMessage = @fieldParentPtr("bytes", vself); - // if (false) { - // parent = @ptrFromInt(@intFromPtr(parent)); - // } + const RSelf = *align(1) @This(); + + pub fn getPayload(self: RSelf) []u8 { const len: *u16 = @ptrFromInt(@intFromPtr(self) - @sizeOf(u16)); - // std.debug.print("relay: {*}\n", .{self}); - // std.debug.print("inPayload: {*}\n", .{parent}); - // std.debug.print("len: {d}\n", .{len.*}); - // std.debug.print("len: {d}\n", .{parent.length}); - // return @as([*]u8, @ptrCast(&self.payload))[0..3]; - // return @as([*]u8, @ptrCast(&self.payload))[0 .. parent.length - @sizeOf(Relay)]; return @as([*]u8, @ptrCast(&self.payload))[0 .. len.* - @sizeOf(Relay)]; } }; @@ -60,10 +52,26 @@ pub const ZeroCopyMessage = packed struct { options: ConnectionOptions = .{}, payload: void, - pub fn getPayload(self: *align(1) Connection) []u8 { + const CSelf = *align(1) Connection; + + pub fn getPayload(self: CSelf) []u8 { const len: *u16 = @ptrFromInt(@intFromPtr(self) - @sizeOf(u16)); return @as([*]u8, @ptrCast(&self.payload))[0 .. len.* - @sizeOf(Connection)]; } + + fn nativeFromNetworkEndian(self: CSelf) Error!void { + self.src_port = bigToNative(@TypeOf(self.src_port), self.src_port); + self.dest_port = bigToNative(@TypeOf(self.dest_port), self.dest_port); + self.seq_num = bigToNative(@TypeOf(self.seq_num), self.seq_num); + self.msg_id = bigToNative(@TypeOf(self.msg_id), self.msg_id); + } + + fn networkFromNativeEndian(self: CSelf) Error!void { + self.src_port = nativeToBig(@TypeOf(self.src_port), self.src_port); + self.dest_port = nativeToBig(@TypeOf(self.dest_port), self.dest_port); + self.seq_num = nativeToBig(@TypeOf(self.seq_num), self.seq_num); + self.msg_id = nativeToBig(@TypeOf(self.msg_id), self.msg_id); + } }; const Self = @This(); @@ -72,14 +80,14 @@ pub const ZeroCopyMessage = packed struct { length: u16, bytes: void = {}, - fn getRelay(self: *align(1) Self) *align(1) Relay { + fn getRelay(self: ZCM) Relay.RSelf { return std.mem.bytesAsValue(Relay, &self.bytes); } - fn getConnection(self: *align(1) Self) *align(1) Connection { + fn getConnection(self: ZCM) Connection.CSelf { return std.mem.bytesAsValue(Connection, &self.bytes); } - pub fn getSaprusTypePayload(self: *align(1) Self) Error!(union(PacketType) { + pub fn getSaprusTypePayload(self: ZCM) Error!(union(PacketType) { relay: *align(1) Relay, file_transfer: void, connection: *align(1) Connection, @@ -92,36 +100,77 @@ pub const ZeroCopyMessage = packed struct { }; } - pub fn toNativeBytes() void {} - pub fn toNetworkBytes() void {} + pub fn nativeFromNetworkEndian(self: ZCM) Error!void { + self.type = @enumFromInt(bigToNative( + @typeInfo(@TypeOf(self.type)).@"enum".tag_type, + @intFromEnum(self.type), + )); + self.length = bigToNative(@TypeOf(self.length), self.length); + try switch (try self.getSaprusTypePayload()) { + .relay => {}, + .connection => |*con| con.*.nativeFromNetworkEndian(), + .file_transfer => Error.NotImplementedSaprusType, + else => Error.UnknownSaprusType, + }; + } + + pub fn networkFromNativeEndian(self: ZCM) Error!void { + try switch (try self.getSaprusTypePayload()) { + .relay => {}, + .connection => |*con| con.*.networkFromNativeEndian(), + .file_transfer => Error.NotImplementedSaprusType, + else => Error.UnknownSaprusType, + }; + self.type = @enumFromInt(nativeToBig( + @typeInfo(@TypeOf(self.type)).@"enum".tag_type, + @intFromEnum(self.type), + )); + self.length = nativeToBig(@TypeOf(self.length), self.length); + } + + pub fn fromBytesUnchecked(bytes: []u8) ZCM { + return @ptrCast(bytes.ptr); + } + + pub fn fromBytes(bytes: []u8) !ZCM { + const res: ZCM = @ptrCast(bytes.ptr); + return if (bytes.len == res.length + @sizeOf(Self)) res else Error.InvalidMessage; + } }; +const ZCM = *align(1) ZeroCopyMessage; + test "testing variable length zero copy struct" { const gpa = std.testing.allocator; - const bytes = try gpa.alloc(u8, @sizeOf(ZeroCopyMessage) + 64); + const payload_len = 48; + const bytes = try gpa.alloc(u8, @sizeOf(ZeroCopyMessage) + payload_len); defer gpa.free(bytes); - const zcm: *align(1) ZeroCopyMessage = @ptrCast(bytes.ptr); + // Create a view of the byte slice as a ZeroCopyMessage + const zcm: ZCM = .fromBytesUnchecked(bytes); + + { + // Set the message values + zcm.type = .relay; + // zcm.length = payload_len; + const relay = (try zcm.getSaprusTypePayload()).relay; + relay.dest = .{ 1, 2, 3, 4 }; + const payload = relay.getPayload(); + const p = "Hello darkness my old friend"; + @memcpy(payload[0..p.len], p); + } + + { + // Print the message as hex using the network + zcm.networkFromNativeEndian() catch unreachable; + defer zcm.nativeFromNetworkEndian() catch unreachable; + std.debug.print("network bytes: {x}\n", .{bytes}); + } - zcm.type = .relay; - zcm.length = 64; - std.debug.print("pre: {*}\n", .{zcm}); - // std.debug.print("{any}\n", .{(try zcm.getSaprusTypePayload()).relay}); - std.debug.print("{x}\n", .{(try zcm.getSaprusTypePayload()).relay.getPayload()}); - std.debug.print("{d}\n", .{(try zcm.getSaprusTypePayload()).relay.getPayload().len}); if (false) { // Illegal behavior std.debug.print("{any}\n", .{(try zcm.getSaprusTypePayload()).connection}); } - if (false) { - std.debug.print("{any}\n", .{zcm.getRelay()}); - std.debug.print("{any}\n", .{zcm.getConnection()}); - std.debug.print("{x}\n", .{std.mem.asBytes(zcm.getRelay())}); - std.debug.print("{x}\n", .{std.mem.asBytes(zcm.getConnection())}); - } - std.debug.print("{x}\n", .{bytes}); - - try std.testing.expect(true); } /// All Saprus messages @@ -266,6 +315,7 @@ const Allocator = std.mem.Allocator; const asBytes = std.mem.asBytes; const nativeToBig = std.mem.nativeToBig; +const bigToNative = std.mem.bigToNative; test "Round trip Relay toBytes and fromBytes" { const gpa = std.testing.allocator; -- cgit