authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2019-10-30 19:27:42-04:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2019-10-30 20:22:05-04:00
log0de862e8bafce9a58c1018e9b6f81b3d17279c10
treed8b75a7683324c713d6fb53023ae6ae88f69e157
parent618ee5b63a2f817492b4da0d5c8b7fa1584680bc
signaturelock-open Commit is signed but in an unrecognized format.

make std.net more portable

* Delete `std.net.TmpWinAddr`. I don't think that was ever meant to be a real thing. * Delete `std.net.OsAddress`. This abstraction was not helpful. * Rename `std.net.Address` to `std.net.IpAddress`. It is now an extern union of IPv4 and IPv6 addresses. * Move `std.net.parseIp4` and `std.net.parseIp6` to the `std.net.IpAddress` namespace. They now return `IpAddress` instead of `u32` and `std.net.Ip6Addr`, which is deleted. * Add `std.net.IpAddress.parse` which accepts a port and parses either an IPv4 or IPv6 address. * Add `std.net.IpAddress.parseExpectingFamily` which additionally accepts a `family` parameter. * `std.net.IpAddress.initIp4` and `std.net.IpAddress.initIp6` are improved to directly take the address fields instead of a weird in-between type. * `std.net.IpAddress.port` is renamed to `std.net.IpAddress.getPort`. * Added `std.net.IpAddress.setPort`. * `os.sockaddr` struct on all targets is improved to match the corresponding system struct. Previously I had made it a union of sockaddr_in, sockaddr_in6, and sockaddr_un. The new abstraction for this is now `std.net.IpAddress`. * `os.sockaddr` and related bits are added for Windows. * `os.sockaddr` and related bits now have the `zero` fields default to zero initialization, and `len` fields default to the correct size. This is enough to abstract the differences across targets, and so no more switch on the target OS is needed in `std.net.IpAddress`. * Add the missing `os.sockaddr_un` on FreeBSD and NetBSD. * `std.net.IpAddress.initPosix` now takes a pointer to `os.sockaddr`.

10 files changed, 466 insertions(+), 427 deletions(-)

