| ... | @@ -10,98 +10,229 @@ test "" { | ... | @@ -10,98 +10,229 @@ test "" { |
| 10 | _ = @import("net/test.zig"); | 10 | _ = @import("net/test.zig"); |
| 11 | } | 11 | } |
| 12 | | 12 | |
| 13 | pub const TmpWinAddr = struct { | 13 | pub 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 | | | |
| 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, | | |
| 27 | | 17 | |
| 28 | // TODO this crashed the compiler | 18 | // 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); |
| 30 | | 20 | |
| 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 | } |
| 56 | | 172 | |
| 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 | } |
| 84 | | 192 | |
| 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 | } |
| 88 | | 202 | |
| 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 | } |
| 92 | | 223 | |
| 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 | } |
| 178 | | 309 | |
| 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 | }; |
| 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 | pub fn connectUnixSocket(path: []const u8) !fs.File { | 325 | pub 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); |
| 313 | | 333 | |
| 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 | }; |
| 320 | | 338 | |
| 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); |
| 325 | | 344 | |
| 326 | return fs.File.openHandle(sockfd); | 345 | return fs.File.openHandle(sockfd); |
| 327 | } | 346 | } |
| 328 | | 347 | |
| 329 | pub const AddressList = struct { | 348 | pub 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, |
| 333 | | 352 | |
| 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 | } |
| 353 | | 372 | |
| 354 | pub fn tcpConnectToAddress(address: Address) !fs.File { | 373 | pub 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()); |
| 360 | | 379 | |
| 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); |
| 430 | | 449 | |
| 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)); |
| 436 | | 455 | |
| 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(); |
| 452 | | 471 | |
| 453 | var canon = std.Buffer.initNull(arena); | 472 | var canon = std.Buffer.initNull(arena); |
| 454 | defer canon.deinit(); | 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 | if (!canon.isNull()) { | 478 | if (!canon.isNull()) { |
| 460 | result.canon_name = canon.toOwnedSlice(); | 479 | result.canon_name = canon.toOwnedSlice(); |
| 461 | } | 480 | } |
| 462 | | 481 | |
| 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 | } |
| 485 | | 486 | |
| 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 | } |
| 490 | | 491 | |
| 491 | const LookupAddr = struct { | 492 | const 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 | }; |
| 497 | | 496 | |
| ... | @@ -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 bufs | 514 | // 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; |
| 528 | | 531 | |
| ... | @@ -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; |
| 536 | | 539 | |
| ... | @@ -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 | } |
| 728 | | 733 | |
| 729 | fn linuxLookupNameFromNumericUnspec(addrs: *std.ArrayList(LookupAddr), name: []const u8) !void { | 734 | fn 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 | | | |
| 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 { | | |
| 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; |
| 837 | | 803 | |
| 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 name | 813 | |
| 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 | } |
| 909 | | 878 | |
| 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 | } |
| 913 | | 882 | |
| 914 | const dpc_ctx = struct { | 883 | const 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 | }; |
| 918 | | 888 | |
| 919 | fn linuxLookupNameFromDns( | 889 | fn 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 | } |
| 1041 | | 1013 | |
| 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 | } |
| 1046 | | 1018 | |
| 1047 | fn eqlSockAddr(a: *const os.sockaddr, b: *const os.sockaddr, len: usize) bool { | 1019 | fn 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 | } |
| 1052 | | 1027 | |
| 1053 | fn resMSendRc( | 1028 | fn 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; |
| 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 | defer ns_list.deinit(); | 1041 | defer ns_list.deinit(); |
| 1067 | | 1042 | |
| 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(); |
| 1070 | | 1045 | |
| 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 | } |
| 1095 | | 1054 | |
| 1096 | // Get local address and open/bind a socket | 1055 | // 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); |
| 1114 | | 1073 | |
| 1115 | // Past this point, there are no errors. Each individual query will | 1074 | // Past this point, there are no errors. Each individual query will |
| 1116 | // yield either no reply (indicated by zero length) or an answer | 1075 | // 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( |
| 1168 | | 1127 | |
| 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; |
| 1172 | | 1131 | |
| 1173 | // Ignore non-identifiable packets | 1132 | // Ignore non-identifiable packets |
| 1174 | if (rlen < 4) continue; | 1133 | if (rlen < 4) continue; |
| 1175 | | 1134 | |
| 1176 | // Ignore replies from addresses we didn't send to | 1135 | // 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; |
| 1180 | | 1139 | |
| 1181 | // Find which query this answer goes with, if any | 1140 | // 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, |
| 1285 | | 1242 | |
| 1286 | /// `undefined` until `listen` returns successfully. | 1243 | /// `undefined` until `listen` returns successfully. |
| 1287 | listen_address: Address, | 1244 | listen_address: IpAddress, |
| 1288 | | 1245 | |
| 1289 | sockfd: ?os.fd_t, | 1246 | sockfd: ?os.fd_t, |
| 1290 | | 1247 | |
| ... | @@ -1311,7 +1268,7 @@ pub const TcpServer = struct { | ... | @@ -1311,7 +1268,7 @@ pub const TcpServer = struct { |
| 1311 | self.* = undefined; | 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 | 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 | } |
| 1323 | | 1280 | |
| 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 | } |
| 1329 | | 1286 | |
| 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 error | 1326 | // We only give SOCK_NONBLOCK when I/O mode is async, in which case this error |