| ... | @@ -14,8 +14,8 @@ const has_unix_sockets = @hasDecl(os, "sockaddr_un"); | ... | @@ -14,8 +14,8 @@ const has_unix_sockets = @hasDecl(os, "sockaddr_un"); |
| 14 | | 14 | |
| 15 | pub const Address = extern union { | 15 | pub const Address = extern union { |
| 16 | any: os.sockaddr, | 16 | any: os.sockaddr, |
| 17 | in: os.sockaddr_in, | 17 | in: Ip4Address, |
| 18 | in6: os.sockaddr_in6, | 18 | in6: Ip6Address, |
| 19 | un: if (has_unix_sockets) os.sockaddr_un else void, | 19 | un: if (has_unix_sockets) os.sockaddr_un else void, |
| 20 | | 20 | |
| 21 | // TODO this crashed the compiler. https://github.com/ziglang/zig/issues/3512 | 21 | // TODO this crashed the compiler. https://github.com/ziglang/zig/issues/3512 |
| ... | @@ -76,19 +76,227 @@ pub const Address = extern union { | ... | @@ -76,19 +76,227 @@ pub const Address = extern union { |
| 76 | } | 76 | } |
| 77 | } | 77 | } |
| 78 | | 78 | |
| | 79 | pub fn parseIp6(buf: []const u8, port: u16) !Address { |
| | 80 | return Address{.in6 = try Ip6Address.parse(buf, port) }; |
| | 81 | } |
| | 82 | |
| | 83 | pub fn resolveIp6(buf: []const u8, port: u16) !Address { |
| | 84 | return Address{.in6 = try Ip6Address.resolve(buf, port) }; |
| | 85 | } |
| | 86 | |
| | 87 | pub fn parseIp4(buf: []const u8, port: u16) !Address { |
| | 88 | return Address {.in = try Ip4Address.parse(buf, port) }; |
| | 89 | } |
| | 90 | |
| | 91 | pub fn initIp4(addr: [4]u8, port: u16) Address { |
| | 92 | return Address{.in = Ip4Address.init(addr, port) }; |
| | 93 | } |
| | 94 | |
| | 95 | pub fn initIp6(addr: [16]u8, port: u16, flowinfo: u32, scope_id: u32) Address { |
| | 96 | return Address{.in6 = Ip6Address.init(addr, port, flowinfo, scope_id) }; |
| | 97 | } |
| | 98 | |
| | 99 | pub fn initUnix(path: []const u8) !Address { |
| | 100 | var sock_addr = os.sockaddr_un{ |
| | 101 | .family = os.AF_UNIX, |
| | 102 | .path = undefined, |
| | 103 | }; |
| | 104 | |
| | 105 | // this enables us to have the proper length of the socket in getOsSockLen |
| | 106 | mem.set(u8, &sock_addr.path, 0); |
| | 107 | |
| | 108 | if (path.len > sock_addr.path.len) return error.NameTooLong; |
| | 109 | mem.copy(u8, &sock_addr.path, path); |
| | 110 | |
| | 111 | return Address{ .un = sock_addr }; |
| | 112 | } |
| | 113 | |
| | 114 | /// Returns the port in native endian. |
| | 115 | /// Asserts that the address is ip4 or ip6. |
| | 116 | pub fn getPort(self: Address) u16 { |
| | 117 | return switch (self.any.family) { |
| | 118 | os.AF_INET => self.in.getPort(), |
| | 119 | os.AF_INET6 => self.in6.getPort(), |
| | 120 | else => unreachable, |
| | 121 | }; |
| | 122 | } |
| | 123 | |
| | 124 | /// `port` is native-endian. |
| | 125 | /// Asserts that the address is ip4 or ip6. |
| | 126 | pub fn setPort(self: *Address, port: u16) void { |
| | 127 | switch (self.any.family) { |
| | 128 | os.AF_INET => self.in.setPort(port), |
| | 129 | os.AF_INET6 => self.in6.setPort(port), |
| | 130 | else => unreachable, |
| | 131 | } |
| | 132 | } |
| | 133 | |
| | 134 | /// Asserts that `addr` is an IP address. |
| | 135 | /// This function will read past the end of the pointer, with a size depending |
| | 136 | /// on the address family. |
| | 137 | pub fn initPosix(addr: *align(4) const os.sockaddr) Address { |
| | 138 | switch (addr.family) { |
| | 139 | os.AF_INET => return Address{ .in = Ip4Address{ .sa = @ptrCast(*const os.sockaddr_in, addr).*} }, |
| | 140 | os.AF_INET6 => return Address{ .in6 = Ip6Address{ .sa = @ptrCast(*const os.sockaddr_in6, addr).*} }, |
| | 141 | else => unreachable, |
| | 142 | } |
| | 143 | } |
| | 144 | |
| | 145 | pub fn format( |
| | 146 | self: Address, |
| | 147 | comptime fmt: []const u8, |
| | 148 | options: std.fmt.FormatOptions, |
| | 149 | out_stream: anytype, |
| | 150 | ) !void { |
| | 151 | switch (self.any.family) { |
| | 152 | os.AF_INET => try self.in.format(fmt, options, out_stream), |
| | 153 | os.AF_INET6 => try self.in6.format(fmt, options, out_stream), |
| | 154 | os.AF_UNIX => { |
| | 155 | if (!has_unix_sockets) { |
| | 156 | unreachable; |
| | 157 | } |
| | 158 | |
| | 159 | try std.fmt.format(out_stream, "{}", .{&self.un.path}); |
| | 160 | }, |
| | 161 | else => unreachable, |
| | 162 | } |
| | 163 | } |
| | 164 | |
| | 165 | pub fn eql(a: Address, b: Address) bool { |
| | 166 | const a_bytes = @ptrCast([*]const u8, &a.any)[0..a.getOsSockLen()]; |
| | 167 | const b_bytes = @ptrCast([*]const u8, &b.any)[0..b.getOsSockLen()]; |
| | 168 | return mem.eql(u8, a_bytes, b_bytes); |
| | 169 | } |
| | 170 | |
| | 171 | pub fn getOsSockLen(self: Address) os.socklen_t { |
| | 172 | switch (self.any.family) { |
| | 173 | os.AF_INET => return self.in.getOsSockLen(), |
| | 174 | os.AF_INET6 => return self.in6.getOsSockLen(), |
| | 175 | os.AF_UNIX => { |
| | 176 | if (!has_unix_sockets) { |
| | 177 | unreachable; |
| | 178 | } |
| | 179 | |
| | 180 | const path_len = std.mem.len(@ptrCast([*:0]const u8, &self.un.path)); |
| | 181 | return @intCast(os.socklen_t, @sizeOf(os.sockaddr_un) - self.un.path.len + path_len); |
| | 182 | }, |
| | 183 | else => unreachable, |
| | 184 | } |
| | 185 | } |
| | 186 | }; |
| | 187 | |
| | 188 | pub const Ip4Address = extern struct { |
| | 189 | sa: os.sockaddr_in, |
| | 190 | |
| | 191 | pub fn parse(buf: []const u8, port: u16) !Ip4Address { |
| | 192 | var result = Ip4Address{ |
| | 193 | .sa = .{ |
| | 194 | .port = mem.nativeToBig(u16, port), |
| | 195 | .addr = undefined, |
| | 196 | } |
| | 197 | }; |
| | 198 | const out_ptr = mem.sliceAsBytes(@as(*[1]u32, &result.sa.addr)[0..]); |
| | 199 | |
| | 200 | var x: u8 = 0; |
| | 201 | var index: u8 = 0; |
| | 202 | var saw_any_digits = false; |
| | 203 | for (buf) |c| { |
| | 204 | if (c == '.') { |
| | 205 | if (!saw_any_digits) { |
| | 206 | return error.InvalidCharacter; |
| | 207 | } |
| | 208 | if (index == 3) { |
| | 209 | return error.InvalidEnd; |
| | 210 | } |
| | 211 | out_ptr[index] = x; |
| | 212 | index += 1; |
| | 213 | x = 0; |
| | 214 | saw_any_digits = false; |
| | 215 | } else if (c >= '0' and c <= '9') { |
| | 216 | saw_any_digits = true; |
| | 217 | x = try std.math.mul(u8, x, 10); |
| | 218 | x = try std.math.add(u8, x, c - '0'); |
| | 219 | } else { |
| | 220 | return error.InvalidCharacter; |
| | 221 | } |
| | 222 | } |
| | 223 | if (index == 3 and saw_any_digits) { |
| | 224 | out_ptr[index] = x; |
| | 225 | return result; |
| | 226 | } |
| | 227 | |
| | 228 | return error.Incomplete; |
| | 229 | } |
| | 230 | |
| | 231 | pub fn resolveIp(name: []const u8, port: u16) !Ip4Address { |
| | 232 | if (parse(name, port)) |ip4| return ip4 else |err| switch (err) { |
| | 233 | error.Overflow, |
| | 234 | error.InvalidEnd, |
| | 235 | error.InvalidCharacter, |
| | 236 | error.Incomplete, |
| | 237 | => {}, |
| | 238 | } |
| | 239 | return error.InvalidIPAddressFormat; |
| | 240 | } |
| | 241 | |
| | 242 | pub fn init(addr: [4]u8, port: u16) Ip4Address { |
| | 243 | return Ip4Address { |
| | 244 | .sa = os.sockaddr_in{ |
| | 245 | .port = mem.nativeToBig(u16, port), |
| | 246 | .addr = @ptrCast(*align(1) const u32, &addr).*, |
| | 247 | }, |
| | 248 | }; |
| | 249 | } |
| | 250 | |
| | 251 | /// Returns the port in native endian. |
| | 252 | /// Asserts that the address is ip4 or ip6. |
| | 253 | pub fn getPort(self: Ip4Address) u16 { |
| | 254 | return mem.bigToNative(u16, self.sa.port); |
| | 255 | } |
| | 256 | |
| | 257 | /// `port` is native-endian. |
| | 258 | /// Asserts that the address is ip4 or ip6. |
| | 259 | pub fn setPort(self: *Ip4Address, port: u16) void { |
| | 260 | self.sa.port = mem.nativeToBig(u16, port); |
| | 261 | } |
| | 262 | |
| | 263 | pub fn format( |
| | 264 | self: Ip4Address, |
| | 265 | comptime fmt: []const u8, |
| | 266 | options: std.fmt.FormatOptions, |
| | 267 | out_stream: anytype, |
| | 268 | ) !void { |
| | 269 | const bytes = @ptrCast(*const [4]u8, &self.sa.addr); |
| | 270 | try std.fmt.format(out_stream, "{}.{}.{}.{}:{}", .{ |
| | 271 | bytes[0], |
| | 272 | bytes[1], |
| | 273 | bytes[2], |
| | 274 | bytes[3], |
| | 275 | self.getPort(), |
| | 276 | }); |
| | 277 | } |
| | 278 | |
| | 279 | pub fn getOsSockLen(self: Ip4Address) os.socklen_t { |
| | 280 | return @sizeOf(os.sockaddr_in); |
| | 281 | } |
| | 282 | }; |
| | 283 | |
| | 284 | pub const Ip6Address = extern struct { |
| | 285 | sa: os.sockaddr_in6, |
| | 286 | |
| 79 | /// Parse a given IPv6 address string into an Address. | 287 | /// Parse a given IPv6 address string into an Address. |
| 80 | /// Assumes the Scope ID of the address is fully numeric. | 288 | /// Assumes the Scope ID of the address is fully numeric. |
| 81 | /// For non-numeric addresses, see `resolveIp6`. | 289 | /// For non-numeric addresses, see `resolveIp6`. |
| 82 | pub fn parseIp6(buf: []const u8, port: u16) !Address { | 290 | pub fn parse(buf: []const u8, port: u16) !Ip6Address { |
| 83 | var result = Address{ | 291 | var result = Ip6Address{ |
| 84 | .in6 = os.sockaddr_in6{ | 292 | .sa = os.sockaddr_in6{ |
| 85 | .scope_id = 0, | 293 | .scope_id = 0, |
| 86 | .port = mem.nativeToBig(u16, port), | 294 | .port = mem.nativeToBig(u16, port), |
| 87 | .flowinfo = 0, | 295 | .flowinfo = 0, |
| 88 | .addr = undefined, | 296 | .addr = undefined, |
| 89 | }, | 297 | }, |
| 90 | }; | 298 | }; |
| 91 | var ip_slice = result.in6.addr[0..]; | 299 | var ip_slice = result.sa.addr[0..]; |
| 92 | | 300 | |
| 93 | var tail: [16]u8 = undefined; | 301 | var tail: [16]u8 = undefined; |
| 94 | | 302 | |
| ... | @@ -101,10 +309,10 @@ pub const Address = extern union { | ... | @@ -101,10 +309,10 @@ pub const Address = extern union { |
| 101 | if (scope_id) { | 309 | if (scope_id) { |
| 102 | if (c >= '0' and c <= '9') { | 310 | if (c >= '0' and c <= '9') { |
| 103 | const digit = c - '0'; | 311 | const digit = c - '0'; |
| 104 | if (@mulWithOverflow(u32, result.in6.scope_id, 10, &result.in6.scope_id)) { | 312 | if (@mulWithOverflow(u32, result.sa.scope_id, 10, &result.sa.scope_id)) { |
| 105 | return error.Overflow; | 313 | return error.Overflow; |
| 106 | } | 314 | } |
| 107 | if (@addWithOverflow(u32, result.in6.scope_id, digit, &result.in6.scope_id)) { | 315 | if (@addWithOverflow(u32, result.sa.scope_id, digit, &result.sa.scope_id)) { |
| 108 | return error.Overflow; | 316 | return error.Overflow; |
| 109 | } | 317 | } |
| 110 | } else { | 318 | } else { |
| ... | @@ -141,10 +349,10 @@ pub const Address = extern union { | ... | @@ -141,10 +349,10 @@ pub const Address = extern union { |
| 141 | return error.InvalidIpv4Mapping; | 349 | return error.InvalidIpv4Mapping; |
| 142 | } | 350 | } |
| 143 | const start_index = mem.lastIndexOfScalar(u8, buf[0..i], ':').? + 1; | 351 | const start_index = mem.lastIndexOfScalar(u8, buf[0..i], ':').? + 1; |
| 144 | const addr = (parseIp4(buf[start_index..], 0) catch { | 352 | const addr = (Ip4Address.parse(buf[start_index..], 0) catch { |
| 145 | return error.InvalidIpv4Mapping; | 353 | return error.InvalidIpv4Mapping; |
| 146 | }).in.addr; | 354 | }).sa.addr; |
| 147 | ip_slice = result.in6.addr[0..]; | 355 | ip_slice = result.sa.addr[0..]; |
| 148 | ip_slice[10] = 0xff; | 356 | ip_slice[10] = 0xff; |
| 149 | ip_slice[11] = 0xff; | 357 | ip_slice[11] = 0xff; |
| 150 | | 358 | |
| ... | @@ -180,22 +388,22 @@ pub const Address = extern union { | ... | @@ -180,22 +388,22 @@ pub const Address = extern union { |
| 180 | index += 1; | 388 | index += 1; |
| 181 | ip_slice[index] = @truncate(u8, x); | 389 | ip_slice[index] = @truncate(u8, x); |
| 182 | index += 1; | 390 | index += 1; |
| 183 | mem.copy(u8, result.in6.addr[16 - index ..], ip_slice[0..index]); | 391 | mem.copy(u8, result.sa.addr[16 - index ..], ip_slice[0..index]); |
| 184 | return result; | 392 | return result; |
| 185 | } | 393 | } |
| 186 | } | 394 | } |
| 187 | | 395 | |
| 188 | pub fn resolveIp6(buf: []const u8, port: u16) !Address { | 396 | pub fn resolve(buf: []const u8, port: u16) !Ip6Address { |
| 189 | // TODO: Unify the implementations of resolveIp6 and parseIp6. | 397 | // TODO: Unify the implementations of resolveIp6 and parseIp6. |
| 190 | var result = Address{ | 398 | var result = Ip6Address{ |
| 191 | .in6 = os.sockaddr_in6{ | 399 | .sa = os.sockaddr_in6{ |
| 192 | .scope_id = 0, | 400 | .scope_id = 0, |
| 193 | .port = mem.nativeToBig(u16, port), | 401 | .port = mem.nativeToBig(u16, port), |
| 194 | .flowinfo = 0, | 402 | .flowinfo = 0, |
| 195 | .addr = undefined, | 403 | .addr = undefined, |
| 196 | }, | 404 | }, |
| 197 | }; | 405 | }; |
| 198 | var ip_slice = result.in6.addr[0..]; | 406 | var ip_slice = result.sa.addr[0..]; |
| 199 | | 407 | |
| 200 | var tail: [16]u8 = undefined; | 408 | var tail: [16]u8 = undefined; |
| 201 | | 409 | |
| ... | @@ -256,10 +464,10 @@ pub const Address = extern union { | ... | @@ -256,10 +464,10 @@ pub const Address = extern union { |
| 256 | return error.InvalidIpv4Mapping; | 464 | return error.InvalidIpv4Mapping; |
| 257 | } | 465 | } |
| 258 | const start_index = mem.lastIndexOfScalar(u8, buf[0..i], ':').? + 1; | 466 | const start_index = mem.lastIndexOfScalar(u8, buf[0..i], ':').? + 1; |
| 259 | const addr = (parseIp4(buf[start_index..], 0) catch { | 467 | const addr = (Ip4Address.parse(buf[start_index..], 0) catch { |
| 260 | return error.InvalidIpv4Mapping; | 468 | return error.InvalidIpv4Mapping; |
| 261 | }).in.addr; | 469 | }).sa.addr; |
| 262 | ip_slice = result.in6.addr[0..]; | 470 | ip_slice = result.sa.addr[0..]; |
| 263 | ip_slice[10] = 0xff; | 471 | ip_slice[10] = 0xff; |
| 264 | ip_slice[11] = 0xff; | 472 | ip_slice[11] = 0xff; |
| 265 | | 473 | |
| ... | @@ -299,7 +507,7 @@ pub const Address = extern union { | ... | @@ -299,7 +507,7 @@ pub const Address = extern union { |
| 299 | }; | 507 | }; |
| 300 | } | 508 | } |
| 301 | | 509 | |
| 302 | result.in6.scope_id = resolved_scope_id; | 510 | result.sa.scope_id = resolved_scope_id; |
| 303 | | 511 | |
| 304 | if (index == 14) { | 512 | if (index == 14) { |
| 305 | ip_slice[14] = @truncate(u8, x >> 8); | 513 | ip_slice[14] = @truncate(u8, x >> 8); |
| ... | @@ -310,63 +518,14 @@ pub const Address = extern union { | ... | @@ -310,63 +518,14 @@ pub const Address = extern union { |
| 310 | index += 1; | 518 | index += 1; |
| 311 | ip_slice[index] = @truncate(u8, x); | 519 | ip_slice[index] = @truncate(u8, x); |
| 312 | index += 1; | 520 | index += 1; |
| 313 | mem.copy(u8, result.in6.addr[16 - index ..], ip_slice[0..index]); | 521 | mem.copy(u8, result.sa.addr[16 - index ..], ip_slice[0..index]); |
| 314 | return result; | | |
| 315 | } | | |
| 316 | } | | |
| 317 | | | |
| 318 | pub fn parseIp4(buf: []const u8, port: u16) !Address { | | |
| 319 | var result = Address{ | | |
| 320 | .in = os.sockaddr_in{ | | |
| 321 | .port = mem.nativeToBig(u16, port), | | |
| 322 | .addr = undefined, | | |
| 323 | }, | | |
| 324 | }; | | |
| 325 | const out_ptr = mem.sliceAsBytes(@as(*[1]u32, &result.in.addr)[0..]); | | |
| 326 | | | |
| 327 | var x: u8 = 0; | | |
| 328 | var index: u8 = 0; | | |
| 329 | var saw_any_digits = false; | | |
| 330 | for (buf) |c| { | | |
| 331 | if (c == '.') { | | |
| 332 | if (!saw_any_digits) { | | |
| 333 | return error.InvalidCharacter; | | |
| 334 | } | | |
| 335 | if (index == 3) { | | |
| 336 | return error.InvalidEnd; | | |
| 337 | } | | |
| 338 | out_ptr[index] = x; | | |
| 339 | index += 1; | | |
| 340 | x = 0; | | |
| 341 | saw_any_digits = false; | | |
| 342 | } else if (c >= '0' and c <= '9') { | | |
| 343 | saw_any_digits = true; | | |
| 344 | x = try std.math.mul(u8, x, 10); | | |
| 345 | x = try std.math.add(u8, x, c - '0'); | | |
| 346 | } else { | | |
| 347 | return error.InvalidCharacter; | | |
| 348 | } | | |
| 349 | } | | |
| 350 | if (index == 3 and saw_any_digits) { | | |
| 351 | out_ptr[index] = x; | | |
| 352 | return result; | 522 | return result; |
| 353 | } | 523 | } |
| 354 | | | |
| 355 | return error.Incomplete; | | |
| 356 | } | 524 | } |
| 357 | | 525 | |
| 358 | pub fn initIp4(addr: [4]u8, port: u16) Address { | 526 | pub fn init(addr: [16]u8, port: u16, flowinfo: u32, scope_id: u32) Ip6Address { |
| 359 | return Address{ | 527 | return Ip6Address{ |
| 360 | .in = os.sockaddr_in{ | 528 | .sa = os.sockaddr_in6{ |
| 361 | .port = mem.nativeToBig(u16, port), | | |
| 362 | .addr = @ptrCast(*align(1) const u32, &addr).*, | | |
| 363 | }, | | |
| 364 | }; | | |
| 365 | } | | |
| 366 | | | |
| 367 | pub fn initIp6(addr: [16]u8, port: u16, flowinfo: u32, scope_id: u32) Address { | | |
| 368 | return Address{ | | |
| 369 | .in6 = os.sockaddr_in6{ | | |
| 370 | .addr = addr, | 529 | .addr = addr, |
| 371 | .port = mem.nativeToBig(u16, port), | 530 | .port = mem.nativeToBig(u16, port), |
| 372 | .flowinfo = flowinfo, | 531 | .flowinfo = flowinfo, |
| ... | @@ -375,147 +534,71 @@ pub const Address = extern union { | ... | @@ -375,147 +534,71 @@ pub const Address = extern union { |
| 375 | }; | 534 | }; |
| 376 | } | 535 | } |
| 377 | | 536 | |
| 378 | pub fn initUnix(path: []const u8) !Address { | | |
| 379 | var sock_addr = os.sockaddr_un{ | | |
| 380 | .family = os.AF_UNIX, | | |
| 381 | .path = undefined, | | |
| 382 | }; | | |
| 383 | | | |
| 384 | // this enables us to have the proper length of the socket in getOsSockLen | | |
| 385 | mem.set(u8, &sock_addr.path, 0); | | |
| 386 | | | |
| 387 | if (path.len > sock_addr.path.len) return error.NameTooLong; | | |
| 388 | mem.copy(u8, &sock_addr.path, path); | | |
| 389 | | | |
| 390 | return Address{ .un = sock_addr }; | | |
| 391 | } | | |
| 392 | | | |
| 393 | /// Returns the port in native endian. | 537 | /// Returns the port in native endian. |
| 394 | /// Asserts that the address is ip4 or ip6. | 538 | /// Asserts that the address is ip4 or ip6. |
| 395 | pub fn getPort(self: Address) u16 { | 539 | pub fn getPort(self: Ip6Address) u16 { |
| 396 | const big_endian_port = switch (self.any.family) { | 540 | return mem.bigToNative(u16, self.sa.port); |
| 397 | os.AF_INET => self.in.port, | | |
| 398 | os.AF_INET6 => self.in6.port, | | |
| 399 | else => unreachable, | | |
| 400 | }; | | |
| 401 | return mem.bigToNative(u16, big_endian_port); | | |
| 402 | } | 541 | } |
| 403 | | 542 | |
| 404 | /// `port` is native-endian. | 543 | /// `port` is native-endian. |
| 405 | /// Asserts that the address is ip4 or ip6. | 544 | /// Asserts that the address is ip4 or ip6. |
| 406 | pub fn setPort(self: *Address, port: u16) void { | 545 | pub fn setPort(self: *Ip6Address, port: u16) void { |
| 407 | const ptr = switch (self.any.family) { | 546 | self.sa.port = mem.nativeToBig(u16, port); |
| 408 | os.AF_INET => &self.in.port, | | |
| 409 | os.AF_INET6 => &self.in6.port, | | |
| 410 | else => unreachable, | | |
| 411 | }; | | |
| 412 | ptr.* = mem.nativeToBig(u16, port); | | |
| 413 | } | | |
| 414 | | | |
| 415 | /// Asserts that `addr` is an IP address. | | |
| 416 | /// This function will read past the end of the pointer, with a size depending | | |
| 417 | /// on the address family. | | |
| 418 | pub fn initPosix(addr: *align(4) const os.sockaddr) Address { | | |
| 419 | switch (addr.family) { | | |
| 420 | os.AF_INET => return Address{ .in = @ptrCast(*const os.sockaddr_in, addr).* }, | | |
| 421 | os.AF_INET6 => return Address{ .in6 = @ptrCast(*const os.sockaddr_in6, addr).* }, | | |
| 422 | else => unreachable, | | |
| 423 | } | | |
| 424 | } | 547 | } |
| 425 | | 548 | |
| 426 | pub fn format( | 549 | pub fn format( |
| 427 | self: Address, | 550 | self: Ip6Address, |
| 428 | comptime fmt: []const u8, | 551 | comptime fmt: []const u8, |
| 429 | options: std.fmt.FormatOptions, | 552 | options: std.fmt.FormatOptions, |
| 430 | out_stream: anytype, | 553 | out_stream: anytype, |
| 431 | ) !void { | 554 | ) !void { |
| 432 | switch (self.any.family) { | 555 | const port = mem.bigToNative(u16, self.sa.port); |
| 433 | os.AF_INET => { | 556 | if (mem.eql(u8, self.sa.addr[0..12], &[_]u8{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xff, 0xff })) { |
| 434 | const port = mem.bigToNative(u16, self.in.port); | 557 | try std.fmt.format(out_stream, "[::ffff:{}.{}.{}.{}]:{}", .{ |
| 435 | const bytes = @ptrCast(*const [4]u8, &self.in.addr); | 558 | self.sa.addr[12], |
| 436 | try std.fmt.format(out_stream, "{}.{}.{}.{}:{}", .{ | 559 | self.sa.addr[13], |
| 437 | bytes[0], | 560 | self.sa.addr[14], |
| 438 | bytes[1], | 561 | self.sa.addr[15], |
| 439 | bytes[2], | 562 | port, |
| 440 | bytes[3], | 563 | }); |
| 441 | port, | 564 | return; |
| 442 | }); | 565 | } |
| 443 | }, | 566 | const big_endian_parts = @ptrCast(*align(1) const [8]u16, &self.sa.addr); |
| 444 | os.AF_INET6 => { | 567 | const native_endian_parts = switch (builtin.endian) { |
| 445 | const port = mem.bigToNative(u16, self.in6.port); | 568 | .Big => big_endian_parts.*, |
| 446 | if (mem.eql(u8, self.in6.addr[0..12], &[_]u8{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xff, 0xff })) { | 569 | .Little => blk: { |
| 447 | try std.fmt.format(out_stream, "[::ffff:{}.{}.{}.{}]:{}", .{ | 570 | var buf: [8]u16 = undefined; |
| 448 | self.in6.addr[12], | 571 | for (big_endian_parts) |part, i| { |
| 449 | self.in6.addr[13], | 572 | buf[i] = mem.bigToNative(u16, part); |
| 450 | self.in6.addr[14], | | |
| 451 | self.in6.addr[15], | | |
| 452 | port, | | |
| 453 | }); | | |
| 454 | return; | | |
| 455 | } | | |
| 456 | const big_endian_parts = @ptrCast(*align(1) const [8]u16, &self.in6.addr); | | |
| 457 | const native_endian_parts = switch (builtin.endian) { | | |
| 458 | .Big => big_endian_parts.*, | | |
| 459 | .Little => blk: { | | |
| 460 | var buf: [8]u16 = undefined; | | |
| 461 | for (big_endian_parts) |part, i| { | | |
| 462 | buf[i] = mem.bigToNative(u16, part); | | |
| 463 | } | | |
| 464 | break :blk buf; | | |
| 465 | }, | | |
| 466 | }; | | |
| 467 | try out_stream.writeAll("["); | | |
| 468 | var i: usize = 0; | | |
| 469 | var abbrv = false; | | |
| 470 | while (i < native_endian_parts.len) : (i += 1) { | | |
| 471 | if (native_endian_parts[i] == 0) { | | |
| 472 | if (!abbrv) { | | |
| 473 | try out_stream.writeAll(if (i == 0) "::" else ":"); | | |
| 474 | abbrv = true; | | |
| 475 | } | | |
| 476 | continue; | | |
| 477 | } | | |
| 478 | try std.fmt.format(out_stream, "{x}", .{native_endian_parts[i]}); | | |
| 479 | if (i != native_endian_parts.len - 1) { | | |
| 480 | try out_stream.writeAll(":"); | | |
| 481 | } | | |
| 482 | } | 573 | } |
| 483 | try std.fmt.format(out_stream, "]:{}", .{port}); | 574 | break :blk buf; |
| 484 | }, | 575 | }, |
| 485 | os.AF_UNIX => { | 576 | }; |
| 486 | if (!has_unix_sockets) { | 577 | try out_stream.writeAll("["); |
| 487 | unreachable; | 578 | var i: usize = 0; |
| | 579 | var abbrv = false; |
| | 580 | while (i < native_endian_parts.len) : (i += 1) { |
| | 581 | if (native_endian_parts[i] == 0) { |
| | 582 | if (!abbrv) { |
| | 583 | try out_stream.writeAll(if (i == 0) "::" else ":"); |
| | 584 | abbrv = true; |
| 488 | } | 585 | } |
| 489 | | 586 | continue; |
| 490 | try std.fmt.format(out_stream, "{}", .{&self.un.path}); | 587 | } |
| 491 | }, | 588 | try std.fmt.format(out_stream, "{x}", .{native_endian_parts[i]}); |
| 492 | else => unreachable, | 589 | if (i != native_endian_parts.len - 1) { |
| | 590 | try out_stream.writeAll(":"); |
| | 591 | } |
| 493 | } | 592 | } |
| | 593 | try std.fmt.format(out_stream, "]:{}", .{port}); |
| 494 | } | 594 | } |
| 495 | | 595 | |
| 496 | pub fn eql(a: Address, b: Address) bool { | 596 | pub fn getOsSockLen(self: Ip6Address) os.socklen_t { |
| 497 | const a_bytes = @ptrCast([*]const u8, &a.any)[0..a.getOsSockLen()]; | 597 | return @sizeOf(os.sockaddr_in6); |
| 498 | const b_bytes = @ptrCast([*]const u8, &b.any)[0..b.getOsSockLen()]; | | |
| 499 | return mem.eql(u8, a_bytes, b_bytes); | | |
| 500 | } | | |
| 501 | | | |
| 502 | pub fn getOsSockLen(self: Address) os.socklen_t { | | |
| 503 | switch (self.any.family) { | | |
| 504 | os.AF_INET => return @sizeOf(os.sockaddr_in), | | |
| 505 | os.AF_INET6 => return @sizeOf(os.sockaddr_in6), | | |
| 506 | os.AF_UNIX => { | | |
| 507 | if (!has_unix_sockets) { | | |
| 508 | unreachable; | | |
| 509 | } | | |
| 510 | | | |
| 511 | const path_len = std.mem.len(@ptrCast([*:0]const u8, &self.un.path)); | | |
| 512 | return @intCast(os.socklen_t, @sizeOf(os.sockaddr_un) - self.un.path.len + path_len); | | |
| 513 | }, | | |
| 514 | else => unreachable, | | |
| 515 | } | | |
| 516 | } | 598 | } |
| 517 | }; | 599 | }; |
| 518 | | 600 | |
| | 601 | |
| 519 | pub fn connectUnixSocket(path: []const u8) !fs.File { | 602 | pub fn connectUnixSocket(path: []const u8) !fs.File { |
| 520 | const opt_non_block = if (std.io.is_async) os.SOCK_NONBLOCK else 0; | 603 | const opt_non_block = if (std.io.is_async) os.SOCK_NONBLOCK else 0; |
| 521 | const sockfd = try os.socket( | 604 | const sockfd = try os.socket( |
| ... | @@ -777,7 +860,7 @@ fn linuxLookupName( | ... | @@ -777,7 +860,7 @@ fn linuxLookupName( |
| 777 | @memset(@ptrCast([*]u8, &sa6), 0, @sizeOf(os.sockaddr_in6)); | 860 | @memset(@ptrCast([*]u8, &sa6), 0, @sizeOf(os.sockaddr_in6)); |
| 778 | var da6 = os.sockaddr_in6{ | 861 | var da6 = os.sockaddr_in6{ |
| 779 | .family = os.AF_INET6, | 862 | .family = os.AF_INET6, |
| 780 | .scope_id = addr.addr.in6.scope_id, | 863 | .scope_id = addr.addr.in6.sa.scope_id, |
| 781 | .port = 65535, | 864 | .port = 65535, |
| 782 | .flowinfo = 0, | 865 | .flowinfo = 0, |
| 783 | .addr = [1]u8{0} ** 16, | 866 | .addr = [1]u8{0} ** 16, |
| ... | @@ -795,7 +878,7 @@ fn linuxLookupName( | ... | @@ -795,7 +878,7 @@ fn linuxLookupName( |
| 795 | var salen: os.socklen_t = undefined; | 878 | var salen: os.socklen_t = undefined; |
| 796 | var dalen: os.socklen_t = undefined; | 879 | var dalen: os.socklen_t = undefined; |
| 797 | if (addr.addr.any.family == os.AF_INET6) { | 880 | if (addr.addr.any.family == os.AF_INET6) { |
| 798 | mem.copy(u8, &da6.addr, &addr.addr.in6.addr); | 881 | mem.copy(u8, &da6.addr, &addr.addr.in6.sa.addr); |
| 799 | da = @ptrCast(*os.sockaddr, &da6); | 882 | da = @ptrCast(*os.sockaddr, &da6); |
| 800 | dalen = @sizeOf(os.sockaddr_in6); | 883 | dalen = @sizeOf(os.sockaddr_in6); |
| 801 | sa = @ptrCast(*os.sockaddr, &sa6); | 884 | sa = @ptrCast(*os.sockaddr, &sa6); |
| ... | @@ -803,8 +886,8 @@ fn linuxLookupName( | ... | @@ -803,8 +886,8 @@ fn linuxLookupName( |
| 803 | } else { | 886 | } else { |
| 804 | mem.copy(u8, &sa6.addr, "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xff\xff"); | 887 | mem.copy(u8, &sa6.addr, "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xff\xff"); |
| 805 | mem.copy(u8, &da6.addr, "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xff\xff"); | 888 | mem.copy(u8, &da6.addr, "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xff\xff"); |
| 806 | mem.writeIntNative(u32, da6.addr[12..], addr.addr.in.addr); | 889 | mem.writeIntNative(u32, da6.addr[12..], addr.addr.in.sa.addr); |
| 807 | da4.addr = addr.addr.in.addr; | 890 | da4.addr = addr.addr.in.sa.addr; |
| 808 | da = @ptrCast(*os.sockaddr, &da4); | 891 | da = @ptrCast(*os.sockaddr, &da4); |
| 809 | dalen = @sizeOf(os.sockaddr_in); | 892 | dalen = @sizeOf(os.sockaddr_in); |
| 810 | sa = @ptrCast(*os.sockaddr, &sa4); | 893 | sa = @ptrCast(*os.sockaddr, &sa4); |