lib/std/mem.zig+1-1
...@@ -99,7 +99,7 @@ pub const Allocator = struct {...@@ -99,7 +99,7 @@ pub const Allocator = struct {
99 /// memory is no longer needed, to avoid a resource leak. If the99 /// memory is no longer needed, to avoid a resource leak. If the
100 /// `Allocator` implementation is unknown, then correct code will100 /// `Allocator` implementation is unknown, then correct code will
101 /// call `free` when done.101 /// call `free` when done.
102 /// 102 ///
103 /// For allocating a single item, see `create`.103 /// For allocating a single item, see `create`.
104 pub fn alloc(self: *Allocator, comptime T: type, n: usize) Error![]T {104 pub fn alloc(self: *Allocator, comptime T: type, n: usize) Error![]T {
105 return self.alignedAlloc(T, null, n);105 return self.alignedAlloc(T, null, n);
lib/std/net.zig+323-366
...@@ -10,98 +10,229 @@ test "" {...@@ -10,98 +10,229 @@ test "" {
10 _ = @import("net/test.zig");10 _ = @import("net/test.zig");
11}11}
1212
13pub const TmpWinAddr = struct {13pub const IpAddress = extern union {
14 family: u8,14 any: os.sockaddr,
15 data: [14]u8,15 in: os.sockaddr_in,
16};16 in6: os.sockaddr_in6,
17
18pub const OsAddress = switch (builtin.os) {
19 .windows => TmpWinAddr,
20 else => os.sockaddr,
21};
22
23/// This data structure is a "view". The underlying data might have references
24/// to owned memory which must live longer than this struct.
25pub const Address = struct {
26 os_addr: OsAddress,
2717
28 // TODO this crashed the compiler18 // TODO this crashed the compiler
29 //pub const localhost = initIp4(parseIp4("127.0.0.1") catch unreachable, 0);19 //pub const localhost = initIp4(parseIp4("127.0.0.1") catch unreachable, 0);
3020
31 pub fn initIp4(ip4: u32, _port: u16) Address {21 pub fn parse(name: []const u8, port: u16) !IpAddress {
32 switch (builtin.os) {22 if (parseIp4(name, port)) |ip4| return ip4 else |err| switch (err) {
33 .linux => return Address{23 error.Overflow,
34 .os_addr = os.sockaddr{24 error.InvalidEnd,
35 .in = os.sockaddr_in{25 error.InvalidCharacter,
36 .family = os.AF_INET,26 error.Incomplete,
37 .port = mem.nativeToBig(u16, _port),27 => {},
38 .addr = ip4,28 }
39 .zero = [_]u8{0} ** 8,29
40 },30 if (parseIp6(name, port)) |ip6| return ip6 else |err| switch (err) {
41 },31 error.Overflow,
32 error.InvalidEnd,
33 error.InvalidCharacter,
34 error.Incomplete,
35 => {},
36 }
37
38 return error.InvalidIPAddressFormat;
39 }
40
41 pub fn parseExpectingFamily(name: []const u8, family: os.sa_family_t, port: u16) !IpAddress {
42 switch (family) {
43 os.AF_INET => return parseIp4(name, port),
44 os.AF_INET6 => return parseIp6(name, port),
45 os.AF_UNSPEC => return parse(name, port),
46 else => unreachable,
47 }
48 }
49
50 pub fn parseIp6(buf: []const u8, port: u16) !IpAddress {
51 var result = IpAddress{
52 .in6 = os.sockaddr_in6{
53 .scope_id = undefined,
54 .port = mem.nativeToBig(u16, port),
55 .flowinfo = 0,
56 .addr = undefined,
42 },57 },
43 else => return Address{58 };
44 .os_addr = os.sockaddr{59 const ip_slice = result.in6.addr[0..];
45 .in = os.sockaddr_in{60
46 .len = @sizeOf(os.sockaddr_in),61 var x: u16 = 0;
47 .family = os.AF_INET,62 var saw_any_digits = false;
48 .port = mem.nativeToBig(u16, _port),63 var index: u8 = 0;
49 .addr = ip4,64 var scope_id = false;
50 .zero = [_]u8{0} ** 8,65 for (buf) |c| {
51 },66 if (scope_id) {
52 },67 if (c >= '0' and c <= '9') {
68 const digit = c - '0';
69 if (@mulWithOverflow(u32, result.in6.scope_id, 10, &result.in6.scope_id)) {
70 return error.Overflow;
71 }
72 if (@addWithOverflow(u32, result.in6.scope_id, digit, &result.in6.scope_id)) {
73 return error.Overflow;
74 }
75 } else {
76 return error.InvalidCharacter;
77 }
78 } else if (c == ':') {
79 if (!saw_any_digits) {
80 return error.InvalidCharacter;
81 }
82 if (index == 14) {
83 return error.InvalidEnd;
84 }
85 ip_slice[index] = @truncate(u8, x >> 8);
86 index += 1;
87 ip_slice[index] = @truncate(u8, x);
88 index += 1;
89
90 x = 0;
91 saw_any_digits = false;
92 } else if (c == '%') {
93 if (!saw_any_digits) {
94 return error.InvalidCharacter;
95 }
96 if (index == 14) {
97 ip_slice[index] = @truncate(u8, x >> 8);
98 index += 1;
99 ip_slice[index] = @truncate(u8, x);
100 index += 1;
101 }
102 scope_id = true;
103 saw_any_digits = false;
104 } else {
105 const digit = try std.fmt.charToDigit(c, 16);
106 if (@mulWithOverflow(u16, x, 16, &x)) {
107 return error.Overflow;
108 }
109 if (@addWithOverflow(u16, x, digit, &x)) {
110 return error.Overflow;
111 }
112 saw_any_digits = true;
113 }
114 }
115
116 if (!saw_any_digits) {
117 return error.Incomplete;
118 }
119
120 if (scope_id) {
121 return result;
122 }
123
124 if (index == 14) {
125 ip_slice[14] = @truncate(u8, x >> 8);
126 ip_slice[15] = @truncate(u8, x);
127 return result;
128 }
129
130 return error.Incomplete;
131 }
132
133 pub fn parseIp4(buf: []const u8, port: u16) !IpAddress {
134 var result = IpAddress{
135 .in = os.sockaddr_in{
136 .port = mem.nativeToBig(u16, port),
137 .addr = undefined,
53 },138 },
139 };
140 const out_ptr = @sliceToBytes((*[1]u32)(&result.in.addr)[0..]);
141
142 var x: u8 = 0;
143 var index: u8 = 0;
144 var saw_any_digits = false;
145 for (buf) |c| {
146 if (c == '.') {
147 if (!saw_any_digits) {
148 return error.InvalidCharacter;
149 }
150 if (index == 3) {
151 return error.InvalidEnd;
152 }
153 out_ptr[index] = x;
154 index += 1;
155 x = 0;
156 saw_any_digits = false;
157 } else if (c >= '0' and c <= '9') {
158 saw_any_digits = true;
159 x = try std.math.mul(u8, x, 10);
160 x = try std.math.add(u8, x, c - '0');
161 } else {
162 return error.InvalidCharacter;
163 }
164 }
165 if (index == 3 and saw_any_digits) {
166 out_ptr[index] = x;
167 return result;
54 }168 }
169
170 return error.Incomplete;
55 }171 }
56172
57 pub fn initIp6(ip6: Ip6Addr, _port: u16) Address {173 pub fn initIp4(addr: [4]u8, port: u16) IpAddress {
58 switch (builtin.os) {174 return IpAddress{
59 .linux => return Address{175 .in = os.sockaddr_in{
60 .os_addr = os.sockaddr{176 .port = mem.nativeToBig(u16, port),
61 .in6 = os.sockaddr_in6{177 .addr = @ptrCast(*align(1) const u32, &addr).*,
62 .family = os.AF_INET6,
63 .port = mem.nativeToBig(u16, _port),
64 .flowinfo = 0,
65 .addr = ip6.addr,
66 .scope_id = ip6.scope_id,
67 },
68 },
69 },178 },
70 else => return Address{179 };
71 .os_addr = os.sockaddr{180 }
72 .in6 = os.sockaddr_in6{181
73 .len = @sizeOf(os.sockaddr_in6),182 pub fn initIp6(addr: [16]u8, port: u16, flowinfo: u32, scope_id: u32) IpAddress {
74 .family = os.AF_INET6,183 return IpAddress{
75 .port = mem.nativeToBig(u16, _port),184 .in6 = os.sockaddr_in6{
76 .flowinfo = 0,185 .addr = addr,
77 .addr = ip6.addr,186 .port = mem.nativeToBig(u16, port),
78 .scope_id = ip6.scope_id,187 .flowinfo = flowinfo,
79 },188 .scope_id = scope_id,
80 },
81 },189 },
82 }190 };
83 }191 }
84192
85 pub fn port(self: Address) u16 {193 /// Returns the port in native endian.
86 return mem.bigToNative(u16, self.os_addr.in.port);194 pub fn getPort(self: IpAddress) u16 {
195 const big_endian_port = switch (self.any.family) {
196 os.AF_INET => self.in.port,
197 os.AF_INET6 => self.in6.port,
198 else => unreachable,
199 };
200 return mem.bigToNative(u16, big_endian_port);
87 }201 }
88202
89 pub fn initPosix(addr: os.sockaddr) Address {203 /// `port` is native-endian.
90 return Address{ .os_addr = addr };204 pub fn setPort(self: *IpAddress, port: u16) void {
205 const ptr = switch (self.any.family) {
206 os.AF_INET => &self.in.port,
207 os.AF_INET6 => &self.in6.port,
208 else => unreachable,
209 };
210 ptr.* = mem.nativeToBig(u16, port);
211 }
212
213 /// Asserts that `addr` is an IP address.
214 /// This function will read past the end of the pointer, with a size depending
215 /// on the address family.
216 pub fn initPosix(addr: *align(4) const os.sockaddr) IpAddress {
217 switch (addr.family) {
218 os.AF_INET => return IpAddress{ .in = @ptrCast(*const os.sockaddr_in, addr).* },
219 os.AF_INET6 => return IpAddress{ .in6 = @ptrCast(*const os.sockaddr_in6, addr).* },
220 else => unreachable,
221 }
91 }222 }
92223
93 pub fn format(224 pub fn format(
94 self: Address,225 self: IpAddress,
95 comptime fmt: []const u8,226 comptime fmt: []const u8,
96 options: std.fmt.FormatOptions,227 options: std.fmt.FormatOptions,
97 context: var,228 context: var,
98 comptime Errors: type,229 comptime Errors: type,
99 output: fn (@typeOf(context), []const u8) Errors!void,230 output: fn (@typeOf(context), []const u8) Errors!void,
100 ) !void {231 ) !void {
101 switch (self.os_addr.in.family) {232 switch (self.any.family) {
102 os.AF_INET => {233 os.AF_INET => {
103 const native_endian_port = mem.bigToNative(u16, self.os_addr.in.port);234 const port = mem.bigToNative(u16, self.in.port);
104 const bytes = @ptrCast(*const [4]u8, &self.os_addr.in.addr);235 const bytes = @ptrCast(*const [4]u8, &self.in.addr);
105 try std.fmt.format(236 try std.fmt.format(
106 context,237 context,
107 Errors,238 Errors,
...@@ -111,7 +242,7 @@ pub const Address = struct {...@@ -111,7 +242,7 @@ pub const Address = struct {
111 bytes[1],242 bytes[1],
112 bytes[2],243 bytes[2],
113 bytes[3],244 bytes[3],
114 native_endian_port,245 port,
115 );246 );
116 },247 },
117 os.AF_INET6 => {248 os.AF_INET6 => {
...@@ -119,8 +250,8 @@ pub const Address = struct {...@@ -119,8 +250,8 @@ pub const Address = struct {
119 index: usize,250 index: usize,
120 count: usize,251 count: usize,
121 };252 };
122 const native_endian_port = mem.bigToNative(u16, self.os_addr.in6.port);253 const port = mem.bigToNative(u16, self.in6.port);
123 const big_endian_parts = @ptrCast(*align(1) const [8]u16, &self.os_addr.in6.addr);254 const big_endian_parts = @ptrCast(*align(1) const [8]u16, &self.in6.addr);
124 const native_endian_parts = switch (builtin.endian) {255 const native_endian_parts = switch (builtin.endian) {
125 .Big => big_endian_parts.*,256 .Big => big_endian_parts.*,
126 .Little => blk: {257 .Little => blk: {
...@@ -170,14 +301,20 @@ pub const Address = struct {...@@ -170,14 +301,20 @@ pub const Address = struct {
170 try std.fmt.format(context, Errors, output, "{x}", part);301 try std.fmt.format(context, Errors, output, "{x}", part);
171 i += 1;302 i += 1;
172 }303 }
173 try std.fmt.format(context, Errors, output, "]:{}", native_endian_port);304 try std.fmt.format(context, Errors, output, "]:{}", port);
174 },305 },
175 else => return output(context, "(unrecognized address family)"),306 else => unreachable,
176 }307 }
177 }308 }
178309
179 fn getOsSockLen(self: Address) os.socklen_t {310 pub fn eql(a: IpAddress, b: IpAddress) bool {
180 switch (self.os_addr.un.family) {311 const a_bytes = @ptrCast([*]const u8, &a.any)[0..a.getOsSockLen()];
312 const b_bytes = @ptrCast([*]const u8, &b.any)[0..b.getOsSockLen()];
313 return mem.eql(u8, a_bytes, b_bytes);
314 }
315
316 fn getOsSockLen(self: IpAddress) os.socklen_t {
317 switch (self.any.family) {
181 os.AF_INET => return @sizeOf(os.sockaddr_in),318 os.AF_INET => return @sizeOf(os.sockaddr_in),
182 os.AF_INET6 => return @sizeOf(os.sockaddr_in6),319 os.AF_INET6 => return @sizeOf(os.sockaddr_in6),
183 else => unreachable,320 else => unreachable,
...@@ -185,123 +322,6 @@ pub const Address = struct {...@@ -185,123 +322,6 @@ pub const Address = struct {
185 }322 }
186};323};
187324
188pub fn parseIp4(buf: []const u8) !u32 {
189 var result: u32 = undefined;
190 const out_ptr = @sliceToBytes((*[1]u32)(&result)[0..]);
191
192 var x: u8 = 0;
193 var index: u8 = 0;
194 var saw_any_digits = false;
195 for (buf) |c| {
196 if (c == '.') {
197 if (!saw_any_digits) {
198 return error.InvalidCharacter;
199 }
200 if (index == 3) {
201 return error.InvalidEnd;
202 }
203 out_ptr[index] = x;
204 index += 1;
205 x = 0;
206 saw_any_digits = false;
207 } else if (c >= '0' and c <= '9') {
208 saw_any_digits = true;
209 x = try std.math.mul(u8, x, 10);
210 x = try std.math.add(u8, x, c - '0');
211 } else {
212 return error.InvalidCharacter;
213 }
214 }
215 if (index == 3 and saw_any_digits) {
216 out_ptr[index] = x;
217 return result;
218 }
219
220 return error.Incomplete;
221}
222
223pub const Ip6Addr = struct {
224 scope_id: u32,
225 addr: [16]u8,
226};
227
228pub fn parseIp6(buf: []const u8) !Ip6Addr {
229 var result: Ip6Addr = undefined;
230 result.scope_id = 0;
231 const ip_slice = result.addr[0..];
232
233 var x: u16 = 0;
234 var saw_any_digits = false;
235 var index: u8 = 0;
236 var scope_id = false;
237 for (buf) |c| {
238 if (scope_id) {
239 if (c >= '0' and c <= '9') {
240 const digit = c - '0';
241 if (@mulWithOverflow(u32, result.scope_id, 10, &result.scope_id)) {
242 return error.Overflow;
243 }
244 if (@addWithOverflow(u32, result.scope_id, digit, &result.scope_id)) {
245 return error.Overflow;
246 }
247 } else {
248 return error.InvalidCharacter;
249 }
250 } else if (c == ':') {
251 if (!saw_any_digits) {
252 return error.InvalidCharacter;
253 }
254 if (index == 14) {
255 return error.InvalidEnd;
256 }
257 ip_slice[index] = @truncate(u8, x >> 8);
258 index += 1;
259 ip_slice[index] = @truncate(u8, x);
260 index += 1;
261
262 x = 0;
263 saw_any_digits = false;
264 } else if (c == '%') {
265 if (!saw_any_digits) {
266 return error.InvalidCharacter;
267 }
268 if (index == 14) {
269 ip_slice[index] = @truncate(u8, x >> 8);
270 index += 1;
271 ip_slice[index] = @truncate(u8, x);
272 index += 1;
273 }
274 scope_id = true;
275 saw_any_digits = false;
276 } else {
277 const digit = try std.fmt.charToDigit(c, 16);
278 if (@mulWithOverflow(u16, x, 16, &x)) {
279 return error.Overflow;
280 }
281 if (@addWithOverflow(u16, x, digit, &x)) {
282 return error.Overflow;
283 }
284 saw_any_digits = true;
285 }
286 }
287
288 if (!saw_any_digits) {
289 return error.Incomplete;
290 }
291
292 if (scope_id) {
293 return result;
294 }
295
296 if (index == 14) {
297 ip_slice[14] = @truncate(u8, x >> 8);
298 ip_slice[15] = @truncate(u8, x);
299 return result;
300 }
301
302 return error.Incomplete;
303}
304
305pub fn connectUnixSocket(path: []const u8) !fs.File {325pub fn connectUnixSocket(path: []const u8) !fs.File {
306 const opt_non_block = if (std.io.mode == .evented) os.SOCK_NONBLOCK else 0;326 const opt_non_block = if (std.io.mode == .evented) os.SOCK_NONBLOCK else 0;
307 const sockfd = try os.socket(327 const sockfd = try os.socket(
...@@ -311,24 +331,23 @@ pub fn connectUnixSocket(path: []const u8) !fs.File {...@@ -311,24 +331,23 @@ pub fn connectUnixSocket(path: []const u8) !fs.File {
311 );331 );
312 errdefer os.close(sockfd);332 errdefer os.close(sockfd);
313333
314 var sock_addr = os.sockaddr{334 var sock_addr = os.sockaddr_un{
315 .un = os.sockaddr_un{335 .family = os.AF_UNIX,
316 .family = os.AF_UNIX,336 .path = undefined,
317 .path = undefined,
318 },
319 };337 };
320338
321 if (path.len > @typeOf(sock_addr.un.path).len) return error.NameTooLong;339 if (path.len > sock_addr.path.len) return error.NameTooLong;
322 mem.copy(u8, sock_addr.un.path[0..], path);340 mem.copy(u8, &sock_addr.path, path);
323 const size = @intCast(u32, @sizeOf(os.sa_family_t) + path.len);341
324 try os.connect(sockfd, sock_addr, size);342 const size = @intCast(u32, @sizeOf(os.sockaddr_un) - sock_addr.path.len + path.len);
343 try os.connect(sockfd, &sock_addr, size);
325344
326 return fs.File.openHandle(sockfd);345 return fs.File.openHandle(sockfd);
327}346}
328347
329pub const AddressList = struct {348pub const AddressList = struct {
330 arena: std.heap.ArenaAllocator,349 arena: std.heap.ArenaAllocator,
331 addrs: []Address,350 addrs: []IpAddress,
332 canon_name: ?[]u8,351 canon_name: ?[]u8,
333352
334 fn deinit(self: *AddressList) void {353 fn deinit(self: *AddressList) void {
...@@ -351,12 +370,12 @@ pub fn tcpConnectToHost(allocator: *mem.Allocator, name: []const u8, port: u16)...@@ -351,12 +370,12 @@ pub fn tcpConnectToHost(allocator: *mem.Allocator, name: []const u8, port: u16)
351 return tcpConnectToAddress(addrs[0], port);370 return tcpConnectToAddress(addrs[0], port);
352}371}
353372
354pub fn tcpConnectToAddress(address: Address) !fs.File {373pub fn tcpConnectToAddress(address: IpAddress) !fs.File {
355 const nonblock = if (std.io.is_async) os.SOCK_NONBLOCK else 0;374 const nonblock = if (std.io.is_async) os.SOCK_NONBLOCK else 0;
356 const sock_flags = os.SOCK_STREAM | os.SOCK_CLOEXEC | nonblock;375 const sock_flags = os.SOCK_STREAM | os.SOCK_CLOEXEC | nonblock;
357 const sockfd = try os.socket(address.os_addr.un.family, sock_flags, os.IPPROTO_TCP);376 const sockfd = try os.socket(address.any.family, sock_flags, os.IPPROTO_TCP);
358 errdefer os.close(sockfd);377 errdefer os.close(sockfd);
359 try os.connect(sockfd, address.os_addr, address.getOsSockLen());378 try os.connect(sockfd, &address.any, address.getOsSockLen());
360379
361 return fs.File{ .handle = sockfd };380 return fs.File{ .handle = sockfd };
362}381}
...@@ -426,13 +445,13 @@ pub fn getAddressList(allocator: *mem.Allocator, name: []const u8, port: u16) !*...@@ -426,13 +445,13 @@ pub fn getAddressList(allocator: *mem.Allocator, name: []const u8, port: u16) !*
426 }445 }
427 break :blk count;446 break :blk count;
428 };447 };
429 result.addrs = try arena.alloc(Address, addr_count);448 result.addrs = try arena.alloc(IpAddress, addr_count);
430449
431 var it: ?*os.addrinfo = res;450 var it: ?*os.addrinfo = res;
432 var i: usize = 0;451 var i: usize = 0;
433 while (it) |info| : (it = info.next) {452 while (it) |info| : (it = info.next) {
434 const addr = info.addr orelse continue;453 const addr = info.addr orelse continue;
435 result.addrs[i] = Address.initPosix(addr.*);454 result.addrs[i] = IpAddress.initPosix(@alignCast(4, addr));
436455
437 if (info.canonname) |n| {456 if (info.canonname) |n| {
438 if (result.canon_name == null) {457 if (result.canon_name == null) {
...@@ -447,40 +466,22 @@ pub fn getAddressList(allocator: *mem.Allocator, name: []const u8, port: u16) !*...@@ -447,40 +466,22 @@ pub fn getAddressList(allocator: *mem.Allocator, name: []const u8, port: u16) !*
447 if (builtin.os == .linux) {466 if (builtin.os == .linux) {
448 const flags = std.c.AI_NUMERICSERV;467 const flags = std.c.AI_NUMERICSERV;
449 const family = os.AF_UNSPEC;468 const family = os.AF_UNSPEC;
450 var addrs = std.ArrayList(LookupAddr).init(allocator);469 var lookup_addrs = std.ArrayList(LookupAddr).init(allocator);
451 defer addrs.deinit();470 defer lookup_addrs.deinit();
452471
453 var canon = std.Buffer.initNull(arena);472 var canon = std.Buffer.initNull(arena);
454 defer canon.deinit();473 defer canon.deinit();
455474
456 try linuxLookupName(&addrs, &canon, name, family, flags);475 try linuxLookupName(&lookup_addrs, &canon, name, family, flags, port);
457476
458 result.addrs = try arena.alloc(Address, addrs.len);477 result.addrs = try arena.alloc(IpAddress, lookup_addrs.len);
459 if (!canon.isNull()) {478 if (!canon.isNull()) {
460 result.canon_name = canon.toOwnedSlice();479 result.canon_name = canon.toOwnedSlice();
461 }480 }
462481
463 for (addrs.toSliceConst()) |addr, i| {482 for (lookup_addrs.toSliceConst()) |lookup_addr, i| {
464 const os_addr = if (addr.family == os.AF_INET6)483 result.addrs[i] = lookup_addr.addr;
465 os.sockaddr{484 assert(result.addrs[i].getPort() == port);
466 .in6 = os.sockaddr_in6{
467 .family = addr.family,
468 .port = mem.nativeToBig(u16, port),
469 .flowinfo = 0,
470 .addr = addr.addr,
471 .scope_id = addr.scope_id,
472 },
473 }
474 else
475 os.sockaddr{
476 .in = os.sockaddr_in{
477 .family = addr.family,
478 .port = mem.nativeToBig(u16, port),
479 .addr = @ptrCast(*align(1) const u32, &addr.addr).*,
480 .zero = [8]u8{ 0, 0, 0, 0, 0, 0, 0, 0 },
481 },
482 };
483 result.addrs[i] = Address.initPosix(os_addr);
484 }485 }
485486
486 return result;487 return result;
...@@ -489,9 +490,7 @@ pub fn getAddressList(allocator: *mem.Allocator, name: []const u8, port: u16) !*...@@ -489,9 +490,7 @@ pub fn getAddressList(allocator: *mem.Allocator, name: []const u8, port: u16) !*
489}490}
490491
491const LookupAddr = struct {492const LookupAddr = struct {
492 family: os.sa_family_t,493 addr: IpAddress,
493 scope_id: u32 = 0,
494 addr: [16]u8, // could be IPv4 or IPv6
495 sortkey: i32 = 0,494 sortkey: i32 = 0,
496};495};
497496
...@@ -507,22 +506,26 @@ fn linuxLookupName(...@@ -507,22 +506,26 @@ fn linuxLookupName(
507 addrs: *std.ArrayList(LookupAddr),506 addrs: *std.ArrayList(LookupAddr),
508 canon: *std.Buffer,507 canon: *std.Buffer,
509 opt_name: ?[]const u8,508 opt_name: ?[]const u8,
510 family: i32,509 family: os.sa_family_t,
511 flags: u32,510 flags: u32,
511 port: u16,
512) !void {512) !void {
513 if (opt_name) |name| {513 if (opt_name) |name| {
514 // reject empty name and check len so it fits into temp bufs514 // reject empty name and check len so it fits into temp bufs
515 try canon.replaceContents(name);515 try canon.replaceContents(name);
516 try linuxLookupNameFromNumeric(addrs, name, family);516 if (IpAddress.parseExpectingFamily(name, family, port)) |addr| {
517 if (addrs.len == 0 and (flags & std.c.AI_NUMERICHOST) == 0) {517 try addrs.append(LookupAddr{ .addr = addr });
518 try linuxLookupNameFromHosts(addrs, canon, name, family);518 } else |name_err| if ((flags & std.c.AI_NUMERICHOST) != 0) {
519 return name_err;
520 } else {
521 try linuxLookupNameFromHosts(addrs, canon, name, family, port);
519 if (addrs.len == 0) {522 if (addrs.len == 0) {
520 try linuxLookupNameFromDnsSearch(addrs, canon, name, family);523 try linuxLookupNameFromDnsSearch(addrs, canon, name, family, port);
521 }524 }
522 }525 }
523 } else {526 } else {
524 try canon.resize(0);527 try canon.resize(0);
525 try linuxLookupNameFromNull(addrs, family, flags);528 try linuxLookupNameFromNull(addrs, family, flags, port);
526 }529 }
527 if (addrs.len == 0) return error.UnknownHostName;530 if (addrs.len == 0) return error.UnknownHostName;
528531
...@@ -530,7 +533,7 @@ fn linuxLookupName(...@@ -530,7 +533,7 @@ fn linuxLookupName(
530 // results or if there are only IPv4 results.533 // results or if there are only IPv4 results.
531 if (addrs.len == 1 or family == os.AF_INET) return;534 if (addrs.len == 1 or family == os.AF_INET) return;
532 const all_ip4 = for (addrs.toSliceConst()) |addr| {535 const all_ip4 = for (addrs.toSliceConst()) |addr| {
533 if (addr.family != os.AF_INET) break false;536 if (addr.addr.any.family != os.AF_INET) break false;
534 } else true;537 } else true;
535 if (all_ip4) return;538 if (all_ip4) return;
536539
...@@ -547,7 +550,7 @@ fn linuxLookupName(...@@ -547,7 +550,7 @@ fn linuxLookupName(
547 @memset(@ptrCast([*]u8, &sa6), 0, @sizeOf(os.sockaddr_in6));550 @memset(@ptrCast([*]u8, &sa6), 0, @sizeOf(os.sockaddr_in6));
548 var da6 = os.sockaddr_in6{551 var da6 = os.sockaddr_in6{
549 .family = os.AF_INET6,552 .family = os.AF_INET6,
550 .scope_id = addr.scope_id,553 .scope_id = addr.addr.in6.scope_id,
551 .port = 65535,554 .port = 65535,
552 .flowinfo = 0,555 .flowinfo = 0,
553 .addr = [1]u8{0} ** 16,556 .addr = [1]u8{0} ** 16,
...@@ -560,12 +563,12 @@ fn linuxLookupName(...@@ -560,12 +563,12 @@ fn linuxLookupName(
560 .addr = 0,563 .addr = 0,
561 .zero = [1]u8{0} ** 8,564 .zero = [1]u8{0} ** 8,
562 };565 };
563 var sa: *os.sockaddr = undefined;566 var sa: *align(4) os.sockaddr = undefined;
564 var da: *os.sockaddr = undefined;567 var da: *align(4) os.sockaddr = undefined;
565 var salen: os.socklen_t = undefined;568 var salen: os.socklen_t = undefined;
566 var dalen: os.socklen_t = undefined;569 var dalen: os.socklen_t = undefined;
567 if (addr.family == os.AF_INET6) {570 if (addr.addr.any.family == os.AF_INET6) {
568 mem.copy(u8, &da6.addr, &addr.addr);571 mem.copy(u8, &da6.addr, &addr.addr.in6.addr);
569 da = @ptrCast(*os.sockaddr, &da6);572 da = @ptrCast(*os.sockaddr, &da6);
570 dalen = @sizeOf(os.sockaddr_in6);573 dalen = @sizeOf(os.sockaddr_in6);
571 sa = @ptrCast(*os.sockaddr, &sa6);574 sa = @ptrCast(*os.sockaddr, &sa6);
...@@ -573,8 +576,9 @@ fn linuxLookupName(...@@ -573,8 +576,9 @@ fn linuxLookupName(
573 } else {576 } else {
574 mem.copy(u8, &sa6.addr, "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xff\xff");577 mem.copy(u8, &sa6.addr, "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xff\xff");
575 mem.copy(u8, &da6.addr, "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xff\xff");578 mem.copy(u8, &da6.addr, "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xff\xff");
576 mem.copy(u8, da6.addr[12..], addr.addr[0..4]);579 // TODO https://github.com/ziglang/zig/issues/863
577 da4.addr = mem.readIntNative(u32, @ptrCast(*const [4]u8, &addr.addr));580 mem.writeIntNative(u32, @ptrCast(*[4]u8, da6.addr[12..].ptr), addr.addr.in.addr);
581 da4.addr = addr.addr.in.addr;
578 da = @ptrCast(*os.sockaddr, &da4);582 da = @ptrCast(*os.sockaddr, &da4);
579 dalen = @sizeOf(os.sockaddr_in);583 dalen = @sizeOf(os.sockaddr_in);
580 sa = @ptrCast(*os.sockaddr, &sa4);584 sa = @ptrCast(*os.sockaddr, &sa4);
...@@ -586,12 +590,13 @@ fn linuxLookupName(...@@ -586,12 +590,13 @@ fn linuxLookupName(
586 const dprec: i32 = dpolicy.prec;590 const dprec: i32 = dpolicy.prec;
587 const MAXADDRS = 3;591 const MAXADDRS = 3;
588 var prefixlen: i32 = 0;592 var prefixlen: i32 = 0;
589 if (os.socket(addr.family, os.SOCK_DGRAM | os.SOCK_CLOEXEC, os.IPPROTO_UDP)) |fd| syscalls: {593 const sock_flags = os.SOCK_DGRAM | os.SOCK_CLOEXEC;
594 if (os.socket(addr.addr.any.family, sock_flags, os.IPPROTO_UDP)) |fd| syscalls: {
590 defer os.close(fd);595 defer os.close(fd);
591 os.connect(fd, da.*, dalen) catch break :syscalls;596 os.connect(fd, da, dalen) catch break :syscalls;
592 key |= DAS_USABLE;597 key |= DAS_USABLE;
593 os.getsockname(fd, sa, &salen) catch break :syscalls;598 os.getsockname(fd, sa, &salen) catch break :syscalls;
594 if (addr.family == os.AF_INET) {599 if (addr.addr.any.family == os.AF_INET) {
595 // TODO sa6.addr[12..16] should return *[4]u8, making this cast unnecessary.600 // TODO sa6.addr[12..16] should return *[4]u8, making this cast unnecessary.
596 mem.writeIntNative(u32, @ptrCast(*[4]u8, &sa6.addr[12]), sa4.addr);601 mem.writeIntNative(u32, @ptrCast(*[4]u8, &sa6.addr[12]), sa4.addr);
597 }602 }
...@@ -726,72 +731,32 @@ fn addrCmpLessThan(b: LookupAddr, a: LookupAddr) bool {...@@ -726,72 +731,32 @@ fn addrCmpLessThan(b: LookupAddr, a: LookupAddr) bool {
726 return a.sortkey < b.sortkey;731 return a.sortkey < b.sortkey;
727}732}
728733
729fn linuxLookupNameFromNumericUnspec(addrs: *std.ArrayList(LookupAddr), name: []const u8) !void {734fn linuxLookupNameFromNull(
730 return linuxLookupNameFromNumeric(addrs, name, os.AF_UNSPEC) catch |err| switch (err) {735 addrs: *std.ArrayList(LookupAddr),
731 error.ExpectedIPv6ButFoundIPv4 => unreachable,736 family: os.sa_family_t,
732 error.ExpectedIPv4ButFoundIPv6 => unreachable,737 flags: u32,
733 else => |e| return e,738 port: u16,
734 };739) !void {
735}
736
737fn linuxLookupNameFromNumeric(addrs: *std.ArrayList(LookupAddr), name: []const u8, family: i32) !void {
738 if (parseIp4(name)) |ip4| {
739 if (family == os.AF_INET6) return error.ExpectedIPv6ButFoundIPv4;
740 const item = try addrs.addOne();
741 // TODO [0..4] should return *[4]u8, making this pointer cast unnecessary
742 mem.writeIntNative(u32, @ptrCast(*[4]u8, &item.addr), ip4);
743 item.family = os.AF_INET;
744 item.scope_id = 0;
745 return;
746 } else |err| switch (err) {
747 error.Overflow,
748 error.InvalidEnd,
749 error.InvalidCharacter,
750 error.Incomplete,
751 => {},
752 }
753
754 if (parseIp6(name)) |ip6| {
755 if (family == os.AF_INET) return error.ExpectedIPv4ButFoundIPv6;
756 const item = try addrs.addOne();
757 @memcpy(&item.addr, &ip6.addr, 16);
758 item.family = os.AF_INET6;
759 item.scope_id = ip6.scope_id;
760 return;
761 } else |err| switch (err) {
762 error.Overflow,
763 error.InvalidEnd,
764 error.InvalidCharacter,
765 error.Incomplete,
766 => {},
767 }
768}
769
770fn linuxLookupNameFromNull(addrs: *std.ArrayList(LookupAddr), family: i32, flags: u32) !void {
771 if ((flags & std.c.AI_PASSIVE) != 0) {740 if ((flags & std.c.AI_PASSIVE) != 0) {
772 if (family != os.AF_INET6) {741 if (family != os.AF_INET6) {
773 (try addrs.addOne()).* = LookupAddr{742 (try addrs.addOne()).* = LookupAddr{
774 .family = os.AF_INET,743 .addr = IpAddress.initIp4([1]u8{0} ** 4, port),
775 .addr = [1]u8{0} ** 16,
776 };744 };
777 }745 }
778 if (family != os.AF_INET) {746 if (family != os.AF_INET) {
779 (try addrs.addOne()).* = LookupAddr{747 (try addrs.addOne()).* = LookupAddr{
780 .family = os.AF_INET6,748 .addr = IpAddress.initIp6([1]u8{0} ** 16, port, 0, 0),
781 .addr = [1]u8{0} ** 16,
782 };749 };
783 }750 }
784 } else {751 } else {
785 if (family != os.AF_INET6) {752 if (family != os.AF_INET6) {
786 (try addrs.addOne()).* = LookupAddr{753 (try addrs.addOne()).* = LookupAddr{
787 .family = os.AF_INET,754 .addr = IpAddress.initIp4([4]u8{ 127, 0, 0, 1 }, port),
788 .addr = [4]u8{ 127, 0, 0, 1 } ++ ([1]u8{0} ** 12),
789 };755 };
790 }756 }
791 if (family != os.AF_INET) {757 if (family != os.AF_INET) {
792 (try addrs.addOne()).* = LookupAddr{758 (try addrs.addOne()).* = LookupAddr{
793 .family = os.AF_INET6,759 .addr = IpAddress.initIp6(([1]u8{0} ** 15) ++ [1]u8{1}, port, 0, 0),
794 .addr = ([1]u8{0} ** 15) ++ [1]u8{1},
795 };760 };
796 }761 }
797 }762 }
...@@ -801,7 +766,8 @@ fn linuxLookupNameFromHosts(...@@ -801,7 +766,8 @@ fn linuxLookupNameFromHosts(
801 addrs: *std.ArrayList(LookupAddr),766 addrs: *std.ArrayList(LookupAddr),
802 canon: *std.Buffer,767 canon: *std.Buffer,
803 name: []const u8,768 name: []const u8,
804 family: i32,769 family: os.sa_family_t,
770 port: u16,
805) !void {771) !void {
806 const file = fs.File.openReadC(c"/etc/hosts") catch |err| switch (err) {772 const file = fs.File.openReadC(c"/etc/hosts") catch |err| switch (err) {
807 error.FileNotFound,773 error.FileNotFound,
...@@ -835,18 +801,20 @@ fn linuxLookupNameFromHosts(...@@ -835,18 +801,20 @@ fn linuxLookupNameFromHosts(
835 }801 }
836 } else continue;802 } else continue;
837803
838 const prev_len = addrs.len;804 const addr = IpAddress.parseExpectingFamily(ip_text, family, port) catch |err| switch (err) {
839 linuxLookupNameFromNumeric(addrs, ip_text, family) catch |err| switch (err) {805 error.Overflow,
840 error.ExpectedIPv6ButFoundIPv4 => continue,806 error.InvalidEnd,
841 error.ExpectedIPv4ButFoundIPv6 => continue,807 error.InvalidCharacter,
842 error.OutOfMemory => |e| return e,808 error.Incomplete,
809 error.InvalidIPAddressFormat,
810 => continue,
843 };811 };
844 if (addrs.len > prev_len) {812 try addrs.append(LookupAddr{ .addr = addr });
845 // first name is canonical name813
846 const name_text = first_name_text.?;814 // first name is canonical name
847 if (isValidHostName(name_text)) {815 const name_text = first_name_text.?;
848 try canon.replaceContents(name_text);816 if (isValidHostName(name_text)) {
849 }817 try canon.replaceContents(name_text);
850 }818 }
851 }819 }
852}820}
...@@ -867,7 +835,8 @@ fn linuxLookupNameFromDnsSearch(...@@ -867,7 +835,8 @@ fn linuxLookupNameFromDnsSearch(
867 addrs: *std.ArrayList(LookupAddr),835 addrs: *std.ArrayList(LookupAddr),
868 canon: *std.Buffer,836 canon: *std.Buffer,
869 name: []const u8,837 name: []const u8,
870 family: i32,838 family: os.sa_family_t,
839 port: u16,
871) !void {840) !void {
872 var rc: ResolvConf = undefined;841 var rc: ResolvConf = undefined;
873 try getResolvConf(addrs.allocator, &rc);842 try getResolvConf(addrs.allocator, &rc);
...@@ -903,32 +872,35 @@ fn linuxLookupNameFromDnsSearch(...@@ -903,32 +872,35 @@ fn linuxLookupNameFromDnsSearch(
903 while (tok_it.next()) |tok| {872 while (tok_it.next()) |tok| {
904 canon.shrink(canon_name.len + 1);873 canon.shrink(canon_name.len + 1);
905 try canon.append(tok);874 try canon.append(tok);
906 try linuxLookupNameFromDns(addrs, canon, canon.toSliceConst(), family, rc);875 try linuxLookupNameFromDns(addrs, canon, canon.toSliceConst(), family, rc, port);
907 if (addrs.len != 0) return;876 if (addrs.len != 0) return;
908 }877 }
909878
910 canon.shrink(canon_name.len);879 canon.shrink(canon_name.len);
911 return linuxLookupNameFromDns(addrs, canon, name, family, rc);880 return linuxLookupNameFromDns(addrs, canon, name, family, rc, port);
912}881}
913882
914const dpc_ctx = struct {883const dpc_ctx = struct {
915 addrs: *std.ArrayList(LookupAddr),884 addrs: *std.ArrayList(LookupAddr),
916 canon: *std.Buffer,885 canon: *std.Buffer,
886 port: u16,
917};887};
918888
919fn linuxLookupNameFromDns(889fn linuxLookupNameFromDns(
920 addrs: *std.ArrayList(LookupAddr),890 addrs: *std.ArrayList(LookupAddr),
921 canon: *std.Buffer,891 canon: *std.Buffer,
922 name: []const u8,892 name: []const u8,
923 family: i32,893 family: os.sa_family_t,
924 rc: ResolvConf,894 rc: ResolvConf,
895 port: u16,
925) !void {896) !void {
926 var ctx = dpc_ctx{897 var ctx = dpc_ctx{
927 .addrs = addrs,898 .addrs = addrs,
928 .canon = canon,899 .canon = canon,
900 .port = port,
929 };901 };
930 const AfRr = struct {902 const AfRr = struct {
931 af: i32,903 af: os.sa_family_t,
932 rr: u8,904 rr: u8,
933 };905 };
934 const afrrs = [_]AfRr{906 const afrrs = [_]AfRr{
...@@ -994,7 +966,7 @@ fn getResolvConf(allocator: *mem.Allocator, rc: *ResolvConf) !void {...@@ -994,7 +966,7 @@ fn getResolvConf(allocator: *mem.Allocator, rc: *ResolvConf) !void {
994 error.FileNotFound,966 error.FileNotFound,
995 error.NotDir,967 error.NotDir,
996 error.AccessDenied,968 error.AccessDenied,
997 => return linuxLookupNameFromNumericUnspec(&rc.ns, "127.0.0.1"),969 => return linuxLookupNameFromNumericUnspec(&rc.ns, "127.0.0.1", 53),
998 else => |e| return e,970 else => |e| return e,
999 };971 };
1000 defer file.close();972 defer file.close();
...@@ -1033,21 +1005,24 @@ fn getResolvConf(allocator: *mem.Allocator, rc: *ResolvConf) !void {...@@ -1033,21 +1005,24 @@ fn getResolvConf(allocator: *mem.Allocator, rc: *ResolvConf) !void {
1033 }1005 }
1034 } else if (mem.eql(u8, token, "nameserver")) {1006 } else if (mem.eql(u8, token, "nameserver")) {
1035 const ip_txt = line_it.next() orelse continue;1007 const ip_txt = line_it.next() orelse continue;
1036 try linuxLookupNameFromNumericUnspec(&rc.ns, ip_txt);1008 try linuxLookupNameFromNumericUnspec(&rc.ns, ip_txt, 53);
1037 } else if (mem.eql(u8, token, "domain") or mem.eql(u8, token, "search")) {1009 } else if (mem.eql(u8, token, "domain") or mem.eql(u8, token, "search")) {
1038 try rc.search.replaceContents(line_it.rest());1010 try rc.search.replaceContents(line_it.rest());
1039 }1011 }
1040 }1012 }
10411013
1042 if (rc.ns.len == 0) {1014 if (rc.ns.len == 0) {
1043 return linuxLookupNameFromNumericUnspec(&rc.ns, "127.0.0.1");1015 return linuxLookupNameFromNumericUnspec(&rc.ns, "127.0.0.1", 53);
1044 }1016 }
1045}1017}
10461018
1047fn eqlSockAddr(a: *const os.sockaddr, b: *const os.sockaddr, len: usize) bool {1019fn linuxLookupNameFromNumericUnspec(
1048 const a_bytes = @ptrCast([*]const u8, a)[0..len];1020 addrs: *std.ArrayList(LookupAddr),
1049 const b_bytes = @ptrCast([*]const u8, b)[0..len];1021 name: []const u8,
1050 return mem.eql(u8, a_bytes, b_bytes);1022 port: u16,
1023) !void {
1024 const addr = try IpAddress.parse(name, port);
1025 (try addrs.addOne()).* = LookupAddr{ .addr = addr };
1051}1026}
10521027
1053fn resMSendRc(1028fn resMSendRc(
...@@ -1062,41 +1037,25 @@ fn resMSendRc(...@@ -1062,41 +1037,25 @@ fn resMSendRc(
1062 var sl: os.socklen_t = @sizeOf(os.sockaddr_in);1037 var sl: os.socklen_t = @sizeOf(os.sockaddr_in);
1063 var family: os.sa_family_t = os.AF_INET;1038 var family: os.sa_family_t = os.AF_INET;
10641039
1065 var ns_list = std.ArrayList(os.sockaddr).init(rc.ns.allocator);1040 var ns_list = std.ArrayList(IpAddress).init(rc.ns.allocator);
1066 defer ns_list.deinit();1041 defer ns_list.deinit();
10671042
1068 try ns_list.resize(rc.ns.len);1043 try ns_list.resize(rc.ns.len);
1069 const ns = ns_list.toSlice();1044 const ns = ns_list.toSlice();
10701045
1071 for (rc.ns.toSliceConst()) |iplit, i| {1046 for (rc.ns.toSliceConst()) |iplit, i| {
1072 if (iplit.family == os.AF_INET) {1047 ns[i] = iplit.addr;
1073 ns[i] = os.sockaddr{1048 assert(ns[i].getPort() == 53);
1074 .in = os.sockaddr_in{1049 if (iplit.addr.any.family != os.AF_INET) {
1075 .family = os.AF_INET,
1076 .port = mem.nativeToBig(u16, 53),
1077 .addr = mem.readIntNative(u32, @ptrCast(*const [4]u8, &iplit.addr)),
1078 .zero = [8]u8{ 0, 0, 0, 0, 0, 0, 0, 0 },
1079 },
1080 };
1081 } else {
1082 ns[i] = os.sockaddr{
1083 .in6 = os.sockaddr_in6{
1084 .family = os.AF_INET6,
1085 .port = mem.nativeToBig(u16, 53),
1086 .flowinfo = 0,
1087 .addr = iplit.addr,
1088 .scope_id = iplit.scope_id,
1089 },
1090 };
1091 sl = @sizeOf(os.sockaddr_in6);1050 sl = @sizeOf(os.sockaddr_in6);
1092 family = os.AF_INET6;1051 family = os.AF_INET6;
1093 }1052 }
1094 }1053 }
10951054
1096 // Get local address and open/bind a socket1055 // Get local address and open/bind a socket
1097 var sa: os.sockaddr = undefined;1056 var sa: IpAddress = undefined;
1098 @memset(@ptrCast([*]u8, &sa), 0, @sizeOf(os.sockaddr));1057 @memset(@ptrCast([*]u8, &sa), 0, @sizeOf(IpAddress));
1099 sa.in.family = family;1058 sa.any.family = family;
1100 const flags = os.SOCK_DGRAM | os.SOCK_CLOEXEC | os.SOCK_NONBLOCK;1059 const flags = os.SOCK_DGRAM | os.SOCK_CLOEXEC | os.SOCK_NONBLOCK;
1101 const fd = os.socket(family, flags, 0) catch |err| switch (err) {1060 const fd = os.socket(family, flags, 0) catch |err| switch (err) {
1102 error.AddressFamilyNotSupported => blk: {1061 error.AddressFamilyNotSupported => blk: {
...@@ -1110,7 +1069,7 @@ fn resMSendRc(...@@ -1110,7 +1069,7 @@ fn resMSendRc(
1110 else => |e| return e,1069 else => |e| return e,
1111 };1070 };
1112 defer os.close(fd);1071 defer os.close(fd);
1113 try os.bind(fd, &sa, sl);1072 try os.bind(fd, &sa.any, sl);
11141073
1115 // Past this point, there are no errors. Each individual query will1074 // Past this point, there are no errors. Each individual query will
1116 // yield either no reply (indicated by zero length) or an answer1075 // yield either no reply (indicated by zero length) or an answer
...@@ -1153,7 +1112,7 @@ fn resMSendRc(...@@ -1153,7 +1112,7 @@ fn resMSendRc(
1153 if (answers[i].len == 0) {1112 if (answers[i].len == 0) {
1154 var j: usize = 0;1113 var j: usize = 0;
1155 while (j < ns.len) : (j += 1) {1114 while (j < ns.len) : (j += 1) {
1156 _ = os.sendto(fd, queries[i], os.MSG_NOSIGNAL, &ns[j], sl) catch undefined;1115 _ = os.sendto(fd, queries[i], os.MSG_NOSIGNAL, &ns[j].any, sl) catch undefined;
1157 }1116 }
1158 }1117 }
1159 }1118 }
...@@ -1168,14 +1127,14 @@ fn resMSendRc(...@@ -1168,14 +1127,14 @@ fn resMSendRc(
11681127
1169 while (true) {1128 while (true) {
1170 var sl_copy = sl;1129 var sl_copy = sl;
1171 const rlen = os.recvfrom(fd, answer_bufs[next], 0, &sa, &sl_copy) catch break;1130 const rlen = os.recvfrom(fd, answer_bufs[next], 0, &sa.any, &sl_copy) catch break;
11721131
1173 // Ignore non-identifiable packets1132 // Ignore non-identifiable packets
1174 if (rlen < 4) continue;1133 if (rlen < 4) continue;
11751134
1176 // Ignore replies from addresses we didn't send to1135 // Ignore replies from addresses we didn't send to
1177 var j: usize = 0;1136 var j: usize = 0;
1178 while (j < ns.len and !eqlSockAddr(&ns[j], &sa, sl)) : (j += 1) {}1137 while (j < ns.len and !ns[j].eql(sa)) : (j += 1) {}
1179 if (j == ns.len) continue;1138 if (j == ns.len) continue;
11801139
1181 // Find which query this answer goes with, if any1140 // Find which query this answer goes with, if any
...@@ -1194,7 +1153,7 @@ fn resMSendRc(...@@ -1194,7 +1153,7 @@ fn resMSendRc(
1194 0, 3 => {},1153 0, 3 => {},
1195 2 => if (servfail_retry != 0) {1154 2 => if (servfail_retry != 0) {
1196 servfail_retry -= 1;1155 servfail_retry -= 1;
1197 _ = os.sendto(fd, queries[i], os.MSG_NOSIGNAL, &ns[j], sl) catch undefined;1156 _ = os.sendto(fd, queries[i], os.MSG_NOSIGNAL, &ns[j].any, sl) catch undefined;
1198 },1157 },
1199 else => continue,1158 else => continue,
1200 }1159 }
...@@ -1252,19 +1211,17 @@ fn dnsParseCallback(ctx: dpc_ctx, rr: u8, data: []const u8, packet: []const u8)...@@ -1252,19 +1211,17 @@ fn dnsParseCallback(ctx: dpc_ctx, rr: u8, data: []const u8, packet: []const u8)
1252 if (data.len != 4) return error.InvalidDnsARecord;1211 if (data.len != 4) return error.InvalidDnsARecord;
1253 const new_addr = try ctx.addrs.addOne();1212 const new_addr = try ctx.addrs.addOne();
1254 new_addr.* = LookupAddr{1213 new_addr.* = LookupAddr{
1255 .family = os.AF_INET,1214 // TODO slice [0..4] to make this *[4]u8 without @ptrCast
1256 .addr = undefined,1215 .addr = IpAddress.initIp4(@ptrCast(*const [4]u8, data.ptr).*, ctx.port),
1257 };1216 };
1258 mem.copy(u8, &new_addr.addr, data);
1259 },1217 },
1260 os.RR_AAAA => {1218 os.RR_AAAA => {
1261 if (data.len != 16) return error.InvalidDnsAAAARecord;1219 if (data.len != 16) return error.InvalidDnsAAAARecord;
1262 const new_addr = try ctx.addrs.addOne();1220 const new_addr = try ctx.addrs.addOne();
1263 new_addr.* = LookupAddr{1221 new_addr.* = LookupAddr{
1264 .family = os.AF_INET6,1222 // TODO slice [0..16] to make this *[16]u8 without @ptrCast
1265 .addr = undefined,1223 .addr = IpAddress.initIp6(@ptrCast(*const [16]u8, data.ptr).*, ctx.port, 0, 0),
1266 };1224 };
1267 mem.copy(u8, &new_addr.addr, data);
1268 },1225 },
1269 os.RR_CNAME => {1226 os.RR_CNAME => {
1270 var tmp: [256]u8 = undefined;1227 var tmp: [256]u8 = undefined;
...@@ -1284,7 +1241,7 @@ pub const TcpServer = struct {...@@ -1284,7 +1241,7 @@ pub const TcpServer = struct {
1284 kernel_backlog: u32,1241 kernel_backlog: u32,
12851242
1286 /// `undefined` until `listen` returns successfully.1243 /// `undefined` until `listen` returns successfully.
1287 listen_address: Address,1244 listen_address: IpAddress,
12881245
1289 sockfd: ?os.fd_t,1246 sockfd: ?os.fd_t,
12901247
...@@ -1311,7 +1268,7 @@ pub const TcpServer = struct {...@@ -1311,7 +1268,7 @@ pub const TcpServer = struct {
1311 self.* = undefined;1268 self.* = undefined;
1312 }1269 }
13131270
1314 pub fn listen(self: *TcpServer, address: Address) !void {1271 pub fn listen(self: *TcpServer, address: IpAddress) !void {
1315 const nonblock = if (std.io.is_async) os.SOCK_NONBLOCK else 0;1272 const nonblock = if (std.io.is_async) os.SOCK_NONBLOCK else 0;
1316 const sock_flags = os.SOCK_STREAM | os.SOCK_CLOEXEC | nonblock;1273 const sock_flags = os.SOCK_STREAM | os.SOCK_CLOEXEC | nonblock;
1317 const sockfd = try os.socket(os.AF_INET, sock_flags, os.PROTO_tcp);1274 const sockfd = try os.socket(os.AF_INET, sock_flags, os.PROTO_tcp);
...@@ -1322,9 +1279,9 @@ pub const TcpServer = struct {...@@ -1322,9 +1279,9 @@ pub const TcpServer = struct {
1322 }1279 }
13231280
1324 var socklen = address.getOsSockLen();1281 var socklen = address.getOsSockLen();
1325 try os.bind(sockfd, &address.os_addr, socklen);1282 try os.bind(sockfd, &address.any, socklen);
1326 try os.listen(sockfd, self.kernel_backlog);1283 try os.listen(sockfd, self.kernel_backlog);
1327 try os.getsockname(sockfd, &self.listen_address.os_addr, &socklen);1284 try os.getsockname(sockfd, &self.listen_address.any, &socklen);
1328 }1285 }
13291286
1330 /// Stop listening. It is still necessary to call `deinit` after stopping listening.1287 /// Stop listening. It is still necessary to call `deinit` after stopping listening.
...@@ -1361,9 +1318,9 @@ pub const TcpServer = struct {...@@ -1361,9 +1318,9 @@ pub const TcpServer = struct {
1361 pub fn accept(self: *TcpServer) AcceptError!fs.File {1318 pub fn accept(self: *TcpServer) AcceptError!fs.File {
1362 const nonblock = if (std.io.is_async) os.SOCK_NONBLOCK else 0;1319 const nonblock = if (std.io.is_async) os.SOCK_NONBLOCK else 0;
1363 const accept_flags = nonblock | os.SOCK_CLOEXEC;1320 const accept_flags = nonblock | os.SOCK_CLOEXEC;
1364 var accepted_addr: Address = undefined;1321 var accepted_addr: IpAddress = undefined;
1365 var adr_len: os.socklen_t = @sizeOf(os.sockaddr);1322 var adr_len: os.socklen_t = @sizeOf(IpAddress);
1366 if (os.accept4(self.sockfd.?, &accepted_addr.os_addr, &adr_len, accept_flags)) |fd| {1323 if (os.accept4(self.sockfd.?, &accepted_addr.any, &adr_len, accept_flags)) |fd| {
1367 return fs.File.openHandle(fd);1324 return fs.File.openHandle(fd);
1368 } else |err| switch (err) {1325 } else |err| switch (err) {
1369 // We only give SOCK_NONBLOCK when I/O mode is async, in which case this error1326 // We only give SOCK_NONBLOCK when I/O mode is async, in which case this error
lib/std/net/test.zig+13-25
...@@ -3,44 +3,32 @@ const net = std.net;...@@ -3,44 +3,32 @@ const net = std.net;
3const mem = std.mem;3const mem = std.mem;
4const testing = std.testing;4const testing = std.testing;
55
6test "parseIp4" {6test "parse and render IPv6 addresses" {
7 testing.expect((try net.parseIp4("127.0.0.1")) == mem.bigToNative(u32, 0x7f000001));7 const addr = net.IpAddress.parseIp6("FF01:0:0:0:0:0:0:FB", 80);
8
9 testParseIp4Fail("256.0.0.1", error.Overflow);
10 testParseIp4Fail("x.0.0.1", error.InvalidCharacter);
11 testParseIp4Fail("127.0.0.1.1", error.InvalidEnd);
12 testParseIp4Fail("127.0.0.", error.Incomplete);
13 testParseIp4Fail("100..0.1", error.InvalidCharacter);
14}
15
16fn testParseIp4Fail(buf: []const u8, expected_err: anyerror) void {
17 if (net.parseIp4(buf)) |_| {
18 @panic("expected error");
19 } else |e| {
20 testing.expect(e == expected_err);
21 }
22}
23
24test "parseIp6" {
25 const ip6 = try net.parseIp6("FF01:0:0:0:0:0:0:FB");
26 const addr = net.Address.initIp6(ip6, 80);
27 var buf: [100]u8 = undefined;8 var buf: [100]u8 = undefined;
28 const printed = try std.fmt.bufPrint(&buf, "{}", addr);9 const printed = try std.fmt.bufPrint(&buf, "{}", addr);
29 std.testing.expect(mem.eql(u8, "[ff01::fb]:80", printed));10 std.testing.expect(mem.eql(u8, "[ff01::fb]:80", printed));
30}11}
3112
32test "ip4s" {13test "parse and render IPv4 addresses" {
33 var buffer: [18]u8 = undefined;14 var buffer: [18]u8 = undefined;
34 for ([_][]const u8{15 for ([_][]const u8{
35 "0.0.0.0",16 "0.0.0.0",
36 "255.255.255.255",17 "255.255.255.255",
37 "1.2.3.4",18 "1.2.3.4",
38 "123.255.0.91",19 "123.255.0.91",
20 "127.0.0.1",
39 }) |ip| {21 }) |ip| {
40 var addr = net.Address.initIp4(net.parseIp4(ip) catch unreachable, 0);22 var addr = net.IpAddress.parseIp4(ip, 0);
41 var newIp = std.fmt.bufPrint(buffer[0..], "{}", addr) catch unreachable;23 var newIp = std.fmt.bufPrint(buffer[0..], "{}", addr) catch unreachable;
42 std.testing.expect(std.mem.eql(u8, ip, newIp[0 .. newIp.len - 2]));24 std.testing.expect(std.mem.eql(u8, ip, newIp[0 .. newIp.len - 2]));
43 }25 }
26
27 testing.expectError(error.Overflow, net.IpAddress.parseIp4("256.0.0.1", 0));
28 testing.expectError(error.InvalidCharacter, net.IpAddress.parseIp4("x.0.0.1", 0));
29 testing.expectError(error.InvalidEnd, net.IpAddress.parseIp4("127.0.0.1.1", 0));
30 testing.expectError(error.Incomplete, net.IpAddress.parseIp4("127.0.0.", 0));
31 testing.expectError(error.InvalidCharacter, net.IpAddress.parseIp4("100..0.1", 0));
44}32}
4533
46test "resolve DNS" {34test "resolve DNS" {
...@@ -72,7 +60,7 @@ test "listen on a port, send bytes, receive bytes" {...@@ -72,7 +60,7 @@ test "listen on a port, send bytes, receive bytes" {
72 }60 }
7361
74 // TODO doing this at comptime crashed the compiler62 // TODO doing this at comptime crashed the compiler
75 const localhost = net.Address.initIp4(net.parseIp4("127.0.0.1") catch unreachable, 0);63 const localhost = net.IpAddress.parse("127.0.0.1", 0);
7664
77 var server = net.TcpServer.init(net.TcpServer.Options{});65 var server = net.TcpServer.init(net.TcpServer.Options{});
78 defer server.deinit();66 defer server.deinit();
...@@ -85,7 +73,7 @@ test "listen on a port, send bytes, receive bytes" {...@@ -85,7 +73,7 @@ test "listen on a port, send bytes, receive bytes" {
85 try await client_frame;73 try await client_frame;
86}74}
8775
88fn testClient(addr: net.Address) anyerror!void {76fn testClient(addr: net.IpAddress) anyerror!void {
89 const socket_file = try net.tcpConnectToAddress(addr);77 const socket_file = try net.tcpConnectToAddress(addr);
90 defer socket_file.close();78 defer socket_file.close();
9179
lib/std/os.zig+2-2
...@@ -1920,9 +1920,9 @@ pub const ConnectError = error{...@@ -1920,9 +1920,9 @@ pub const ConnectError = error{
1920} || UnexpectedError;1920} || UnexpectedError;
19211921
1922/// Initiate a connection on a socket.1922/// Initiate a connection on a socket.
1923pub fn connect(sockfd: fd_t, sock_addr: sockaddr, len: socklen_t) ConnectError!void {1923pub fn connect(sockfd: fd_t, sock_addr: *const sockaddr, len: socklen_t) ConnectError!void {
1924 while (true) {1924 while (true) {
1925 switch (errno(system.connect(sockfd, &sock_addr, len))) {1925 switch (errno(system.connect(sockfd, sock_addr, len))) {
1926 0 => return,1926 0 => return,
1927 EACCES => return error.PermissionDenied,1927 EACCES => return error.PermissionDenied,
1928 EPERM => return error.PermissionDenied,1928 EPERM => return error.PermissionDenied,
lib/std/os/bits/darwin.zig+13-10
...@@ -9,28 +9,31 @@ pub const in_port_t = u16;...@@ -9,28 +9,31 @@ pub const in_port_t = u16;
9pub const sa_family_t = u8;9pub const sa_family_t = u8;
10pub const socklen_t = u32;10pub const socklen_t = u32;
11pub const sockaddr = extern union {11pub const sockaddr = extern union {
12 in: sockaddr_in,
13 in6: sockaddr_in6,
14 un: sockaddr_un,
15};
16pub const sockaddr_in = extern struct {
17 len: u8,12 len: u8,
18 family: sa_family_t,13 family: sa_family_t,
14 data: [14]u8,
15};
16pub const sockaddr_in = extern struct {
17 len: u8 = @sizeOf(sockaddr_in),
18 family: sa_family_t = AF_INET,
19 port: in_port_t,19 port: in_port_t,
20 addr: u32,20 addr: u32,
21 zero: [8]u8,21 zero: [8]u8 = [8]u8{ 0, 0, 0, 0, 0, 0, 0, 0 },
22};22};
23pub const sockaddr_in6 = extern struct {23pub const sockaddr_in6 = extern struct {
24 len: u8,24 len: u8 = @sizeOf(sockaddr_in6),
25 family: sa_family_t,25 family: sa_family_t = AF_INET6,
26 port: in_port_t,26 port: in_port_t,
27 flowinfo: u32,27 flowinfo: u32,
28 addr: [16]u8,28 addr: [16]u8,
29 scope_id: u32,29 scope_id: u32,
30};30};
31
32/// UNIX domain socket
31pub const sockaddr_un = extern struct {33pub const sockaddr_un = extern struct {
32 len: u8,34 len: u8 = @sizeOf(sockaddr_un),
33 family: sa_family_t,35 family: sa_family_t = AF_UNIX,
36 path: [104]u8,
34};37};
3538
36pub const timeval = extern struct {39pub const timeval = extern struct {
lib/std/os/bits/freebsd.zig+20-8
...@@ -138,27 +138,39 @@ pub const in_port_t = u16;...@@ -138,27 +138,39 @@ pub const in_port_t = u16;
138pub const sa_family_t = u16;138pub const sa_family_t = u16;
139139
140pub const sockaddr = extern union {140pub const sockaddr = extern union {
141 in: sockaddr_in,141 /// total length
142 in6: sockaddr_in6,142 len: u8,
143
144 /// address family
145 family: sa_family_t,
146
147 /// actually longer; address value
148 data: [14]u8,
143};149};
144150
145pub const sockaddr_in = extern struct {151pub const sockaddr_in = extern struct {
146 len: u8,152 len: u8 = @sizeOf(sockaddr_in),
147 family: sa_family_t,153 family: sa_family_t = AF_INET,
148 port: in_port_t,154 port: in_port_t,
149 addr: [16]u8,155 addr: u32,
150 zero: [8]u8,156 zero: [8]u8 = [8]u8{ 0, 0, 0, 0, 0, 0, 0, 0 },
151};157};
152158
153pub const sockaddr_in6 = extern struct {159pub const sockaddr_in6 = extern struct {
154 len: u8,160 len: u8 = @sizeOf(sockaddr_in6),
155 family: sa_family_t,161 family: sa_family_t = AF_INET6,
156 port: in_port_t,162 port: in_port_t,
157 flowinfo: u32,163 flowinfo: u32,
158 addr: [16]u8,164 addr: [16]u8,
159 scope_id: u32,165 scope_id: u32,
160};166};
161167
168pub const sockaddr_un = extern struct {
169 len: u8 = @sizeOf(sockaddr_un),
170 family: sa_family_t = AF_UNIX,
171 path: [104]u8,
172};
173
162pub const CTL_KERN = 1;174pub const CTL_KERN = 1;
163pub const CTL_DEBUG = 5;175pub const CTL_DEBUG = 5;
164176
lib/std/os/bits/linux.zig+9-8
...@@ -846,30 +846,31 @@ pub const in_port_t = u16;...@@ -846,30 +846,31 @@ pub const in_port_t = u16;
846pub const sa_family_t = u16;846pub const sa_family_t = u16;
847pub const socklen_t = u32;847pub const socklen_t = u32;
848848
849/// This intentionally only has ip4 and ip6
850pub const sockaddr = extern union {849pub const sockaddr = extern union {
851 in: sockaddr_in,850 family: sa_family_t,
852 in6: sockaddr_in6,851 data: [14]u8,
853 un: sockaddr_un,
854};852};
855853
854/// IPv4 socket address
856pub const sockaddr_in = extern struct {855pub const sockaddr_in = extern struct {
857 family: sa_family_t,856 family: sa_family_t = AF_INET,
858 port: in_port_t,857 port: in_port_t,
859 addr: u32,858 addr: u32,
860 zero: [8]u8,859 zero: [8]u8 = [8]u8{ 0, 0, 0, 0, 0, 0, 0, 0 },
861};860};
862861
862/// IPv6 socket address
863pub const sockaddr_in6 = extern struct {863pub const sockaddr_in6 = extern struct {
864 family: sa_family_t,864 family: sa_family_t = AF_INET6,
865 port: in_port_t,865 port: in_port_t,
866 flowinfo: u32,866 flowinfo: u32,
867 addr: [16]u8,867 addr: [16]u8,
868 scope_id: u32,868 scope_id: u32,
869};869};
870870
871/// UNIX domain socket address
871pub const sockaddr_un = extern struct {872pub const sockaddr_un = extern struct {
872 family: sa_family_t,873 family: sa_family_t = AF_UNIX,
873 path: [108]u8,874 path: [108]u8,
874};875};
875876
lib/std/os/bits/netbsd.zig+23-5
...@@ -134,20 +134,26 @@ pub const in_port_t = u16;...@@ -134,20 +134,26 @@ pub const in_port_t = u16;
134pub const sa_family_t = u8;134pub const sa_family_t = u8;
135135
136pub const sockaddr = extern union {136pub const sockaddr = extern union {
137 in: sockaddr_in,137 /// total length
138 in6: sockaddr_in6,138 len: u8,
139
140 /// address family
141 family: sa_family_t,
142
143 /// actually longer; address value
144 data: [14]u8,
139};145};
140146
141pub const sockaddr_in = extern struct {147pub const sockaddr_in = extern struct {
142 len: u8,148 len: u8 = @sizeOf(sockaddr_in),
143 family: sa_family_t,149 family: sa_family_t,
144 port: in_port_t,150 port: in_port_t,
145 addr: u32,151 addr: u32,
146 zero: [8]u8,152 zero: [8]u8 = [8]u8{ 0, 0, 0, 0, 0, 0, 0, 0 },
147};153};
148154
149pub const sockaddr_in6 = extern struct {155pub const sockaddr_in6 = extern struct {
150 len: u8,156 len: u8 = @sizeOf(sockaddr_in6),
151 family: sa_family_t,157 family: sa_family_t,
152 port: in_port_t,158 port: in_port_t,
153 flowinfo: u32,159 flowinfo: u32,
...@@ -155,6 +161,18 @@ pub const sockaddr_in6 = extern struct {...@@ -155,6 +161,18 @@ pub const sockaddr_in6 = extern struct {
155 scope_id: u32,161 scope_id: u32,
156};162};
157163
164/// Definitions for UNIX IPC domain.
165pub const sockaddr_un = extern struct {
166 /// total sockaddr length
167 len: u8 = @sizeOf(sockaddr_un),
168
169 /// AF_LOCAL
170 family: sa_family_t,
171
172 /// path name
173 path: [104]u8,
174};
175
158pub const CTL_KERN = 1;176pub const CTL_KERN = 1;
159pub const CTL_DEBUG = 5;177pub const CTL_DEBUG = 5;
160178
lib/std/os/bits/windows.zig+60
...@@ -161,3 +161,63 @@ pub const F_OK = 0;...@@ -161,3 +161,63 @@ pub const F_OK = 0;
161161
162/// Remove directory instead of unlinking file162/// Remove directory instead of unlinking file
163pub const AT_REMOVEDIR = 0x200;163pub const AT_REMOVEDIR = 0x200;
164
165pub const in_port_t = u16;
166pub const sa_family_t = u16;
167pub const socklen_t = u32;
168
169pub const sockaddr = extern struct {
170 family: sa_family_t,
171 data: [14]u8,
172};
173pub const sockaddr_in = extern struct {
174 family: sa_family_t = AF_INET,
175 port: in_port_t,
176 addr: in_addr,
177 zero: [8]u8 = [8]u8{ 0, 0, 0, 0, 0, 0, 0, 0 },
178};
179pub const sockaddr_in6 = extern struct {
180 family: sa_family_t = AF_INET6,
181 port: in_port_t,
182 flowinfo: u32,
183 addr: in6_addr,
184 scope_id: u32,
185};
186pub const in6_addr = [16]u8;
187pub const in_addr = u32;
188
189pub const AF_UNSPEC = 0;
190pub const AF_UNIX = 1;
191pub const AF_INET = 2;
192pub const AF_IMPLINK = 3;
193pub const AF_PUP = 4;
194pub const AF_CHAOS = 5;
195pub const AF_NS = 6;
196pub const AF_IPX = AF_NS;
197pub const AF_ISO = 7;
198pub const AF_OSI = AF_ISO;
199pub const AF_ECMA = 8;
200pub const AF_DATAKIT = 9;
201pub const AF_CCITT = 10;
202pub const AF_SNA = 11;
203pub const AF_DECnet = 12;
204pub const AF_DLI = 13;
205pub const AF_LAT = 14;
206pub const AF_HYLINK = 15;
207pub const AF_APPLETALK = 16;
208pub const AF_NETBIOS = 17;
209pub const AF_VOICEVIEW = 18;
210pub const AF_FIREFOX = 19;
211pub const AF_UNKNOWN1 = 20;
212pub const AF_BAN = 21;
213pub const AF_ATM = 22;
214pub const AF_INET6 = 23;
215pub const AF_CLUSTER = 24;
216pub const AF_12844 = 25;
217pub const AF_IRDA = 26;
218pub const AF_NETDES = 28;
219pub const AF_TCNPROCESS = 29;
220pub const AF_TCNMESSAGE = 30;
221pub const AF_ICLFXBM = 31;
222pub const AF_BTH = 32;
223pub const AF_MAX = 33;
test/compile_errors.zig+2-2
...@@ -162,9 +162,9 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -162,9 +162,9 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
162 \\ const obj = AstObject{ .lhsExpr = lhsExpr };162 \\ const obj = AstObject{ .lhsExpr = lhsExpr };
163 \\}163 \\}
164 ,164 ,
165 "tmp.zig:1:17: error: struct 'LhsExpr' depends on itself",165 "tmp.zig:4:19: error: union 'AstObject' depends on itself",
166 "tmp.zig:5:5: note: while checking this field",
167 "tmp.zig:2:5: note: while checking this field",166 "tmp.zig:2:5: note: while checking this field",
167 "tmp.zig:5:5: note: while checking this field",
168 );168 );
169169
170 cases.add(170 cases.add(