| ... | ... | @@ -14,8 +14,8 @@ const has_unix_sockets = @hasDecl(os, "sockaddr_un"); |
| 14 | 14 | |
| 15 | 15 | pub const Address = extern union { |
| 16 | 16 | any: os.sockaddr, |
| 17 | | in: os.sockaddr_in, |
| 18 | | in6: os.sockaddr_in6, |
| 17 | in: Ip4Address, |
| 18 | in6: Ip6Address, |
| 19 | 19 | un: if (has_unix_sockets) os.sockaddr_un else void, |
| 20 | 20 | |
| 21 | 21 | // TODO this crashed the compiler. https://github.com/ziglang/zig/issues/3512 |
| ... | ... | @@ -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 | 287 | /// Parse a given IPv6 address string into an Address. |
| 80 | 288 | /// Assumes the Scope ID of the address is fully numeric. |
| 81 | 289 | /// For non-numeric addresses, see `resolveIp6`. |
| 82 | | pub fn parseIp6(buf: []const u8, port: u16) !Address { |
| 83 | | var result = Address{ |
| 84 | | .in6 = os.sockaddr_in6{ |
| 290 | pub fn parse(buf: []const u8, port: u16) !Ip6Address { |
| 291 | var result = Ip6Address{ |
| 292 | .sa = os.sockaddr_in6{ |
| 85 | 293 | .scope_id = 0, |
| 86 | 294 | .port = mem.nativeToBig(u16, port), |
| 87 | 295 | .flowinfo = 0, |
| 88 | 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 | 301 | var tail: [16]u8 = undefined; |
| 94 | 302 | |
| ... | ... | @@ -101,10 +309,10 @@ pub const Address = extern union { |
| 101 | 309 | if (scope_id) { |
| 102 | 310 | if (c >= '0' and c <= '9') { |
| 103 | 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 | 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 | 316 | return error.Overflow; |
| 109 | 317 | } |
| 110 | 318 | } else { |
| ... | ... | @@ -141,10 +349,10 @@ pub const Address = extern union { |
| 141 | 349 | return error.InvalidIpv4Mapping; |
| 142 | 350 | } |
| 143 | 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 | 353 | return error.InvalidIpv4Mapping; |
| 146 | | }).in.addr; |
| 147 | | ip_slice = result.in6.addr[0..]; |
| 354 | }).sa.addr; |
| 355 | ip_slice = result.sa.addr[0..]; |
| 148 | 356 | ip_slice[10] = 0xff; |
| 149 | 357 | ip_slice[11] = 0xff; |
| 150 | 358 | |
| ... | ... | @@ -180,22 +388,22 @@ pub const Address = extern union { |
| 180 | 388 | index += 1; |
| 181 | 389 | ip_slice[index] = @truncate(u8, x); |
| 182 | 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 | 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 | 397 | // TODO: Unify the implementations of resolveIp6 and parseIp6. |
| 190 | | var result = Address{ |
| 191 | | .in6 = os.sockaddr_in6{ |
| 398 | var result = Ip6Address{ |
| 399 | .sa = os.sockaddr_in6{ |
| 192 | 400 | .scope_id = 0, |
| 193 | 401 | .port = mem.nativeToBig(u16, port), |
| 194 | 402 | .flowinfo = 0, |
| 195 | 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 | 408 | var tail: [16]u8 = undefined; |
| 201 | 409 | |
| ... | ... | @@ -256,10 +464,10 @@ pub const Address = extern union { |
| 256 | 464 | return error.InvalidIpv4Mapping; |
| 257 | 465 | } |
| 258 | 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 | 468 | return error.InvalidIpv4Mapping; |
| 261 | | }).in.addr; |
| 262 | | ip_slice = result.in6.addr[0..]; |
| 469 | }).sa.addr; |
| 470 | ip_slice = result.sa.addr[0..]; |
| 263 | 471 | ip_slice[10] = 0xff; |
| 264 | 472 | ip_slice[11] = 0xff; |
| 265 | 473 | |
| ... | ... | @@ -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 | 512 | if (index == 14) { |
| 305 | 513 | ip_slice[14] = @truncate(u8, x >> 8); |
| ... | ... | @@ -310,63 +518,14 @@ pub const Address = extern union { |
| 310 | 518 | index += 1; |
| 311 | 519 | ip_slice[index] = @truncate(u8, x); |
| 312 | 520 | index += 1; |
| 313 | | mem.copy(u8, result.in6.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; |
| 521 | mem.copy(u8, result.sa.addr[16 - index ..], ip_slice[0..index]); |
| 352 | 522 | return result; |
| 353 | 523 | } |
| 354 | | |
| 355 | | return error.Incomplete; |
| 356 | 524 | } |
| 357 | 525 | |
| 358 | | pub fn initIp4(addr: [4]u8, port: u16) Address { |
| 359 | | return Address{ |
| 360 | | .in = os.sockaddr_in{ |
| 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{ |
| 526 | pub fn init(addr: [16]u8, port: u16, flowinfo: u32, scope_id: u32) Ip6Address { |
| 527 | return Ip6Address{ |
| 528 | .sa = os.sockaddr_in6{ |
| 370 | 529 | .addr = addr, |
| 371 | 530 | .port = mem.nativeToBig(u16, port), |
| 372 | 531 | .flowinfo = flowinfo, |
| ... | ... | @@ -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 | 537 | /// Returns the port in native endian. |
| 394 | 538 | /// Asserts that the address is ip4 or ip6. |
| 395 | | pub fn getPort(self: Address) u16 { |
| 396 | | const big_endian_port = switch (self.any.family) { |
| 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); |
| 539 | pub fn getPort(self: Ip6Address) u16 { |
| 540 | return mem.bigToNative(u16, self.sa.port); |
| 402 | 541 | } |
| 403 | 542 | |
| 404 | 543 | /// `port` is native-endian. |
| 405 | 544 | /// Asserts that the address is ip4 or ip6. |
| 406 | | pub fn setPort(self: *Address, port: u16) void { |
| 407 | | const ptr = switch (self.any.family) { |
| 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 | | } |
| 545 | pub fn setPort(self: *Ip6Address, port: u16) void { |
| 546 | self.sa.port = mem.nativeToBig(u16, port); |
| 424 | 547 | } |
| 425 | 548 | |
| 426 | 549 | pub fn format( |
| 427 | | self: Address, |
| 550 | self: Ip6Address, |
| 428 | 551 | comptime fmt: []const u8, |
| 429 | 552 | options: std.fmt.FormatOptions, |
| 430 | 553 | out_stream: anytype, |
| 431 | 554 | ) !void { |
| 432 | | switch (self.any.family) { |
| 433 | | os.AF_INET => { |
| 434 | | const port = mem.bigToNative(u16, self.in.port); |
| 435 | | const bytes = @ptrCast(*const [4]u8, &self.in.addr); |
| 436 | | try std.fmt.format(out_stream, "{}.{}.{}.{}:{}", .{ |
| 437 | | bytes[0], |
| 438 | | bytes[1], |
| 439 | | bytes[2], |
| 440 | | bytes[3], |
| 441 | | port, |
| 442 | | }); |
| 443 | | }, |
| 444 | | os.AF_INET6 => { |
| 445 | | const port = mem.bigToNative(u16, self.in6.port); |
| 446 | | if (mem.eql(u8, self.in6.addr[0..12], &[_]u8{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xff, 0xff })) { |
| 447 | | try std.fmt.format(out_stream, "[::ffff:{}.{}.{}.{}]:{}", .{ |
| 448 | | self.in6.addr[12], |
| 449 | | self.in6.addr[13], |
| 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 | | } |
| 555 | const port = mem.bigToNative(u16, self.sa.port); |
| 556 | if (mem.eql(u8, self.sa.addr[0..12], &[_]u8{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xff, 0xff })) { |
| 557 | try std.fmt.format(out_stream, "[::ffff:{}.{}.{}.{}]:{}", .{ |
| 558 | self.sa.addr[12], |
| 559 | self.sa.addr[13], |
| 560 | self.sa.addr[14], |
| 561 | self.sa.addr[15], |
| 562 | port, |
| 563 | }); |
| 564 | return; |
| 565 | } |
| 566 | const big_endian_parts = @ptrCast(*align(1) const [8]u16, &self.sa.addr); |
| 567 | const native_endian_parts = switch (builtin.endian) { |
| 568 | .Big => big_endian_parts.*, |
| 569 | .Little => blk: { |
| 570 | var buf: [8]u16 = undefined; |
| 571 | for (big_endian_parts) |part, i| { |
| 572 | buf[i] = mem.bigToNative(u16, part); |
| 482 | 573 | } |
| 483 | | try std.fmt.format(out_stream, "]:{}", .{port}); |
| 574 | break :blk buf; |
| 484 | 575 | }, |
| 485 | | os.AF_UNIX => { |
| 486 | | if (!has_unix_sockets) { |
| 487 | | unreachable; |
| 576 | }; |
| 577 | try out_stream.writeAll("["); |
| 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 | | |
| 490 | | try std.fmt.format(out_stream, "{}", .{&self.un.path}); |
| 491 | | }, |
| 492 | | else => unreachable, |
| 586 | continue; |
| 587 | } |
| 588 | try std.fmt.format(out_stream, "{x}", .{native_endian_parts[i]}); |
| 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 { |
| 497 | | const a_bytes = @ptrCast([*]const u8, &a.any)[0..a.getOsSockLen()]; |
| 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 | | } |
| 596 | pub fn getOsSockLen(self: Ip6Address) os.socklen_t { |
| 597 | return @sizeOf(os.sockaddr_in6); |
| 516 | 598 | } |
| 517 | 599 | }; |
| 518 | 600 | |
| 601 | |
| 519 | 602 | pub fn connectUnixSocket(path: []const u8) !fs.File { |
| 520 | 603 | const opt_non_block = if (std.io.is_async) os.SOCK_NONBLOCK else 0; |
| 521 | 604 | const sockfd = try os.socket( |
| ... | ... | @@ -777,7 +860,7 @@ fn linuxLookupName( |
| 777 | 860 | @memset(@ptrCast([*]u8, &sa6), 0, @sizeOf(os.sockaddr_in6)); |
| 778 | 861 | var da6 = os.sockaddr_in6{ |
| 779 | 862 | .family = os.AF_INET6, |
| 780 | | .scope_id = addr.addr.in6.scope_id, |
| 863 | .scope_id = addr.addr.in6.sa.scope_id, |
| 781 | 864 | .port = 65535, |
| 782 | 865 | .flowinfo = 0, |
| 783 | 866 | .addr = [1]u8{0} ** 16, |
| ... | ... | @@ -795,7 +878,7 @@ fn linuxLookupName( |
| 795 | 878 | var salen: os.socklen_t = undefined; |
| 796 | 879 | var dalen: os.socklen_t = undefined; |
| 797 | 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 | 882 | da = @ptrCast(*os.sockaddr, &da6); |
| 800 | 883 | dalen = @sizeOf(os.sockaddr_in6); |
| 801 | 884 | sa = @ptrCast(*os.sockaddr, &sa6); |
| ... | ... | @@ -803,8 +886,8 @@ fn linuxLookupName( |
| 803 | 886 | } else { |
| 804 | 887 | mem.copy(u8, &sa6.addr, "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xff\xff"); |
| 805 | 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); |
| 807 | | da4.addr = addr.addr.in.addr; |
| 889 | mem.writeIntNative(u32, da6.addr[12..], addr.addr.in.sa.addr); |
| 890 | da4.addr = addr.addr.in.sa.addr; |
| 808 | 891 | da = @ptrCast(*os.sockaddr, &da4); |
| 809 | 892 | dalen = @sizeOf(os.sockaddr_in); |
| 810 | 893 | sa = @ptrCast(*os.sockaddr, &sa4); |