| ... | ... | @@ -10,98 +10,229 @@ test "" { |
| 10 | 10 | _ = @import("net/test.zig"); |
| 11 | 11 | } |
| 12 | 12 | |
| 13 | | pub const TmpWinAddr = struct { |
| 14 | | family: u8, |
| 15 | | data: [14]u8, |
| 16 | | }; |
| 17 | | |
| 18 | | pub 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. |
| 25 | | pub const Address = struct { |
| 26 | | os_addr: OsAddress, |
| 13 | pub const IpAddress = extern union { |
| 14 | any: os.sockaddr, |
| 15 | in: os.sockaddr_in, |
| 16 | in6: os.sockaddr_in6, |
| 27 | 17 | |
| 28 | 18 | // TODO this crashed the compiler |
| 29 | 19 | //pub const localhost = initIp4(parseIp4("127.0.0.1") catch unreachable, 0); |
| 30 | 20 | |
| 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, |
| 42 | 57 | }, |
| 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, |
| 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 | } |
| 56 | 172 | |
| 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).*, |
| 69 | 178 | }, |
| 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, |
| 81 | 189 | }, |
| 82 | | } |
| 190 | }; |
| 83 | 191 | } |
| 84 | 192 | |
| 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); |
| 87 | 201 | } |
| 88 | 202 | |
| 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 | } |
| 91 | 222 | } |
| 92 | 223 | |
| 93 | 224 | pub fn format( |
| 94 | | self: Address, |
| 225 | self: IpAddress, |
| 95 | 226 | comptime fmt: []const u8, |
| 96 | 227 | options: std.fmt.FormatOptions, |
| 97 | 228 | context: var, |
| 98 | 229 | comptime Errors: type, |
| 99 | 230 | output: fn (@typeOf(context), []const u8) Errors!void, |
| 100 | 231 | ) !void { |
| 101 | | switch (self.os_addr.in.family) { |
| 232 | switch (self.any.family) { |
| 102 | 233 | 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); |
| 105 | 236 | try std.fmt.format( |
| 106 | 237 | context, |
| 107 | 238 | Errors, |
| ... | ... | @@ -111,7 +242,7 @@ pub const Address = struct { |
| 111 | 242 | bytes[1], |
| 112 | 243 | bytes[2], |
| 113 | 244 | bytes[3], |
| 114 | | native_endian_port, |
| 245 | port, |
| 115 | 246 | ); |
| 116 | 247 | }, |
| 117 | 248 | os.AF_INET6 => { |
| ... | ... | @@ -119,8 +250,8 @@ pub const Address = struct { |
| 119 | 250 | index: usize, |
| 120 | 251 | count: usize, |
| 121 | 252 | }; |
| 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); |
| 124 | 255 | const native_endian_parts = switch (builtin.endian) { |
| 125 | 256 | .Big => big_endian_parts.*, |
| 126 | 257 | .Little => blk: { |
| ... | ... | @@ -170,14 +301,20 @@ pub const Address = struct { |
| 170 | 301 | try std.fmt.format(context, Errors, output, "{x}", part); |
| 171 | 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 | } |
| 178 | 309 | |
| 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) { |
| 181 | 318 | os.AF_INET => return @sizeOf(os.sockaddr_in), |
| 182 | 319 | os.AF_INET6 => return @sizeOf(os.sockaddr_in6), |
| 183 | 320 | else => unreachable, |
| ... | ... | @@ -185,123 +322,6 @@ pub const Address = struct { |
| 185 | 322 | } |
| 186 | 323 | }; |
| 187 | 324 | |
| 188 | | pub 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 | | |
| 223 | | pub const Ip6Addr = struct { |
| 224 | | scope_id: u32, |
| 225 | | addr: [16]u8, |
| 226 | | }; |
| 227 | | |
| 228 | | pub 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 | | |
| 305 | 325 | pub fn connectUnixSocket(path: []const u8) !fs.File { |
| 306 | 326 | const opt_non_block = if (std.io.mode == .evented) os.SOCK_NONBLOCK else 0; |
| 307 | 327 | const sockfd = try os.socket( |
| ... | ... | @@ -311,24 +331,23 @@ pub fn connectUnixSocket(path: []const u8) !fs.File { |
| 311 | 331 | ); |
| 312 | 332 | errdefer os.close(sockfd); |
| 313 | 333 | |
| 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, |
| 319 | 337 | }; |
| 320 | 338 | |
| 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); |
| 325 | 344 | |
| 326 | 345 | return fs.File.openHandle(sockfd); |
| 327 | 346 | } |
| 328 | 347 | |
| 329 | 348 | pub const AddressList = struct { |
| 330 | 349 | arena: std.heap.ArenaAllocator, |
| 331 | | addrs: []Address, |
| 350 | addrs: []IpAddress, |
| 332 | 351 | canon_name: ?[]u8, |
| 333 | 352 | |
| 334 | 353 | fn deinit(self: *AddressList) void { |
| ... | ... | @@ -351,12 +370,12 @@ pub fn tcpConnectToHost(allocator: *mem.Allocator, name: []const u8, port: u16) |
| 351 | 370 | return tcpConnectToAddress(addrs[0], port); |
| 352 | 371 | } |
| 353 | 372 | |
| 354 | | pub fn tcpConnectToAddress(address: Address) !fs.File { |
| 373 | pub fn tcpConnectToAddress(address: IpAddress) !fs.File { |
| 355 | 374 | const nonblock = if (std.io.is_async) os.SOCK_NONBLOCK else 0; |
| 356 | 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 | 377 | errdefer os.close(sockfd); |
| 359 | | try os.connect(sockfd, address.os_addr, address.getOsSockLen()); |
| 378 | try os.connect(sockfd, &address.any, address.getOsSockLen()); |
| 360 | 379 | |
| 361 | 380 | return fs.File{ .handle = sockfd }; |
| 362 | 381 | } |
| ... | ... | @@ -426,13 +445,13 @@ pub fn getAddressList(allocator: *mem.Allocator, name: []const u8, port: u16) !* |
| 426 | 445 | } |
| 427 | 446 | break :blk count; |
| 428 | 447 | }; |
| 429 | | result.addrs = try arena.alloc(Address, addr_count); |
| 448 | result.addrs = try arena.alloc(IpAddress, addr_count); |
| 430 | 449 | |
| 431 | 450 | var it: ?*os.addrinfo = res; |
| 432 | 451 | var i: usize = 0; |
| 433 | 452 | while (it) |info| : (it = info.next) { |
| 434 | 453 | const addr = info.addr orelse continue; |
| 435 | | result.addrs[i] = Address.initPosix(addr.*); |
| 454 | result.addrs[i] = IpAddress.initPosix(@alignCast(4, addr)); |
| 436 | 455 | |
| 437 | 456 | if (info.canonname) |n| { |
| 438 | 457 | if (result.canon_name == null) { |
| ... | ... | @@ -447,40 +466,22 @@ pub fn getAddressList(allocator: *mem.Allocator, name: []const u8, port: u16) !* |
| 447 | 466 | if (builtin.os == .linux) { |
| 448 | 467 | const flags = std.c.AI_NUMERICSERV; |
| 449 | 468 | 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(); |
| 452 | 471 | |
| 453 | 472 | var canon = std.Buffer.initNull(arena); |
| 454 | 473 | defer canon.deinit(); |
| 455 | 474 | |
| 456 | | try linuxLookupName(&addrs, &canon, name, family, flags); |
| 475 | try linuxLookupName(&lookup_addrs, &canon, name, family, flags, port); |
| 457 | 476 | |
| 458 | | result.addrs = try arena.alloc(Address, addrs.len); |
| 477 | result.addrs = try arena.alloc(IpAddress, lookup_addrs.len); |
| 459 | 478 | if (!canon.isNull()) { |
| 460 | 479 | result.canon_name = canon.toOwnedSlice(); |
| 461 | 480 | } |
| 462 | 481 | |
| 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); |
| 484 | 485 | } |
| 485 | 486 | |
| 486 | 487 | return result; |
| ... | ... | @@ -489,9 +490,7 @@ pub fn getAddressList(allocator: *mem.Allocator, name: []const u8, port: u16) !* |
| 489 | 490 | } |
| 490 | 491 | |
| 491 | 492 | const 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, |
| 495 | 494 | sortkey: i32 = 0, |
| 496 | 495 | }; |
| 497 | 496 | |
| ... | ... | @@ -507,22 +506,26 @@ fn linuxLookupName( |
| 507 | 506 | addrs: *std.ArrayList(LookupAddr), |
| 508 | 507 | canon: *std.Buffer, |
| 509 | 508 | opt_name: ?[]const u8, |
| 510 | | family: i32, |
| 509 | family: os.sa_family_t, |
| 511 | 510 | flags: u32, |
| 511 | port: u16, |
| 512 | 512 | ) !void { |
| 513 | 513 | if (opt_name) |name| { |
| 514 | 514 | // reject empty name and check len so it fits into temp bufs |
| 515 | 515 | 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); |
| 519 | 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 | 526 | } else { |
| 524 | 527 | try canon.resize(0); |
| 525 | | try linuxLookupNameFromNull(addrs, family, flags); |
| 528 | try linuxLookupNameFromNull(addrs, family, flags, port); |
| 526 | 529 | } |
| 527 | 530 | if (addrs.len == 0) return error.UnknownHostName; |
| 528 | 531 | |
| ... | ... | @@ -530,7 +533,7 @@ fn linuxLookupName( |
| 530 | 533 | // results or if there are only IPv4 results. |
| 531 | 534 | if (addrs.len == 1 or family == os.AF_INET) return; |
| 532 | 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 | 537 | } else true; |
| 535 | 538 | if (all_ip4) return; |
| 536 | 539 | |
| ... | ... | @@ -547,7 +550,7 @@ fn linuxLookupName( |
| 547 | 550 | @memset(@ptrCast([*]u8, &sa6), 0, @sizeOf(os.sockaddr_in6)); |
| 548 | 551 | var da6 = os.sockaddr_in6{ |
| 549 | 552 | .family = os.AF_INET6, |
| 550 | | .scope_id = addr.scope_id, |
| 553 | .scope_id = addr.addr.in6.scope_id, |
| 551 | 554 | .port = 65535, |
| 552 | 555 | .flowinfo = 0, |
| 553 | 556 | .addr = [1]u8{0} ** 16, |
| ... | ... | @@ -560,12 +563,12 @@ fn linuxLookupName( |
| 560 | 563 | .addr = 0, |
| 561 | 564 | .zero = [1]u8{0} ** 8, |
| 562 | 565 | }; |
| 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; |
| 565 | 568 | var salen: os.socklen_t = undefined; |
| 566 | 569 | 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); |
| 569 | 572 | da = @ptrCast(*os.sockaddr, &da6); |
| 570 | 573 | dalen = @sizeOf(os.sockaddr_in6); |
| 571 | 574 | sa = @ptrCast(*os.sockaddr, &sa6); |
| ... | ... | @@ -573,8 +576,9 @@ fn linuxLookupName( |
| 573 | 576 | } else { |
| 574 | 577 | mem.copy(u8, &sa6.addr, "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xff\xff"); |
| 575 | 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]); |
| 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; |
| 578 | 582 | da = @ptrCast(*os.sockaddr, &da4); |
| 579 | 583 | dalen = @sizeOf(os.sockaddr_in); |
| 580 | 584 | sa = @ptrCast(*os.sockaddr, &sa4); |
| ... | ... | @@ -586,12 +590,13 @@ fn linuxLookupName( |
| 586 | 590 | const dprec: i32 = dpolicy.prec; |
| 587 | 591 | const MAXADDRS = 3; |
| 588 | 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 | 595 | defer os.close(fd); |
| 591 | | os.connect(fd, da.*, dalen) catch break :syscalls; |
| 596 | os.connect(fd, da, dalen) catch break :syscalls; |
| 592 | 597 | key |= DAS_USABLE; |
| 593 | 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 | 600 | // TODO sa6.addr[12..16] should return *[4]u8, making this cast unnecessary. |
| 596 | 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 | 731 | return a.sortkey < b.sortkey; |
| 727 | 732 | } |
| 728 | 733 | |
| 729 | | fn 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 | | |
| 737 | | fn 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 | | |
| 770 | | fn linuxLookupNameFromNull(addrs: *std.ArrayList(LookupAddr), family: i32, flags: u32) !void { |
| 734 | fn linuxLookupNameFromNull( |
| 735 | addrs: *std.ArrayList(LookupAddr), |
| 736 | family: os.sa_family_t, |
| 737 | flags: u32, |
| 738 | port: u16, |
| 739 | ) !void { |
| 771 | 740 | if ((flags & std.c.AI_PASSIVE) != 0) { |
| 772 | 741 | if (family != os.AF_INET6) { |
| 773 | 742 | (try addrs.addOne()).* = LookupAddr{ |
| 774 | | .family = os.AF_INET, |
| 775 | | .addr = [1]u8{0} ** 16, |
| 743 | .addr = IpAddress.initIp4([1]u8{0} ** 4, port), |
| 776 | 744 | }; |
| 777 | 745 | } |
| 778 | 746 | if (family != os.AF_INET) { |
| 779 | 747 | (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), |
| 782 | 749 | }; |
| 783 | 750 | } |
| 784 | 751 | } else { |
| 785 | 752 | if (family != os.AF_INET6) { |
| 786 | 753 | (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), |
| 789 | 755 | }; |
| 790 | 756 | } |
| 791 | 757 | if (family != os.AF_INET) { |
| 792 | 758 | (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), |
| 795 | 760 | }; |
| 796 | 761 | } |
| 797 | 762 | } |
| ... | ... | @@ -801,7 +766,8 @@ fn linuxLookupNameFromHosts( |
| 801 | 766 | addrs: *std.ArrayList(LookupAddr), |
| 802 | 767 | canon: *std.Buffer, |
| 803 | 768 | name: []const u8, |
| 804 | | family: i32, |
| 769 | family: os.sa_family_t, |
| 770 | port: u16, |
| 805 | 771 | ) !void { |
| 806 | 772 | const file = fs.File.openReadC(c"/etc/hosts") catch |err| switch (err) { |
| 807 | 773 | error.FileNotFound, |
| ... | ... | @@ -835,18 +801,20 @@ fn linuxLookupNameFromHosts( |
| 835 | 801 | } |
| 836 | 802 | } else continue; |
| 837 | 803 | |
| 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, |
| 843 | 811 | }; |
| 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); |
| 850 | 818 | } |
| 851 | 819 | } |
| 852 | 820 | } |
| ... | ... | @@ -867,7 +835,8 @@ fn linuxLookupNameFromDnsSearch( |
| 867 | 835 | addrs: *std.ArrayList(LookupAddr), |
| 868 | 836 | canon: *std.Buffer, |
| 869 | 837 | name: []const u8, |
| 870 | | family: i32, |
| 838 | family: os.sa_family_t, |
| 839 | port: u16, |
| 871 | 840 | ) !void { |
| 872 | 841 | var rc: ResolvConf = undefined; |
| 873 | 842 | try getResolvConf(addrs.allocator, &rc); |
| ... | ... | @@ -903,32 +872,35 @@ fn linuxLookupNameFromDnsSearch( |
| 903 | 872 | while (tok_it.next()) |tok| { |
| 904 | 873 | canon.shrink(canon_name.len + 1); |
| 905 | 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 | 876 | if (addrs.len != 0) return; |
| 908 | 877 | } |
| 909 | 878 | |
| 910 | 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 | } |
| 913 | 882 | |
| 914 | 883 | const dpc_ctx = struct { |
| 915 | 884 | addrs: *std.ArrayList(LookupAddr), |
| 916 | 885 | canon: *std.Buffer, |
| 886 | port: u16, |
| 917 | 887 | }; |
| 918 | 888 | |
| 919 | 889 | fn linuxLookupNameFromDns( |
| 920 | 890 | addrs: *std.ArrayList(LookupAddr), |
| 921 | 891 | canon: *std.Buffer, |
| 922 | 892 | name: []const u8, |
| 923 | | family: i32, |
| 893 | family: os.sa_family_t, |
| 924 | 894 | rc: ResolvConf, |
| 895 | port: u16, |
| 925 | 896 | ) !void { |
| 926 | 897 | var ctx = dpc_ctx{ |
| 927 | 898 | .addrs = addrs, |
| 928 | 899 | .canon = canon, |
| 900 | .port = port, |
| 929 | 901 | }; |
| 930 | 902 | const AfRr = struct { |
| 931 | | af: i32, |
| 903 | af: os.sa_family_t, |
| 932 | 904 | rr: u8, |
| 933 | 905 | }; |
| 934 | 906 | const afrrs = [_]AfRr{ |
| ... | ... | @@ -994,7 +966,7 @@ fn getResolvConf(allocator: *mem.Allocator, rc: *ResolvConf) !void { |
| 994 | 966 | error.FileNotFound, |
| 995 | 967 | error.NotDir, |
| 996 | 968 | error.AccessDenied, |
| 997 | | => return linuxLookupNameFromNumericUnspec(&rc.ns, "127.0.0.1"), |
| 969 | => return linuxLookupNameFromNumericUnspec(&rc.ns, "127.0.0.1", 53), |
| 998 | 970 | else => |e| return e, |
| 999 | 971 | }; |
| 1000 | 972 | defer file.close(); |
| ... | ... | @@ -1033,21 +1005,24 @@ fn getResolvConf(allocator: *mem.Allocator, rc: *ResolvConf) !void { |
| 1033 | 1005 | } |
| 1034 | 1006 | } else if (mem.eql(u8, token, "nameserver")) { |
| 1035 | 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 | 1009 | } else if (mem.eql(u8, token, "domain") or mem.eql(u8, token, "search")) { |
| 1038 | 1010 | try rc.search.replaceContents(line_it.rest()); |
| 1039 | 1011 | } |
| 1040 | 1012 | } |
| 1041 | 1013 | |
| 1042 | 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 | } |
| 1046 | 1018 | |
| 1047 | | fn 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); |
| 1019 | fn 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 }; |
| 1051 | 1026 | } |
| 1052 | 1027 | |
| 1053 | 1028 | fn resMSendRc( |
| ... | ... | @@ -1062,41 +1037,25 @@ fn resMSendRc( |
| 1062 | 1037 | var sl: os.socklen_t = @sizeOf(os.sockaddr_in); |
| 1063 | 1038 | var family: os.sa_family_t = os.AF_INET; |
| 1064 | 1039 | |
| 1065 | | var ns_list = std.ArrayList(os.sockaddr).init(rc.ns.allocator); |
| 1040 | var ns_list = std.ArrayList(IpAddress).init(rc.ns.allocator); |
| 1066 | 1041 | defer ns_list.deinit(); |
| 1067 | 1042 | |
| 1068 | 1043 | try ns_list.resize(rc.ns.len); |
| 1069 | 1044 | const ns = ns_list.toSlice(); |
| 1070 | 1045 | |
| 1071 | 1046 | 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) { |
| 1091 | 1050 | sl = @sizeOf(os.sockaddr_in6); |
| 1092 | 1051 | family = os.AF_INET6; |
| 1093 | 1052 | } |
| 1094 | 1053 | } |
| 1095 | 1054 | |
| 1096 | 1055 | // 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; |
| 1100 | 1059 | const flags = os.SOCK_DGRAM | os.SOCK_CLOEXEC | os.SOCK_NONBLOCK; |
| 1101 | 1060 | const fd = os.socket(family, flags, 0) catch |err| switch (err) { |
| 1102 | 1061 | error.AddressFamilyNotSupported => blk: { |
| ... | ... | @@ -1110,7 +1069,7 @@ fn resMSendRc( |
| 1110 | 1069 | else => |e| return e, |
| 1111 | 1070 | }; |
| 1112 | 1071 | defer os.close(fd); |
| 1113 | | try os.bind(fd, &sa, sl); |
| 1072 | try os.bind(fd, &sa.any, sl); |
| 1114 | 1073 | |
| 1115 | 1074 | // Past this point, there are no errors. Each individual query will |
| 1116 | 1075 | // yield either no reply (indicated by zero length) or an answer |
| ... | ... | @@ -1153,7 +1112,7 @@ fn resMSendRc( |
| 1153 | 1112 | if (answers[i].len == 0) { |
| 1154 | 1113 | var j: usize = 0; |
| 1155 | 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 | 1127 | |
| 1169 | 1128 | while (true) { |
| 1170 | 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; |
| 1172 | 1131 | |
| 1173 | 1132 | // Ignore non-identifiable packets |
| 1174 | 1133 | if (rlen < 4) continue; |
| 1175 | 1134 | |
| 1176 | 1135 | // Ignore replies from addresses we didn't send to |
| 1177 | 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 | 1138 | if (j == ns.len) continue; |
| 1180 | 1139 | |
| 1181 | 1140 | // Find which query this answer goes with, if any |
| ... | ... | @@ -1194,7 +1153,7 @@ fn resMSendRc( |
| 1194 | 1153 | 0, 3 => {}, |
| 1195 | 1154 | 2 => if (servfail_retry != 0) { |
| 1196 | 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 | 1158 | else => continue, |
| 1200 | 1159 | } |
| ... | ... | @@ -1252,19 +1211,17 @@ fn dnsParseCallback(ctx: dpc_ctx, rr: u8, data: []const u8, packet: []const u8) |
| 1252 | 1211 | if (data.len != 4) return error.InvalidDnsARecord; |
| 1253 | 1212 | const new_addr = try ctx.addrs.addOne(); |
| 1254 | 1213 | 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), |
| 1257 | 1216 | }; |
| 1258 | | mem.copy(u8, &new_addr.addr, data); |
| 1259 | 1217 | }, |
| 1260 | 1218 | os.RR_AAAA => { |
| 1261 | 1219 | if (data.len != 16) return error.InvalidDnsAAAARecord; |
| 1262 | 1220 | const new_addr = try ctx.addrs.addOne(); |
| 1263 | 1221 | 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), |
| 1266 | 1224 | }; |
| 1267 | | mem.copy(u8, &new_addr.addr, data); |
| 1268 | 1225 | }, |
| 1269 | 1226 | os.RR_CNAME => { |
| 1270 | 1227 | var tmp: [256]u8 = undefined; |
| ... | ... | @@ -1284,7 +1241,7 @@ pub const TcpServer = struct { |
| 1284 | 1241 | kernel_backlog: u32, |
| 1285 | 1242 | |
| 1286 | 1243 | /// `undefined` until `listen` returns successfully. |
| 1287 | | listen_address: Address, |
| 1244 | listen_address: IpAddress, |
| 1288 | 1245 | |
| 1289 | 1246 | sockfd: ?os.fd_t, |
| 1290 | 1247 | |
| ... | ... | @@ -1311,7 +1268,7 @@ pub const TcpServer = struct { |
| 1311 | 1268 | self.* = undefined; |
| 1312 | 1269 | } |
| 1313 | 1270 | |
| 1314 | | pub fn listen(self: *TcpServer, address: Address) !void { |
| 1271 | pub fn listen(self: *TcpServer, address: IpAddress) !void { |
| 1315 | 1272 | const nonblock = if (std.io.is_async) os.SOCK_NONBLOCK else 0; |
| 1316 | 1273 | const sock_flags = os.SOCK_STREAM | os.SOCK_CLOEXEC | nonblock; |
| 1317 | 1274 | const sockfd = try os.socket(os.AF_INET, sock_flags, os.PROTO_tcp); |
| ... | ... | @@ -1322,9 +1279,9 @@ pub const TcpServer = struct { |
| 1322 | 1279 | } |
| 1323 | 1280 | |
| 1324 | 1281 | var socklen = address.getOsSockLen(); |
| 1325 | | try os.bind(sockfd, &address.os_addr, socklen); |
| 1282 | try os.bind(sockfd, &address.any, socklen); |
| 1326 | 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 | } |
| 1329 | 1286 | |
| 1330 | 1287 | /// Stop listening. It is still necessary to call `deinit` after stopping listening. |
| ... | ... | @@ -1361,9 +1318,9 @@ pub const TcpServer = struct { |
| 1361 | 1318 | pub fn accept(self: *TcpServer) AcceptError!fs.File { |
| 1362 | 1319 | const nonblock = if (std.io.is_async) os.SOCK_NONBLOCK else 0; |
| 1363 | 1320 | 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| { |
| 1367 | 1324 | return fs.File.openHandle(fd); |
| 1368 | 1325 | } else |err| switch (err) { |
| 1369 | 1326 | // We only give SOCK_NONBLOCK when I/O mode is async, in which case this error |