Files
castle/packages/web/src/Address.zig

82 lines
2.4 KiB
Zig

const std = @import("std");
const linux = std.os.linux;
pub const Address = extern union {
any: linux.sockaddr,
in: linux.sockaddr.in,
in6: linux.sockaddr.in6,
un: linux.sockaddr.un,
pub fn initIp4(addr: [4]u8, port: u16) Address {
return .{
.in = .{
.addr = @bitCast(addr),
.port = std.mem.nativeToBig(u16, port),
},
};
}
pub fn initIp6(addr: [16]u8, port: u16, flowinfo: u32, scope_id: u32) Address {
return .{
.in6 = .{
.addr = addr,
.port = std.mem.nativeToBig(u16, port),
.flowinfo = flowinfo,
.scope_id = scope_id,
},
};
}
pub fn initUnix(path: []const u8) !Address {
var un: linux.sockaddr.un = .{
.path = @splat(0),
};
// Ensure there is space for null terminator; already present by
// initializing the path to zeroes above.
if (path.len + 1 > un.path.len) return error.NameTooLong;
@memcpy(&un.path[0..path.len], path);
return .{ .un = un };
}
pub fn getOsSockLen(self: Address) linux.socklen_t {
return switch (self.any.family) {
linux.AF.INET => @sizeOf(linux.sockaddr.in),
linux.AF.INET6 => @sizeOf(linux.sockaddr.in6),
// NOTE According to zig's 0.15.2 stdlib, this is technically always
// correct especially since we ensure there is a space for a null
// terminator in init.
linux.AF.UNIX => @sizeOf(linux.sockaddr.un),
else => unreachable,
};
}
pub fn format(self: *const Address, writer: *std.Io.Writer) std.Io.Writer.Error!void {
switch (self.any.family) {
linux.AF.INET => {
const addr: std.Io.net.Ip4Address = .{
.bytes = @bitCast(self.in.addr),
.port = std.mem.bigToNative(u16, self.in.port),
};
try addr.format(writer);
},
linux.AF.INET6 => {
const addr: std.Io.net.Ip6Address.Unresolved = .{
.bytes = self.in6.addr,
.interface_name = null,
};
try addr.format(writer);
},
linux.AF.UNIX => {
try writer.writeAll(std.mem.sliceTo(&self.un.path, 0));
},
else => unreachable,
}
}
};