mirror of
https://git.robbyzambito.me/zaprus
synced 2025-12-20 16:24:50 +00:00
Rename Saprus to Client internally
This commit is contained in:
124
src/Client.zig
Normal file
124
src/Client.zig
Normal file
@@ -0,0 +1,124 @@
|
||||
var rand: ?Random = null;
|
||||
|
||||
pub fn init() !void {
|
||||
var prng = Random.DefaultPrng.init(blk: {
|
||||
var seed: u64 = undefined;
|
||||
try posix.getrandom(mem.asBytes(&seed));
|
||||
break :blk seed;
|
||||
});
|
||||
rand = prng.random();
|
||||
try network.init();
|
||||
}
|
||||
|
||||
pub fn deinit() void {
|
||||
network.deinit();
|
||||
}
|
||||
|
||||
fn broadcastSaprusMessage(msg: SaprusMessage, udp_port: u16, allocator: Allocator) !void {
|
||||
const msg_bytes = try msg.toBytes(allocator);
|
||||
defer allocator.free(msg_bytes);
|
||||
|
||||
var sock = try network.Socket.create(.ipv4, .udp);
|
||||
defer sock.close();
|
||||
|
||||
try sock.setBroadcast(true);
|
||||
|
||||
// Bind to 0.0.0.0:0
|
||||
const bind_addr = network.EndPoint{
|
||||
.address = network.Address{ .ipv4 = network.Address.IPv4.any },
|
||||
.port = 0,
|
||||
};
|
||||
|
||||
const dest_addr = network.EndPoint{
|
||||
.address = network.Address{ .ipv4 = network.Address.IPv4.broadcast },
|
||||
.port = udp_port,
|
||||
};
|
||||
|
||||
try sock.bind(bind_addr);
|
||||
|
||||
_ = try sock.sendTo(dest_addr, msg_bytes);
|
||||
}
|
||||
|
||||
pub fn sendRelay(payload: []const u8, allocator: Allocator) !void {
|
||||
const msg = SaprusMessage{
|
||||
.relay = .{
|
||||
.header = .{ .dest = .{ 70, 70, 70, 70 } },
|
||||
.payload = payload,
|
||||
},
|
||||
};
|
||||
|
||||
try broadcastSaprusMessage(msg, 8888, allocator);
|
||||
}
|
||||
|
||||
fn randomPort() u16 {
|
||||
var p: u16 = 0;
|
||||
if (rand) |r| {
|
||||
p = r.intRangeAtMost(u16, 1024, 65000);
|
||||
} else unreachable;
|
||||
|
||||
return p;
|
||||
}
|
||||
|
||||
pub fn sendInitialConnection(payload: []const u8, initial_port: u16, allocator: Allocator) !SaprusMessage {
|
||||
const dest_port = randomPort();
|
||||
const msg = SaprusMessage{
|
||||
.connection = .{
|
||||
.header = .{
|
||||
.src_port = initial_port,
|
||||
.dest_port = dest_port,
|
||||
},
|
||||
.payload = payload,
|
||||
},
|
||||
};
|
||||
|
||||
try broadcastSaprusMessage(msg, 8888, allocator);
|
||||
|
||||
return msg;
|
||||
}
|
||||
|
||||
pub fn connect(payload: []const u8, allocator: Allocator) !?SaprusMessage {
|
||||
var initial_port: u16 = 0;
|
||||
if (rand) |r| {
|
||||
initial_port = r.intRangeAtMost(u16, 1024, 65000);
|
||||
} else unreachable;
|
||||
|
||||
var initial_conn_res: ?SaprusMessage = null;
|
||||
errdefer if (initial_conn_res) |c| c.deinit(allocator);
|
||||
|
||||
var sock = try network.Socket.create(.ipv4, .udp);
|
||||
defer sock.close();
|
||||
|
||||
// Bind to 255.255.255.255:8888
|
||||
const bind_addr = network.EndPoint{
|
||||
.address = network.Address{ .ipv4 = network.Address.IPv4.broadcast },
|
||||
.port = 8888,
|
||||
};
|
||||
|
||||
// timeout 1s
|
||||
try sock.setReadTimeout(1 * std.time.us_per_s);
|
||||
try sock.bind(bind_addr);
|
||||
|
||||
const msg = try sendInitialConnection(payload, initial_port, allocator);
|
||||
|
||||
var response_buf: [4096]u8 = undefined;
|
||||
_ = try sock.receive(&response_buf); // Ignore message that I sent.
|
||||
const len = try sock.receive(&response_buf);
|
||||
|
||||
initial_conn_res = try SaprusMessage.fromBytes(response_buf[0..len], allocator);
|
||||
|
||||
// Complete handshake after awaiting response
|
||||
try broadcastSaprusMessage(msg, randomPort(), allocator);
|
||||
|
||||
return initial_conn_res;
|
||||
}
|
||||
|
||||
const SaprusMessage = @import("message.zig").Message;
|
||||
|
||||
const std = @import("std");
|
||||
const Random = std.Random;
|
||||
const posix = std.posix;
|
||||
const mem = std.mem;
|
||||
|
||||
const network = @import("network");
|
||||
|
||||
const Allocator = mem.Allocator;
|
||||
Reference in New Issue
Block a user