| ... | @@ -10,15 +10,18 @@ test "" { | ... | @@ -10,15 +10,18 @@ test "" { |
| 10 | _ = @import("net/test.zig"); | 10 | _ = @import("net/test.zig"); |
| 11 | } | 11 | } |
| 12 | | 12 | |
| 13 | pub const IpAddress = extern union { | 13 | const has_unix_sockets = @hasDecl(os, "sockaddr_un"); |
| | 14 | |
| | 15 | pub const Address = extern union { |
| 14 | any: os.sockaddr, | 16 | any: os.sockaddr, |
| 15 | in: os.sockaddr_in, | 17 | in: os.sockaddr_in, |
| 16 | in6: os.sockaddr_in6, | 18 | in6: os.sockaddr_in6, |
| | 19 | un: if (has_unix_sockets) os.sockaddr_un else void, |
| 17 | | 20 | |
| 18 | // TODO this crashed the compiler | 21 | // TODO this crashed the compiler |
| 19 | //pub const localhost = initIp4(parseIp4("127.0.0.1") catch unreachable, 0); | 22 | //pub const localhost = initIp4(parseIp4("127.0.0.1") catch unreachable, 0); |
| 20 | | 23 | |
| 21 | pub fn parse(name: []const u8, port: u16) !IpAddress { | 24 | pub fn parseIp(name: []const u8, port: u16) !Address { |
| 22 | if (parseIp4(name, port)) |ip4| return ip4 else |err| switch (err) { | 25 | if (parseIp4(name, port)) |ip4| return ip4 else |err| switch (err) { |
| 23 | error.Overflow, | 26 | error.Overflow, |
| 24 | error.InvalidEnd, | 27 | error.InvalidEnd, |
| ... | @@ -39,17 +42,17 @@ pub const IpAddress = extern union { | ... | @@ -39,17 +42,17 @@ pub const IpAddress = extern union { |
| 39 | return error.InvalidIPAddressFormat; | 42 | return error.InvalidIPAddressFormat; |
| 40 | } | 43 | } |
| 41 | | 44 | |
| 42 | pub fn parseExpectingFamily(name: []const u8, family: os.sa_family_t, port: u16) !IpAddress { | 45 | pub fn parseExpectingFamily(name: []const u8, family: os.sa_family_t, port: u16) !Address { |
| 43 | switch (family) { | 46 | switch (family) { |
| 44 | os.AF_INET => return parseIp4(name, port), | 47 | os.AF_INET => return parseIp4(name, port), |
| 45 | os.AF_INET6 => return parseIp6(name, port), | 48 | os.AF_INET6 => return parseIp6(name, port), |
| 46 | os.AF_UNSPEC => return parse(name, port), | 49 | os.AF_UNSPEC => return parseIp(name, port), |
| 47 | else => unreachable, | 50 | else => unreachable, |
| 48 | } | 51 | } |
| 49 | } | 52 | } |
| 50 | | 53 | |
| 51 | pub fn parseIp6(buf: []const u8, port: u16) !IpAddress { | 54 | pub fn parseIp6(buf: []const u8, port: u16) !Address { |
| 52 | var result = IpAddress{ | 55 | var result = Address{ |
| 53 | .in6 = os.sockaddr_in6{ | 56 | .in6 = os.sockaddr_in6{ |
| 54 | .scope_id = 0, | 57 | .scope_id = 0, |
| 55 | .port = mem.nativeToBig(u16, port), | 58 | .port = mem.nativeToBig(u16, port), |
| ... | @@ -154,8 +157,8 @@ pub const IpAddress = extern union { | ... | @@ -154,8 +157,8 @@ pub const IpAddress = extern union { |
| 154 | } | 157 | } |
| 155 | } | 158 | } |
| 156 | | 159 | |
| 157 | pub fn parseIp4(buf: []const u8, port: u16) !IpAddress { | 160 | pub fn parseIp4(buf: []const u8, port: u16) !Address { |
| 158 | var result = IpAddress{ | 161 | var result = Address{ |
| 159 | .in = os.sockaddr_in{ | 162 | .in = os.sockaddr_in{ |
| 160 | .port = mem.nativeToBig(u16, port), | 163 | .port = mem.nativeToBig(u16, port), |
| 161 | .addr = undefined, | 164 | .addr = undefined, |
| ... | @@ -194,8 +197,8 @@ pub const IpAddress = extern union { | ... | @@ -194,8 +197,8 @@ pub const IpAddress = extern union { |
| 194 | return error.Incomplete; | 197 | return error.Incomplete; |
| 195 | } | 198 | } |
| 196 | | 199 | |
| 197 | pub fn initIp4(addr: [4]u8, port: u16) IpAddress { | 200 | pub fn initIp4(addr: [4]u8, port: u16) Address { |
| 198 | return IpAddress{ | 201 | return Address{ |
| 199 | .in = os.sockaddr_in{ | 202 | .in = os.sockaddr_in{ |
| 200 | .port = mem.nativeToBig(u16, port), | 203 | .port = mem.nativeToBig(u16, port), |
| 201 | .addr = @ptrCast(*align(1) const u32, &addr).*, | 204 | .addr = @ptrCast(*align(1) const u32, &addr).*, |
| ... | @@ -203,8 +206,8 @@ pub const IpAddress = extern union { | ... | @@ -203,8 +206,8 @@ pub const IpAddress = extern union { |
| 203 | }; | 206 | }; |
| 204 | } | 207 | } |
| 205 | | 208 | |
| 206 | pub fn initIp6(addr: [16]u8, port: u16, flowinfo: u32, scope_id: u32) IpAddress { | 209 | pub fn initIp6(addr: [16]u8, port: u16, flowinfo: u32, scope_id: u32) Address { |
| 207 | return IpAddress{ | 210 | return Address{ |
| 208 | .in6 = os.sockaddr_in6{ | 211 | .in6 = os.sockaddr_in6{ |
| 209 | .addr = addr, | 212 | .addr = addr, |
| 210 | .port = mem.nativeToBig(u16, port), | 213 | .port = mem.nativeToBig(u16, port), |
| ... | @@ -214,8 +217,24 @@ pub const IpAddress = extern union { | ... | @@ -214,8 +217,24 @@ pub const IpAddress = extern union { |
| 214 | }; | 217 | }; |
| 215 | } | 218 | } |
| 216 | | 219 | |
| | 220 | pub fn initUnix(path: []const u8) !Address { |
| | 221 | var sock_addr = os.sockaddr_un{ |
| | 222 | .family = os.AF_UNIX, |
| | 223 | .path = undefined, |
| | 224 | }; |
| | 225 | |
| | 226 | // this enables us to have the proper length of the socket in getOsSockLen |
| | 227 | mem.set(u8, &sock_addr.path, 0); |
| | 228 | |
| | 229 | if (path.len > sock_addr.path.len) return error.NameTooLong; |
| | 230 | mem.copy(u8, &sock_addr.path, path); |
| | 231 | |
| | 232 | return Address{ .un = sock_addr }; |
| | 233 | } |
| | 234 | |
| 217 | /// Returns the port in native endian. | 235 | /// Returns the port in native endian. |
| 218 | pub fn getPort(self: IpAddress) u16 { | 236 | /// Asserts that the address is ip4 or ip6. |
| | 237 | pub fn getPort(self: Address) u16 { |
| 219 | const big_endian_port = switch (self.any.family) { | 238 | const big_endian_port = switch (self.any.family) { |
| 220 | os.AF_INET => self.in.port, | 239 | os.AF_INET => self.in.port, |
| 221 | os.AF_INET6 => self.in6.port, | 240 | os.AF_INET6 => self.in6.port, |
| ... | @@ -225,7 +244,8 @@ pub const IpAddress = extern union { | ... | @@ -225,7 +244,8 @@ pub const IpAddress = extern union { |
| 225 | } | 244 | } |
| 226 | | 245 | |
| 227 | /// `port` is native-endian. | 246 | /// `port` is native-endian. |
| 228 | pub fn setPort(self: *IpAddress, port: u16) void { | 247 | /// Asserts that the address is ip4 or ip6. |
| | 248 | pub fn setPort(self: *Address, port: u16) void { |
| 229 | const ptr = switch (self.any.family) { | 249 | const ptr = switch (self.any.family) { |
| 230 | os.AF_INET => &self.in.port, | 250 | os.AF_INET => &self.in.port, |
| 231 | os.AF_INET6 => &self.in6.port, | 251 | os.AF_INET6 => &self.in6.port, |
| ... | @@ -237,16 +257,16 @@ pub const IpAddress = extern union { | ... | @@ -237,16 +257,16 @@ pub const IpAddress = extern union { |
| 237 | /// Asserts that `addr` is an IP address. | 257 | /// Asserts that `addr` is an IP address. |
| 238 | /// This function will read past the end of the pointer, with a size depending | 258 | /// This function will read past the end of the pointer, with a size depending |
| 239 | /// on the address family. | 259 | /// on the address family. |
| 240 | pub fn initPosix(addr: *align(4) const os.sockaddr) IpAddress { | 260 | pub fn initPosix(addr: *align(4) const os.sockaddr) Address { |
| 241 | switch (addr.family) { | 261 | switch (addr.family) { |
| 242 | os.AF_INET => return IpAddress{ .in = @ptrCast(*const os.sockaddr_in, addr).* }, | 262 | os.AF_INET => return Address{ .in = @ptrCast(*const os.sockaddr_in, addr).* }, |
| 243 | os.AF_INET6 => return IpAddress{ .in6 = @ptrCast(*const os.sockaddr_in6, addr).* }, | 263 | os.AF_INET6 => return Address{ .in6 = @ptrCast(*const os.sockaddr_in6, addr).* }, |
| 244 | else => unreachable, | 264 | else => unreachable, |
| 245 | } | 265 | } |
| 246 | } | 266 | } |
| 247 | | 267 | |
| 248 | pub fn format( | 268 | pub fn format( |
| 249 | self: IpAddress, | 269 | self: Address, |
| 250 | comptime fmt: []const u8, | 270 | comptime fmt: []const u8, |
| 251 | options: std.fmt.FormatOptions, | 271 | options: std.fmt.FormatOptions, |
| 252 | context: var, | 272 | context: var, |
| ... | @@ -314,20 +334,35 @@ pub const IpAddress = extern union { | ... | @@ -314,20 +334,35 @@ pub const IpAddress = extern union { |
| 314 | } | 334 | } |
| 315 | try std.fmt.format(context, Errors, output, "]:{}", port); | 335 | try std.fmt.format(context, Errors, output, "]:{}", port); |
| 316 | }, | 336 | }, |
| | 337 | os.AF_UNIX => { |
| | 338 | if (!has_unix_sockets) { |
| | 339 | unreachable; |
| | 340 | } |
| | 341 | |
| | 342 | try std.fmt.format(context, Errors, output, "{}", self.un.path); |
| | 343 | }, |
| 317 | else => unreachable, | 344 | else => unreachable, |
| 318 | } | 345 | } |
| 319 | } | 346 | } |
| 320 | | 347 | |
| 321 | pub fn eql(a: IpAddress, b: IpAddress) bool { | 348 | pub fn eql(a: Address, b: Address) bool { |
| 322 | const a_bytes = @ptrCast([*]const u8, &a.any)[0..a.getOsSockLen()]; | 349 | const a_bytes = @ptrCast([*]const u8, &a.any)[0..a.getOsSockLen()]; |
| 323 | const b_bytes = @ptrCast([*]const u8, &b.any)[0..b.getOsSockLen()]; | 350 | const b_bytes = @ptrCast([*]const u8, &b.any)[0..b.getOsSockLen()]; |
| 324 | return mem.eql(u8, a_bytes, b_bytes); | 351 | return mem.eql(u8, a_bytes, b_bytes); |
| 325 | } | 352 | } |
| 326 | | 353 | |
| 327 | fn getOsSockLen(self: IpAddress) os.socklen_t { | 354 | fn getOsSockLen(self: Address) os.socklen_t { |
| 328 | switch (self.any.family) { | 355 | switch (self.any.family) { |
| 329 | os.AF_INET => return @sizeOf(os.sockaddr_in), | 356 | os.AF_INET => return @sizeOf(os.sockaddr_in), |
| 330 | os.AF_INET6 => return @sizeOf(os.sockaddr_in6), | 357 | os.AF_INET6 => return @sizeOf(os.sockaddr_in6), |
| | 358 | os.AF_UNIX => { |
| | 359 | if (!has_unix_sockets) { |
| | 360 | unreachable; |
| | 361 | } |
| | 362 | |
| | 363 | const path_len = std.mem.len(u8, &self.un.path); |
| | 364 | return @intCast(os.socklen_t, @sizeOf(os.sockaddr_un) - self.un.path.len + path_len); |
| | 365 | }, |
| 331 | else => unreachable, | 366 | else => unreachable, |
| 332 | } | 367 | } |
| 333 | } | 368 | } |
| ... | @@ -342,23 +377,20 @@ pub fn connectUnixSocket(path: []const u8) !fs.File { | ... | @@ -342,23 +377,20 @@ pub fn connectUnixSocket(path: []const u8) !fs.File { |
| 342 | ); | 377 | ); |
| 343 | errdefer os.close(sockfd); | 378 | errdefer os.close(sockfd); |
| 344 | | 379 | |
| 345 | var sock_addr = os.sockaddr_un{ | 380 | var addr = try std.net.Address.initUnix(path); |
| 346 | .family = os.AF_UNIX, | | |
| 347 | .path = undefined, | | |
| 348 | }; | | |
| 349 | | | |
| 350 | if (path.len > sock_addr.path.len) return error.NameTooLong; | | |
| 351 | mem.copy(u8, &sock_addr.path, path); | | |
| 352 | | 381 | |
| 353 | const size = @intCast(u32, @sizeOf(os.sockaddr_un) - sock_addr.path.len + path.len); | 382 | try os.connect( |
| 354 | try os.connect(sockfd, &sock_addr, size); | 383 | sockfd, |
| | 384 | &addr.any, |
| | 385 | addr.getOsSockLen(), |
| | 386 | ); |
| 355 | | 387 | |
| 356 | return fs.File.openHandle(sockfd); | 388 | return fs.File.openHandle(sockfd); |
| 357 | } | 389 | } |
| 358 | | 390 | |
| 359 | pub const AddressList = struct { | 391 | pub const AddressList = struct { |
| 360 | arena: std.heap.ArenaAllocator, | 392 | arena: std.heap.ArenaAllocator, |
| 361 | addrs: []IpAddress, | 393 | addrs: []Address, |
| 362 | canon_name: ?[]u8, | 394 | canon_name: ?[]u8, |
| 363 | | 395 | |
| 364 | fn deinit(self: *AddressList) void { | 396 | fn deinit(self: *AddressList) void { |
| ... | @@ -381,7 +413,7 @@ pub fn tcpConnectToHost(allocator: *mem.Allocator, name: []const u8, port: u16) | ... | @@ -381,7 +413,7 @@ pub fn tcpConnectToHost(allocator: *mem.Allocator, name: []const u8, port: u16) |
| 381 | return tcpConnectToAddress(addrs[0], port); | 413 | return tcpConnectToAddress(addrs[0], port); |
| 382 | } | 414 | } |
| 383 | | 415 | |
| 384 | pub fn tcpConnectToAddress(address: IpAddress) !fs.File { | 416 | pub fn tcpConnectToAddress(address: Address) !fs.File { |
| 385 | const nonblock = if (std.io.is_async) os.SOCK_NONBLOCK else 0; | 417 | const nonblock = if (std.io.is_async) os.SOCK_NONBLOCK else 0; |
| 386 | const sock_flags = os.SOCK_STREAM | os.SOCK_CLOEXEC | nonblock; | 418 | const sock_flags = os.SOCK_STREAM | os.SOCK_CLOEXEC | nonblock; |
| 387 | const sockfd = try os.socket(address.any.family, sock_flags, os.IPPROTO_TCP); | 419 | const sockfd = try os.socket(address.any.family, sock_flags, os.IPPROTO_TCP); |
| ... | @@ -456,13 +488,13 @@ pub fn getAddressList(allocator: *mem.Allocator, name: []const u8, port: u16) !* | ... | @@ -456,13 +488,13 @@ pub fn getAddressList(allocator: *mem.Allocator, name: []const u8, port: u16) !* |
| 456 | } | 488 | } |
| 457 | break :blk count; | 489 | break :blk count; |
| 458 | }; | 490 | }; |
| 459 | result.addrs = try arena.alloc(IpAddress, addr_count); | 491 | result.addrs = try arena.alloc(Address, addr_count); |
| 460 | | 492 | |
| 461 | var it: ?*os.addrinfo = res; | 493 | var it: ?*os.addrinfo = res; |
| 462 | var i: usize = 0; | 494 | var i: usize = 0; |
| 463 | while (it) |info| : (it = info.next) { | 495 | while (it) |info| : (it = info.next) { |
| 464 | const addr = info.addr orelse continue; | 496 | const addr = info.addr orelse continue; |
| 465 | result.addrs[i] = IpAddress.initPosix(@alignCast(4, addr)); | 497 | result.addrs[i] = Address.initPosix(@alignCast(4, addr)); |
| 466 | | 498 | |
| 467 | if (info.canonname) |n| { | 499 | if (info.canonname) |n| { |
| 468 | if (result.canon_name == null) { | 500 | if (result.canon_name == null) { |
| ... | @@ -485,7 +517,7 @@ pub fn getAddressList(allocator: *mem.Allocator, name: []const u8, port: u16) !* | ... | @@ -485,7 +517,7 @@ pub fn getAddressList(allocator: *mem.Allocator, name: []const u8, port: u16) !* |
| 485 | | 517 | |
| 486 | try linuxLookupName(&lookup_addrs, &canon, name, family, flags, port); | 518 | try linuxLookupName(&lookup_addrs, &canon, name, family, flags, port); |
| 487 | | 519 | |
| 488 | result.addrs = try arena.alloc(IpAddress, lookup_addrs.len); | 520 | result.addrs = try arena.alloc(Address, lookup_addrs.len); |
| 489 | if (!canon.isNull()) { | 521 | if (!canon.isNull()) { |
| 490 | result.canon_name = canon.toOwnedSlice(); | 522 | result.canon_name = canon.toOwnedSlice(); |
| 491 | } | 523 | } |
| ... | @@ -501,7 +533,7 @@ pub fn getAddressList(allocator: *mem.Allocator, name: []const u8, port: u16) !* | ... | @@ -501,7 +533,7 @@ pub fn getAddressList(allocator: *mem.Allocator, name: []const u8, port: u16) !* |
| 501 | } | 533 | } |
| 502 | | 534 | |
| 503 | const LookupAddr = struct { | 535 | const LookupAddr = struct { |
| 504 | addr: IpAddress, | 536 | addr: Address, |
| 505 | sortkey: i32 = 0, | 537 | sortkey: i32 = 0, |
| 506 | }; | 538 | }; |
| 507 | | 539 | |
| ... | @@ -524,7 +556,7 @@ fn linuxLookupName( | ... | @@ -524,7 +556,7 @@ fn linuxLookupName( |
| 524 | if (opt_name) |name| { | 556 | if (opt_name) |name| { |
| 525 | // reject empty name and check len so it fits into temp bufs | 557 | // reject empty name and check len so it fits into temp bufs |
| 526 | try canon.replaceContents(name); | 558 | try canon.replaceContents(name); |
| 527 | if (IpAddress.parseExpectingFamily(name, family, port)) |addr| { | 559 | if (Address.parseExpectingFamily(name, family, port)) |addr| { |
| 528 | try addrs.append(LookupAddr{ .addr = addr }); | 560 | try addrs.append(LookupAddr{ .addr = addr }); |
| 529 | } else |name_err| if ((flags & std.c.AI_NUMERICHOST) != 0) { | 561 | } else |name_err| if ((flags & std.c.AI_NUMERICHOST) != 0) { |
| 530 | return name_err; | 562 | return name_err; |
| ... | @@ -751,23 +783,23 @@ fn linuxLookupNameFromNull( | ... | @@ -751,23 +783,23 @@ fn linuxLookupNameFromNull( |
| 751 | if ((flags & std.c.AI_PASSIVE) != 0) { | 783 | if ((flags & std.c.AI_PASSIVE) != 0) { |
| 752 | if (family != os.AF_INET6) { | 784 | if (family != os.AF_INET6) { |
| 753 | (try addrs.addOne()).* = LookupAddr{ | 785 | (try addrs.addOne()).* = LookupAddr{ |
| 754 | .addr = IpAddress.initIp4([1]u8{0} ** 4, port), | 786 | .addr = Address.initIp4([1]u8{0} ** 4, port), |
| 755 | }; | 787 | }; |
| 756 | } | 788 | } |
| 757 | if (family != os.AF_INET) { | 789 | if (family != os.AF_INET) { |
| 758 | (try addrs.addOne()).* = LookupAddr{ | 790 | (try addrs.addOne()).* = LookupAddr{ |
| 759 | .addr = IpAddress.initIp6([1]u8{0} ** 16, port, 0, 0), | 791 | .addr = Address.initIp6([1]u8{0} ** 16, port, 0, 0), |
| 760 | }; | 792 | }; |
| 761 | } | 793 | } |
| 762 | } else { | 794 | } else { |
| 763 | if (family != os.AF_INET6) { | 795 | if (family != os.AF_INET6) { |
| 764 | (try addrs.addOne()).* = LookupAddr{ | 796 | (try addrs.addOne()).* = LookupAddr{ |
| 765 | .addr = IpAddress.initIp4([4]u8{ 127, 0, 0, 1 }, port), | 797 | .addr = Address.initIp4([4]u8{ 127, 0, 0, 1 }, port), |
| 766 | }; | 798 | }; |
| 767 | } | 799 | } |
| 768 | if (family != os.AF_INET) { | 800 | if (family != os.AF_INET) { |
| 769 | (try addrs.addOne()).* = LookupAddr{ | 801 | (try addrs.addOne()).* = LookupAddr{ |
| 770 | .addr = IpAddress.initIp6(([1]u8{0} ** 15) ++ [1]u8{1}, port, 0, 0), | 802 | .addr = Address.initIp6(([1]u8{0} ** 15) ++ [1]u8{1}, port, 0, 0), |
| 771 | }; | 803 | }; |
| 772 | } | 804 | } |
| 773 | } | 805 | } |
| ... | @@ -812,7 +844,7 @@ fn linuxLookupNameFromHosts( | ... | @@ -812,7 +844,7 @@ fn linuxLookupNameFromHosts( |
| 812 | } | 844 | } |
| 813 | } else continue; | 845 | } else continue; |
| 814 | | 846 | |
| 815 | const addr = IpAddress.parseExpectingFamily(ip_text, family, port) catch |err| switch (err) { | 847 | const addr = Address.parseExpectingFamily(ip_text, family, port) catch |err| switch (err) { |
| 816 | error.Overflow, | 848 | error.Overflow, |
| 817 | error.InvalidEnd, | 849 | error.InvalidEnd, |
| 818 | error.InvalidCharacter, | 850 | error.InvalidCharacter, |
| ... | @@ -1033,7 +1065,7 @@ fn linuxLookupNameFromNumericUnspec( | ... | @@ -1033,7 +1065,7 @@ fn linuxLookupNameFromNumericUnspec( |
| 1033 | name: []const u8, | 1065 | name: []const u8, |
| 1034 | port: u16, | 1066 | port: u16, |
| 1035 | ) !void { | 1067 | ) !void { |
| 1036 | const addr = try IpAddress.parse(name, port); | 1068 | const addr = try Address.parseIp(name, port); |
| 1037 | (try addrs.addOne()).* = LookupAddr{ .addr = addr }; | 1069 | (try addrs.addOne()).* = LookupAddr{ .addr = addr }; |
| 1038 | } | 1070 | } |
| 1039 | | 1071 | |
| ... | @@ -1049,7 +1081,7 @@ fn resMSendRc( | ... | @@ -1049,7 +1081,7 @@ fn resMSendRc( |
| 1049 | var sl: os.socklen_t = @sizeOf(os.sockaddr_in); | 1081 | var sl: os.socklen_t = @sizeOf(os.sockaddr_in); |
| 1050 | var family: os.sa_family_t = os.AF_INET; | 1082 | var family: os.sa_family_t = os.AF_INET; |
| 1051 | | 1083 | |
| 1052 | var ns_list = std.ArrayList(IpAddress).init(rc.ns.allocator); | 1084 | var ns_list = std.ArrayList(Address).init(rc.ns.allocator); |
| 1053 | defer ns_list.deinit(); | 1085 | defer ns_list.deinit(); |
| 1054 | | 1086 | |
| 1055 | try ns_list.resize(rc.ns.len); | 1087 | try ns_list.resize(rc.ns.len); |
| ... | @@ -1065,8 +1097,8 @@ fn resMSendRc( | ... | @@ -1065,8 +1097,8 @@ fn resMSendRc( |
| 1065 | } | 1097 | } |
| 1066 | | 1098 | |
| 1067 | // Get local address and open/bind a socket | 1099 | // Get local address and open/bind a socket |
| 1068 | var sa: IpAddress = undefined; | 1100 | var sa: Address = undefined; |
| 1069 | @memset(@ptrCast([*]u8, &sa), 0, @sizeOf(IpAddress)); | 1101 | @memset(@ptrCast([*]u8, &sa), 0, @sizeOf(Address)); |
| 1070 | sa.any.family = family; | 1102 | sa.any.family = family; |
| 1071 | const flags = os.SOCK_DGRAM | os.SOCK_CLOEXEC | os.SOCK_NONBLOCK; | 1103 | const flags = os.SOCK_DGRAM | os.SOCK_CLOEXEC | os.SOCK_NONBLOCK; |
| 1072 | const fd = os.socket(family, flags, 0) catch |err| switch (err) { | 1104 | const fd = os.socket(family, flags, 0) catch |err| switch (err) { |
| ... | @@ -1224,7 +1256,7 @@ fn dnsParseCallback(ctx: dpc_ctx, rr: u8, data: []const u8, packet: []const u8) | ... | @@ -1224,7 +1256,7 @@ fn dnsParseCallback(ctx: dpc_ctx, rr: u8, data: []const u8, packet: []const u8) |
| 1224 | const new_addr = try ctx.addrs.addOne(); | 1256 | const new_addr = try ctx.addrs.addOne(); |
| 1225 | new_addr.* = LookupAddr{ | 1257 | new_addr.* = LookupAddr{ |
| 1226 | // TODO slice [0..4] to make this *[4]u8 without @ptrCast | 1258 | // TODO slice [0..4] to make this *[4]u8 without @ptrCast |
| 1227 | .addr = IpAddress.initIp4(@ptrCast(*const [4]u8, data.ptr).*, ctx.port), | 1259 | .addr = Address.initIp4(@ptrCast(*const [4]u8, data.ptr).*, ctx.port), |
| 1228 | }; | 1260 | }; |
| 1229 | }, | 1261 | }, |
| 1230 | os.RR_AAAA => { | 1262 | os.RR_AAAA => { |
| ... | @@ -1232,7 +1264,7 @@ fn dnsParseCallback(ctx: dpc_ctx, rr: u8, data: []const u8, packet: []const u8) | ... | @@ -1232,7 +1264,7 @@ fn dnsParseCallback(ctx: dpc_ctx, rr: u8, data: []const u8, packet: []const u8) |
| 1232 | const new_addr = try ctx.addrs.addOne(); | 1264 | const new_addr = try ctx.addrs.addOne(); |
| 1233 | new_addr.* = LookupAddr{ | 1265 | new_addr.* = LookupAddr{ |
| 1234 | // TODO slice [0..16] to make this *[16]u8 without @ptrCast | 1266 | // TODO slice [0..16] to make this *[16]u8 without @ptrCast |
| 1235 | .addr = IpAddress.initIp6(@ptrCast(*const [16]u8, data.ptr).*, ctx.port, 0, 0), | 1267 | .addr = Address.initIp6(@ptrCast(*const [16]u8, data.ptr).*, ctx.port, 0, 0), |
| 1236 | }; | 1268 | }; |
| 1237 | }, | 1269 | }, |
| 1238 | os.RR_CNAME => { | 1270 | os.RR_CNAME => { |
| ... | @@ -1248,12 +1280,12 @@ fn dnsParseCallback(ctx: dpc_ctx, rr: u8, data: []const u8, packet: []const u8) | ... | @@ -1248,12 +1280,12 @@ fn dnsParseCallback(ctx: dpc_ctx, rr: u8, data: []const u8, packet: []const u8) |
| 1248 | } | 1280 | } |
| 1249 | } | 1281 | } |
| 1250 | | 1282 | |
| 1251 | pub const TcpServer = struct { | 1283 | pub const StreamServer = struct { |
| 1252 | /// Copied from `Options` on `init`. | 1284 | /// Copied from `Options` on `init`. |
| 1253 | kernel_backlog: u32, | 1285 | kernel_backlog: u32, |
| 1254 | | 1286 | |
| 1255 | /// `undefined` until `listen` returns successfully. | 1287 | /// `undefined` until `listen` returns successfully. |
| 1256 | listen_address: IpAddress, | 1288 | listen_address: Address, |
| 1257 | | 1289 | |
| 1258 | sockfd: ?os.fd_t, | 1290 | sockfd: ?os.fd_t, |
| 1259 | | 1291 | |
| ... | @@ -1266,24 +1298,26 @@ pub const TcpServer = struct { | ... | @@ -1266,24 +1298,26 @@ pub const TcpServer = struct { |
| 1266 | | 1298 | |
| 1267 | /// After this call succeeds, resources have been acquired and must | 1299 | /// After this call succeeds, resources have been acquired and must |
| 1268 | /// be released with `deinit`. | 1300 | /// be released with `deinit`. |
| 1269 | pub fn init(options: Options) TcpServer { | 1301 | pub fn init(options: Options) StreamServer { |
| 1270 | return TcpServer{ | 1302 | return StreamServer{ |
| 1271 | .sockfd = null, | 1303 | .sockfd = null, |
| 1272 | .kernel_backlog = options.kernel_backlog, | 1304 | .kernel_backlog = options.kernel_backlog, |
| 1273 | .listen_address = undefined, | 1305 | .listen_address = undefined, |
| 1274 | }; | 1306 | }; |
| 1275 | } | 1307 | } |
| 1276 | | 1308 | |
| 1277 | /// Release all resources. The `TcpServer` memory becomes `undefined`. | 1309 | /// Release all resources. The `StreamServer` memory becomes `undefined`. |
| 1278 | pub fn deinit(self: *TcpServer) void { | 1310 | pub fn deinit(self: *StreamServer) void { |
| 1279 | self.close(); | 1311 | self.close(); |
| 1280 | self.* = undefined; | 1312 | self.* = undefined; |
| 1281 | } | 1313 | } |
| 1282 | | 1314 | |
| 1283 | pub fn listen(self: *TcpServer, address: IpAddress) !void { | 1315 | pub fn listen(self: *StreamServer, address: Address) !void { |
| 1284 | const nonblock = if (std.io.is_async) os.SOCK_NONBLOCK else 0; | 1316 | const nonblock = if (std.io.is_async) os.SOCK_NONBLOCK else 0; |
| 1285 | const sock_flags = os.SOCK_STREAM | os.SOCK_CLOEXEC | nonblock; | 1317 | const sock_flags = os.SOCK_STREAM | os.SOCK_CLOEXEC | nonblock; |
| 1286 | const sockfd = try os.socket(os.AF_INET, sock_flags, os.IPPROTO_TCP); | 1318 | const proto = if (address.any.family == os.AF_UNIX) @as(u32, 0) else os.IPPROTO_TCP; |
| | 1319 | |
| | 1320 | const sockfd = try os.socket(address.any.family, sock_flags, proto); |
| 1287 | self.sockfd = sockfd; | 1321 | self.sockfd = sockfd; |
| 1288 | errdefer { | 1322 | errdefer { |
| 1289 | os.close(sockfd); | 1323 | os.close(sockfd); |
| ... | @@ -1299,7 +1333,7 @@ pub const TcpServer = struct { | ... | @@ -1299,7 +1333,7 @@ pub const TcpServer = struct { |
| 1299 | /// Stop listening. It is still necessary to call `deinit` after stopping listening. | 1333 | /// Stop listening. It is still necessary to call `deinit` after stopping listening. |
| 1300 | /// Calling `deinit` will automatically call `close`. It is safe to call `close` when | 1334 | /// Calling `deinit` will automatically call `close`. It is safe to call `close` when |
| 1301 | /// not listening. | 1335 | /// not listening. |
| 1302 | pub fn close(self: *TcpServer) void { | 1336 | pub fn close(self: *StreamServer) void { |
| 1303 | if (self.sockfd) |fd| { | 1337 | if (self.sockfd) |fd| { |
| 1304 | os.close(fd); | 1338 | os.close(fd); |
| 1305 | self.sockfd = null; | 1339 | self.sockfd = null; |
| ... | @@ -1327,11 +1361,11 @@ pub const TcpServer = struct { | ... | @@ -1327,11 +1361,11 @@ pub const TcpServer = struct { |
| 1327 | } || os.UnexpectedError; | 1361 | } || os.UnexpectedError; |
| 1328 | | 1362 | |
| 1329 | /// If this function succeeds, the returned `fs.File` is a caller-managed resource. | 1363 | /// If this function succeeds, the returned `fs.File` is a caller-managed resource. |
| 1330 | pub fn accept(self: *TcpServer) AcceptError!fs.File { | 1364 | pub fn accept(self: *StreamServer) AcceptError!fs.File { |
| 1331 | const nonblock = if (std.io.is_async) os.SOCK_NONBLOCK else 0; | 1365 | const nonblock = if (std.io.is_async) os.SOCK_NONBLOCK else 0; |
| 1332 | const accept_flags = nonblock | os.SOCK_CLOEXEC; | 1366 | const accept_flags = nonblock | os.SOCK_CLOEXEC; |
| 1333 | var accepted_addr: IpAddress = undefined; | 1367 | var accepted_addr: Address = undefined; |
| 1334 | var adr_len: os.socklen_t = @sizeOf(IpAddress); | 1368 | var adr_len: os.socklen_t = @sizeOf(Address); |
| 1335 | if (os.accept4(self.sockfd.?, &accepted_addr.any, &adr_len, accept_flags)) |fd| { | 1369 | if (os.accept4(self.sockfd.?, &accepted_addr.any, &adr_len, accept_flags)) |fd| { |
| 1336 | return fs.File.openHandle(fd); | 1370 | return fs.File.openHandle(fd); |
| 1337 | } else |err| switch (err) { | 1371 | } else |err| switch (err) { |