it works well!

This commit is contained in:
2025-09-23 16:16:12 -04:00
parent b8313e4fa4
commit b06cb6dada
2 changed files with 108 additions and 152 deletions

View File

@@ -30,166 +30,60 @@ pub fn deinit(self: *Self) void {
/// Used for relay messages and connection handshake. /// Used for relay messages and connection handshake.
/// Assumes Client .init has been called. /// 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 writer = self.writer;
// const EthernetHeaders = packed struct { const total_len = ((@bitSizeOf(EthernetHeaders) + @bitSizeOf(IpHeaders) + @bitSizeOf(UdpHeaders)) / 8) + msg_bytes.len;
// 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;
std.debug.assert(writer.buffer.len >= total_len); std.debug.assert(writer.buffer.len >= total_len);
_ = writer.consumeAll(); _ = writer.consumeAll();
// var ether_headers: EthernetHeaders = .{ const ether_headers: EthernetHeaders = .{
// .dest_mac = .{ 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff }, .dest_mac = .{ 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff },
// // .src_mac = .{ 0xee, 0xee, 0xee, 0xee, 0xee, 0xee }, .src_mac = .{ 0xee, 0xee, 0xee, 0xee, 0xee, 0xee },
// .src_mac = blk: { // .src_mac = blk: {
// var output_bytes: [6]u8 = undefined; // var output_bytes: [6]u8 = undefined;
// // const r_bytes = try writer.writableArray(6); // // const r_bytes = try writer.writableArray(6);
// self.rand.bytes(&output_bytes); // self.rand.bytes(&output_bytes);
// break :blk output_bytes; // break :blk output_bytes;
// }, // },
// .ether_type = 0x0800, .ether_type = 0x0800,
// }; };
var ip_headers: IpHeaders = .{ // @compileLog((@bitSizeOf(EthernetHeaders) / 8));
const ip_headers: IpHeaders = .{
// .ip_version = 0x4, // .ip_version = 0x4,
// .header_length = 0x5, // .header_length = 0x5,
// .total_length = 130, //@intCast(total_len - 8), // 8 is the ethernet frame length (macs + type) .total_length = @intCast(total_len - 92),
.total_length = 0x00,
.ttl = 0x64, .ttl = 0x64,
.protocol = 0x11, .protocol = 0x11,
.src_ip = .{ 0xff, 0x02, 0x03, 0x04 }, .src_ip = .{ 0xff, 0x02, 0x03, 0x04 },
.dest_ip = .{ 0xff, 0xff, 0xff, 0xff }, .dest_ip = .{ 0xff, 0xff, 0xff, 0xff },
}; };
var udp_headers: UdpHeaders = .{ const udp_headers: UdpHeaders = .{
.src_port = .{ 0, 0x01 }, .src_port = 0xbbbb,
.dest_port = .{ 0xb8, 0x22 }, .dest_port = 8888,
.length = @intCast(msg_bytes.len), .length = @intCast(msg_bytes.len),
}; };
_ = &ip_headers;
_ = &udp_headers;
// _ = &ether_headers;
// _ = try writer.write(&@as([@bitSizeOf(UdpHeaders) / 8]u8, @bitCast(headers))); try ether_headers.write(writer);
try ip_headers.write(writer);
try udp_headers.write(writer);
// std.mem.byteSwapAllFields(EthernetHeaders, &ether_headers); // Saprus
// try writer.writeStruct(ether_headers, native_endian); 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();
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
// // Set IPv4 version to 4
// try writer.writeByte(0x45);
// // 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]}); 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(); try writer.flush();
} }
// fn broadcastSaprusMessage(msg_bytes: []align(@alignOf(SaprusMessage)) u8) !void {} // fn broadcastSaprusMessage(msg_bytes: []align(@alignOf(SaprusMessage)) u8) !void {}
fn broadcastSaprusMessage(msg_bytes: []align(@alignOf(SaprusMessage)) u8, udp_port: u16) !void { fn broadcastSaprusMessage(msg_bytes: []u8, udp_port: u16) !void {
const msg: *SaprusMessage = try .bytesAsValue(msg_bytes); const msg: *align(1) SaprusMessage = try .bytesAsValue(msg_bytes);
try msg.networkFromNativeEndian(); try msg.networkFromNativeEndian();
defer msg.nativeFromNetworkEndian() catch unreachable; defer msg.nativeFromNetworkEndian() catch unreachable;
@@ -222,7 +116,7 @@ pub fn sendRelay(self: *Self, payload: []const u8, dest: [4]u8) !void {
.relay, .relay,
base64Enc.calcSize(payload.len), 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; const relay = (try msg.getSaprusTypePayload()).relay;
relay.dest = dest; relay.dest = dest;
@@ -238,15 +132,15 @@ fn randomPort(self: Self) u16 {
pub fn sendInitialConnection( pub fn sendInitialConnection(
self: Self, self: Self,
payload: []const u8, payload: []const u8,
output_bytes: []align(@alignOf(SaprusMessage)) u8, output_bytes: []u8,
initial_port: u16, initial_port: u16,
) !*SaprusMessage { ) !*align(1) SaprusMessage {
const dest_port = self.randomPort(); const dest_port = self.randomPort();
const msg_bytes = output_bytes[0..try SaprusMessage.calcSize( const msg_bytes = output_bytes[0..try SaprusMessage.calcSize(
.connection, .connection,
base64Enc.calcSize(payload.len), 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; const connection = (try msg.getSaprusTypePayload()).connection;
connection.src_port = initial_port; connection.src_port = initial_port;
@@ -261,7 +155,7 @@ pub fn sendInitialConnection(
pub fn connect(self: Self, payload: []const u8) !?SaprusConnection { pub fn connect(self: Self, payload: []const u8) !?SaprusConnection {
const initial_port = self.randomPort(); 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); var sock = try network.Socket.create(.ipv4, .udp);
defer sock.close(); defer sock.close();
@@ -294,6 +188,68 @@ pub fn connect(self: Self, payload: []const u8) !?SaprusConnection {
return null; 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 SaprusMessage = @import("message.zig").Message;
const SaprusConnection = @import("Connection.zig"); const SaprusConnection = @import("Connection.zig");

View File

@@ -71,7 +71,7 @@ pub const Message = packed struct {
}; };
const Self = @This(); const Self = @This();
const SelfBytes = []align(@alignOf(Self)) u8; const SelfBytes = []align(1) u8;
type: PacketType, type: PacketType,
length: u16, length: u16,
@@ -81,9 +81,9 @@ pub const Message = packed struct {
/// This properly initializes the top level headers within 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, /// This is used for creating new messages. For reading messages from the network,
/// see: networkBytesAsValue. /// 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)); 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.type = @"type";
res.length = @intCast(bytes.len - @sizeOf(Self)); res.length = @intCast(bytes.len - @sizeOf(Self));
return res; return res;
@@ -100,15 +100,15 @@ pub const Message = packed struct {
return @intCast(payload_len + @sizeOf(Self) + header_size); 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); 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); return std.mem.bytesAsValue(Connection, &self.bytes);
} }
/// Access the message Saprus payload. /// 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, relay: *align(1) Relay,
file_transfer: void, file_transfer: void,
connection: *align(1) Connection, connection: *align(1) Connection,
@@ -122,7 +122,7 @@ pub const Message = packed struct {
} }
/// Convert the message to native endianness from network endianness in-place. /// 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( self.type = @enumFromInt(bigToNative(
@typeInfo(@TypeOf(self.type)).@"enum".tag_type, @typeInfo(@TypeOf(self.type)).@"enum".tag_type,
@intFromEnum(self.type), @intFromEnum(self.type),
@@ -146,7 +146,7 @@ pub const Message = packed struct {
} }
/// Convert the message to network endianness from native endianness in-place. /// 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()) { try switch (try self.getSaprusTypePayload()) {
.relay => {}, .relay => {},
.connection => |*con| con.*.networkFromNativeEndian(), .connection => |*con| con.*.networkFromNativeEndian(),
@@ -161,7 +161,7 @@ pub const Message = packed struct {
} }
/// Convert network endian bytes to a native endian value in-place. /// 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); const res = std.mem.bytesAsValue(Self, bytes);
try res.nativeFromNetworkEndian(); try res.nativeFromNetworkEndian();
return .bytesAsValue(bytes); 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, /// Create a structured view of the bytes without initializing the length or type,
/// and without converting the endianness. /// 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); const res = std.mem.bytesAsValue(Self, bytes);
return switch (res.type) { return switch (res.type) {
.relay, .connection => if (bytes.len == res.length + @sizeOf(Self)) .relay, .connection => if (bytes.len == res.length + @sizeOf(Self))
@@ -183,9 +183,9 @@ pub const Message = packed struct {
/// Deprecated. /// Deprecated.
/// If I need the bytes, I should just pass around the slice that is backing this to begin with. /// 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; 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];
} }
}; };