diff options
| -rw-r--r-- | src/NetWriter.zig | 238 | ||||
| -rw-r--r-- | src/RawSocketWriter.zig | 32 | ||||
| -rw-r--r-- | src/message.zig | 610 | ||||
| -rw-r--r-- | src/root.zig | 2 |
4 files changed, 343 insertions, 539 deletions
diff --git a/src/NetWriter.zig b/src/NetWriter.zig deleted file mode 100644 index f0f617d..0000000 --- a/src/NetWriter.zig +++ /dev/null @@ -1,238 +0,0 @@ -//! Wraps a writer with UDP headers. -//! This is useful for wrapping RawSocket Writer with appropriate headers. - -rand: Random, -wrapped: *Writer, -interface: Writer, - -pub fn init(w: *Writer, buffer: []u8) !NetWriter { - std.debug.assert(buffer.len > @sizeOf(EthernetHeaders) + @sizeOf(IpHeaders) + @sizeOf(UdpHeaders)); - - var prng = Random.DefaultPrng.init(blk: { - var seed: u64 = undefined; - try posix.getrandom(mem.asBytes(&seed)); - break :blk seed; - }); - - return .{ - .rand = prng.random(), - .wrapped = w, - .interface = .{ - .vtable = &.{ - .drain = drain, - // .flush = flush, - }, - .buffer = buffer, - }, - }; -} - -fn drain(io_w: *Writer, data: []const []const u8, splat: usize) Writer.Error!usize { - const w: *NetWriter = @alignCast(@fieldParentPtr("interface", io_w)); - const headers_byte_len = comptime (EthernetHeaders.byte_len + (@bitSizeOf(IpHeaders) / 8) + @sizeOf(UdpHeaders)); - const headers: [headers_byte_len]u8 = blk: { - const ether_headers: EthernetHeaders = .{ - .dest_mac = .{ 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff }, - .src_mac = src_blk: { - var output_bytes: [6]u8 = undefined; - output_bytes[0] = 0xee; - w.rand.bytes(output_bytes[1..]); - break :src_blk output_bytes; - }, - .ether_type = 0x0800, - }; - - const total_len = Writer.countSplat(data, splat) + w.interface.end; - - const ip_headers: IpHeaders = .{ - // length of the packet minus eth header - .total_length = @intCast(headers_byte_len + total_len - EthernetHeaders.byte_len), //@intCast(total_len), - .ttl = 64, - .protocol = 0x11, - .src_ip = .{ 0xff, 0x02, 0x03, 0x04 }, - .dest_ip = .{ 0xff, 0xff, 0xff, 0xff }, - }; - - const udp_headers: UdpHeaders = .{ - .src_port = 0xbbbb, - .dest_port = 8888, - .length = @intCast(total_len + @sizeOf(UdpHeaders)), - }; - - var buf: [headers_byte_len]u8 = undefined; - var buf_w = Writer.fixed(&buf); - - _ = try ether_headers.write(&buf_w); - try ip_headers.write(&buf_w); - try buf_w.writeStruct(udp_headers, .big); - - break :blk buf; - }; - - _ = try w.wrapped.write(&headers); - const total_len = try w.wrapped.writeSplatHeader(w.interface.buffered(), data, splat); - - try w.wrapped.flush(); - return total_len - w.interface.consumeAll(); -} - -const EthernetHeaders = struct { - dest_mac: @Vector(6, u8), - - src_mac: @Vector(6, u8), - - ether_type: u16, - - fn write(hdr: EthernetHeaders, writer: *std.Io.Writer) Writer.Error!usize { - try writer.writeInt(u48, @bitCast(hdr.dest_mac), .big); - try writer.writeInt(u48, @bitCast(hdr.src_mac), .big); - try writer.writeInt(u16, hdr.ether_type, .big); - return byte_len; - } - - const byte_len = blk: { - var res: usize = 0; - res += @bitSizeOf(u48) / 8; - res += @bitSizeOf(u48) / 8; - res += @bitSizeOf(u16) / 8; - break :blk res; - }; - - fn bytes(hdr: EthernetHeaders) [byte_len]u8 { - var res: [byte_len]u8 = undefined; - hdr.write(Writer.fixed(&res)) catch unreachable; - } -}; - -const IpHeaders = extern struct { - dest_ip: @Vector(4, u8) align(1), - src_ip: @Vector(4, u8) align(1), - header_checksum: @Vector(2, u8) align(1) = .{ 0, 0 }, - protocol: u8 align(1) = 0, - ttl: u8 align(1) = 0, - fragment_and_flags: packed struct(u16) { - fragment_offset: u13 = 0, - ethernet_flags: u3 = 0, - } = .{}, - // fragment_offset: u13 = 0, - // ethernet_flags: u3 = 0, - identification: u16 align(1) = 0, - total_length: u16 align(1) = 0x04, - type_of_service: u8 align(1) = 0, - header_and_version: packed struct(u8) { - header_length: u4 = 5, - ip_version: u4 = 4, - } = .{}, - // header_length: u4 = 5, - // ip_version: u4 = 4, - - fn write(hdr: IpHeaders, writer: *std.Io.Writer) Writer.Error!void { - try writer.writeInt(u8, 0x45, .big); // ip version and header length - try writer.writeByte(hdr.type_of_service); - try writer.writeInt(u16, hdr.total_length, .big); - try writer.writeInt(u16, hdr.identification, .big); - try writer.writeInt(u16, 0x00, .big); // ethernet flags and fragment offset - try writer.writeByte(hdr.ttl); - try writer.writeByte(hdr.protocol); - try writer.writeInt(u16, @bitCast(hdr.header_checksum), .big); - try writer.writeInt(u32, @bitCast(hdr.src_ip), .big); - try writer.writeInt(u32, @bitCast(hdr.dest_ip), .big); - } - - fn bytes(hdr: IpHeaders) [@bitSizeOf(IpHeaders) / 8]u8 { - var res: [@bitSizeOf(IpHeaders) / 8]u8 = undefined; - var w = Writer.fixed(&res); - _ = hdr.write(&w) catch unreachable; - return res; - } -}; - -test IpHeaders { - var a: IpHeaders = .{ - .dest_ip = .{ 1, 2, 3, 4 }, - .src_ip = .{ 5, 6, 7, 8 }, - // .header_checksum = .{ 0x1, 0x1 }, - // .protocol = 0, - // .ttl = 0x64, - // .identification = 3, - // .type_of_service = 7, - }; - // a.dest_ip = .{ 1, 2, 3, 4 }; - // a.src_ip = .{ 5, 6, 7, 8 }; - std.debug.print("ip struct: {}\n", .{a}); - std.debug.print("dest ip: {}\n", .{a.dest_ip}); - std.debug.print("src ip: {}\n", .{a.src_ip}); - - std.debug.print("raw b : {x}\n", .{@as([@bitSizeOf(IpHeaders) / 8]u8, @bitCast(a))}); - - std.debug.print("ip bytes: {x}\n", .{a.bytes()}); - var a_struct: [@bitSizeOf(IpHeaders) / 8]u8 = undefined; - var a_struct_w = Writer.fixed(&a_struct); - _ = a_struct_w.writeStruct(a, .big) catch unreachable; - std.debug.print("ip struct: {x}\n", .{a_struct}); - try std.testing.expectEqual(a, a); -} - -const UdpHeaders = packed struct { - checksum: @Vector(2, u8) = .{ 0, 0 }, - length: u16, - dest_port: u16, - src_port: u16, - - fn write(hdr: UdpHeaders, writer: *std.Io.Writer) Writer.Error!void { - try writer.writeStruct(hdr, .big); - } - - fn bytes(hdr: UdpHeaders) [@sizeOf(UdpHeaders)]u8 { - var res: [@sizeOf(UdpHeaders)]u8 = undefined; - var w = Writer.fixed(&res); - _ = hdr.write(&w) catch unreachable; - return res; - } -}; - -test UdpHeaders { - const a: UdpHeaders = .{ - .src_port = 1, - .dest_port = 2, - .length = 3, - .checksum = .{ 0x04, 0x05 }, - }; - var a_struct: [@sizeOf(UdpHeaders)]u8 = undefined; - var a_struct_w = Writer.fixed(&a_struct); - _ = a_struct_w.writeStruct(a, .big) catch unreachable; - try std.testing.expectEqual(a.bytes(), a_struct); -} - -const std = @import("std"); -const Random = std.Random; -const posix = std.posix; -const Writer = std.Io.Writer; -const mem = std.mem; - -const NetWriter = @This(); - -const saprusOptions: std.Io.net.BindOptions = .{ - .mode = .raw, - .protocol = 0, -}; - -fn netSaprusBindIpPosix( - userdata: ?*anyopaque, - address: *const IpAddress, - options: IpAddress.BindOptions, -) IpAddress.BindError!net.Socket { - if (!have_networking) return error.NetworkDown; - const t: *Threaded = @ptrCast(@alignCast(userdata)); - const family = std.os.linux.PF.PACKET; - const socket_fd = try openSocketPosix(t, family, options); - errdefer posix.close(socket_fd); - var storage: PosixAddress = undefined; - var addr_len = addressToPosix(address, &storage); - try posixBind(t, socket_fd, &storage.any, addr_len); - try posixGetSockName(t, socket_fd, &storage.any, &addr_len); - return .{ - .handle = socket_fd, - .address = addressFromPosix(&storage), - }; -} diff --git a/src/RawSocketWriter.zig b/src/RawSocketWriter.zig deleted file mode 100644 index cffe11a..0000000 --- a/src/RawSocketWriter.zig +++ /dev/null @@ -1,32 +0,0 @@ -const std = @import("std"); -const gcat = @import("gatorcat"); -const RawSocketWriter = @This(); -const Writer = std.Io.Writer; -const assert = std.debug.assert; - -interface: Writer, -socket: gcat.nic.RawSocket, - -fn drain(io_w: *std.Io.Writer, data: []const []const u8, splat: usize) Writer.Error!usize { - const w: *RawSocketWriter = @alignCast(@fieldParentPtr("interface", io_w)); - const rem_buf = io_w.unusedCapacitySlice(); - var rem_w = Writer.fixed(rem_buf); - const res = rem_w.writeSplat(data, splat) catch rem_buf.len; - io_w.advance(res); - const buffered = io_w.buffered(); - w.socket.linkLayer().send(buffered) catch return error.WriteFailed; - _ = io_w.consumeAll(); - - return res; -} - -pub fn init(interface_name: [:0]const u8, buffer: []u8) !RawSocketWriter { - std.debug.assert(buffer.len > 0); - return .{ - .interface = .{ - .vtable = &.{ .drain = drain }, - .buffer = buffer, - }, - .socket = try .init(interface_name), - }; -} diff --git a/src/message.zig b/src/message.zig index eb15557..c705a0f 100644 --- a/src/message.zig +++ b/src/message.zig @@ -28,289 +28,365 @@ pub const MessageParseError = MessageTypeError || error{ InvalidMessage, }; -// ZERO COPY STUFF -// &payload could be a void value that is treated as a pointer to a [*]u8 -/// All Saprus messages -pub const Message = packed struct { - pub const Relay = packed struct { - dest: @Vector(4, u8), - payload: void, - - pub fn getPayload(self: *align(1) Relay) []u8 { - const len: *u16 = @ptrFromInt(@intFromPtr(self) - @sizeOf(u16)); - return @as([*]u8, @ptrCast(&self.payload))[0 .. len.* - @bitSizeOf(Relay) / 8]; +pub const RelayMessage = struct { + dest: Dest, + payload: []const u8, + + pub const @"type": PacketType = .relay; + pub const Dest = struct { + bytes: [4]u8, + + /// Asserts bytes is less than or equal to 4 bytes + pub fn fromBytes(bytes: []const u8) Dest { + var buf: [4]u8 = @splat(0); + std.debug.assert(bytes.len <= buf.len); + @memcpy(buf[0..bytes.len], bytes); + return .{ .bytes = buf }; } }; - pub const Connection = packed struct { - src_port: u16, // random number > 1024 - dest_port: u16, // random number > 1024 - seq_num: u32 = 0, - msg_id: u32 = 0, - reserved: u8 = 0, - options: ConnectionOptions = .{}, - payload: void, - - pub fn getPayload(self: *align(1) Connection) []u8 { - const len: *u16 = @ptrFromInt(@intFromPtr(self) - @sizeOf(u16)); - return @as([*]u8, @ptrCast(&self.payload))[0 .. len.* - @bitSizeOf(Connection) / 8]; - } - - fn nativeFromNetworkEndian(self: *align(1) Connection) 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: *align(1) Connection) 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(); - const SelfBytes = []align(1) u8; - - type: PacketType, - length: u16, - bytes: void = {}, - - /// Takes a byte slice, and returns a Message struct backed by the slice. - /// This properly initializes the top level headers within the slice. - /// This is used for creating new messages. For reading messages from the network, - /// see: networkBytesAsValue. - pub fn init(@"type": PacketType, bytes: []u8) *align(1) Self { - std.debug.assert(bytes.len >= @sizeOf(Self)); - const res: *align(1) Self = @ptrCast(bytes.ptr); - res.type = @"type"; - res.length = @intCast(bytes.len - @sizeOf(Self)); - return res; - } - - /// Compute the number of bytes required to store a given payload size for a given message type. - pub fn calcSize(comptime @"type": PacketType, payload_len: usize) MessageTypeError!u16 { - const header_size = @bitSizeOf(switch (@"type") { - .relay => Relay, - .connection => Connection, - .file_transfer => return MessageTypeError.NotImplementedSaprusType, - else => return MessageTypeError.UnknownSaprusType, - }) / 8; - return @intCast(payload_len + @sizeOf(Self) + header_size); - } - - fn getRelay(self: *align(1) Self) *align(1) Relay { - return std.mem.bytesAsValue(Relay, &self.bytes); - } - fn getConnection(self: *align(1) Self) *align(1) Connection { - return std.mem.bytesAsValue(Connection, &self.bytes); - } - /// Access the message Saprus payload. - pub fn getSaprusTypePayload(self: *align(1) Self) MessageTypeError!(union(PacketType) { - relay: *align(1) Relay, - file_transfer: void, - connection: *align(1) Connection, - }) { - return switch (self.type) { - .relay => .{ .relay = self.getRelay() }, - .connection => .{ .connection = self.getConnection() }, - .file_transfer => MessageTypeError.NotImplementedSaprusType, - else => MessageTypeError.UnknownSaprusType, - }; + pub fn init(dest: Dest, payload: []const u8) RelayMessage { + return .{ .dest = dest, .payload = payload }; } - /// Convert the message to native endianness from network endianness in-place. - pub fn nativeFromNetworkEndian(self: *align(1) Self) MessageTypeError!void { - self.type = @enumFromInt(bigToNative( - @typeInfo(@TypeOf(self.type)).@"enum".tag_type, - @intFromEnum(self.type), - )); - self.length = bigToNative(@TypeOf(self.length), self.length); - errdefer { - // If the payload specific headers fail, revert the top level header values - self.type = @enumFromInt(nativeToBig( - @typeInfo(@TypeOf(self.type)).@"enum".tag_type, - @intFromEnum(self.type), - )); - self.length = nativeToBig(@TypeOf(self.length), self.length); - } - switch (try self.getSaprusTypePayload()) { - .relay => {}, - .connection => |*con| con.*.nativeFromNetworkEndian(), - // We know other values are unreachable, - // because they would have returned an error from the switch condition. - else => unreachable, - } + /// Asserts that buf is large enough to fit the relay message. + pub fn toBytes(self: RelayMessage, buf: []u8) []u8 { + var out: Writer = .fixed(buf); + out.writeInt(u16, @intFromEnum(RelayMessage.type), .big) catch unreachable; + out.writeInt(u16, @intCast(self.payload.len + self.dest.bytes.len), .big) catch unreachable; + out.writeAll(&self.dest.bytes) catch unreachable; + out.writeAll(self.payload) catch unreachable; + return out.buffered(); } - /// Convert the message to network endianness from native endianness in-place. - pub fn networkFromNativeEndian(self: *align(1) Self) MessageTypeError!void { - try switch (try self.getSaprusTypePayload()) { - .relay => {}, - .connection => |*con| con.*.networkFromNativeEndian(), - .file_transfer => MessageTypeError.NotImplementedSaprusType, - else => MessageTypeError.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 fromBytes(buf: []const u8) RelayMessage { + var in: Reader = .fixed(buf); } - /// Convert network endian bytes to a native endian value in-place. - pub fn networkBytesAsValue(bytes: SelfBytes) MessageParseError!*align(1) Self { - const res = std.mem.bytesAsValue(Self, bytes); - try res.nativeFromNetworkEndian(); - return .bytesAsValue(bytes); - } - - /// Create a structured view of the bytes without initializing the length or type, - /// and without converting the endianness. - pub fn bytesAsValue(bytes: SelfBytes) MessageParseError!*align(1) Self { - const res = std.mem.bytesAsValue(Self, bytes); - return switch (res.type) { - .relay, .connection => if (bytes.len == res.length + @sizeOf(Self)) - res - else - MessageParseError.InvalidMessage, - .file_transfer => MessageParseError.NotImplementedSaprusType, - else => MessageParseError.UnknownSaprusType, + test toBytes { + var buf: [1024]u8 = undefined; + const relay: RelayMessage = .init( + .fromBytes(&.{ 172, 18, 1, 30 }), + // zig fmt: off + &[_]u8{ + 0x72, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x20, 0x65, 0x76, 0x65, + 0x6e, 0x74, 0x20, 0x6c, 0x6f, 0x67, 0x67, 0x65, 0x64 + }, + // zig fmt: on + ); + // zig fmt: off + var expected = [_]u8{ + 0x00, 0x3c, 0x00, 0x17, 0xac, 0x12, 0x01, 0x1e, 0x72, + 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x20, 0x65, 0x76, 0x65, + 0x6e, 0x74, 0x20, 0x6c, 0x6f, 0x67, 0x67, 0x65, 0x64 }; - } - - /// Deprecated. - /// If I need the bytes, I should just pass around the slice that is backing this to begin with. - pub fn asBytes(self: *align(1) Self) SelfBytes { - const size = @sizeOf(Self) + self.length; - return @as([*]align(1) u8, @ptrCast(self))[0..size]; + // zig fmt: on + try std.testing.expectEqualSlices(u8, &expected, relay.toBytes(&buf)); } }; -test "testing variable length zero copy struct" { - { - // Relay test - const payload = "Hello darkness my old friend"; - var msg_bytes: [try Message.calcSize(.relay, payload.len)]u8 align(@alignOf(Message)) = undefined; - - // Create a view of the byte slice as a Message - const msg: *align(1) Message = .init(.relay, &msg_bytes); - - { - // Set the message values - { - // These are both set by the init call. - // msg.type = .relay; - // msg.length = payload_len; - } - const relay = (try msg.getSaprusTypePayload()).relay; - relay.dest = .{ 1, 2, 3, 4 }; - @memcpy(relay.getPayload(), payload); - } - - { - // Print the message as hex using the network byte order - try msg.networkFromNativeEndian(); - // We know the error from nativeFromNetworkEndian is unreachable because - // it would have returned an error from networkFromNativeEndian. - defer msg.nativeFromNetworkEndian() catch unreachable; - std.debug.print("relay network bytes: {x}\n", .{msg_bytes}); - std.debug.print("bytes len: {d}\n", .{msg_bytes.len}); - } - - if (false) { - // Illegal behavior - std.debug.print("{any}\n", .{(try msg.getSaprusTypePayload()).connection}); - } - - try std.testing.expectEqualDeep(msg, try Message.bytesAsValue(msg.asBytes())); - } - - { - // Connection test - const payload = "Hello darkness my old friend"; - var msg_bytes: [try Message.calcSize(.connection, payload.len)]u8 align(@alignOf(Message)) = undefined; - - // Create a view of the byte slice as a Message - const msg: *align(1) Message = .init(.connection, &msg_bytes); - - { - // Initializing connection header values - const connection = (try msg.getSaprusTypePayload()).connection; - connection.src_port = 1; - connection.dest_port = 2; - connection.seq_num = 3; - connection.msg_id = 4; - connection.reserved = 5; - connection.options = @bitCast(@as(u8, 6)); - @memcpy(connection.getPayload(), payload); - } - - { - // Print the message as hex using the network byte order - try msg.networkFromNativeEndian(); - // We know the error from nativeFromNetworkEndian is unreachable because - // it would have returned an error from networkFromNativeEndian. - defer msg.nativeFromNetworkEndian() catch unreachable; - std.debug.print("connection network bytes: {x}\n", .{msg_bytes}); - std.debug.print("bytes len: {d}\n", .{msg_bytes.len}); - } - } -} +// pub const ConnectionMessage = struct { +// length: u16, +// src_port: u16, +// dest_port: u16, +// seq_num: u32 = 0, +// msg_id: u32 = 0, +// // _reserved: u8 = 0, +// options: ConnectionOptions = .{}, +// payload: []u8, + +// pub const type: PacketType = .connection; + +// /// Asserts that buf is large enough to fit the connection message. +// fn toBytes(self: ConnectionMessage, buf: []u8) []u8 { +// var out: Writer = .fixed(buf); +// out.writeInt(u16, ConnectionMessage.type, .big) catch unreachable; +// return w.buffered(); +// } +// }; + +// // ZERO COPY STUFF +// // &payload could be a void value that is treated as a pointer to a [*]u8 +// /// All Saprus messages +// pub const Message = packed struct { +// pub const Relay = packed struct { +// dest: @Vector(4, u8), +// payload: void, + +// pub fn getPayload(self: *align(1) Relay) []u8 { +// const len: *u16 = @ptrFromInt(@intFromPtr(self) - @sizeOf(u16)); +// return @as([*]u8, @ptrCast(&self.payload))[0 .. len.* - @bitSizeOf(Relay) / 8]; +// } +// }; +// pub const Connection = packed struct { +// src_port: u16, // random number > 1024 +// dest_port: u16, // random number > 1024 +// seq_num: u32 = 0, +// msg_id: u32 = 0, +// reserved: u8 = 0, +// options: ConnectionOptions = .{}, +// payload: void, + +// pub fn getPayload(self: *align(1) Connection) []u8 { +// const len: *u16 = @ptrFromInt(@intFromPtr(self) - @sizeOf(u16)); +// return @as([*]u8, @ptrCast(&self.payload))[0 .. len.* - @bitSizeOf(Connection) / 8]; +// } + +// fn nativeFromNetworkEndian(self: *align(1) Connection) 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: *align(1) Connection) 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(); +// const SelfBytes = []align(1) u8; + +// type: PacketType, +// length: u16, +// bytes: void = {}, + +// /// Takes a byte slice, and returns a Message struct backed by the slice. +// /// This properly initializes the top level headers within the slice. +// /// This is used for creating new messages. For reading messages from the network, +// /// see: networkBytesAsValue. +// pub fn init(@"type": PacketType, bytes: []u8) *align(1) Self { +// std.debug.assert(bytes.len >= @sizeOf(Self)); +// const res: *align(1) Self = @ptrCast(bytes.ptr); +// res.type = @"type"; +// res.length = @intCast(bytes.len - @sizeOf(Self)); +// return res; +// } + +// /// Compute the number of bytes required to store a given payload size for a given message type. +// pub fn calcSize(comptime @"type": PacketType, payload_len: usize) MessageTypeError!u16 { +// const header_size = @bitSizeOf(switch (@"type") { +// .relay => Relay, +// .connection => Connection, +// .file_transfer => return MessageTypeError.NotImplementedSaprusType, +// else => return MessageTypeError.UnknownSaprusType, +// }) / 8; +// return @intCast(payload_len + @sizeOf(Self) + header_size); +// } + +// fn getRelay(self: *align(1) Self) *align(1) Relay { +// return std.mem.bytesAsValue(Relay, &self.bytes); +// } +// fn getConnection(self: *align(1) Self) *align(1) Connection { +// return std.mem.bytesAsValue(Connection, &self.bytes); +// } + +// /// Access the message Saprus payload. +// pub fn getSaprusTypePayload(self: *align(1) Self) MessageTypeError!(union(PacketType) { +// relay: *align(1) Relay, +// file_transfer: void, +// connection: *align(1) Connection, +// }) { +// return switch (self.type) { +// .relay => .{ .relay = self.getRelay() }, +// .connection => .{ .connection = self.getConnection() }, +// .file_transfer => MessageTypeError.NotImplementedSaprusType, +// else => MessageTypeError.UnknownSaprusType, +// }; +// } + +// /// Convert the message to native endianness from network endianness in-place. +// pub fn nativeFromNetworkEndian(self: *align(1) Self) MessageTypeError!void { +// self.type = @enumFromInt(bigToNative( +// @typeInfo(@TypeOf(self.type)).@"enum".tag_type, +// @intFromEnum(self.type), +// )); +// self.length = bigToNative(@TypeOf(self.length), self.length); +// errdefer { +// // If the payload specific headers fail, revert the top level header values +// self.type = @enumFromInt(nativeToBig( +// @typeInfo(@TypeOf(self.type)).@"enum".tag_type, +// @intFromEnum(self.type), +// )); +// self.length = nativeToBig(@TypeOf(self.length), self.length); +// } +// switch (try self.getSaprusTypePayload()) { +// .relay => {}, +// .connection => |*con| con.*.nativeFromNetworkEndian(), +// // We know other values are unreachable, +// // because they would have returned an error from the switch condition. +// else => unreachable, +// } +// } + +// /// Convert the message to network endianness from native endianness in-place. +// pub fn networkFromNativeEndian(self: *align(1) Self) MessageTypeError!void { +// try switch (try self.getSaprusTypePayload()) { +// .relay => {}, +// .connection => |*con| con.*.networkFromNativeEndian(), +// .file_transfer => MessageTypeError.NotImplementedSaprusType, +// else => MessageTypeError.UnknownSaprusType, +// }; +// self.type = @enumFromInt(nativeToBig( +// @typeInfo(@TypeOf(self.type)).@"enum".tag_type, +// @intFromEnum(self.type), +// )); +// self.length = nativeToBig(@TypeOf(self.length), self.length); +// } + +// /// Convert network endian bytes to a native endian value in-place. +// pub fn networkBytesAsValue(bytes: SelfBytes) MessageParseError!*align(1) Self { +// const res = std.mem.bytesAsValue(Self, bytes); +// try res.nativeFromNetworkEndian(); +// return .bytesAsValue(bytes); +// } + +// /// Create a structured view of the bytes without initializing the length or type, +// /// and without converting the endianness. +// pub fn bytesAsValue(bytes: SelfBytes) MessageParseError!*align(1) Self { +// const res = std.mem.bytesAsValue(Self, bytes); +// return switch (res.type) { +// .relay, .connection => if (bytes.len == res.length + @sizeOf(Self)) +// res +// else +// MessageParseError.InvalidMessage, +// .file_transfer => MessageParseError.NotImplementedSaprusType, +// else => MessageParseError.UnknownSaprusType, +// }; +// } + +// /// Deprecated. +// /// If I need the bytes, I should just pass around the slice that is backing this to begin with. +// pub fn asBytes(self: *align(1) Self) SelfBytes { +// const size = @sizeOf(Self) + self.length; +// return @as([*]align(1) u8, @ptrCast(self))[0..size]; +// } +// }; + +// test "testing variable length zero copy struct" { +// { +// // Relay test +// const payload = "Hello darkness my old friend"; +// var msg_bytes: [try Message.calcSize(.relay, payload.len)]u8 align(@alignOf(Message)) = undefined; + +// // Create a view of the byte slice as a Message +// const msg: *align(1) Message = .init(.relay, &msg_bytes); + +// { +// // Set the message values +// { +// // These are both set by the init call. +// // msg.type = .relay; +// // msg.length = payload_len; +// } +// const relay = (try msg.getSaprusTypePayload()).relay; +// relay.dest = .{ 1, 2, 3, 4 }; +// @memcpy(relay.getPayload(), payload); +// } + +// { +// // Print the message as hex using the network byte order +// try msg.networkFromNativeEndian(); +// // We know the error from nativeFromNetworkEndian is unreachable because +// // it would have returned an error from networkFromNativeEndian. +// defer msg.nativeFromNetworkEndian() catch unreachable; +// std.debug.print("relay network bytes: {x}\n", .{msg_bytes}); +// std.debug.print("bytes len: {d}\n", .{msg_bytes.len}); +// } + +// if (false) { +// // Illegal behavior +// std.debug.print("{any}\n", .{(try msg.getSaprusTypePayload()).connection}); +// } + +// try std.testing.expectEqualDeep(msg, try Message.bytesAsValue(msg.asBytes())); +// } + +// { +// // Connection test +// const payload = "Hello darkness my old friend"; +// var msg_bytes: [try Message.calcSize(.connection, payload.len)]u8 align(@alignOf(Message)) = undefined; + +// // Create a view of the byte slice as a Message +// const msg: *align(1) Message = .init(.connection, &msg_bytes); + +// { +// // Initializing connection header values +// const connection = (try msg.getSaprusTypePayload()).connection; +// connection.src_port = 1; +// connection.dest_port = 2; +// connection.seq_num = 3; +// connection.msg_id = 4; +// connection.reserved = 5; +// connection.options = @bitCast(@as(u8, 6)); +// @memcpy(connection.getPayload(), payload); +// } + +// { +// // Print the message as hex using the network byte order +// try msg.networkFromNativeEndian(); +// // We know the error from nativeFromNetworkEndian is unreachable because +// // it would have returned an error from networkFromNativeEndian. +// defer msg.nativeFromNetworkEndian() catch unreachable; +// std.debug.print("connection network bytes: {x}\n", .{msg_bytes}); +// std.debug.print("bytes len: {d}\n", .{msg_bytes.len}); +// } +// } +// } const std = @import("std"); 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" { - if (false) { - const gpa = std.testing.allocator; - const msg = Message{ - .relay = .{ - .header = .{ .dest = .{ 255, 255, 255, 255 } }, - .payload = "Hello darkness my old friend", - }, - }; - - const to_bytes = try msg.toBytes(gpa); - defer gpa.free(to_bytes); - - const from_bytes = try Message.fromBytes(to_bytes, gpa); - defer from_bytes.deinit(gpa); - - try std.testing.expectEqualDeep(msg, from_bytes); - } - return error.SkipZigTest; -} - -test "Round trip Connection toBytes and fromBytes" { - if (false) { - const gpa = std.testing.allocator; - const msg = Message{ - .connection = .{ - .header = .{ - .src_port = 0, - .dest_port = 0, - }, - .payload = "Hello darkness my old friend", - }, - }; - - const to_bytes = try msg.toBytes(gpa); - defer gpa.free(to_bytes); - - const from_bytes = try Message.fromBytes(to_bytes, gpa); - defer from_bytes.deinit(gpa); - - try std.testing.expectEqualDeep(msg, from_bytes); - } - return error.SkipZigTest; -} +const Writer = std.Io.Writer; + +// const asBytes = std.mem.asBytes; +// const nativeToBig = std.mem.nativeToBig; +// const bigToNative = std.mem.bigToNative; + +// test "Round trip Relay toBytes and fromBytes" { +// if (true) return error.SkipZigTest; +// const gpa = std.testing.allocator; +// const msg = Message{ +// .relay = .{ +// .header = .{ .dest = .{ 255, 255, 255, 255 } }, +// .payload = "Hello darkness my old friend", +// }, +// }; + +// const to_bytes = try msg.toBytes(gpa); +// defer gpa.free(to_bytes); + +// const from_bytes = try Message.fromBytes(to_bytes, gpa); +// defer from_bytes.deinit(gpa); + +// try std.testing.expectEqualDeep(msg, from_bytes); +// } + +// test "Round trip Connection toBytes and fromBytes" { +// if (false) { +// const gpa = std.testing.allocator; +// const msg = Message{ +// .connection = .{ +// .header = .{ +// .src_port = 0, +// .dest_port = 0, +// }, +// .payload = "Hello darkness my old friend", +// }, +// }; + +// const to_bytes = try msg.toBytes(gpa); +// defer gpa.free(to_bytes); + +// const from_bytes = try Message.fromBytes(to_bytes, gpa); +// defer from_bytes.deinit(gpa); + +// try std.testing.expectEqualDeep(msg, from_bytes); +// } +// return error.SkipZigTest; +// } test { std.testing.refAllDeclsRecursive(@This()); diff --git a/src/root.zig b/src/root.zig index ed3648a..5aa9d9d 100644 --- a/src/root.zig +++ b/src/root.zig @@ -1,7 +1,5 @@ pub const Client = @import("Client.zig"); pub const Connection = @import("Connection.zig"); -pub const RawSocketWriter = @import("RawSocketWriter.zig"); -// pub const NetWriter = @import("NetWriter.zig"); const msg = @import("message.zig"); |
