diff options
| author | Robby Zambito <contact@robbyzambito.me> | 2025-09-23 16:16:12 -0400 |
|---|---|---|
| committer | Robby Zambito <contact@robbyzambito.me> | 2025-09-23 16:22:57 -0400 |
| commit | b06cb6dadac809322b6a293fbedf401870028d6e (patch) | |
| tree | 4f53d71d846f6a0aed6b0f95199d45b2c35bf8e6 | |
| parent | b8313e4fa4ced3462e2fadaa123c917fcb063c18 (diff) | |
it works well!
| -rw-r--r-- | src/Client.zig | 238 | ||||
| -rw-r--r-- | src/message.zig | 24 |
2 files changed, 109 insertions, 153 deletions
diff --git a/src/Client.zig b/src/Client.zig index 0c82129..86b08d4 100644 --- a/src/Client.zig +++ b/src/Client.zig @@ -30,166 +30,60 @@ pub fn deinit(self: *Self) void { /// Used for relay messages and connection handshake. /// Assumes Client .init has been called. -fn broadcastInitialInterestMessage(self: *Self, msg_bytes: []align(@alignOf(SaprusMessage)) u8) !void { +fn broadcastInitialInterestMessage(self: *Self, msg_bytes: []u8) !void { const writer = self.writer; - // const EthernetHeaders = packed struct { - // dest_mac: @Vector(6, u8), - - // src_mac: @Vector(6, u8), - - // ether_type: u16, - // }; - - const IpHeaders = packed struct { - _: u8 = 0x45, - // ip_version: u4, - // header_length: u4 = 0, - type_of_service: u8 = 0, - total_length: u16 = 0x04, - - identification: u16 = 0, - __: u16 = 0x0, - // ethernet_flags: u3 = 0, - // fragment_offset: u13 = 0, - ttl: u8 = 0, - protocol: u8 = 0, - - header_checksum: @Vector(2, u8) = .{ 0, 0 }, - src_ip: @Vector(4, u8), - - dest_ip: @Vector(4, u8), - }; - - const UdpHeaders = packed struct { - src_port: @Vector(2, u8), - - dest_port: @Vector(2, u8), - length: u16, - checksum: @Vector(2, u8) = .{ 0, 0 }, - }; - - // const total_len = ((@bitSizeOf(IpHeaders) + @bitSizeOf(UdpHeaders)) / 8) + msg_bytes.len; - const total_len = 130; + const total_len = ((@bitSizeOf(EthernetHeaders) + @bitSizeOf(IpHeaders) + @bitSizeOf(UdpHeaders)) / 8) + msg_bytes.len; std.debug.assert(writer.buffer.len >= total_len); _ = writer.consumeAll(); - // var ether_headers: EthernetHeaders = .{ - // .dest_mac = .{ 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff }, - // // .src_mac = .{ 0xee, 0xee, 0xee, 0xee, 0xee, 0xee }, - // .src_mac = blk: { - // var output_bytes: [6]u8 = undefined; - // // const r_bytes = try writer.writableArray(6); - // self.rand.bytes(&output_bytes); - // break :blk output_bytes; - // }, - // .ether_type = 0x0800, - // }; - - var ip_headers: IpHeaders = .{ + const ether_headers: EthernetHeaders = .{ + .dest_mac = .{ 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff }, + .src_mac = .{ 0xee, 0xee, 0xee, 0xee, 0xee, 0xee }, + // .src_mac = blk: { + // var output_bytes: [6]u8 = undefined; + // // const r_bytes = try writer.writableArray(6); + // self.rand.bytes(&output_bytes); + // break :blk output_bytes; + // }, + .ether_type = 0x0800, + }; + + // @compileLog((@bitSizeOf(EthernetHeaders) / 8)); + const ip_headers: IpHeaders = .{ // .ip_version = 0x4, // .header_length = 0x5, - // .total_length = 130, //@intCast(total_len - 8), // 8 is the ethernet frame length (macs + type) - .total_length = 0x00, + .total_length = @intCast(total_len - 92), .ttl = 0x64, .protocol = 0x11, .src_ip = .{ 0xff, 0x02, 0x03, 0x04 }, .dest_ip = .{ 0xff, 0xff, 0xff, 0xff }, }; - var udp_headers: UdpHeaders = .{ - .src_port = .{ 0, 0x01 }, - .dest_port = .{ 0xb8, 0x22 }, + const udp_headers: UdpHeaders = .{ + .src_port = 0xbbbb, + .dest_port = 8888, .length = @intCast(msg_bytes.len), }; - _ = &ip_headers; - _ = &udp_headers; - // _ = ðer_headers; - - // _ = try writer.write(&@as([@bitSizeOf(UdpHeaders) / 8]u8, @bitCast(headers))); - - // std.mem.byteSwapAllFields(EthernetHeaders, ðer_headers); - // try writer.writeStruct(ether_headers, native_endian); - - std.mem.byteSwapAllFields(IpHeaders, &ip_headers); - try writer.writeStruct(ip_headers, native_endian); - - // std.mem.byteSwapAllFields(UdpHeaders, &udp_headers); - // try writer.writeStruct(udp_headers, native_endian); - - // // Ensure buffer is large enough - // std.debug.assert(writer.buffer.len > 38 + msg_bytes.len); - - // // Ensure writer is clean - // writer.consumeAll(); - - // // Destination MAC addr to FF:FF:FF:FF:FF:FF - // try writer.write(); - - // // Source MAC to random bytes - // { - // } - - // // 96 bits - - // // Set EtherType to IPv4 - // try writer.write(.{ 0x08, 0x00 }); - // // 112 bits + try ether_headers.write(writer); + try ip_headers.write(writer); + try udp_headers.write(writer); - // // Set IPv4 version to 4 - // try writer.writeByte(0x45); + // Saprus + const msg_target_bytes = try writer.writableSlice(msg_bytes.len); + @memcpy(msg_target_bytes, msg_bytes); + var msg_target: *align(1) SaprusMessage = try .bytesAsValue(msg_target_bytes); + try msg_target.networkFromNativeEndian(); - // // 120 bits - - // // Unset section (Version, IHL, ToS) - // writer.advance(2); - - // // 136 bits - - // // Total length - // try write.writeInt(u16, 38 + msg_bytes.len); - - // // Destination broadcast - // writer.splatByte(0xff, 0x22 - 0x1e); - - // var packet_bytes: [_]u8 = comptime blk: { - // var b: [max_message_size]u8 = @splat(0); - - // for (0x1e..0x22) |i| { - // b[i] = 0xff; - // } - - // // Set TTL - // b[0x16] = 0x40; - - // // Set IPv4 protocol to UDP - // b[0x17] = 0x11; - - // // Set interest filter value to 8888. - // b[0x24] = 0x22; - // b[0x25] = 0xb8; - // break :blk &b; - // }; - var msg: *SaprusMessage = try .bytesAsValue(msg_bytes); - try msg.networkFromNativeEndian(); - defer msg.nativeFromNetworkEndian() catch unreachable; - - // std.debug.print("headers: {x}\n", .{@as([@bitSizeOf(UdpHeaders) / 8]u8, @bitCast(headers))}); std.debug.print("bytes: {x}\n", .{writer.buffer[0..writer.end]}); - _ = try writer.write(msg_bytes); - - // The byte position within the packet that the saprus message starts at. - // const saprus_start_byte = 42; - // @memcpy(packet_bytes[saprus_start_byte .. saprus_start_byte + msg_bytes.len], msg_bytes); - // _ = try writer.write(packet_bytes[0 .. saprus_start_byte + msg_bytes.len]); try writer.flush(); } // fn broadcastSaprusMessage(msg_bytes: []align(@alignOf(SaprusMessage)) u8) !void {} -fn broadcastSaprusMessage(msg_bytes: []align(@alignOf(SaprusMessage)) u8, udp_port: u16) !void { - const msg: *SaprusMessage = try .bytesAsValue(msg_bytes); +fn broadcastSaprusMessage(msg_bytes: []u8, udp_port: u16) !void { + const msg: *align(1) SaprusMessage = try .bytesAsValue(msg_bytes); try msg.networkFromNativeEndian(); defer msg.nativeFromNetworkEndian() catch unreachable; @@ -222,7 +116,7 @@ pub fn sendRelay(self: *Self, payload: []const u8, dest: [4]u8) !void { .relay, base64Enc.calcSize(payload.len), )]; - const msg: *SaprusMessage = .init(.relay, msg_bytes); + const msg: *align(1) SaprusMessage = .init(.relay, msg_bytes); const relay = (try msg.getSaprusTypePayload()).relay; relay.dest = dest; @@ -238,15 +132,15 @@ fn randomPort(self: Self) u16 { pub fn sendInitialConnection( self: Self, payload: []const u8, - output_bytes: []align(@alignOf(SaprusMessage)) u8, + output_bytes: []u8, initial_port: u16, -) !*SaprusMessage { +) !*align(1) SaprusMessage { const dest_port = self.randomPort(); const msg_bytes = output_bytes[0..try SaprusMessage.calcSize( .connection, base64Enc.calcSize(payload.len), )]; - const msg: *SaprusMessage = .init(.connection, msg_bytes); + const msg: *align(1) SaprusMessage = .init(.connection, msg_bytes); const connection = (try msg.getSaprusTypePayload()).connection; connection.src_port = initial_port; @@ -261,7 +155,7 @@ pub fn sendInitialConnection( pub fn connect(self: Self, payload: []const u8) !?SaprusConnection { const initial_port = self.randomPort(); - var initial_conn_res: ?*SaprusMessage = null; + var initial_conn_res: ?*align(1) SaprusMessage = null; var sock = try network.Socket.create(.ipv4, .udp); defer sock.close(); @@ -294,6 +188,68 @@ pub fn connect(self: Self, payload: []const u8) !?SaprusConnection { return null; } +const EthernetHeaders = struct { + dest_mac: @Vector(6, u8), + + src_mac: @Vector(6, u8), + + ether_type: u16, + + fn write(hdr: @This(), writer: *std.Io.Writer) !void { + 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); + } +}; + +const IpHeaders = struct { + _: u8 = 0x45, + // ip_version: u4, + // header_length: u4 = 0, + type_of_service: u8 = 0, + total_length: u16 = 0x04, + + identification: u16 = 0, + __: u16 = 0x0, + // ethernet_flags: u3 = 0, + // fragment_offset: u13 = 0, + ttl: u8 = 0, + protocol: u8 = 0, + + header_checksum: @Vector(2, u8) = .{ 0, 0 }, + src_ip: @Vector(4, u8), + + dest_ip: @Vector(4, u8), + + fn write(hdr: @This(), writer: *std.Io.Writer) !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); + } +}; + +const UdpHeaders = packed struct { + src_port: u16, + + dest_port: u16, + length: u16, + checksum: @Vector(2, u8) = .{ 0, 0 }, + + fn write(hdr: @This(), writer: *std.Io.Writer) !void { + try writer.writeInt(u16, hdr.src_port, .big); + try writer.writeInt(u16, hdr.dest_port, .big); + try writer.writeInt(u16, hdr.length, .big); + try writer.writeInt(u16, @bitCast(hdr.checksum), .big); + } +}; + const SaprusMessage = @import("message.zig").Message; const SaprusConnection = @import("Connection.zig"); diff --git a/src/message.zig b/src/message.zig index 1308d54..59864ba 100644 --- a/src/message.zig +++ b/src/message.zig @@ -71,7 +71,7 @@ pub const Message = packed struct { }; const Self = @This(); - const SelfBytes = []align(@alignOf(Self)) u8; + const SelfBytes = []align(1) u8; type: PacketType, length: u16, @@ -81,9 +81,9 @@ pub const Message = packed struct { /// 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: []align(@alignOf(Self)) u8) *Self { + pub fn init(@"type": PacketType, bytes: []u8) *align(1) Self { std.debug.assert(bytes.len >= @sizeOf(Self)); - const res: *Self = @ptrCast(bytes.ptr); + const res: *align(1) Self = @ptrCast(bytes.ptr); res.type = @"type"; res.length = @intCast(bytes.len - @sizeOf(Self)); return res; @@ -100,15 +100,15 @@ pub const Message = packed struct { return @intCast(payload_len + @sizeOf(Self) + header_size); } - fn getRelay(self: *Self) *align(1) Relay { + fn getRelay(self: *align(1) Self) *align(1) Relay { return std.mem.bytesAsValue(Relay, &self.bytes); } - fn getConnection(self: *Self) *align(1) Connection { + 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: *Self) MessageTypeError!(union(PacketType) { + pub fn getSaprusTypePayload(self: *align(1) Self) MessageTypeError!(union(PacketType) { relay: *align(1) Relay, file_transfer: void, connection: *align(1) Connection, @@ -122,7 +122,7 @@ pub const Message = packed struct { } /// Convert the message to native endianness from network endianness in-place. - pub fn nativeFromNetworkEndian(self: *Self) MessageTypeError!void { + pub fn nativeFromNetworkEndian(self: *align(1) Self) MessageTypeError!void { self.type = @enumFromInt(bigToNative( @typeInfo(@TypeOf(self.type)).@"enum".tag_type, @intFromEnum(self.type), @@ -146,7 +146,7 @@ pub const Message = packed struct { } /// Convert the message to network endianness from native endianness in-place. - pub fn networkFromNativeEndian(self: *Self) MessageTypeError!void { + pub fn networkFromNativeEndian(self: *align(1) Self) MessageTypeError!void { try switch (try self.getSaprusTypePayload()) { .relay => {}, .connection => |*con| con.*.networkFromNativeEndian(), @@ -161,7 +161,7 @@ pub const Message = packed struct { } /// Convert network endian bytes to a native endian value in-place. - pub fn networkBytesAsValue(bytes: SelfBytes) MessageParseError!*Self { + pub fn networkBytesAsValue(bytes: SelfBytes) MessageParseError!*align(1) Self { const res = std.mem.bytesAsValue(Self, bytes); try res.nativeFromNetworkEndian(); return .bytesAsValue(bytes); @@ -169,7 +169,7 @@ pub const Message = packed struct { /// Create a structured view of the bytes without initializing the length or type, /// and without converting the endianness. - pub fn bytesAsValue(bytes: SelfBytes) MessageParseError!*Self { + 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)) @@ -183,9 +183,9 @@ pub const Message = packed struct { /// Deprecated. /// If I need the bytes, I should just pass around the slice that is backing this to begin with. - pub fn asBytes(self: *Self) SelfBytes { + pub fn asBytes(self: *align(1) Self) SelfBytes { const size = @sizeOf(Self) + self.length; - return @as([*]align(@alignOf(Self)) u8, @ptrCast(self))[0..size]; + return @as([*]align(1) u8, @ptrCast(self))[0..size]; } }; |
