summaryrefslogtreecommitdiff
path: root/src/Client.zig
diff options
context:
space:
mode:
authorRobby Zambito <contact@robbyzambito.me>2026-01-20 22:41:53 -0500
committerRobby Zambito <contact@robbyzambito.me>2026-01-21 22:25:20 -0500
commit213a01afc8407749e31a350c52a5809b5394a918 (patch)
tree05cdff41612355ef6da4e534c4c84a0988817923 /src/Client.zig
parent067a11ab232e03ad8d368beccb58b1e64ec96829 (diff)
Implemented client and connectionHEADmaster
Diffstat (limited to 'src/Client.zig')
-rw-r--r--src/Client.zig179
1 files changed, 110 insertions, 69 deletions
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;