authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2025-10-22 13:21:13-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2025-10-29 06:20:51-07:00
logdf84dc18bc2fa18770591be4d1e0cabc8d4b28c2
tree2be3888eb740771dc39593a07b032512a3ecab86
parentd6b0686b055070f390bc3465dbcf678bb590ecae

add bind


2 files changed, 195 insertions(+), 24 deletions(-)

lib/std/Io/Kqueue.zig+187-16
...@@ -9,6 +9,9 @@ const net = std.Io.net;...@@ -9,6 +9,9 @@ const net = std.Io.net;
9const assert = std.debug.assert;9const assert = std.debug.assert;
10const Allocator = std.mem.Allocator;10const Allocator = std.mem.Allocator;
11const Alignment = std.mem.Alignment;11const Alignment = std.mem.Alignment;
12const posix = std.posix;
13const IpAddress = std.Io.net.IpAddress;
14const errnoBug = std.Io.Threaded.errnoBug;
1215
13/// Must be a thread-safe allocator.16/// Must be a thread-safe allocator.
14gpa: Allocator,17gpa: Allocator,
...@@ -97,14 +100,10 @@ fn async(...@@ -97,14 +100,10 @@ fn async(
97 context_alignment: std.mem.Alignment,100 context_alignment: std.mem.Alignment,
98 start: *const fn (context: *const anyopaque, result: *anyopaque) void,101 start: *const fn (context: *const anyopaque, result: *anyopaque) void,
99) ?*Io.AnyFuture {102) ?*Io.AnyFuture {
100 const k: *Kqueue = @ptrCast(@alignCast(userdata));103 return concurrent(userdata, result.len, result_alignment, context, context_alignment, start) catch {
101 _ = k;104 start(context.ptr, result.ptr);
102 _ = result;105 return null;
103 _ = result_alignment;106 };
104 _ = context;
105 _ = context_alignment;
106 _ = start;
107 @panic("TODO");
108}107}
109108
110fn concurrent(109fn concurrent(
...@@ -156,7 +155,7 @@ fn cancel(...@@ -156,7 +155,7 @@ fn cancel(
156fn cancelRequested(userdata: ?*anyopaque) bool {155fn cancelRequested(userdata: ?*anyopaque) bool {
157 const k: *Kqueue = @ptrCast(@alignCast(userdata));156 const k: *Kqueue = @ptrCast(@alignCast(userdata));
158 _ = k;157 _ = k;
159 @panic("TODO");158 return false; // TODO
160}159}
161160
162fn groupAsync(161fn groupAsync(
...@@ -419,12 +418,23 @@ fn netAccept(userdata: ?*anyopaque, server: net.Socket.Handle) net.Server.Accept...@@ -419,12 +418,23 @@ fn netAccept(userdata: ?*anyopaque, server: net.Socket.Handle) net.Server.Accept
419 _ = server;418 _ = server;
420 @panic("TODO");419 @panic("TODO");
421}420}
422fn netBindIp(userdata: ?*anyopaque, address: *const net.IpAddress, options: net.IpAddress.BindOptions) net.IpAddress.BindError!net.Socket {421fn netBindIp(
423 const k: *Kqueue = @ptrCast(@alignCast(userdata));422 userdata: ?*anyopaque,
424 _ = k;423 address: *const net.IpAddress,
425 _ = address;424 options: net.IpAddress.BindOptions,
426 _ = options;425) net.IpAddress.BindError!net.Socket {
427 @panic("TODO");426 const k: *Kqueue = @ptrCast(@alignCast(userdata));
427 const family = Io.Threaded.posixAddressFamily(address);
428 const socket_fd = try openSocketPosix(k, family, options);
429 errdefer posix.close(socket_fd);
430 var storage: Io.Threaded.PosixAddress = undefined;
431 var addr_len = Io.Threaded.addressToPosix(address, &storage);
432 try posixBind(k, socket_fd, &storage.any, addr_len);
433 try posixGetSockName(k, socket_fd, &storage.any, &addr_len);
434 return .{
435 .handle = socket_fd,
436 .address = Io.Threaded.addressFromPosix(&storage),
437 };
428}438}
429fn netConnectIp(userdata: ?*anyopaque, address: *const net.IpAddress, options: net.IpAddress.ConnectOptions) net.IpAddress.ConnectError!net.Stream {439fn netConnectIp(userdata: ?*anyopaque, address: *const net.IpAddress, options: net.IpAddress.ConnectOptions) net.IpAddress.ConnectError!net.Stream {
430 const k: *Kqueue = @ptrCast(@alignCast(userdata));440 const k: *Kqueue = @ptrCast(@alignCast(userdata));
...@@ -453,6 +463,7 @@ fn netConnectUnix(...@@ -453,6 +463,7 @@ fn netConnectUnix(
453 _ = unix_address;463 _ = unix_address;
454 @panic("TODO");464 @panic("TODO");
455}465}
466
456fn netSend(467fn netSend(
457 userdata: ?*anyopaque,468 userdata: ?*anyopaque,
458 handle: net.Socket.Handle,469 handle: net.Socket.Handle,
...@@ -460,12 +471,22 @@ fn netSend(...@@ -460,12 +471,22 @@ fn netSend(
460 flags: net.SendFlags,471 flags: net.SendFlags,
461) struct { ?net.Socket.SendError, usize } {472) struct { ?net.Socket.SendError, usize } {
462 const k: *Kqueue = @ptrCast(@alignCast(userdata));473 const k: *Kqueue = @ptrCast(@alignCast(userdata));
474
475 const posix_flags: u32 =
476 @as(u32, if (@hasDecl(posix.MSG, "CONFIRM") and flags.confirm) posix.MSG.CONFIRM else 0) |
477 @as(u32, if (@hasDecl(posix.MSG, "DONTROUTE") and flags.dont_route) posix.MSG.DONTROUTE else 0) |
478 @as(u32, if (@hasDecl(posix.MSG, "EOR") and flags.eor) posix.MSG.EOR else 0) |
479 @as(u32, if (@hasDecl(posix.MSG, "OOB") and flags.oob) posix.MSG.OOB else 0) |
480 @as(u32, if (@hasDecl(posix.MSG, "FASTOPEN") and flags.fastopen) posix.MSG.FASTOPEN else 0) |
481 posix.MSG.NOSIGNAL;
482
463 _ = k;483 _ = k;
484 _ = posix_flags;
464 _ = handle;485 _ = handle;
465 _ = outgoing_messages;486 _ = outgoing_messages;
466 _ = flags;
467 @panic("TODO");487 @panic("TODO");
468}488}
489
469fn netReceive(490fn netReceive(
470 userdata: ?*anyopaque,491 userdata: ?*anyopaque,
471 handle: net.Socket.Handle,492 handle: net.Socket.Handle,
...@@ -533,3 +554,153 @@ fn netLookup(...@@ -533,3 +554,153 @@ fn netLookup(
533 _ = options;554 _ = options;
534 @panic("TODO");555 @panic("TODO");
535}556}
557
558fn openSocketPosix(
559 k: *Kqueue,
560 family: posix.sa_family_t,
561 options: IpAddress.BindOptions,
562) error{
563 AddressFamilyUnsupported,
564 ProtocolUnsupportedBySystem,
565 ProcessFdQuotaExceeded,
566 SystemFdQuotaExceeded,
567 SystemResources,
568 ProtocolUnsupportedByAddressFamily,
569 SocketModeUnsupported,
570 OptionUnsupported,
571 Unexpected,
572 Canceled,
573}!posix.socket_t {
574 const mode = Io.Threaded.posixSocketMode(options.mode);
575 const protocol = Io.Threaded.posixProtocol(options.protocol);
576 const socket_fd = while (true) {
577 try k.checkCancel();
578 const flags: u32 = mode | if (Io.Threaded.socket_flags_unsupported) 0 else posix.SOCK.CLOEXEC;
579 const socket_rc = posix.system.socket(family, flags, protocol);
580 switch (posix.errno(socket_rc)) {
581 .SUCCESS => {
582 const fd: posix.fd_t = @intCast(socket_rc);
583 errdefer posix.close(fd);
584 if (Io.Threaded.socket_flags_unsupported) {
585 while (true) {
586 try k.checkCancel();
587 switch (posix.errno(posix.system.fcntl(fd, posix.F.SETFD, @as(usize, posix.FD_CLOEXEC)))) {
588 .SUCCESS => break,
589 .INTR => continue,
590 .CANCELED => return error.Canceled,
591 else => |err| return posix.unexpectedErrno(err),
592 }
593 }
594
595 var fl_flags: usize = while (true) {
596 try k.checkCancel();
597 const rc = posix.system.fcntl(fd, posix.F.GETFL, @as(usize, 0));
598 switch (posix.errno(rc)) {
599 .SUCCESS => break @intCast(rc),
600 .INTR => continue,
601 .CANCELED => return error.Canceled,
602 else => |err| return posix.unexpectedErrno(err),
603 }
604 };
605 fl_flags &= ~@as(usize, 1 << @bitOffsetOf(posix.O, "NONBLOCK"));
606 while (true) {
607 try k.checkCancel();
608 switch (posix.errno(posix.system.fcntl(fd, posix.F.SETFL, fl_flags))) {
609 .SUCCESS => break,
610 .INTR => continue,
611 .CANCELED => return error.Canceled,
612 else => |err| return posix.unexpectedErrno(err),
613 }
614 }
615 }
616 break fd;
617 },
618 .INTR => continue,
619 .CANCELED => return error.Canceled,
620
621 .AFNOSUPPORT => return error.AddressFamilyUnsupported,
622 .INVAL => return error.ProtocolUnsupportedBySystem,
623 .MFILE => return error.ProcessFdQuotaExceeded,
624 .NFILE => return error.SystemFdQuotaExceeded,
625 .NOBUFS => return error.SystemResources,
626 .NOMEM => return error.SystemResources,
627 .PROTONOSUPPORT => return error.ProtocolUnsupportedByAddressFamily,
628 .PROTOTYPE => return error.SocketModeUnsupported,
629 else => |err| return posix.unexpectedErrno(err),
630 }
631 };
632 errdefer posix.close(socket_fd);
633
634 if (options.ip6_only) {
635 if (posix.IPV6 == void) return error.OptionUnsupported;
636 try setSocketOption(k, socket_fd, posix.IPPROTO.IPV6, posix.IPV6.V6ONLY, 0);
637 }
638
639 return socket_fd;
640}
641
642fn posixBind(
643 k: *Kqueue,
644 socket_fd: posix.socket_t,
645 addr: *const posix.sockaddr,
646 addr_len: posix.socklen_t,
647) !void {
648 while (true) {
649 try k.checkCancel();
650 switch (posix.errno(posix.system.bind(socket_fd, addr, addr_len))) {
651 .SUCCESS => break,
652 .INTR => continue,
653 .CANCELED => return error.Canceled,
654
655 .ADDRINUSE => return error.AddressInUse,
656 .BADF => |err| return errnoBug(err), // File descriptor used after closed.
657 .INVAL => |err| return errnoBug(err), // invalid parameters
658 .NOTSOCK => |err| return errnoBug(err), // invalid `sockfd`
659 .AFNOSUPPORT => return error.AddressFamilyUnsupported,
660 .ADDRNOTAVAIL => return error.AddressUnavailable,
661 .FAULT => |err| return errnoBug(err), // invalid `addr` pointer
662 .NOMEM => return error.SystemResources,
663 else => |err| return posix.unexpectedErrno(err),
664 }
665 }
666}
667
668fn posixGetSockName(k: *Kqueue, socket_fd: posix.fd_t, addr: *posix.sockaddr, addr_len: *posix.socklen_t) !void {
669 while (true) {
670 try k.checkCancel();
671 switch (posix.errno(posix.system.getsockname(socket_fd, addr, addr_len))) {
672 .SUCCESS => break,
673 .INTR => continue,
674 .CANCELED => return error.Canceled,
675
676 .BADF => |err| return errnoBug(err), // File descriptor used after closed.
677 .FAULT => |err| return errnoBug(err),
678 .INVAL => |err| return errnoBug(err), // invalid parameters
679 .NOTSOCK => |err| return errnoBug(err), // always a race condition
680 .NOBUFS => return error.SystemResources,
681 else => |err| return posix.unexpectedErrno(err),
682 }
683 }
684}
685
686fn setSocketOption(k: *Kqueue, fd: posix.fd_t, level: i32, opt_name: u32, option: u32) !void {
687 const o: []const u8 = @ptrCast(&option);
688 while (true) {
689 try k.checkCancel();
690 switch (posix.errno(posix.system.setsockopt(fd, level, opt_name, o.ptr, @intCast(o.len)))) {
691 .SUCCESS => return,
692 .INTR => continue,
693 .CANCELED => return error.Canceled,
694
695 .BADF => |err| return errnoBug(err), // File descriptor used after closed.
696 .NOTSOCK => |err| return errnoBug(err),
697 .INVAL => |err| return errnoBug(err),
698 .FAULT => |err| return errnoBug(err),
699 else => |err| return posix.unexpectedErrno(err),
700 }
701 }
702}
703
704fn checkCancel(k: *Kqueue) error{Canceled}!void {
705 if (cancelRequested(k)) return error.Canceled;
706}
lib/std/Io/Threaded.zig+8-8
...@@ -285,7 +285,7 @@ pub fn io(t: *Threaded) Io {...@@ -285,7 +285,7 @@ pub fn io(t: *Threaded) Io {
285 };285 };
286}286}
287287
288const socket_flags_unsupported = builtin.os.tag.isDarwin() or native_os == .haiku; // 💩💩288pub const socket_flags_unsupported = builtin.os.tag.isDarwin() or native_os == .haiku; // 💩💩
289const have_accept4 = !socket_flags_unsupported;289const have_accept4 = !socket_flags_unsupported;
290const have_flock_open_flags = @hasField(posix.O, "EXLOCK");290const have_flock_open_flags = @hasField(posix.O, "EXLOCK");
291const have_networking = builtin.os.tag != .wasi;291const have_networking = builtin.os.tag != .wasi;
...@@ -4283,7 +4283,7 @@ fn netLookupFallible(...@@ -4283,7 +4283,7 @@ fn netLookupFallible(
4283 return error.OptionUnsupported;4283 return error.OptionUnsupported;
4284}4284}
42854285
4286const PosixAddress = extern union {4286pub const PosixAddress = extern union {
4287 any: posix.sockaddr,4287 any: posix.sockaddr,
4288 in: posix.sockaddr.in,4288 in: posix.sockaddr.in,
4289 in6: posix.sockaddr.in6,4289 in6: posix.sockaddr.in6,
...@@ -4301,14 +4301,14 @@ const WsaAddress = extern union {...@@ -4301,14 +4301,14 @@ const WsaAddress = extern union {
4301 un: ws2_32.sockaddr.un,4301 un: ws2_32.sockaddr.un,
4302};4302};
43034303
4304fn posixAddressFamily(a: *const IpAddress) posix.sa_family_t {4304pub fn posixAddressFamily(a: *const IpAddress) posix.sa_family_t {
4305 return switch (a.*) {4305 return switch (a.*) {
4306 .ip4 => posix.AF.INET,4306 .ip4 => posix.AF.INET,
4307 .ip6 => posix.AF.INET6,4307 .ip6 => posix.AF.INET6,
4308 };4308 };
4309}4309}
43104310
4311fn addressFromPosix(posix_address: *const PosixAddress) IpAddress {4311pub fn addressFromPosix(posix_address: *const PosixAddress) IpAddress {
4312 return switch (posix_address.any.family) {4312 return switch (posix_address.any.family) {
4313 posix.AF.INET => .{ .ip4 = address4FromPosix(&posix_address.in) },4313 posix.AF.INET => .{ .ip4 = address4FromPosix(&posix_address.in) },
4314 posix.AF.INET6 => .{ .ip6 = address6FromPosix(&posix_address.in6) },4314 posix.AF.INET6 => .{ .ip6 = address6FromPosix(&posix_address.in6) },
...@@ -4324,7 +4324,7 @@ fn addressFromWsa(wsa_address: *const WsaAddress) IpAddress {...@@ -4324,7 +4324,7 @@ fn addressFromWsa(wsa_address: *const WsaAddress) IpAddress {
4324 };4324 };
4325}4325}
43264326
4327fn addressToPosix(a: *const IpAddress, storage: *PosixAddress) posix.socklen_t {4327pub fn addressToPosix(a: *const IpAddress, storage: *PosixAddress) posix.socklen_t {
4328 return switch (a.*) {4328 return switch (a.*) {
4329 .ip4 => |ip4| {4329 .ip4 => |ip4| {
4330 storage.in = address4ToPosix(ip4);4330 storage.in = address4ToPosix(ip4);
...@@ -4405,7 +4405,7 @@ fn address6ToPosix(a: *const net.Ip6Address) posix.sockaddr.in6 {...@@ -4405,7 +4405,7 @@ fn address6ToPosix(a: *const net.Ip6Address) posix.sockaddr.in6 {
4405 };4405 };
4406}4406}
44074407
4408fn errnoBug(err: posix.E) Io.UnexpectedError {4408pub fn errnoBug(err: posix.E) Io.UnexpectedError {
4409 switch (builtin.mode) {4409 switch (builtin.mode) {
4410 .Debug => std.debug.panic("programmer bug caused syscall error: {t}", .{err}),4410 .Debug => std.debug.panic("programmer bug caused syscall error: {t}", .{err}),
4411 else => return error.Unexpected,4411 else => return error.Unexpected,
...@@ -4419,7 +4419,7 @@ fn wsaErrorBug(err: ws2_32.WinsockError) Io.UnexpectedError {...@@ -4419,7 +4419,7 @@ fn wsaErrorBug(err: ws2_32.WinsockError) Io.UnexpectedError {
4419 }4419 }
4420}4420}
44214421
4422fn posixSocketMode(mode: net.Socket.Mode) u32 {4422pub fn posixSocketMode(mode: net.Socket.Mode) u32 {
4423 return switch (mode) {4423 return switch (mode) {
4424 .stream => posix.SOCK.STREAM,4424 .stream => posix.SOCK.STREAM,
4425 .dgram => posix.SOCK.DGRAM,4425 .dgram => posix.SOCK.DGRAM,
...@@ -4429,7 +4429,7 @@ fn posixSocketMode(mode: net.Socket.Mode) u32 {...@@ -4429,7 +4429,7 @@ fn posixSocketMode(mode: net.Socket.Mode) u32 {
4429 };4429 };
4430}4430}
44314431
4432fn posixProtocol(protocol: ?net.Protocol) u32 {4432pub fn posixProtocol(protocol: ?net.Protocol) u32 {
4433 return @intFromEnum(protocol orelse return 0);4433 return @intFromEnum(protocol orelse return 0);
4434}4434}
44354435