const base64_enc = std.base64.standard.Encoder; const base64_dec = std.base64.standard.Decoder; const Client = @This(); const max_message_size = 2048; socket: RawSocket, pub fn init() !Client { const socket: RawSocket = try .init(); return .{ .socket = socket, }; } pub fn deinit(self: *Client) void { self.socket.deinit(); self.* = undefined; } pub fn sendRelay(self: *Client, io: Io, payload: []const u8, dest: [4]u8) !void { const rand = blk: { const io_source: std.Random.IoSource = .{ .io = io }; break :blk io_source.interface(); }; var headers: EthIpUdp = .{ .src_mac = self.socket.mac, .ip = .{ .id = rand.int(u16), .src_addr = 0, //rand.int(u32), .dst_addr = @bitCast([_]u8{ 255, 255, 255, 255 }), .len = undefined, }, .udp = .{ .src_port = rand.intRangeAtMost(u16, 1025, std.math.maxInt(u16)), .dst_port = 8888, .len = undefined, }, }; const relay: SaprusMessage = .{ .relay = .{ .dest = .fromBytes(&dest), .payload = payload, }, }; var relay_buf: [max_message_size - (@bitSizeOf(EthIpUdp) / 8)]u8 = undefined; const relay_bytes = relay.toBytes(&relay_buf); headers.setPayloadLen(relay_bytes.len); const full_msg = blk: { var msg_buf: [max_message_size]u8 = undefined; var msg_w: Writer = .fixed(&msg_buf); msg_w.writeAll(&headers.toBytes()) catch unreachable; msg_w.writeAll(relay_bytes) catch unreachable; break :blk msg_w.buffered(); }; try self.socket.send(full_msg); } pub fn connect(self: Client, io: Io, payload: []const u8) !SaprusConnection { const rand = blk: { const io_source: std.Random.IoSource = .{ .io = io }; break :blk io_source.interface(); }; var headers: EthIpUdp = .{ .src_mac = self.socket.mac, .ip = .{ .id = rand.int(u16), .src_addr = 0, //rand.int(u32), .dst_addr = @bitCast([_]u8{ 255, 255, 255, 255 }), .len = undefined, }, .udp = .{ .src_port = rand.intRangeAtMost(u16, 1025, std.math.maxInt(u16)), .dst_port = 8888, .len = undefined, }, }; // udp dest port should not be 8888 after first const udp_dest_port = rand.intRangeAtMost(u16, 9000, std.math.maxInt(u16)); var connection: SaprusMessage = .{ .connection = .{ .src = rand.intRangeAtMost(u16, 1025, std.math.maxInt(u16)), .dest = rand.intRangeAtMost(u16, 1025, std.math.maxInt(u16)), .seq = undefined, .id = undefined, .payload = payload, }, }; try self.socket.attachSaprusPortFilter(connection.connection.src); var connection_buf: [2048]u8 = undefined; var connection_bytes = connection.toBytes(&connection_buf); headers.setPayloadLen(connection_bytes.len); var full_msg = blk: { var msg_buf: [2048]u8 = undefined; var msg_w: Writer = .fixed(&msg_buf); msg_w.writeAll(&headers.toBytes()) catch unreachable; msg_w.writeAll(connection_bytes) catch unreachable; break :blk msg_w.buffered(); }; try self.socket.send(full_msg); var res_buf: [4096]u8 = undefined; // Ignore response from sentinel, just accept that we got one. _ = try self.socket.receive(&res_buf); try io.sleep(.fromMilliseconds(40), .real); headers.udp.dst_port = udp_dest_port; headers.ip.id = rand.int(u16); full_msg = blk: { var msg_buf: [2048]u8 = undefined; var msg_w: Writer = .fixed(&msg_buf); msg_w.writeAll(&headers.toBytes()) catch unreachable; msg_w.writeAll(connection_bytes) catch unreachable; break :blk msg_w.buffered(); }; try self.socket.send(full_msg); return .init(self.socket, headers, connection); } const RawSocket = @import("./RawSocket.zig"); const SaprusMessage = @import("message.zig").Message; const SaprusConnection = @import("Connection.zig"); const EthIpUdp = @import("./EthIpUdp.zig").EthIpUdp; const std = @import("std"); const Io = std.Io; const Writer = std.Io.Writer;