Commit 0de862e8ba
Changed files (10)
lib/std/net/test.zig
@@ -3,44 +3,32 @@ const net = std.net;
const mem = std.mem;
const testing = std.testing;
-test "parseIp4" {
- testing.expect((try net.parseIp4("127.0.0.1")) == mem.bigToNative(u32, 0x7f000001));
-
- testParseIp4Fail("256.0.0.1", error.Overflow);
- testParseIp4Fail("x.0.0.1", error.InvalidCharacter);
- testParseIp4Fail("127.0.0.1.1", error.InvalidEnd);
- testParseIp4Fail("127.0.0.", error.Incomplete);
- testParseIp4Fail("100..0.1", error.InvalidCharacter);
-}
-
-fn testParseIp4Fail(buf: []const u8, expected_err: anyerror) void {
- if (net.parseIp4(buf)) |_| {
- @panic("expected error");
- } else |e| {
- testing.expect(e == expected_err);
- }
-}
-
-test "parseIp6" {
- const ip6 = try net.parseIp6("FF01:0:0:0:0:0:0:FB");
- const addr = net.Address.initIp6(ip6, 80);
+test "parse and render IPv6 addresses" {
+ const addr = net.IpAddress.parseIp6("FF01:0:0:0:0:0:0:FB", 80);
var buf: [100]u8 = undefined;
const printed = try std.fmt.bufPrint(&buf, "{}", addr);
std.testing.expect(mem.eql(u8, "[ff01::fb]:80", printed));
}
-test "ip4s" {
+test "parse and render IPv4 addresses" {
var buffer: [18]u8 = undefined;
for ([_][]const u8{
"0.0.0.0",
"255.255.255.255",
"1.2.3.4",
"123.255.0.91",
+ "127.0.0.1",
}) |ip| {
- var addr = net.Address.initIp4(net.parseIp4(ip) catch unreachable, 0);
+ var addr = net.IpAddress.parseIp4(ip, 0);
var newIp = std.fmt.bufPrint(buffer[0..], "{}", addr) catch unreachable;
std.testing.expect(std.mem.eql(u8, ip, newIp[0 .. newIp.len - 2]));
}
+
+ testing.expectError(error.Overflow, net.IpAddress.parseIp4("256.0.0.1", 0));
+ testing.expectError(error.InvalidCharacter, net.IpAddress.parseIp4("x.0.0.1", 0));
+ testing.expectError(error.InvalidEnd, net.IpAddress.parseIp4("127.0.0.1.1", 0));
+ testing.expectError(error.Incomplete, net.IpAddress.parseIp4("127.0.0.", 0));
+ testing.expectError(error.InvalidCharacter, net.IpAddress.parseIp4("100..0.1", 0));
}
test "resolve DNS" {
@@ -72,7 +60,7 @@ test "listen on a port, send bytes, receive bytes" {
}
// TODO doing this at comptime crashed the compiler
- const localhost = net.Address.initIp4(net.parseIp4("127.0.0.1") catch unreachable, 0);
+ const localhost = net.IpAddress.parse("127.0.0.1", 0);
var server = net.TcpServer.init(net.TcpServer.Options{});
defer server.deinit();
@@ -85,7 +73,7 @@ test "listen on a port, send bytes, receive bytes" {
try await client_frame;
}
-fn testClient(addr: net.Address) anyerror!void {
+fn testClient(addr: net.IpAddress) anyerror!void {
const socket_file = try net.tcpConnectToAddress(addr);
defer socket_file.close();
lib/std/os/bits/darwin.zig
@@ -9,28 +9,31 @@ pub const in_port_t = u16;
pub const sa_family_t = u8;
pub const socklen_t = u32;
pub const sockaddr = extern union {
- in: sockaddr_in,
- in6: sockaddr_in6,
- un: sockaddr_un,
-};
-pub const sockaddr_in = extern struct {
len: u8,
family: sa_family_t,
+ data: [14]u8,
+};
+pub const sockaddr_in = extern struct {
+ len: u8 = @sizeOf(sockaddr_in),
+ family: sa_family_t = AF_INET,
port: in_port_t,
addr: u32,
- zero: [8]u8,
+ zero: [8]u8 = [8]u8{ 0, 0, 0, 0, 0, 0, 0, 0 },
};
pub const sockaddr_in6 = extern struct {
- len: u8,
- family: sa_family_t,
+ len: u8 = @sizeOf(sockaddr_in6),
+ family: sa_family_t = AF_INET6,
port: in_port_t,
flowinfo: u32,
addr: [16]u8,
scope_id: u32,
};
+
+/// UNIX domain socket
pub const sockaddr_un = extern struct {
- len: u8,
- family: sa_family_t,
+ len: u8 = @sizeOf(sockaddr_un),
+ family: sa_family_t = AF_UNIX,
+ path: [104]u8,
};
pub const timeval = extern struct {
lib/std/os/bits/freebsd.zig
@@ -138,27 +138,39 @@ pub const in_port_t = u16;
pub const sa_family_t = u16;
pub const sockaddr = extern union {
- in: sockaddr_in,
- in6: sockaddr_in6,
+ /// total length
+ len: u8,
+
+ /// address family
+ family: sa_family_t,
+
+ /// actually longer; address value
+ data: [14]u8,
};
pub const sockaddr_in = extern struct {
- len: u8,
- family: sa_family_t,
+ len: u8 = @sizeOf(sockaddr_in),
+ family: sa_family_t = AF_INET,
port: in_port_t,
- addr: [16]u8,
- zero: [8]u8,
+ addr: u32,
+ zero: [8]u8 = [8]u8{ 0, 0, 0, 0, 0, 0, 0, 0 },
};
pub const sockaddr_in6 = extern struct {
- len: u8,
- family: sa_family_t,
+ len: u8 = @sizeOf(sockaddr_in6),
+ family: sa_family_t = AF_INET6,
port: in_port_t,
flowinfo: u32,
addr: [16]u8,
scope_id: u32,
};
+pub const sockaddr_un = extern struct {
+ len: u8 = @sizeOf(sockaddr_un),
+ family: sa_family_t = AF_UNIX,
+ path: [104]u8,
+};
+
pub const CTL_KERN = 1;
pub const CTL_DEBUG = 5;
lib/std/os/bits/linux.zig
@@ -846,30 +846,31 @@ pub const in_port_t = u16;
pub const sa_family_t = u16;
pub const socklen_t = u32;
-/// This intentionally only has ip4 and ip6
pub const sockaddr = extern union {
- in: sockaddr_in,
- in6: sockaddr_in6,
- un: sockaddr_un,
+ family: sa_family_t,
+ data: [14]u8,
};
+/// IPv4 socket address
pub const sockaddr_in = extern struct {
- family: sa_family_t,
+ family: sa_family_t = AF_INET,
port: in_port_t,
addr: u32,
- zero: [8]u8,
+ zero: [8]u8 = [8]u8{ 0, 0, 0, 0, 0, 0, 0, 0 },
};
+/// IPv6 socket address
pub const sockaddr_in6 = extern struct {
- family: sa_family_t,
+ family: sa_family_t = AF_INET6,
port: in_port_t,
flowinfo: u32,
addr: [16]u8,
scope_id: u32,
};
+/// UNIX domain socket address
pub const sockaddr_un = extern struct {
- family: sa_family_t,
+ family: sa_family_t = AF_UNIX,
path: [108]u8,
};
lib/std/os/bits/netbsd.zig
@@ -134,20 +134,26 @@ pub const in_port_t = u16;
pub const sa_family_t = u8;
pub const sockaddr = extern union {
- in: sockaddr_in,
- in6: sockaddr_in6,
+ /// total length
+ len: u8,
+
+ /// address family
+ family: sa_family_t,
+
+ /// actually longer; address value
+ data: [14]u8,
};
pub const sockaddr_in = extern struct {
- len: u8,
+ len: u8 = @sizeOf(sockaddr_in),
family: sa_family_t,
port: in_port_t,
addr: u32,
- zero: [8]u8,
+ zero: [8]u8 = [8]u8{ 0, 0, 0, 0, 0, 0, 0, 0 },
};
pub const sockaddr_in6 = extern struct {
- len: u8,
+ len: u8 = @sizeOf(sockaddr_in6),
family: sa_family_t,
port: in_port_t,
flowinfo: u32,
@@ -155,6 +161,18 @@ pub const sockaddr_in6 = extern struct {
scope_id: u32,
};
+/// Definitions for UNIX IPC domain.
+pub const sockaddr_un = extern struct {
+ /// total sockaddr length
+ len: u8 = @sizeOf(sockaddr_un),
+
+ /// AF_LOCAL
+ family: sa_family_t,
+
+ /// path name
+ path: [104]u8,
+};
+
pub const CTL_KERN = 1;
pub const CTL_DEBUG = 5;
lib/std/os/bits/windows.zig
@@ -161,3 +161,63 @@ pub const F_OK = 0;
/// Remove directory instead of unlinking file
pub const AT_REMOVEDIR = 0x200;
+
+pub const in_port_t = u16;
+pub const sa_family_t = u16;
+pub const socklen_t = u32;
+
+pub const sockaddr = extern struct {
+ family: sa_family_t,
+ data: [14]u8,
+};
+pub const sockaddr_in = extern struct {
+ family: sa_family_t = AF_INET,
+ port: in_port_t,
+ addr: in_addr,
+ zero: [8]u8 = [8]u8{ 0, 0, 0, 0, 0, 0, 0, 0 },
+};
+pub const sockaddr_in6 = extern struct {
+ family: sa_family_t = AF_INET6,
+ port: in_port_t,
+ flowinfo: u32,
+ addr: in6_addr,
+ scope_id: u32,
+};
+pub const in6_addr = [16]u8;
+pub const in_addr = u32;
+
+pub const AF_UNSPEC = 0;
+pub const AF_UNIX = 1;
+pub const AF_INET = 2;
+pub const AF_IMPLINK = 3;
+pub const AF_PUP = 4;
+pub const AF_CHAOS = 5;
+pub const AF_NS = 6;
+pub const AF_IPX = AF_NS;
+pub const AF_ISO = 7;
+pub const AF_OSI = AF_ISO;
+pub const AF_ECMA = 8;
+pub const AF_DATAKIT = 9;
+pub const AF_CCITT = 10;
+pub const AF_SNA = 11;
+pub const AF_DECnet = 12;
+pub const AF_DLI = 13;
+pub const AF_LAT = 14;
+pub const AF_HYLINK = 15;
+pub const AF_APPLETALK = 16;
+pub const AF_NETBIOS = 17;
+pub const AF_VOICEVIEW = 18;
+pub const AF_FIREFOX = 19;
+pub const AF_UNKNOWN1 = 20;
+pub const AF_BAN = 21;
+pub const AF_ATM = 22;
+pub const AF_INET6 = 23;
+pub const AF_CLUSTER = 24;
+pub const AF_12844 = 25;
+pub const AF_IRDA = 26;
+pub const AF_NETDES = 28;
+pub const AF_TCNPROCESS = 29;
+pub const AF_TCNMESSAGE = 30;
+pub const AF_ICLFXBM = 31;
+pub const AF_BTH = 32;
+pub const AF_MAX = 33;
lib/std/mem.zig
@@ -99,7 +99,7 @@ pub const Allocator = struct {
/// memory is no longer needed, to avoid a resource leak. If the
/// `Allocator` implementation is unknown, then correct code will
/// call `free` when done.
- ///
+ ///
/// For allocating a single item, see `create`.
pub fn alloc(self: *Allocator, comptime T: type, n: usize) Error![]T {
return self.alignedAlloc(T, null, n);
lib/std/net.zig
@@ -10,98 +10,229 @@ test "" {
_ = @import("net/test.zig");
}
-pub const TmpWinAddr = struct {
- family: u8,
- data: [14]u8,
-};
-
-pub const OsAddress = switch (builtin.os) {
- .windows => TmpWinAddr,
- else => os.sockaddr,
-};
-
-/// This data structure is a "view". The underlying data might have references
-/// to owned memory which must live longer than this struct.
-pub const Address = struct {
- os_addr: OsAddress,
+pub const IpAddress = extern union {
+ any: os.sockaddr,
+ in: os.sockaddr_in,
+ in6: os.sockaddr_in6,
// TODO this crashed the compiler
//pub const localhost = initIp4(parseIp4("127.0.0.1") catch unreachable, 0);
- pub fn initIp4(ip4: u32, _port: u16) Address {
- switch (builtin.os) {
- .linux => return Address{
- .os_addr = os.sockaddr{
- .in = os.sockaddr_in{
- .family = os.AF_INET,
- .port = mem.nativeToBig(u16, _port),
- .addr = ip4,
- .zero = [_]u8{0} ** 8,
- },
- },
+ pub fn parse(name: []const u8, port: u16) !IpAddress {
+ if (parseIp4(name, port)) |ip4| return ip4 else |err| switch (err) {
+ error.Overflow,
+ error.InvalidEnd,
+ error.InvalidCharacter,
+ error.Incomplete,
+ => {},
+ }
+
+ if (parseIp6(name, port)) |ip6| return ip6 else |err| switch (err) {
+ error.Overflow,
+ error.InvalidEnd,
+ error.InvalidCharacter,
+ error.Incomplete,
+ => {},
+ }
+
+ return error.InvalidIPAddressFormat;
+ }
+
+ pub fn parseExpectingFamily(name: []const u8, family: os.sa_family_t, port: u16) !IpAddress {
+ switch (family) {
+ os.AF_INET => return parseIp4(name, port),
+ os.AF_INET6 => return parseIp6(name, port),
+ os.AF_UNSPEC => return parse(name, port),
+ else => unreachable,
+ }
+ }
+
+ pub fn parseIp6(buf: []const u8, port: u16) !IpAddress {
+ var result = IpAddress{
+ .in6 = os.sockaddr_in6{
+ .scope_id = undefined,
+ .port = mem.nativeToBig(u16, port),
+ .flowinfo = 0,
+ .addr = undefined,
},
- else => return Address{
- .os_addr = os.sockaddr{
- .in = os.sockaddr_in{
- .len = @sizeOf(os.sockaddr_in),
- .family = os.AF_INET,
- .port = mem.nativeToBig(u16, _port),
- .addr = ip4,
- .zero = [_]u8{0} ** 8,
- },
- },
+ };
+ const ip_slice = result.in6.addr[0..];
+
+ var x: u16 = 0;
+ var saw_any_digits = false;
+ var index: u8 = 0;
+ var scope_id = false;
+ for (buf) |c| {
+ if (scope_id) {
+ if (c >= '0' and c <= '9') {
+ const digit = c - '0';
+ if (@mulWithOverflow(u32, result.in6.scope_id, 10, &result.in6.scope_id)) {
+ return error.Overflow;
+ }
+ if (@addWithOverflow(u32, result.in6.scope_id, digit, &result.in6.scope_id)) {
+ return error.Overflow;
+ }
+ } else {
+ return error.InvalidCharacter;
+ }
+ } else if (c == ':') {
+ if (!saw_any_digits) {
+ return error.InvalidCharacter;
+ }
+ if (index == 14) {
+ return error.InvalidEnd;
+ }
+ ip_slice[index] = @truncate(u8, x >> 8);
+ index += 1;
+ ip_slice[index] = @truncate(u8, x);
+ index += 1;
+
+ x = 0;
+ saw_any_digits = false;
+ } else if (c == '%') {
+ if (!saw_any_digits) {
+ return error.InvalidCharacter;
+ }
+ if (index == 14) {
+ ip_slice[index] = @truncate(u8, x >> 8);
+ index += 1;
+ ip_slice[index] = @truncate(u8, x);
+ index += 1;
+ }
+ scope_id = true;
+ saw_any_digits = false;
+ } else {
+ const digit = try std.fmt.charToDigit(c, 16);
+ if (@mulWithOverflow(u16, x, 16, &x)) {
+ return error.Overflow;
+ }
+ if (@addWithOverflow(u16, x, digit, &x)) {
+ return error.Overflow;
+ }
+ saw_any_digits = true;
+ }
+ }
+
+ if (!saw_any_digits) {
+ return error.Incomplete;
+ }
+
+ if (scope_id) {
+ return result;
+ }
+
+ if (index == 14) {
+ ip_slice[14] = @truncate(u8, x >> 8);
+ ip_slice[15] = @truncate(u8, x);
+ return result;
+ }
+
+ return error.Incomplete;
+ }
+
+ pub fn parseIp4(buf: []const u8, port: u16) !IpAddress {
+ var result = IpAddress{
+ .in = os.sockaddr_in{
+ .port = mem.nativeToBig(u16, port),
+ .addr = undefined,
},
+ };
+ const out_ptr = @sliceToBytes((*[1]u32)(&result.in.addr)[0..]);
+
+ var x: u8 = 0;
+ var index: u8 = 0;
+ var saw_any_digits = false;
+ for (buf) |c| {
+ if (c == '.') {
+ if (!saw_any_digits) {
+ return error.InvalidCharacter;
+ }
+ if (index == 3) {
+ return error.InvalidEnd;
+ }
+ out_ptr[index] = x;
+ index += 1;
+ x = 0;
+ saw_any_digits = false;
+ } else if (c >= '0' and c <= '9') {
+ saw_any_digits = true;
+ x = try std.math.mul(u8, x, 10);
+ x = try std.math.add(u8, x, c - '0');
+ } else {
+ return error.InvalidCharacter;
+ }
+ }
+ if (index == 3 and saw_any_digits) {
+ out_ptr[index] = x;
+ return result;
}
+
+ return error.Incomplete;
}
- pub fn initIp6(ip6: Ip6Addr, _port: u16) Address {
- switch (builtin.os) {
- .linux => return Address{
- .os_addr = os.sockaddr{
- .in6 = os.sockaddr_in6{
- .family = os.AF_INET6,
- .port = mem.nativeToBig(u16, _port),
- .flowinfo = 0,
- .addr = ip6.addr,
- .scope_id = ip6.scope_id,
- },
- },
+ pub fn initIp4(addr: [4]u8, port: u16) IpAddress {
+ return IpAddress{
+ .in = os.sockaddr_in{
+ .port = mem.nativeToBig(u16, port),
+ .addr = @ptrCast(*align(1) const u32, &addr).*,
},
- else => return Address{
- .os_addr = os.sockaddr{
- .in6 = os.sockaddr_in6{
- .len = @sizeOf(os.sockaddr_in6),
- .family = os.AF_INET6,
- .port = mem.nativeToBig(u16, _port),
- .flowinfo = 0,
- .addr = ip6.addr,
- .scope_id = ip6.scope_id,
- },
- },
+ };
+ }
+
+ pub fn initIp6(addr: [16]u8, port: u16, flowinfo: u32, scope_id: u32) IpAddress {
+ return IpAddress{
+ .in6 = os.sockaddr_in6{
+ .addr = addr,
+ .port = mem.nativeToBig(u16, port),
+ .flowinfo = flowinfo,
+ .scope_id = scope_id,
},
- }
+ };
}
- pub fn port(self: Address) u16 {
- return mem.bigToNative(u16, self.os_addr.in.port);
+ /// Returns the port in native endian.
+ pub fn getPort(self: IpAddress) u16 {
+ const big_endian_port = switch (self.any.family) {
+ os.AF_INET => self.in.port,
+ os.AF_INET6 => self.in6.port,
+ else => unreachable,
+ };
+ return mem.bigToNative(u16, big_endian_port);
}
- pub fn initPosix(addr: os.sockaddr) Address {
- return Address{ .os_addr = addr };
+ /// `port` is native-endian.
+ pub fn setPort(self: *IpAddress, port: u16) void {
+ const ptr = switch (self.any.family) {
+ os.AF_INET => &self.in.port,
+ os.AF_INET6 => &self.in6.port,
+ else => unreachable,
+ };
+ ptr.* = mem.nativeToBig(u16, port);
+ }
+
+ /// Asserts that `addr` is an IP address.
+ /// This function will read past the end of the pointer, with a size depending
+ /// on the address family.
+ pub fn initPosix(addr: *align(4) const os.sockaddr) IpAddress {
+ switch (addr.family) {
+ os.AF_INET => return IpAddress{ .in = @ptrCast(*const os.sockaddr_in, addr).* },
+ os.AF_INET6 => return IpAddress{ .in6 = @ptrCast(*const os.sockaddr_in6, addr).* },
+ else => unreachable,
+ }
}
pub fn format(
- self: Address,
+ self: IpAddress,
comptime fmt: []const u8,
options: std.fmt.FormatOptions,
context: var,
comptime Errors: type,
output: fn (@typeOf(context), []const u8) Errors!void,
) !void {
- switch (self.os_addr.in.family) {
+ switch (self.any.family) {
os.AF_INET => {
- const native_endian_port = mem.bigToNative(u16, self.os_addr.in.port);
- const bytes = @ptrCast(*const [4]u8, &self.os_addr.in.addr);
+ const port = mem.bigToNative(u16, self.in.port);
+ const bytes = @ptrCast(*const [4]u8, &self.in.addr);
try std.fmt.format(
context,
Errors,
@@ -111,7 +242,7 @@ pub const Address = struct {
bytes[1],
bytes[2],
bytes[3],
- native_endian_port,
+ port,
);
},
os.AF_INET6 => {
@@ -119,8 +250,8 @@ pub const Address = struct {
index: usize,
count: usize,
};
- const native_endian_port = mem.bigToNative(u16, self.os_addr.in6.port);
- const big_endian_parts = @ptrCast(*align(1) const [8]u16, &self.os_addr.in6.addr);
+ const port = mem.bigToNative(u16, self.in6.port);
+ const big_endian_parts = @ptrCast(*align(1) const [8]u16, &self.in6.addr);
const native_endian_parts = switch (builtin.endian) {
.Big => big_endian_parts.*,
.Little => blk: {
@@ -170,14 +301,20 @@ pub const Address = struct {
try std.fmt.format(context, Errors, output, "{x}", part);
i += 1;
}
- try std.fmt.format(context, Errors, output, "]:{}", native_endian_port);
+ try std.fmt.format(context, Errors, output, "]:{}", port);
},
- else => return output(context, "(unrecognized address family)"),
+ else => unreachable,
}
}
- fn getOsSockLen(self: Address) os.socklen_t {
- switch (self.os_addr.un.family) {
+ pub fn eql(a: IpAddress, b: IpAddress) bool {
+ const a_bytes = @ptrCast([*]const u8, &a.any)[0..a.getOsSockLen()];
+ const b_bytes = @ptrCast([*]const u8, &b.any)[0..b.getOsSockLen()];
+ return mem.eql(u8, a_bytes, b_bytes);
+ }
+
+ fn getOsSockLen(self: IpAddress) os.socklen_t {
+ switch (self.any.family) {
os.AF_INET => return @sizeOf(os.sockaddr_in),
os.AF_INET6 => return @sizeOf(os.sockaddr_in6),
else => unreachable,
@@ -185,123 +322,6 @@ pub const Address = struct {
}
};
-pub fn parseIp4(buf: []const u8) !u32 {
- var result: u32 = undefined;
- const out_ptr = @sliceToBytes((*[1]u32)(&result)[0..]);
-
- var x: u8 = 0;
- var index: u8 = 0;
- var saw_any_digits = false;
- for (buf) |c| {
- if (c == '.') {
- if (!saw_any_digits) {
- return error.InvalidCharacter;
- }
- if (index == 3) {
- return error.InvalidEnd;
- }
- out_ptr[index] = x;
- index += 1;
- x = 0;
- saw_any_digits = false;
- } else if (c >= '0' and c <= '9') {
- saw_any_digits = true;
- x = try std.math.mul(u8, x, 10);
- x = try std.math.add(u8, x, c - '0');
- } else {
- return error.InvalidCharacter;
- }
- }
- if (index == 3 and saw_any_digits) {
- out_ptr[index] = x;
- return result;
- }
-
- return error.Incomplete;
-}
-
-pub const Ip6Addr = struct {
- scope_id: u32,
- addr: [16]u8,
-};
-
-pub fn parseIp6(buf: []const u8) !Ip6Addr {
- var result: Ip6Addr = undefined;
- result.scope_id = 0;
- const ip_slice = result.addr[0..];
-
- var x: u16 = 0;
- var saw_any_digits = false;
- var index: u8 = 0;
- var scope_id = false;
- for (buf) |c| {
- if (scope_id) {
- if (c >= '0' and c <= '9') {
- const digit = c - '0';
- if (@mulWithOverflow(u32, result.scope_id, 10, &result.scope_id)) {
- return error.Overflow;
- }
- if (@addWithOverflow(u32, result.scope_id, digit, &result.scope_id)) {
- return error.Overflow;
- }
- } else {
- return error.InvalidCharacter;
- }
- } else if (c == ':') {
- if (!saw_any_digits) {
- return error.InvalidCharacter;
- }
- if (index == 14) {
- return error.InvalidEnd;
- }
- ip_slice[index] = @truncate(u8, x >> 8);
- index += 1;
- ip_slice[index] = @truncate(u8, x);
- index += 1;
-
- x = 0;
- saw_any_digits = false;
- } else if (c == '%') {
- if (!saw_any_digits) {
- return error.InvalidCharacter;
- }
- if (index == 14) {
- ip_slice[index] = @truncate(u8, x >> 8);
- index += 1;
- ip_slice[index] = @truncate(u8, x);
- index += 1;
- }
- scope_id = true;
- saw_any_digits = false;
- } else {
- const digit = try std.fmt.charToDigit(c, 16);
- if (@mulWithOverflow(u16, x, 16, &x)) {
- return error.Overflow;
- }
- if (@addWithOverflow(u16, x, digit, &x)) {
- return error.Overflow;
- }
- saw_any_digits = true;
- }
- }
-
- if (!saw_any_digits) {
- return error.Incomplete;
- }
-
- if (scope_id) {
- return result;
- }
-
- if (index == 14) {
- ip_slice[14] = @truncate(u8, x >> 8);
- ip_slice[15] = @truncate(u8, x);
- return result;
- }
-
- return error.Incomplete;
-}
-
pub fn connectUnixSocket(path: []const u8) !fs.File {
const opt_non_block = if (std.io.mode == .evented) os.SOCK_NONBLOCK else 0;
const sockfd = try os.socket(
@@ -311,24 +331,23 @@ pub fn connectUnixSocket(path: []const u8) !fs.File {
);
errdefer os.close(sockfd);
- var sock_addr = os.sockaddr{
- .un = os.sockaddr_un{
- .family = os.AF_UNIX,
- .path = undefined,
- },
+ var sock_addr = os.sockaddr_un{
+ .family = os.AF_UNIX,
+ .path = undefined,
};
- if (path.len > @typeOf(sock_addr.un.path).len) return error.NameTooLong;
- mem.copy(u8, sock_addr.un.path[0..], path);
- const size = @intCast(u32, @sizeOf(os.sa_family_t) + path.len);
- try os.connect(sockfd, sock_addr, size);
+ if (path.len > sock_addr.path.len) return error.NameTooLong;
+ mem.copy(u8, &sock_addr.path, path);
+
+ const size = @intCast(u32, @sizeOf(os.sockaddr_un) - sock_addr.path.len + path.len);
+ try os.connect(sockfd, &sock_addr, size);
return fs.File.openHandle(sockfd);
}
pub const AddressList = struct {
arena: std.heap.ArenaAllocator,
- addrs: []Address,
+ addrs: []IpAddress,
canon_name: ?[]u8,
fn deinit(self: *AddressList) void {
@@ -351,12 +370,12 @@ pub fn tcpConnectToHost(allocator: *mem.Allocator, name: []const u8, port: u16)
return tcpConnectToAddress(addrs[0], port);
}
-pub fn tcpConnectToAddress(address: Address) !fs.File {
+pub fn tcpConnectToAddress(address: IpAddress) !fs.File {
const nonblock = if (std.io.is_async) os.SOCK_NONBLOCK else 0;
const sock_flags = os.SOCK_STREAM | os.SOCK_CLOEXEC | nonblock;
- const sockfd = try os.socket(address.os_addr.un.family, sock_flags, os.IPPROTO_TCP);
+ const sockfd = try os.socket(address.any.family, sock_flags, os.IPPROTO_TCP);
errdefer os.close(sockfd);
- try os.connect(sockfd, address.os_addr, address.getOsSockLen());
+ try os.connect(sockfd, &address.any, address.getOsSockLen());
return fs.File{ .handle = sockfd };
}
@@ -426,13 +445,13 @@ pub fn getAddressList(allocator: *mem.Allocator, name: []const u8, port: u16) !*
}
break :blk count;
};
- result.addrs = try arena.alloc(Address, addr_count);
+ result.addrs = try arena.alloc(IpAddress, addr_count);
var it: ?*os.addrinfo = res;
var i: usize = 0;
while (it) |info| : (it = info.next) {
const addr = info.addr orelse continue;
- result.addrs[i] = Address.initPosix(addr.*);
+ result.addrs[i] = IpAddress.initPosix(@alignCast(4, addr));
if (info.canonname) |n| {
if (result.canon_name == null) {
@@ -447,40 +466,22 @@ pub fn getAddressList(allocator: *mem.Allocator, name: []const u8, port: u16) !*
if (builtin.os == .linux) {
const flags = std.c.AI_NUMERICSERV;
const family = os.AF_UNSPEC;
- var addrs = std.ArrayList(LookupAddr).init(allocator);
- defer addrs.deinit();
+ var lookup_addrs = std.ArrayList(LookupAddr).init(allocator);
+ defer lookup_addrs.deinit();
var canon = std.Buffer.initNull(arena);
defer canon.deinit();
- try linuxLookupName(&addrs, &canon, name, family, flags);
+ try linuxLookupName(&lookup_addrs, &canon, name, family, flags, port);
- result.addrs = try arena.alloc(Address, addrs.len);
+ result.addrs = try arena.alloc(IpAddress, lookup_addrs.len);
if (!canon.isNull()) {
result.canon_name = canon.toOwnedSlice();
}
- for (addrs.toSliceConst()) |addr, i| {
- const os_addr = if (addr.family == os.AF_INET6)
- os.sockaddr{
- .in6 = os.sockaddr_in6{
- .family = addr.family,
- .port = mem.nativeToBig(u16, port),
- .flowinfo = 0,
- .addr = addr.addr,
- .scope_id = addr.scope_id,
- },
- }
- else
- os.sockaddr{
- .in = os.sockaddr_in{
- .family = addr.family,
- .port = mem.nativeToBig(u16, port),
- .addr = @ptrCast(*align(1) const u32, &addr.addr).*,
- .zero = [8]u8{ 0, 0, 0, 0, 0, 0, 0, 0 },
- },
- };
- result.addrs[i] = Address.initPosix(os_addr);
+ for (lookup_addrs.toSliceConst()) |lookup_addr, i| {
+ result.addrs[i] = lookup_addr.addr;
+ assert(result.addrs[i].getPort() == port);
}
return result;
@@ -489,9 +490,7 @@ pub fn getAddressList(allocator: *mem.Allocator, name: []const u8, port: u16) !*
}
const LookupAddr = struct {
- family: os.sa_family_t,
- scope_id: u32 = 0,
- addr: [16]u8, // could be IPv4 or IPv6
+ addr: IpAddress,
sortkey: i32 = 0,
};
@@ -507,22 +506,26 @@ fn linuxLookupName(
addrs: *std.ArrayList(LookupAddr),
canon: *std.Buffer,
opt_name: ?[]const u8,
- family: i32,
+ family: os.sa_family_t,
flags: u32,
+ port: u16,
) !void {
if (opt_name) |name| {
// reject empty name and check len so it fits into temp bufs
try canon.replaceContents(name);
- try linuxLookupNameFromNumeric(addrs, name, family);
- if (addrs.len == 0 and (flags & std.c.AI_NUMERICHOST) == 0) {
- try linuxLookupNameFromHosts(addrs, canon, name, family);
+ if (IpAddress.parseExpectingFamily(name, family, port)) |addr| {
+ try addrs.append(LookupAddr{ .addr = addr });
+ } else |name_err| if ((flags & std.c.AI_NUMERICHOST) != 0) {
+ return name_err;
+ } else {
+ try linuxLookupNameFromHosts(addrs, canon, name, family, port);
if (addrs.len == 0) {
- try linuxLookupNameFromDnsSearch(addrs, canon, name, family);
+ try linuxLookupNameFromDnsSearch(addrs, canon, name, family, port);
}
}
} else {
try canon.resize(0);
- try linuxLookupNameFromNull(addrs, family, flags);
+ try linuxLookupNameFromNull(addrs, family, flags, port);
}
if (addrs.len == 0) return error.UnknownHostName;
@@ -530,7 +533,7 @@ fn linuxLookupName(
// results or if there are only IPv4 results.
if (addrs.len == 1 or family == os.AF_INET) return;
const all_ip4 = for (addrs.toSliceConst()) |addr| {
- if (addr.family != os.AF_INET) break false;
+ if (addr.addr.any.family != os.AF_INET) break false;
} else true;
if (all_ip4) return;
@@ -547,7 +550,7 @@ fn linuxLookupName(
@memset(@ptrCast([*]u8, &sa6), 0, @sizeOf(os.sockaddr_in6));
var da6 = os.sockaddr_in6{
.family = os.AF_INET6,
- .scope_id = addr.scope_id,
+ .scope_id = addr.addr.in6.scope_id,
.port = 65535,
.flowinfo = 0,
.addr = [1]u8{0} ** 16,
@@ -560,12 +563,12 @@ fn linuxLookupName(
.addr = 0,
.zero = [1]u8{0} ** 8,
};
- var sa: *os.sockaddr = undefined;
- var da: *os.sockaddr = undefined;
+ var sa: *align(4) os.sockaddr = undefined;
+ var da: *align(4) os.sockaddr = undefined;
var salen: os.socklen_t = undefined;
var dalen: os.socklen_t = undefined;
- if (addr.family == os.AF_INET6) {
- mem.copy(u8, &da6.addr, &addr.addr);
+ if (addr.addr.any.family == os.AF_INET6) {
+ mem.copy(u8, &da6.addr, &addr.addr.in6.addr);
da = @ptrCast(*os.sockaddr, &da6);
dalen = @sizeOf(os.sockaddr_in6);
sa = @ptrCast(*os.sockaddr, &sa6);
@@ -573,8 +576,9 @@ fn linuxLookupName(
} else {
mem.copy(u8, &sa6.addr, "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xff\xff");
mem.copy(u8, &da6.addr, "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xff\xff");
- mem.copy(u8, da6.addr[12..], addr.addr[0..4]);
- da4.addr = mem.readIntNative(u32, @ptrCast(*const [4]u8, &addr.addr));
+ // TODO https://github.com/ziglang/zig/issues/863
+ mem.writeIntNative(u32, @ptrCast(*[4]u8, da6.addr[12..].ptr), addr.addr.in.addr);
+ da4.addr = addr.addr.in.addr;
da = @ptrCast(*os.sockaddr, &da4);
dalen = @sizeOf(os.sockaddr_in);
sa = @ptrCast(*os.sockaddr, &sa4);
@@ -586,12 +590,13 @@ fn linuxLookupName(
const dprec: i32 = dpolicy.prec;
const MAXADDRS = 3;
var prefixlen: i32 = 0;
- if (os.socket(addr.family, os.SOCK_DGRAM | os.SOCK_CLOEXEC, os.IPPROTO_UDP)) |fd| syscalls: {
+ const sock_flags = os.SOCK_DGRAM | os.SOCK_CLOEXEC;
+ if (os.socket(addr.addr.any.family, sock_flags, os.IPPROTO_UDP)) |fd| syscalls: {
defer os.close(fd);
- os.connect(fd, da.*, dalen) catch break :syscalls;
+ os.connect(fd, da, dalen) catch break :syscalls;
key |= DAS_USABLE;
os.getsockname(fd, sa, &salen) catch break :syscalls;
- if (addr.family == os.AF_INET) {
+ if (addr.addr.any.family == os.AF_INET) {
// TODO sa6.addr[12..16] should return *[4]u8, making this cast unnecessary.
mem.writeIntNative(u32, @ptrCast(*[4]u8, &sa6.addr[12]), sa4.addr);
}
@@ -726,72 +731,32 @@ fn addrCmpLessThan(b: LookupAddr, a: LookupAddr) bool {
return a.sortkey < b.sortkey;
}
-fn linuxLookupNameFromNumericUnspec(addrs: *std.ArrayList(LookupAddr), name: []const u8) !void {
- return linuxLookupNameFromNumeric(addrs, name, os.AF_UNSPEC) catch |err| switch (err) {
- error.ExpectedIPv6ButFoundIPv4 => unreachable,
- error.ExpectedIPv4ButFoundIPv6 => unreachable,
- else => |e| return e,
- };
-}
-
-fn linuxLookupNameFromNumeric(addrs: *std.ArrayList(LookupAddr), name: []const u8, family: i32) !void {
- if (parseIp4(name)) |ip4| {
- if (family == os.AF_INET6) return error.ExpectedIPv6ButFoundIPv4;
- const item = try addrs.addOne();
- // TODO [0..4] should return *[4]u8, making this pointer cast unnecessary
- mem.writeIntNative(u32, @ptrCast(*[4]u8, &item.addr), ip4);
- item.family = os.AF_INET;
- item.scope_id = 0;
- return;
- } else |err| switch (err) {
- error.Overflow,
- error.InvalidEnd,
- error.InvalidCharacter,
- error.Incomplete,
- => {},
- }
-
- if (parseIp6(name)) |ip6| {
- if (family == os.AF_INET) return error.ExpectedIPv4ButFoundIPv6;
- const item = try addrs.addOne();
- @memcpy(&item.addr, &ip6.addr, 16);
- item.family = os.AF_INET6;
- item.scope_id = ip6.scope_id;
- return;
- } else |err| switch (err) {
- error.Overflow,
- error.InvalidEnd,
- error.InvalidCharacter,
- error.Incomplete,
- => {},
- }
-}
-
-fn linuxLookupNameFromNull(addrs: *std.ArrayList(LookupAddr), family: i32, flags: u32) !void {
+fn linuxLookupNameFromNull(
+ addrs: *std.ArrayList(LookupAddr),
+ family: os.sa_family_t,
+ flags: u32,
+ port: u16,
+) !void {
if ((flags & std.c.AI_PASSIVE) != 0) {
if (family != os.AF_INET6) {
(try addrs.addOne()).* = LookupAddr{
- .family = os.AF_INET,
- .addr = [1]u8{0} ** 16,
+ .addr = IpAddress.initIp4([1]u8{0} ** 4, port),
};
}
if (family != os.AF_INET) {
(try addrs.addOne()).* = LookupAddr{
- .family = os.AF_INET6,
- .addr = [1]u8{0} ** 16,
+ .addr = IpAddress.initIp6([1]u8{0} ** 16, port, 0, 0),
};
}
} else {
if (family != os.AF_INET6) {
(try addrs.addOne()).* = LookupAddr{
- .family = os.AF_INET,
- .addr = [4]u8{ 127, 0, 0, 1 } ++ ([1]u8{0} ** 12),
+ .addr = IpAddress.initIp4([4]u8{ 127, 0, 0, 1 }, port),
};
}
if (family != os.AF_INET) {
(try addrs.addOne()).* = LookupAddr{
- .family = os.AF_INET6,
- .addr = ([1]u8{0} ** 15) ++ [1]u8{1},
+ .addr = IpAddress.initIp6(([1]u8{0} ** 15) ++ [1]u8{1}, port, 0, 0),
};
}
}
@@ -801,7 +766,8 @@ fn linuxLookupNameFromHosts(
addrs: *std.ArrayList(LookupAddr),
canon: *std.Buffer,
name: []const u8,
- family: i32,
+ family: os.sa_family_t,
+ port: u16,
) !void {
const file = fs.File.openReadC(c"/etc/hosts") catch |err| switch (err) {
error.FileNotFound,
@@ -835,18 +801,20 @@ fn linuxLookupNameFromHosts(
}
} else continue;
- const prev_len = addrs.len;
- linuxLookupNameFromNumeric(addrs, ip_text, family) catch |err| switch (err) {
- error.ExpectedIPv6ButFoundIPv4 => continue,
- error.ExpectedIPv4ButFoundIPv6 => continue,
- error.OutOfMemory => |e| return e,
+ const addr = IpAddress.parseExpectingFamily(ip_text, family, port) catch |err| switch (err) {
+ error.Overflow,
+ error.InvalidEnd,
+ error.InvalidCharacter,
+ error.Incomplete,
+ error.InvalidIPAddressFormat,
+ => continue,
};
- if (addrs.len > prev_len) {
- // first name is canonical name
- const name_text = first_name_text.?;
- if (isValidHostName(name_text)) {
- try canon.replaceContents(name_text);
- }
+ try addrs.append(LookupAddr{ .addr = addr });
+
+ // first name is canonical name
+ const name_text = first_name_text.?;
+ if (isValidHostName(name_text)) {
+ try canon.replaceContents(name_text);
}
}
}
@@ -867,7 +835,8 @@ fn linuxLookupNameFromDnsSearch(
addrs: *std.ArrayList(LookupAddr),
canon: *std.Buffer,
name: []const u8,
- family: i32,
+ family: os.sa_family_t,
+ port: u16,
) !void {
var rc: ResolvConf = undefined;
try getResolvConf(addrs.allocator, &rc);
@@ -903,32 +872,35 @@ fn linuxLookupNameFromDnsSearch(
while (tok_it.next()) |tok| {
canon.shrink(canon_name.len + 1);
try canon.append(tok);
- try linuxLookupNameFromDns(addrs, canon, canon.toSliceConst(), family, rc);
+ try linuxLookupNameFromDns(addrs, canon, canon.toSliceConst(), family, rc, port);
if (addrs.len != 0) return;
}
canon.shrink(canon_name.len);
- return linuxLookupNameFromDns(addrs, canon, name, family, rc);
+ return linuxLookupNameFromDns(addrs, canon, name, family, rc, port);
}
const dpc_ctx = struct {
addrs: *std.ArrayList(LookupAddr),
canon: *std.Buffer,
+ port: u16,
};
fn linuxLookupNameFromDns(
addrs: *std.ArrayList(LookupAddr),
canon: *std.Buffer,
name: []const u8,
- family: i32,
+ family: os.sa_family_t,
rc: ResolvConf,
+ port: u16,
) !void {
var ctx = dpc_ctx{
.addrs = addrs,
.canon = canon,
+ .port = port,
};
const AfRr = struct {
- af: i32,
+ af: os.sa_family_t,
rr: u8,
};
const afrrs = [_]AfRr{
@@ -994,7 +966,7 @@ fn getResolvConf(allocator: *mem.Allocator, rc: *ResolvConf) !void {
error.FileNotFound,
error.NotDir,
error.AccessDenied,
- => return linuxLookupNameFromNumericUnspec(&rc.ns, "127.0.0.1"),
+ => return linuxLookupNameFromNumericUnspec(&rc.ns, "127.0.0.1", 53),
else => |e| return e,
};
defer file.close();
@@ -1033,21 +1005,24 @@ fn getResolvConf(allocator: *mem.Allocator, rc: *ResolvConf) !void {
}
} else if (mem.eql(u8, token, "nameserver")) {
const ip_txt = line_it.next() orelse continue;
- try linuxLookupNameFromNumericUnspec(&rc.ns, ip_txt);
+ try linuxLookupNameFromNumericUnspec(&rc.ns, ip_txt, 53);
} else if (mem.eql(u8, token, "domain") or mem.eql(u8, token, "search")) {
try rc.search.replaceContents(line_it.rest());
}
}
if (rc.ns.len == 0) {
- return linuxLookupNameFromNumericUnspec(&rc.ns, "127.0.0.1");
+ return linuxLookupNameFromNumericUnspec(&rc.ns, "127.0.0.1", 53);
}
}
-fn eqlSockAddr(a: *const os.sockaddr, b: *const os.sockaddr, len: usize) bool {
- const a_bytes = @ptrCast([*]const u8, a)[0..len];
- const b_bytes = @ptrCast([*]const u8, b)[0..len];
- return mem.eql(u8, a_bytes, b_bytes);
+fn linuxLookupNameFromNumericUnspec(
+ addrs: *std.ArrayList(LookupAddr),
+ name: []const u8,
+ port: u16,
+) !void {
+ const addr = try IpAddress.parse(name, port);
+ (try addrs.addOne()).* = LookupAddr{ .addr = addr };
}
fn resMSendRc(
@@ -1062,41 +1037,25 @@ fn resMSendRc(
var sl: os.socklen_t = @sizeOf(os.sockaddr_in);
var family: os.sa_family_t = os.AF_INET;
- var ns_list = std.ArrayList(os.sockaddr).init(rc.ns.allocator);
+ var ns_list = std.ArrayList(IpAddress).init(rc.ns.allocator);
defer ns_list.deinit();
try ns_list.resize(rc.ns.len);
const ns = ns_list.toSlice();
for (rc.ns.toSliceConst()) |iplit, i| {
- if (iplit.family == os.AF_INET) {
- ns[i] = os.sockaddr{
- .in = os.sockaddr_in{
- .family = os.AF_INET,
- .port = mem.nativeToBig(u16, 53),
- .addr = mem.readIntNative(u32, @ptrCast(*const [4]u8, &iplit.addr)),
- .zero = [8]u8{ 0, 0, 0, 0, 0, 0, 0, 0 },
- },
- };
- } else {
- ns[i] = os.sockaddr{
- .in6 = os.sockaddr_in6{
- .family = os.AF_INET6,
- .port = mem.nativeToBig(u16, 53),
- .flowinfo = 0,
- .addr = iplit.addr,
- .scope_id = iplit.scope_id,
- },
- };
+ ns[i] = iplit.addr;
+ assert(ns[i].getPort() == 53);
+ if (iplit.addr.any.family != os.AF_INET) {
sl = @sizeOf(os.sockaddr_in6);
family = os.AF_INET6;
}
}
// Get local address and open/bind a socket
- var sa: os.sockaddr = undefined;
- @memset(@ptrCast([*]u8, &sa), 0, @sizeOf(os.sockaddr));
- sa.in.family = family;
+ var sa: IpAddress = undefined;
+ @memset(@ptrCast([*]u8, &sa), 0, @sizeOf(IpAddress));
+ sa.any.family = family;
const flags = os.SOCK_DGRAM | os.SOCK_CLOEXEC | os.SOCK_NONBLOCK;
const fd = os.socket(family, flags, 0) catch |err| switch (err) {
error.AddressFamilyNotSupported => blk: {
@@ -1110,7 +1069,7 @@ fn resMSendRc(
else => |e| return e,
};
defer os.close(fd);
- try os.bind(fd, &sa, sl);
+ try os.bind(fd, &sa.any, sl);
// Past this point, there are no errors. Each individual query will
// yield either no reply (indicated by zero length) or an answer
@@ -1153,7 +1112,7 @@ fn resMSendRc(
if (answers[i].len == 0) {
var j: usize = 0;
while (j < ns.len) : (j += 1) {
- _ = os.sendto(fd, queries[i], os.MSG_NOSIGNAL, &ns[j], sl) catch undefined;
+ _ = os.sendto(fd, queries[i], os.MSG_NOSIGNAL, &ns[j].any, sl) catch undefined;
}
}
}
@@ -1168,14 +1127,14 @@ fn resMSendRc(
while (true) {
var sl_copy = sl;
- const rlen = os.recvfrom(fd, answer_bufs[next], 0, &sa, &sl_copy) catch break;
+ const rlen = os.recvfrom(fd, answer_bufs[next], 0, &sa.any, &sl_copy) catch break;
// Ignore non-identifiable packets
if (rlen < 4) continue;
// Ignore replies from addresses we didn't send to
var j: usize = 0;
- while (j < ns.len and !eqlSockAddr(&ns[j], &sa, sl)) : (j += 1) {}
+ while (j < ns.len and !ns[j].eql(sa)) : (j += 1) {}
if (j == ns.len) continue;
// Find which query this answer goes with, if any
@@ -1194,7 +1153,7 @@ fn resMSendRc(
0, 3 => {},
2 => if (servfail_retry != 0) {
servfail_retry -= 1;
- _ = os.sendto(fd, queries[i], os.MSG_NOSIGNAL, &ns[j], sl) catch undefined;
+ _ = os.sendto(fd, queries[i], os.MSG_NOSIGNAL, &ns[j].any, sl) catch undefined;
},
else => continue,
}
@@ -1252,19 +1211,17 @@ fn dnsParseCallback(ctx: dpc_ctx, rr: u8, data: []const u8, packet: []const u8)
if (data.len != 4) return error.InvalidDnsARecord;
const new_addr = try ctx.addrs.addOne();
new_addr.* = LookupAddr{
- .family = os.AF_INET,
- .addr = undefined,
+ // TODO slice [0..4] to make this *[4]u8 without @ptrCast
+ .addr = IpAddress.initIp4(@ptrCast(*const [4]u8, data.ptr).*, ctx.port),
};
- mem.copy(u8, &new_addr.addr, data);
},
os.RR_AAAA => {
if (data.len != 16) return error.InvalidDnsAAAARecord;
const new_addr = try ctx.addrs.addOne();
new_addr.* = LookupAddr{
- .family = os.AF_INET6,
- .addr = undefined,
+ // TODO slice [0..16] to make this *[16]u8 without @ptrCast
+ .addr = IpAddress.initIp6(@ptrCast(*const [16]u8, data.ptr).*, ctx.port, 0, 0),
};
- mem.copy(u8, &new_addr.addr, data);
},
os.RR_CNAME => {
var tmp: [256]u8 = undefined;
@@ -1284,7 +1241,7 @@ pub const TcpServer = struct {
kernel_backlog: u32,
/// `undefined` until `listen` returns successfully.
- listen_address: Address,
+ listen_address: IpAddress,
sockfd: ?os.fd_t,
@@ -1311,7 +1268,7 @@ pub const TcpServer = struct {
self.* = undefined;
}
- pub fn listen(self: *TcpServer, address: Address) !void {
+ pub fn listen(self: *TcpServer, address: IpAddress) !void {
const nonblock = if (std.io.is_async) os.SOCK_NONBLOCK else 0;
const sock_flags = os.SOCK_STREAM | os.SOCK_CLOEXEC | nonblock;
const sockfd = try os.socket(os.AF_INET, sock_flags, os.PROTO_tcp);
@@ -1322,9 +1279,9 @@ pub const TcpServer = struct {
}
var socklen = address.getOsSockLen();
- try os.bind(sockfd, &address.os_addr, socklen);
+ try os.bind(sockfd, &address.any, socklen);
try os.listen(sockfd, self.kernel_backlog);
- try os.getsockname(sockfd, &self.listen_address.os_addr, &socklen);
+ try os.getsockname(sockfd, &self.listen_address.any, &socklen);
}
/// Stop listening. It is still necessary to call `deinit` after stopping listening.
@@ -1361,9 +1318,9 @@ pub const TcpServer = struct {
pub fn accept(self: *TcpServer) AcceptError!fs.File {
const nonblock = if (std.io.is_async) os.SOCK_NONBLOCK else 0;
const accept_flags = nonblock | os.SOCK_CLOEXEC;
- var accepted_addr: Address = undefined;
- var adr_len: os.socklen_t = @sizeOf(os.sockaddr);
- if (os.accept4(self.sockfd.?, &accepted_addr.os_addr, &adr_len, accept_flags)) |fd| {
+ var accepted_addr: IpAddress = undefined;
+ var adr_len: os.socklen_t = @sizeOf(IpAddress);
+ if (os.accept4(self.sockfd.?, &accepted_addr.any, &adr_len, accept_flags)) |fd| {
return fs.File.openHandle(fd);
} else |err| switch (err) {
// We only give SOCK_NONBLOCK when I/O mode is async, in which case this error
lib/std/os.zig
@@ -1920,9 +1920,9 @@ pub const ConnectError = error{
} || UnexpectedError;
/// Initiate a connection on a socket.
-pub fn connect(sockfd: fd_t, sock_addr: sockaddr, len: socklen_t) ConnectError!void {
+pub fn connect(sockfd: fd_t, sock_addr: *const sockaddr, len: socklen_t) ConnectError!void {
while (true) {
- switch (errno(system.connect(sockfd, &sock_addr, len))) {
+ switch (errno(system.connect(sockfd, sock_addr, len))) {
0 => return,
EACCES => return error.PermissionDenied,
EPERM => return error.PermissionDenied,
test/compile_errors.zig
@@ -162,9 +162,9 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ const obj = AstObject{ .lhsExpr = lhsExpr };
\\}
,
- "tmp.zig:1:17: error: struct 'LhsExpr' depends on itself",
- "tmp.zig:5:5: note: while checking this field",
+ "tmp.zig:4:19: error: union 'AstObject' depends on itself",
"tmp.zig:2:5: note: while checking this field",
+ "tmp.zig:5:5: note: while checking this field",
);
cases.add(