From 213a01afc8407749e31a350c52a5809b5394a918 Mon Sep 17 00:00:00 2001 From: Robby Zambito Date: Tue, 20 Jan 2026 22:41:53 -0500 Subject: Implemented client and connection --- src/Client.zig | 179 +++++++++++++++++++++++++++++++++++---------------------- 1 file changed, 110 insertions(+), 69 deletions(-) (limited to 'src/Client.zig') diff --git a/src/Client.zig b/src/Client.zig index ebd446c..76de9fe 100644 --- a/src/Client.zig +++ b/src/Client.zig @@ -1,101 +1,142 @@ -const base64_enc = std.base64.Base64Encoder.init(std.base64.standard_alphabet_chars, '='); -const base64_dec = std.base64.Base64Decoder.init(std.base64.standard_alphabet_chars, '='); +const base64_enc = std.base64.standard.Encoder; +const base64_dec = std.base64.standard.Decoder; -writer: *std.Io.Writer, - -const Self = @This(); +const Client = @This(); const max_message_size = 2048; -pub fn init(writer: *std.Io.Writer) !Self { +socket: RawSocket, + +pub fn init() !Client { + const socket: RawSocket = try .init(); return .{ - .writer = writer, + .socket = socket, }; } -pub fn deinit(self: *Self) void { - self.writer.flush() catch {}; +pub fn deinit(self: *Client) void { + self.socket.deinit(); + self.* = undefined; } -pub fn sendRelay(self: *Self, payload: []const u8, dest: [4]u8) !void { - const payload_len = base64_enc.calcSize(payload.len); +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(); + }; - // Ensure the writer is in a valid state - std.debug.assert(self.writer.buffer.len - self.writer.end >= payload_len); + 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 headers_buf = try self.writer.writableSlice(@sizeOf(SaprusMessage) + @sizeOf(SaprusMessage.Relay)); - const msg: *align(1) SaprusMessage = .init(.relay, headers_buf); - msg.length = @intCast(payload_len); - const relay = (try msg.getSaprusTypePayload()).relay; - relay.dest = dest; + const relay: SaprusMessage = .{ + .relay = .{ + .dest = .fromBytes(&dest), + .payload = payload, + }, + }; - try base64_enc.encodeWriter(self.writer, payload); - try msg.networkFromNativeEndian(); - try self.writer.flush(); -} + var relay_buf: [max_message_size - (@bitSizeOf(EthIpUdp) / 8)]u8 = undefined; + const relay_bytes = relay.toBytes(&relay_buf); + headers.setPayloadLen(relay_bytes.len); -// pub fn sendInitialConnection( -// self: Self, -// payload: []const u8, -// output_bytes: []u8, -// initial_port: u16, -// ) !*align(1) SaprusMessage { -// const dest_port = self.randomPort(); -// const msg_bytes = output_bytes[0..try SaprusMessage.calcSize( -// .connection, -// base64_enc.calcSize(payload.len), -// )]; -// const msg: *align(1) SaprusMessage = .init(.connection, msg_bytes); + 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(); + }; -// const connection = (try msg.getSaprusTypePayload()).connection; -// connection.src_port = initial_port; -// connection.dest_port = dest_port; -// _ = base64_enc.encode(connection.getPayload(), payload); + try self.socket.send(full_msg); +} -// try broadcastSaprusMessage(msg_bytes, 8888); +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(); + }; -// return msg; -// } + 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, + }, + }; -// pub fn connect(self: Self, payload: []const u8) !?SaprusConnection { -// const initial_port = self.randomPort(); + // 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, + }, + }; -// var initial_conn_res: ?*align(1) SaprusMessage = null; + try self.socket.attachSaprusPortFilter(connection.connection.src); -// var sock = try network.Socket.create(.ipv4, .udp); -// defer sock.close(); + var connection_buf: [2048]u8 = undefined; + var connection_bytes = connection.toBytes(&connection_buf); + headers.setPayloadLen(connection_bytes.len); -// // Bind to 255.255.255.255:8888 -// const bind_addr = network.EndPoint{ -// .address = network.Address{ .ipv4 = network.Address.IPv4.broadcast }, -// .port = 8888, -// }; + 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(); + }; -// // timeout 1s -// try sock.setReadTimeout(1 * std.time.us_per_s); -// try sock.bind(bind_addr); + try self.socket.send(full_msg); + var res_buf: [4096]u8 = undefined; -// var sent_msg_bytes: [max_message_size]u8 align(@alignOf(SaprusMessage)) = undefined; -// const msg = try self.sendInitialConnection(payload, &sent_msg_bytes, initial_port); + // Ignore response from sentinel, just accept that we got one. + _ = try self.socket.receive(&res_buf); + try io.sleep(.fromMilliseconds(40), .real); -// var response_buf: [max_message_size]u8 align(@alignOf(SaprusMessage)) = undefined; -// _ = try sock.receive(&response_buf); // Ignore message that I sent. -// const len = try sock.receive(&response_buf); + headers.udp.dst_port = udp_dest_port; + headers.ip.id = rand.int(u16); -// initial_conn_res = try .networkBytesAsValue(response_buf[0..len]); + 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); -// // Complete handshake after awaiting response -// try broadcastSaprusMessage(msg.asBytes(), self.randomPort()); + return .init(self.socket, headers, connection); +} -// if (false) { -// return initial_conn_res.?; -// } -// return null; -// } +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 network = @import("network"); +const Io = std.Io; +const Writer = std.Io.Writer; -- cgit