summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRobby Zambito <contact@robbyzambito.me>2025-09-23 16:16:12 -0400
committerRobby Zambito <contact@robbyzambito.me>2025-09-23 16:22:57 -0400
commitb06cb6dadac809322b6a293fbedf401870028d6e (patch)
tree4f53d71d846f6a0aed6b0f95199d45b2c35bf8e6
parentb8313e4fa4ced3462e2fadaa123c917fcb063c18 (diff)
it works well!
-rw-r--r--src/Client.zig238
-rw-r--r--src/message.zig24
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;
- // _ = &ether_headers;
-
- // _ = try writer.write(&@as([@bitSizeOf(UdpHeaders) / 8]u8, @bitCast(headers)));
-
- // std.mem.byteSwapAllFields(EthernetHeaders, &ether_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];
}
};