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 {
9999 /// memory is no longer needed, to avoid a resource leak. If the
100100 /// `Allocator` implementation is unknown, then correct code will
101101 /// call `free` when done.
102 ///
102 ///
103103 /// For allocating a single item, see `create`.
104104 pub fn alloc(self: *Allocator, comptime T: type, n: usize) Error![]T {
105105 return self.alignedAlloc(T, null, n);
lib/std/net.zig+323-366
......@@ -10,98 +10,229 @@ test "" {
1010 _ = @import("net/test.zig");
1111}
1212
13pub const TmpWinAddr = struct {
14 family: u8,
15 data: [14]u8,
16};
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,
13pub const IpAddress = extern union {
14 any: os.sockaddr,
15 in: os.sockaddr_in,
16 in6: os.sockaddr_in6,
2717
2818 // TODO this crashed the compiler
2919 //pub const localhost = initIp4(parseIp4("127.0.0.1") catch unreachable, 0);
3020
31 pub fn initIp4(ip4: u32, _port: u16) Address {
32 switch (builtin.os) {
33 .linux => return Address{
34 .os_addr = os.sockaddr{
35 .in = os.sockaddr_in{
36 .family = os.AF_INET,
37 .port = mem.nativeToBig(u16, _port),
38 .addr = ip4,
39 .zero = [_]u8{0} ** 8,
40 },
41 },
21 pub fn parse(name: []const u8, port: u16) !IpAddress {
22 if (parseIp4(name, port)) |ip4| return ip4 else |err| switch (err) {
23 error.Overflow,
24 error.InvalidEnd,
25 error.InvalidCharacter,
26 error.Incomplete,
27 => {},
28 }
29
30 if (parseIp6(name, port)) |ip6| return ip6 else |err| switch (err) {
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,
4257 },
43 else => return Address{
44 .os_addr = os.sockaddr{
45 .in = os.sockaddr_in{
46 .len = @sizeOf(os.sockaddr_in),
47 .family = os.AF_INET,
48 .port = mem.nativeToBig(u16, _port),
49 .addr = ip4,
50 .zero = [_]u8{0} ** 8,
51 },
52 },
58 };
59 const ip_slice = result.in6.addr[0..];
60
61 var x: u16 = 0;
62 var saw_any_digits = false;
63 var index: u8 = 0;
64 var scope_id = false;
65 for (buf) |c| {
66 if (scope_id) {
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,
53138 },
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;
54168 }
169
170 return error.Incomplete;
55171 }
56172
57 pub fn initIp6(ip6: Ip6Addr, _port: u16) Address {
58 switch (builtin.os) {
59 .linux => return Address{
60 .os_addr = os.sockaddr{
61 .in6 = os.sockaddr_in6{
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 },
173 pub fn initIp4(addr: [4]u8, port: u16) IpAddress {
174 return IpAddress{
175 .in = os.sockaddr_in{
176 .port = mem.nativeToBig(u16, port),
177 .addr = @ptrCast(*align(1) const u32, &addr).*,
69178 },
70 else => return Address{
71 .os_addr = os.sockaddr{
72 .in6 = os.sockaddr_in6{
73 .len = @sizeOf(os.sockaddr_in6),
74 .family = os.AF_INET6,
75 .port = mem.nativeToBig(u16, _port),
76 .flowinfo = 0,
77 .addr = ip6.addr,
78 .scope_id = ip6.scope_id,
79 },
80 },
179 };
180 }
181
182 pub fn initIp6(addr: [16]u8, port: u16, flowinfo: u32, scope_id: u32) IpAddress {
183 return IpAddress{
184 .in6 = os.sockaddr_in6{
185 .addr = addr,
186 .port = mem.nativeToBig(u16, port),
187 .flowinfo = flowinfo,
188 .scope_id = scope_id,
81189 },
82 }
190 };
83191 }
84192
85 pub fn port(self: Address) u16 {
86 return mem.bigToNative(u16, self.os_addr.in.port);
193 /// Returns the port in native endian.
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);
87201 }
88202
89 pub fn initPosix(addr: os.sockaddr) Address {
90 return Address{ .os_addr = addr };
203 /// `port` is native-endian.
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 }
91222 }
92223
93224 pub fn format(
94 self: Address,
225 self: IpAddress,
95226 comptime fmt: []const u8,
96227 options: std.fmt.FormatOptions,
97228 context: var,
98229 comptime Errors: type,
99230 output: fn (@typeOf(context), []const u8) Errors!void,
100231 ) !void {
101 switch (self.os_addr.in.family) {
232 switch (self.any.family) {
102233 os.AF_INET => {
103 const native_endian_port = mem.bigToNative(u16, self.os_addr.in.port);
104 const bytes = @ptrCast(*const [4]u8, &self.os_addr.in.addr);
234 const port = mem.bigToNative(u16, self.in.port);
235 const bytes = @ptrCast(*const [4]u8, &self.in.addr);
105236 try std.fmt.format(
106237 context,
107238 Errors,
......@@ -111,7 +242,7 @@ pub const Address = struct {
111242 bytes[1],
112243 bytes[2],
113244 bytes[3],
114 native_endian_port,
245 port,
115246 );
116247 },
117248 os.AF_INET6 => {
......@@ -119,8 +250,8 @@ pub const Address = struct {
119250 index: usize,
120251 count: usize,
121252 };
122 const native_endian_port = mem.bigToNative(u16, self.os_addr.in6.port);
123 const big_endian_parts = @ptrCast(*align(1) const [8]u16, &self.os_addr.in6.addr);
253 const port = mem.bigToNative(u16, self.in6.port);
254 const big_endian_parts = @ptrCast(*align(1) const [8]u16, &self.in6.addr);
124255 const native_endian_parts = switch (builtin.endian) {
125256 .Big => big_endian_parts.*,
126257 .Little => blk: {
......@@ -170,14 +301,20 @@ pub const Address = struct {
170301 try std.fmt.format(context, Errors, output, "{x}", part);
171302 i += 1;
172303 }
173 try std.fmt.format(context, Errors, output, "]:{}", native_endian_port);
304 try std.fmt.format(context, Errors, output, "]:{}", port);
174305 },
175 else => return output(context, "(unrecognized address family)"),
306 else => unreachable,
176307 }
177308 }
178309
179 fn getOsSockLen(self: Address) os.socklen_t {
180 switch (self.os_addr.un.family) {
310 pub fn eql(a: IpAddress, b: IpAddress) bool {
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) {
181318 os.AF_INET => return @sizeOf(os.sockaddr_in),
182319 os.AF_INET6 => return @sizeOf(os.sockaddr_in6),
183320 else => unreachable,
......@@ -185,123 +322,6 @@ pub const Address = struct {
185322 }
186323};
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
305325pub fn connectUnixSocket(path: []const u8) !fs.File {
306326 const opt_non_block = if (std.io.mode == .evented) os.SOCK_NONBLOCK else 0;
307327 const sockfd = try os.socket(
......@@ -311,24 +331,23 @@ pub fn connectUnixSocket(path: []const u8) !fs.File {
311331 );
312332 errdefer os.close(sockfd);
313333
314 var sock_addr = os.sockaddr{
315 .un = os.sockaddr_un{
316 .family = os.AF_UNIX,
317 .path = undefined,
318 },
334 var sock_addr = os.sockaddr_un{
335 .family = os.AF_UNIX,
336 .path = undefined,
319337 };
320338
321 if (path.len > @typeOf(sock_addr.un.path).len) return error.NameTooLong;
322 mem.copy(u8, sock_addr.un.path[0..], path);
323 const size = @intCast(u32, @sizeOf(os.sa_family_t) + path.len);
324 try os.connect(sockfd, sock_addr, size);
339 if (path.len > sock_addr.path.len) return error.NameTooLong;
340 mem.copy(u8, &sock_addr.path, path);
341
342 const size = @intCast(u32, @sizeOf(os.sockaddr_un) - sock_addr.path.len + path.len);
343 try os.connect(sockfd, &sock_addr, size);
325344
326345 return fs.File.openHandle(sockfd);
327346}
328347
329348pub const AddressList = struct {
330349 arena: std.heap.ArenaAllocator,
331 addrs: []Address,
350 addrs: []IpAddress,
332351 canon_name: ?[]u8,
333352
334353 fn deinit(self: *AddressList) void {
......@@ -351,12 +370,12 @@ pub fn tcpConnectToHost(allocator: *mem.Allocator, name: []const u8, port: u16)
351370 return tcpConnectToAddress(addrs[0], port);
352371}
353372
354pub fn tcpConnectToAddress(address: Address) !fs.File {
373pub fn tcpConnectToAddress(address: IpAddress) !fs.File {
355374 const nonblock = if (std.io.is_async) os.SOCK_NONBLOCK else 0;
356375 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);
358377 errdefer os.close(sockfd);
359 try os.connect(sockfd, address.os_addr, address.getOsSockLen());
378 try os.connect(sockfd, &address.any, address.getOsSockLen());
360379
361380 return fs.File{ .handle = sockfd };
362381}
......@@ -426,13 +445,13 @@ pub fn getAddressList(allocator: *mem.Allocator, name: []const u8, port: u16) !*
426445 }
427446 break :blk count;
428447 };
429 result.addrs = try arena.alloc(Address, addr_count);
448 result.addrs = try arena.alloc(IpAddress, addr_count);
430449
431450 var it: ?*os.addrinfo = res;
432451 var i: usize = 0;
433452 while (it) |info| : (it = info.next) {
434453 const addr = info.addr orelse continue;
435 result.addrs[i] = Address.initPosix(addr.*);
454 result.addrs[i] = IpAddress.initPosix(@alignCast(4, addr));
436455
437456 if (info.canonname) |n| {
438457 if (result.canon_name == null) {
......@@ -447,40 +466,22 @@ pub fn getAddressList(allocator: *mem.Allocator, name: []const u8, port: u16) !*
447466 if (builtin.os == .linux) {
448467 const flags = std.c.AI_NUMERICSERV;
449468 const family = os.AF_UNSPEC;
450 var addrs = std.ArrayList(LookupAddr).init(allocator);
451 defer addrs.deinit();
469 var lookup_addrs = std.ArrayList(LookupAddr).init(allocator);
470 defer lookup_addrs.deinit();
452471
453472 var canon = std.Buffer.initNull(arena);
454473 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);
459478 if (!canon.isNull()) {
460479 result.canon_name = canon.toOwnedSlice();
461480 }
462481
463 for (addrs.toSliceConst()) |addr, i| {
464 const os_addr = if (addr.family == os.AF_INET6)
465 os.sockaddr{
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);
482 for (lookup_addrs.toSliceConst()) |lookup_addr, i| {
483 result.addrs[i] = lookup_addr.addr;
484 assert(result.addrs[i].getPort() == port);
484485 }
485486
486487 return result;
......@@ -489,9 +490,7 @@ pub fn getAddressList(allocator: *mem.Allocator, name: []const u8, port: u16) !*
489490}
490491
491492const LookupAddr = struct {
492 family: os.sa_family_t,
493 scope_id: u32 = 0,
494 addr: [16]u8, // could be IPv4 or IPv6
493 addr: IpAddress,
495494 sortkey: i32 = 0,
496495};
497496
......@@ -507,22 +506,26 @@ fn linuxLookupName(
507506 addrs: *std.ArrayList(LookupAddr),
508507 canon: *std.Buffer,
509508 opt_name: ?[]const u8,
510 family: i32,
509 family: os.sa_family_t,
511510 flags: u32,
511 port: u16,
512512) !void {
513513 if (opt_name) |name| {
514514 // reject empty name and check len so it fits into temp bufs
515515 try canon.replaceContents(name);
516 try linuxLookupNameFromNumeric(addrs, name, family);
517 if (addrs.len == 0 and (flags & std.c.AI_NUMERICHOST) == 0) {
518 try linuxLookupNameFromHosts(addrs, canon, name, family);
516 if (IpAddress.parseExpectingFamily(name, family, port)) |addr| {
517 try addrs.append(LookupAddr{ .addr = addr });
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);
519522 if (addrs.len == 0) {
520 try linuxLookupNameFromDnsSearch(addrs, canon, name, family);
523 try linuxLookupNameFromDnsSearch(addrs, canon, name, family, port);
521524 }
522525 }
523526 } else {
524527 try canon.resize(0);
525 try linuxLookupNameFromNull(addrs, family, flags);
528 try linuxLookupNameFromNull(addrs, family, flags, port);
526529 }
527530 if (addrs.len == 0) return error.UnknownHostName;
528531
......@@ -530,7 +533,7 @@ fn linuxLookupName(
530533 // results or if there are only IPv4 results.
531534 if (addrs.len == 1 or family == os.AF_INET) return;
532535 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;
534537 } else true;
535538 if (all_ip4) return;
536539
......@@ -547,7 +550,7 @@ fn linuxLookupName(
547550 @memset(@ptrCast([*]u8, &sa6), 0, @sizeOf(os.sockaddr_in6));
548551 var da6 = os.sockaddr_in6{
549552 .family = os.AF_INET6,
550 .scope_id = addr.scope_id,
553 .scope_id = addr.addr.in6.scope_id,
551554 .port = 65535,
552555 .flowinfo = 0,
553556 .addr = [1]u8{0} ** 16,
......@@ -560,12 +563,12 @@ fn linuxLookupName(
560563 .addr = 0,
561564 .zero = [1]u8{0} ** 8,
562565 };
563 var sa: *os.sockaddr = undefined;
564 var da: *os.sockaddr = undefined;
566 var sa: *align(4) os.sockaddr = undefined;
567 var da: *align(4) os.sockaddr = undefined;
565568 var salen: os.socklen_t = undefined;
566569 var dalen: os.socklen_t = undefined;
567 if (addr.family == os.AF_INET6) {
568 mem.copy(u8, &da6.addr, &addr.addr);
570 if (addr.addr.any.family == os.AF_INET6) {
571 mem.copy(u8, &da6.addr, &addr.addr.in6.addr);
569572 da = @ptrCast(*os.sockaddr, &da6);
570573 dalen = @sizeOf(os.sockaddr_in6);
571574 sa = @ptrCast(*os.sockaddr, &sa6);
......@@ -573,8 +576,9 @@ fn linuxLookupName(
573576 } else {
574577 mem.copy(u8, &sa6.addr, "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xff\xff");
575578 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]);
577 da4.addr = mem.readIntNative(u32, @ptrCast(*const [4]u8, &addr.addr));
579 // TODO https://github.com/ziglang/zig/issues/863
580 mem.writeIntNative(u32, @ptrCast(*[4]u8, da6.addr[12..].ptr), addr.addr.in.addr);
581 da4.addr = addr.addr.in.addr;
578582 da = @ptrCast(*os.sockaddr, &da4);
579583 dalen = @sizeOf(os.sockaddr_in);
580584 sa = @ptrCast(*os.sockaddr, &sa4);
......@@ -586,12 +590,13 @@ fn linuxLookupName(
586590 const dprec: i32 = dpolicy.prec;
587591 const MAXADDRS = 3;
588592 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: {
590595 defer os.close(fd);
591 os.connect(fd, da.*, dalen) catch break :syscalls;
596 os.connect(fd, da, dalen) catch break :syscalls;
592597 key |= DAS_USABLE;
593598 os.getsockname(fd, sa, &salen) catch break :syscalls;
594 if (addr.family == os.AF_INET) {
599 if (addr.addr.any.family == os.AF_INET) {
595600 // TODO sa6.addr[12..16] should return *[4]u8, making this cast unnecessary.
596601 mem.writeIntNative(u32, @ptrCast(*[4]u8, &sa6.addr[12]), sa4.addr);
597602 }
......@@ -726,72 +731,32 @@ fn addrCmpLessThan(b: LookupAddr, a: LookupAddr) bool {
726731 return a.sortkey < b.sortkey;
727732}
728733
729fn linuxLookupNameFromNumericUnspec(addrs: *std.ArrayList(LookupAddr), name: []const u8) !void {
730 return linuxLookupNameFromNumeric(addrs, name, os.AF_UNSPEC) catch |err| switch (err) {
731 error.ExpectedIPv6ButFoundIPv4 => unreachable,
732 error.ExpectedIPv4ButFoundIPv6 => unreachable,
733 else => |e| return e,
734 };
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 {
734fn linuxLookupNameFromNull(
735 addrs: *std.ArrayList(LookupAddr),
736 family: os.sa_family_t,
737 flags: u32,
738 port: u16,
739) !void {
771740 if ((flags & std.c.AI_PASSIVE) != 0) {
772741 if (family != os.AF_INET6) {
773742 (try addrs.addOne()).* = LookupAddr{
774 .family = os.AF_INET,
775 .addr = [1]u8{0} ** 16,
743 .addr = IpAddress.initIp4([1]u8{0} ** 4, port),
776744 };
777745 }
778746 if (family != os.AF_INET) {
779747 (try addrs.addOne()).* = LookupAddr{
780 .family = os.AF_INET6,
781 .addr = [1]u8{0} ** 16,
748 .addr = IpAddress.initIp6([1]u8{0} ** 16, port, 0, 0),
782749 };
783750 }
784751 } else {
785752 if (family != os.AF_INET6) {
786753 (try addrs.addOne()).* = LookupAddr{
787 .family = os.AF_INET,
788 .addr = [4]u8{ 127, 0, 0, 1 } ++ ([1]u8{0} ** 12),
754 .addr = IpAddress.initIp4([4]u8{ 127, 0, 0, 1 }, port),
789755 };
790756 }
791757 if (family != os.AF_INET) {
792758 (try addrs.addOne()).* = LookupAddr{
793 .family = os.AF_INET6,
794 .addr = ([1]u8{0} ** 15) ++ [1]u8{1},
759 .addr = IpAddress.initIp6(([1]u8{0} ** 15) ++ [1]u8{1}, port, 0, 0),
795760 };
796761 }
797762 }
......@@ -801,7 +766,8 @@ fn linuxLookupNameFromHosts(
801766 addrs: *std.ArrayList(LookupAddr),
802767 canon: *std.Buffer,
803768 name: []const u8,
804 family: i32,
769 family: os.sa_family_t,
770 port: u16,
805771) !void {
806772 const file = fs.File.openReadC(c"/etc/hosts") catch |err| switch (err) {
807773 error.FileNotFound,
......@@ -835,18 +801,20 @@ fn linuxLookupNameFromHosts(
835801 }
836802 } else continue;
837803
838 const prev_len = addrs.len;
839 linuxLookupNameFromNumeric(addrs, ip_text, family) catch |err| switch (err) {
840 error.ExpectedIPv6ButFoundIPv4 => continue,
841 error.ExpectedIPv4ButFoundIPv6 => continue,
842 error.OutOfMemory => |e| return e,
804 const addr = IpAddress.parseExpectingFamily(ip_text, family, port) catch |err| switch (err) {
805 error.Overflow,
806 error.InvalidEnd,
807 error.InvalidCharacter,
808 error.Incomplete,
809 error.InvalidIPAddressFormat,
810 => continue,
843811 };
844 if (addrs.len > prev_len) {
845 // first name is canonical name
846 const name_text = first_name_text.?;
847 if (isValidHostName(name_text)) {
848 try canon.replaceContents(name_text);
849 }
812 try addrs.append(LookupAddr{ .addr = addr });
813
814 // first name is canonical name
815 const name_text = first_name_text.?;
816 if (isValidHostName(name_text)) {
817 try canon.replaceContents(name_text);
850818 }
851819 }
852820}
......@@ -867,7 +835,8 @@ fn linuxLookupNameFromDnsSearch(
867835 addrs: *std.ArrayList(LookupAddr),
868836 canon: *std.Buffer,
869837 name: []const u8,
870 family: i32,
838 family: os.sa_family_t,
839 port: u16,
871840) !void {
872841 var rc: ResolvConf = undefined;
873842 try getResolvConf(addrs.allocator, &rc);
......@@ -903,32 +872,35 @@ fn linuxLookupNameFromDnsSearch(
903872 while (tok_it.next()) |tok| {
904873 canon.shrink(canon_name.len + 1);
905874 try canon.append(tok);
906 try linuxLookupNameFromDns(addrs, canon, canon.toSliceConst(), family, rc);
875 try linuxLookupNameFromDns(addrs, canon, canon.toSliceConst(), family, rc, port);
907876 if (addrs.len != 0) return;
908877 }
909878
910879 canon.shrink(canon_name.len);
911 return linuxLookupNameFromDns(addrs, canon, name, family, rc);
880 return linuxLookupNameFromDns(addrs, canon, name, family, rc, port);
912881}
913882
914883const dpc_ctx = struct {
915884 addrs: *std.ArrayList(LookupAddr),
916885 canon: *std.Buffer,
886 port: u16,
917887};
918888
919889fn linuxLookupNameFromDns(
920890 addrs: *std.ArrayList(LookupAddr),
921891 canon: *std.Buffer,
922892 name: []const u8,
923 family: i32,
893 family: os.sa_family_t,
924894 rc: ResolvConf,
895 port: u16,
925896) !void {
926897 var ctx = dpc_ctx{
927898 .addrs = addrs,
928899 .canon = canon,
900 .port = port,
929901 };
930902 const AfRr = struct {
931 af: i32,
903 af: os.sa_family_t,
932904 rr: u8,
933905 };
934906 const afrrs = [_]AfRr{
......@@ -994,7 +966,7 @@ fn getResolvConf(allocator: *mem.Allocator, rc: *ResolvConf) !void {
994966 error.FileNotFound,
995967 error.NotDir,
996968 error.AccessDenied,
997 => return linuxLookupNameFromNumericUnspec(&rc.ns, "127.0.0.1"),
969 => return linuxLookupNameFromNumericUnspec(&rc.ns, "127.0.0.1", 53),
998970 else => |e| return e,
999971 };
1000972 defer file.close();
......@@ -1033,21 +1005,24 @@ fn getResolvConf(allocator: *mem.Allocator, rc: *ResolvConf) !void {
10331005 }
10341006 } else if (mem.eql(u8, token, "nameserver")) {
10351007 const ip_txt = line_it.next() orelse continue;
1036 try linuxLookupNameFromNumericUnspec(&rc.ns, ip_txt);
1008 try linuxLookupNameFromNumericUnspec(&rc.ns, ip_txt, 53);
10371009 } else if (mem.eql(u8, token, "domain") or mem.eql(u8, token, "search")) {
10381010 try rc.search.replaceContents(line_it.rest());
10391011 }
10401012 }
10411013
10421014 if (rc.ns.len == 0) {
1043 return linuxLookupNameFromNumericUnspec(&rc.ns, "127.0.0.1");
1015 return linuxLookupNameFromNumericUnspec(&rc.ns, "127.0.0.1", 53);
10441016 }
10451017}
10461018
1047fn eqlSockAddr(a: *const os.sockaddr, b: *const os.sockaddr, len: usize) bool {
1048 const a_bytes = @ptrCast([*]const u8, a)[0..len];
1049 const b_bytes = @ptrCast([*]const u8, b)[0..len];
1050 return mem.eql(u8, a_bytes, b_bytes);
1019fn linuxLookupNameFromNumericUnspec(
1020 addrs: *std.ArrayList(LookupAddr),
1021 name: []const u8,
1022 port: u16,
1023) !void {
1024 const addr = try IpAddress.parse(name, port);
1025 (try addrs.addOne()).* = LookupAddr{ .addr = addr };
10511026}
10521027
10531028fn resMSendRc(
......@@ -1062,41 +1037,25 @@ fn resMSendRc(
10621037 var sl: os.socklen_t = @sizeOf(os.sockaddr_in);
10631038 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);
10661041 defer ns_list.deinit();
10671042
10681043 try ns_list.resize(rc.ns.len);
10691044 const ns = ns_list.toSlice();
10701045
10711046 for (rc.ns.toSliceConst()) |iplit, i| {
1072 if (iplit.family == os.AF_INET) {
1073 ns[i] = os.sockaddr{
1074 .in = os.sockaddr_in{
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 };
1047 ns[i] = iplit.addr;
1048 assert(ns[i].getPort() == 53);
1049 if (iplit.addr.any.family != os.AF_INET) {
10911050 sl = @sizeOf(os.sockaddr_in6);
10921051 family = os.AF_INET6;
10931052 }
10941053 }
10951054
10961055 // Get local address and open/bind a socket
1097 var sa: os.sockaddr = undefined;
1098 @memset(@ptrCast([*]u8, &sa), 0, @sizeOf(os.sockaddr));
1099 sa.in.family = family;
1056 var sa: IpAddress = undefined;
1057 @memset(@ptrCast([*]u8, &sa), 0, @sizeOf(IpAddress));
1058 sa.any.family = family;
11001059 const flags = os.SOCK_DGRAM | os.SOCK_CLOEXEC | os.SOCK_NONBLOCK;
11011060 const fd = os.socket(family, flags, 0) catch |err| switch (err) {
11021061 error.AddressFamilyNotSupported => blk: {
......@@ -1110,7 +1069,7 @@ fn resMSendRc(
11101069 else => |e| return e,
11111070 };
11121071 defer os.close(fd);
1113 try os.bind(fd, &sa, sl);
1072 try os.bind(fd, &sa.any, sl);
11141073
11151074 // Past this point, there are no errors. Each individual query will
11161075 // yield either no reply (indicated by zero length) or an answer
......@@ -1153,7 +1112,7 @@ fn resMSendRc(
11531112 if (answers[i].len == 0) {
11541113 var j: usize = 0;
11551114 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;
11571116 }
11581117 }
11591118 }
......@@ -1168,14 +1127,14 @@ fn resMSendRc(
11681127
11691128 while (true) {
11701129 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
11731132 // Ignore non-identifiable packets
11741133 if (rlen < 4) continue;
11751134
11761135 // Ignore replies from addresses we didn't send to
11771136 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) {}
11791138 if (j == ns.len) continue;
11801139
11811140 // Find which query this answer goes with, if any
......@@ -1194,7 +1153,7 @@ fn resMSendRc(
11941153 0, 3 => {},
11951154 2 => if (servfail_retry != 0) {
11961155 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;
11981157 },
11991158 else => continue,
12001159 }
......@@ -1252,19 +1211,17 @@ fn dnsParseCallback(ctx: dpc_ctx, rr: u8, data: []const u8, packet: []const u8)
12521211 if (data.len != 4) return error.InvalidDnsARecord;
12531212 const new_addr = try ctx.addrs.addOne();
12541213 new_addr.* = LookupAddr{
1255 .family = os.AF_INET,
1256 .addr = undefined,
1214 // TODO slice [0..4] to make this *[4]u8 without @ptrCast
1215 .addr = IpAddress.initIp4(@ptrCast(*const [4]u8, data.ptr).*, ctx.port),
12571216 };
1258 mem.copy(u8, &new_addr.addr, data);
12591217 },
12601218 os.RR_AAAA => {
12611219 if (data.len != 16) return error.InvalidDnsAAAARecord;
12621220 const new_addr = try ctx.addrs.addOne();
12631221 new_addr.* = LookupAddr{
1264 .family = os.AF_INET6,
1265 .addr = undefined,
1222 // TODO slice [0..16] to make this *[16]u8 without @ptrCast
1223 .addr = IpAddress.initIp6(@ptrCast(*const [16]u8, data.ptr).*, ctx.port, 0, 0),
12661224 };
1267 mem.copy(u8, &new_addr.addr, data);
12681225 },
12691226 os.RR_CNAME => {
12701227 var tmp: [256]u8 = undefined;
......@@ -1284,7 +1241,7 @@ pub const TcpServer = struct {
12841241 kernel_backlog: u32,
12851242
12861243 /// `undefined` until `listen` returns successfully.
1287 listen_address: Address,
1244 listen_address: IpAddress,
12881245
12891246 sockfd: ?os.fd_t,
12901247
......@@ -1311,7 +1268,7 @@ pub const TcpServer = struct {
13111268 self.* = undefined;
13121269 }
13131270
1314 pub fn listen(self: *TcpServer, address: Address) !void {
1271 pub fn listen(self: *TcpServer, address: IpAddress) !void {
13151272 const nonblock = if (std.io.is_async) os.SOCK_NONBLOCK else 0;
13161273 const sock_flags = os.SOCK_STREAM | os.SOCK_CLOEXEC | nonblock;
13171274 const sockfd = try os.socket(os.AF_INET, sock_flags, os.PROTO_tcp);
......@@ -1322,9 +1279,9 @@ pub const TcpServer = struct {
13221279 }
13231280
13241281 var socklen = address.getOsSockLen();
1325 try os.bind(sockfd, &address.os_addr, socklen);
1282 try os.bind(sockfd, &address.any, socklen);
13261283 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);
13281285 }
13291286
13301287 /// Stop listening. It is still necessary to call `deinit` after stopping listening.
......@@ -1361,9 +1318,9 @@ pub const TcpServer = struct {
13611318 pub fn accept(self: *TcpServer) AcceptError!fs.File {
13621319 const nonblock = if (std.io.is_async) os.SOCK_NONBLOCK else 0;
13631320 const accept_flags = nonblock | os.SOCK_CLOEXEC;
1364 var accepted_addr: Address = undefined;
1365 var adr_len: os.socklen_t = @sizeOf(os.sockaddr);
1366 if (os.accept4(self.sockfd.?, &accepted_addr.os_addr, &adr_len, accept_flags)) |fd| {
1321 var accepted_addr: IpAddress = undefined;
1322 var adr_len: os.socklen_t = @sizeOf(IpAddress);
1323 if (os.accept4(self.sockfd.?, &accepted_addr.any, &adr_len, accept_flags)) |fd| {
13671324 return fs.File.openHandle(fd);
13681325 } else |err| switch (err) {
13691326 // 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;
33const mem = std.mem;
44const testing = std.testing;
55
6test "parseIp4" {
7 testing.expect((try net.parseIp4("127.0.0.1")) == mem.bigToNative(u32, 0x7f000001));
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);
6test "parse and render IPv6 addresses" {
7 const addr = net.IpAddress.parseIp6("FF01:0:0:0:0:0:0:FB", 80);
278 var buf: [100]u8 = undefined;
289 const printed = try std.fmt.bufPrint(&buf, "{}", addr);
2910 std.testing.expect(mem.eql(u8, "[ff01::fb]:80", printed));
3011}
3112
32test "ip4s" {
13test "parse and render IPv4 addresses" {
3314 var buffer: [18]u8 = undefined;
3415 for ([_][]const u8{
3516 "0.0.0.0",
3617 "255.255.255.255",
3718 "1.2.3.4",
3819 "123.255.0.91",
20 "127.0.0.1",
3921 }) |ip| {
40 var addr = net.Address.initIp4(net.parseIp4(ip) catch unreachable, 0);
22 var addr = net.IpAddress.parseIp4(ip, 0);
4123 var newIp = std.fmt.bufPrint(buffer[0..], "{}", addr) catch unreachable;
4224 std.testing.expect(std.mem.eql(u8, ip, newIp[0 .. newIp.len - 2]));
4325 }
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));
4432}
4533
4634test "resolve DNS" {
......@@ -72,7 +60,7 @@ test "listen on a port, send bytes, receive bytes" {
7260 }
7361
7462 // 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
7765 var server = net.TcpServer.init(net.TcpServer.Options{});
7866 defer server.deinit();
......@@ -85,7 +73,7 @@ test "listen on a port, send bytes, receive bytes" {
8573 try await client_frame;
8674}
8775
88fn testClient(addr: net.Address) anyerror!void {
76fn testClient(addr: net.IpAddress) anyerror!void {
8977 const socket_file = try net.tcpConnectToAddress(addr);
9078 defer socket_file.close();
9179
lib/std/os.zig+2-2
......@@ -1920,9 +1920,9 @@ pub const ConnectError = error{
19201920} || UnexpectedError;
19211921
19221922/// 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 {
19241924 while (true) {
1925 switch (errno(system.connect(sockfd, &sock_addr, len))) {
1925 switch (errno(system.connect(sockfd, sock_addr, len))) {
19261926 0 => return,
19271927 EACCES => return error.PermissionDenied,
19281928 EPERM => return error.PermissionDenied,
lib/std/os/bits/darwin.zig+13-10
......@@ -9,28 +9,31 @@ pub const in_port_t = u16;
99pub const sa_family_t = u8;
1010pub const socklen_t = u32;
1111pub const sockaddr = extern union {
12 in: sockaddr_in,
13 in6: sockaddr_in6,
14 un: sockaddr_un,
15};
16pub const sockaddr_in = extern struct {
1712 len: u8,
1813 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,
1919 port: in_port_t,
2020 addr: u32,
21 zero: [8]u8,
21 zero: [8]u8 = [8]u8{ 0, 0, 0, 0, 0, 0, 0, 0 },
2222};
2323pub const sockaddr_in6 = extern struct {
24 len: u8,
25 family: sa_family_t,
24 len: u8 = @sizeOf(sockaddr_in6),
25 family: sa_family_t = AF_INET6,
2626 port: in_port_t,
2727 flowinfo: u32,
2828 addr: [16]u8,
2929 scope_id: u32,
3030};
31
32/// UNIX domain socket
3133pub const sockaddr_un = extern struct {
32 len: u8,
33 family: sa_family_t,
34 len: u8 = @sizeOf(sockaddr_un),
35 family: sa_family_t = AF_UNIX,
36 path: [104]u8,
3437};
3538
3639pub const timeval = extern struct {
lib/std/os/bits/freebsd.zig+20-8
......@@ -138,27 +138,39 @@ pub const in_port_t = u16;
138138pub const sa_family_t = u16;
139139
140140pub const sockaddr = extern union {
141 in: sockaddr_in,
142 in6: sockaddr_in6,
141 /// total length
142 len: u8,
143
144 /// address family
145 family: sa_family_t,
146
147 /// actually longer; address value
148 data: [14]u8,
143149};
144150
145151pub const sockaddr_in = extern struct {
146 len: u8,
147 family: sa_family_t,
152 len: u8 = @sizeOf(sockaddr_in),
153 family: sa_family_t = AF_INET,
148154 port: in_port_t,
149 addr: [16]u8,
150 zero: [8]u8,
155 addr: u32,
156 zero: [8]u8 = [8]u8{ 0, 0, 0, 0, 0, 0, 0, 0 },
151157};
152158
153159pub const sockaddr_in6 = extern struct {
154 len: u8,
155 family: sa_family_t,
160 len: u8 = @sizeOf(sockaddr_in6),
161 family: sa_family_t = AF_INET6,
156162 port: in_port_t,
157163 flowinfo: u32,
158164 addr: [16]u8,
159165 scope_id: u32,
160166};
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
162174pub const CTL_KERN = 1;
163175pub const CTL_DEBUG = 5;
164176
lib/std/os/bits/linux.zig+9-8
......@@ -846,30 +846,31 @@ pub const in_port_t = u16;
846846pub const sa_family_t = u16;
847847pub const socklen_t = u32;
848848
849/// This intentionally only has ip4 and ip6
850849pub const sockaddr = extern union {
851 in: sockaddr_in,
852 in6: sockaddr_in6,
853 un: sockaddr_un,
850 family: sa_family_t,
851 data: [14]u8,
854852};
855853
854/// IPv4 socket address
856855pub const sockaddr_in = extern struct {
857 family: sa_family_t,
856 family: sa_family_t = AF_INET,
858857 port: in_port_t,
859858 addr: u32,
860 zero: [8]u8,
859 zero: [8]u8 = [8]u8{ 0, 0, 0, 0, 0, 0, 0, 0 },
861860};
862861
862/// IPv6 socket address
863863pub const sockaddr_in6 = extern struct {
864 family: sa_family_t,
864 family: sa_family_t = AF_INET6,
865865 port: in_port_t,
866866 flowinfo: u32,
867867 addr: [16]u8,
868868 scope_id: u32,
869869};
870870
871/// UNIX domain socket address
871872pub const sockaddr_un = extern struct {
872 family: sa_family_t,
873 family: sa_family_t = AF_UNIX,
873874 path: [108]u8,
874875};
875876
lib/std/os/bits/netbsd.zig+23-5
......@@ -134,20 +134,26 @@ pub const in_port_t = u16;
134134pub const sa_family_t = u8;
135135
136136pub const sockaddr = extern union {
137 in: sockaddr_in,
138 in6: sockaddr_in6,
137 /// total length
138 len: u8,
139
140 /// address family
141 family: sa_family_t,
142
143 /// actually longer; address value
144 data: [14]u8,
139145};
140146
141147pub const sockaddr_in = extern struct {
142 len: u8,
148 len: u8 = @sizeOf(sockaddr_in),
143149 family: sa_family_t,
144150 port: in_port_t,
145151 addr: u32,
146 zero: [8]u8,
152 zero: [8]u8 = [8]u8{ 0, 0, 0, 0, 0, 0, 0, 0 },
147153};
148154
149155pub const sockaddr_in6 = extern struct {
150 len: u8,
156 len: u8 = @sizeOf(sockaddr_in6),
151157 family: sa_family_t,
152158 port: in_port_t,
153159 flowinfo: u32,
......@@ -155,6 +161,18 @@ pub const sockaddr_in6 = extern struct {
155161 scope_id: u32,
156162};
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
158176pub const CTL_KERN = 1;
159177pub const CTL_DEBUG = 5;
160178
lib/std/os/bits/windows.zig+60
......@@ -161,3 +161,63 @@ pub const F_OK = 0;
161161
162162/// Remove directory instead of unlinking file
163163pub 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 {
162162 \\ const obj = AstObject{ .lhsExpr = lhsExpr };
163163 \\}
164164 ,
165 "tmp.zig:1:17: error: struct 'LhsExpr' depends on itself",
166 "tmp.zig:5:5: note: while checking this field",
165 "tmp.zig:4:19: error: union 'AstObject' depends on itself",
167166 "tmp.zig:2:5: note: while checking this field",
167 "tmp.zig:5:5: note: while checking this field",
168168 );
169169
170170 cases.add(