| ... | ... | @@ -10,15 +10,18 @@ test "" { |
| 10 | 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 | 16 | any: os.sockaddr, |
| 15 | 17 | in: os.sockaddr_in, |
| 16 | 18 | in6: os.sockaddr_in6, |
| 19 | un: if (has_unix_sockets) os.sockaddr_un else void, |
| 17 | 20 | |
| 18 | 21 | // TODO this crashed the compiler |
| 19 | 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 | 25 | if (parseIp4(name, port)) |ip4| return ip4 else |err| switch (err) { |
| 23 | 26 | error.Overflow, |
| 24 | 27 | error.InvalidEnd, |
| ... | ... | @@ -39,17 +42,17 @@ pub const IpAddress = extern union { |
| 39 | 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 | 46 | switch (family) { |
| 44 | 47 | os.AF_INET => return parseIp4(name, port), |
| 45 | 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 | 50 | else => unreachable, |
| 48 | 51 | } |
| 49 | 52 | } |
| 50 | 53 | |
| 51 | | pub fn parseIp6(buf: []const u8, port: u16) !IpAddress { |
| 52 | | var result = IpAddress{ |
| 54 | pub fn parseIp6(buf: []const u8, port: u16) !Address { |
| 55 | var result = Address{ |
| 53 | 56 | .in6 = os.sockaddr_in6{ |
| 54 | 57 | .scope_id = 0, |
| 55 | 58 | .port = mem.nativeToBig(u16, port), |
| ... | ... | @@ -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 { |
| 158 | | var result = IpAddress{ |
| 160 | pub fn parseIp4(buf: []const u8, port: u16) !Address { |
| 161 | var result = Address{ |
| 159 | 162 | .in = os.sockaddr_in{ |
| 160 | 163 | .port = mem.nativeToBig(u16, port), |
| 161 | 164 | .addr = undefined, |
| ... | ... | @@ -194,8 +197,8 @@ pub const IpAddress = extern union { |
| 194 | 197 | return error.Incomplete; |
| 195 | 198 | } |
| 196 | 199 | |
| 197 | | pub fn initIp4(addr: [4]u8, port: u16) IpAddress { |
| 198 | | return IpAddress{ |
| 200 | pub fn initIp4(addr: [4]u8, port: u16) Address { |
| 201 | return Address{ |
| 199 | 202 | .in = os.sockaddr_in{ |
| 200 | 203 | .port = mem.nativeToBig(u16, port), |
| 201 | 204 | .addr = @ptrCast(*align(1) const u32, &addr).*, |
| ... | ... | @@ -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 { |
| 207 | | return IpAddress{ |
| 209 | pub fn initIp6(addr: [16]u8, port: u16, flowinfo: u32, scope_id: u32) Address { |
| 210 | return Address{ |
| 208 | 211 | .in6 = os.sockaddr_in6{ |
| 209 | 212 | .addr = addr, |
| 210 | 213 | .port = mem.nativeToBig(u16, port), |
| ... | ... | @@ -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 | 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 | 238 | const big_endian_port = switch (self.any.family) { |
| 220 | 239 | os.AF_INET => self.in.port, |
| 221 | 240 | os.AF_INET6 => self.in6.port, |
| ... | ... | @@ -225,7 +244,8 @@ pub const IpAddress = extern union { |
| 225 | 244 | } |
| 226 | 245 | |
| 227 | 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 | 249 | const ptr = switch (self.any.family) { |
| 230 | 250 | os.AF_INET => &self.in.port, |
| 231 | 251 | os.AF_INET6 => &self.in6.port, |
| ... | ... | @@ -237,16 +257,16 @@ pub const IpAddress = extern union { |
| 237 | 257 | /// Asserts that `addr` is an IP address. |
| 238 | 258 | /// This function will read past the end of the pointer, with a size depending |
| 239 | 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 | 261 | switch (addr.family) { |
| 242 | | os.AF_INET => return IpAddress{ .in = @ptrCast(*const os.sockaddr_in, addr).* }, |
| 243 | | os.AF_INET6 => return IpAddress{ .in6 = @ptrCast(*const os.sockaddr_in6, addr).* }, |
| 262 | os.AF_INET => return Address{ .in = @ptrCast(*const os.sockaddr_in, addr).* }, |
| 263 | os.AF_INET6 => return Address{ .in6 = @ptrCast(*const os.sockaddr_in6, addr).* }, |
| 244 | 264 | else => unreachable, |
| 245 | 265 | } |
| 246 | 266 | } |
| 247 | 267 | |
| 248 | 268 | pub fn format( |
| 249 | | self: IpAddress, |
| 269 | self: Address, |
| 250 | 270 | comptime fmt: []const u8, |
| 251 | 271 | options: std.fmt.FormatOptions, |
| 252 | 272 | context: var, |
| ... | ... | @@ -314,20 +334,35 @@ pub const IpAddress = extern union { |
| 314 | 334 | } |
| 315 | 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 | 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 | 349 | const a_bytes = @ptrCast([*]const u8, &a.any)[0..a.getOsSockLen()]; |
| 323 | 350 | const b_bytes = @ptrCast([*]const u8, &b.any)[0..b.getOsSockLen()]; |
| 324 | 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 | 355 | switch (self.any.family) { |
| 329 | 356 | os.AF_INET => return @sizeOf(os.sockaddr_in), |
| 330 | 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 | 366 | else => unreachable, |
| 332 | 367 | } |
| 333 | 368 | } |
| ... | ... | @@ -342,23 +377,20 @@ pub fn connectUnixSocket(path: []const u8) !fs.File { |
| 342 | 377 | ); |
| 343 | 378 | errdefer os.close(sockfd); |
| 344 | 379 | |
| 345 | | var sock_addr = os.sockaddr_un{ |
| 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); |
| 380 | var addr = try std.net.Address.initUnix(path); |
| 352 | 381 | |
| 353 | | const size = @intCast(u32, @sizeOf(os.sockaddr_un) - sock_addr.path.len + path.len); |
| 354 | | try os.connect(sockfd, &sock_addr, size); |
| 382 | try os.connect( |
| 383 | sockfd, |
| 384 | &addr.any, |
| 385 | addr.getOsSockLen(), |
| 386 | ); |
| 355 | 387 | |
| 356 | 388 | return fs.File.openHandle(sockfd); |
| 357 | 389 | } |
| 358 | 390 | |
| 359 | 391 | pub const AddressList = struct { |
| 360 | 392 | arena: std.heap.ArenaAllocator, |
| 361 | | addrs: []IpAddress, |
| 393 | addrs: []Address, |
| 362 | 394 | canon_name: ?[]u8, |
| 363 | 395 | |
| 364 | 396 | fn deinit(self: *AddressList) void { |
| ... | ... | @@ -381,7 +413,7 @@ pub fn tcpConnectToHost(allocator: *mem.Allocator, name: []const u8, port: u16) |
| 381 | 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 | 417 | const nonblock = if (std.io.is_async) os.SOCK_NONBLOCK else 0; |
| 386 | 418 | const sock_flags = os.SOCK_STREAM | os.SOCK_CLOEXEC | nonblock; |
| 387 | 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 | 488 | } |
| 457 | 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 | 493 | var it: ?*os.addrinfo = res; |
| 462 | 494 | var i: usize = 0; |
| 463 | 495 | while (it) |info| : (it = info.next) { |
| 464 | 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 | 499 | if (info.canonname) |n| { |
| 468 | 500 | if (result.canon_name == null) { |
| ... | ... | @@ -485,7 +517,7 @@ pub fn getAddressList(allocator: *mem.Allocator, name: []const u8, port: u16) !* |
| 485 | 517 | |
| 486 | 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 | 521 | if (!canon.isNull()) { |
| 490 | 522 | result.canon_name = canon.toOwnedSlice(); |
| 491 | 523 | } |
| ... | ... | @@ -501,7 +533,7 @@ pub fn getAddressList(allocator: *mem.Allocator, name: []const u8, port: u16) !* |
| 501 | 533 | } |
| 502 | 534 | |
| 503 | 535 | const LookupAddr = struct { |
| 504 | | addr: IpAddress, |
| 536 | addr: Address, |
| 505 | 537 | sortkey: i32 = 0, |
| 506 | 538 | }; |
| 507 | 539 | |
| ... | ... | @@ -524,7 +556,7 @@ fn linuxLookupName( |
| 524 | 556 | if (opt_name) |name| { |
| 525 | 557 | // reject empty name and check len so it fits into temp bufs |
| 526 | 558 | try canon.replaceContents(name); |
| 527 | | if (IpAddress.parseExpectingFamily(name, family, port)) |addr| { |
| 559 | if (Address.parseExpectingFamily(name, family, port)) |addr| { |
| 528 | 560 | try addrs.append(LookupAddr{ .addr = addr }); |
| 529 | 561 | } else |name_err| if ((flags & std.c.AI_NUMERICHOST) != 0) { |
| 530 | 562 | return name_err; |
| ... | ... | @@ -751,23 +783,23 @@ fn linuxLookupNameFromNull( |
| 751 | 783 | if ((flags & std.c.AI_PASSIVE) != 0) { |
| 752 | 784 | if (family != os.AF_INET6) { |
| 753 | 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 | 789 | if (family != os.AF_INET) { |
| 758 | 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 | 794 | } else { |
| 763 | 795 | if (family != os.AF_INET6) { |
| 764 | 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 | 800 | if (family != os.AF_INET) { |
| 769 | 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 | 844 | } |
| 813 | 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 | 848 | error.Overflow, |
| 817 | 849 | error.InvalidEnd, |
| 818 | 850 | error.InvalidCharacter, |
| ... | ... | @@ -1033,7 +1065,7 @@ fn linuxLookupNameFromNumericUnspec( |
| 1033 | 1065 | name: []const u8, |
| 1034 | 1066 | port: u16, |
| 1035 | 1067 | ) !void { |
| 1036 | | const addr = try IpAddress.parse(name, port); |
| 1068 | const addr = try Address.parseIp(name, port); |
| 1037 | 1069 | (try addrs.addOne()).* = LookupAddr{ .addr = addr }; |
| 1038 | 1070 | } |
| 1039 | 1071 | |
| ... | ... | @@ -1049,7 +1081,7 @@ fn resMSendRc( |
| 1049 | 1081 | var sl: os.socklen_t = @sizeOf(os.sockaddr_in); |
| 1050 | 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 | 1085 | defer ns_list.deinit(); |
| 1054 | 1086 | |
| 1055 | 1087 | try ns_list.resize(rc.ns.len); |
| ... | ... | @@ -1065,8 +1097,8 @@ fn resMSendRc( |
| 1065 | 1097 | } |
| 1066 | 1098 | |
| 1067 | 1099 | // Get local address and open/bind a socket |
| 1068 | | var sa: IpAddress = undefined; |
| 1069 | | @memset(@ptrCast([*]u8, &sa), 0, @sizeOf(IpAddress)); |
| 1100 | var sa: Address = undefined; |
| 1101 | @memset(@ptrCast([*]u8, &sa), 0, @sizeOf(Address)); |
| 1070 | 1102 | sa.any.family = family; |
| 1071 | 1103 | const flags = os.SOCK_DGRAM | os.SOCK_CLOEXEC | os.SOCK_NONBLOCK; |
| 1072 | 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 | 1256 | const new_addr = try ctx.addrs.addOne(); |
| 1225 | 1257 | new_addr.* = LookupAddr{ |
| 1226 | 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 | 1262 | os.RR_AAAA => { |
| ... | ... | @@ -1232,7 +1264,7 @@ fn dnsParseCallback(ctx: dpc_ctx, rr: u8, data: []const u8, packet: []const u8) |
| 1232 | 1264 | const new_addr = try ctx.addrs.addOne(); |
| 1233 | 1265 | new_addr.* = LookupAddr{ |
| 1234 | 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 | 1270 | os.RR_CNAME => { |
| ... | ... | @@ -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 | 1284 | /// Copied from `Options` on `init`. |
| 1253 | 1285 | kernel_backlog: u32, |
| 1254 | 1286 | |
| 1255 | 1287 | /// `undefined` until `listen` returns successfully. |
| 1256 | | listen_address: IpAddress, |
| 1288 | listen_address: Address, |
| 1257 | 1289 | |
| 1258 | 1290 | sockfd: ?os.fd_t, |
| 1259 | 1291 | |
| ... | ... | @@ -1266,24 +1298,26 @@ pub const TcpServer = struct { |
| 1266 | 1298 | |
| 1267 | 1299 | /// After this call succeeds, resources have been acquired and must |
| 1268 | 1300 | /// be released with `deinit`. |
| 1269 | | pub fn init(options: Options) TcpServer { |
| 1270 | | return TcpServer{ |
| 1301 | pub fn init(options: Options) StreamServer { |
| 1302 | return StreamServer{ |
| 1271 | 1303 | .sockfd = null, |
| 1272 | 1304 | .kernel_backlog = options.kernel_backlog, |
| 1273 | 1305 | .listen_address = undefined, |
| 1274 | 1306 | }; |
| 1275 | 1307 | } |
| 1276 | 1308 | |
| 1277 | | /// Release all resources. The `TcpServer` memory becomes `undefined`. |
| 1278 | | pub fn deinit(self: *TcpServer) void { |
| 1309 | /// Release all resources. The `StreamServer` memory becomes `undefined`. |
| 1310 | pub fn deinit(self: *StreamServer) void { |
| 1279 | 1311 | self.close(); |
| 1280 | 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 | 1316 | const nonblock = if (std.io.is_async) os.SOCK_NONBLOCK else 0; |
| 1285 | 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 | 1321 | self.sockfd = sockfd; |
| 1288 | 1322 | errdefer { |
| 1289 | 1323 | os.close(sockfd); |
| ... | ... | @@ -1299,7 +1333,7 @@ pub const TcpServer = struct { |
| 1299 | 1333 | /// Stop listening. It is still necessary to call `deinit` after stopping listening. |
| 1300 | 1334 | /// Calling `deinit` will automatically call `close`. It is safe to call `close` when |
| 1301 | 1335 | /// not listening. |
| 1302 | | pub fn close(self: *TcpServer) void { |
| 1336 | pub fn close(self: *StreamServer) void { |
| 1303 | 1337 | if (self.sockfd) |fd| { |
| 1304 | 1338 | os.close(fd); |
| 1305 | 1339 | self.sockfd = null; |
| ... | ... | @@ -1327,11 +1361,11 @@ pub const TcpServer = struct { |
| 1327 | 1361 | } || os.UnexpectedError; |
| 1328 | 1362 | |
| 1329 | 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 | 1365 | const nonblock = if (std.io.is_async) os.SOCK_NONBLOCK else 0; |
| 1332 | 1366 | const accept_flags = nonblock | os.SOCK_CLOEXEC; |
| 1333 | | var accepted_addr: IpAddress = undefined; |
| 1334 | | var adr_len: os.socklen_t = @sizeOf(IpAddress); |
| 1367 | var accepted_addr: Address = undefined; |
| 1368 | var adr_len: os.socklen_t = @sizeOf(Address); |
| 1335 | 1369 | if (os.accept4(self.sockfd.?, &accepted_addr.any, &adr_len, accept_flags)) |fd| { |
| 1336 | 1370 | return fs.File.openHandle(fd); |
| 1337 | 1371 | } else |err| switch (err) { |