authorgravatar for bblack@wikimedia.orgBrandon Black <bblack@wikimedia.org> 2025-09-08 13:33:00-05:00
committergravatar for bblack@wikimedia.orgBrandon Black <bblack@wikimedia.org> 2025-09-08 14:45:51-05:00
log79313d844f96f9f661cd2621a33890cefa8fb859
treeb215bc2e0e3e5d8dfe3c5270186f3858a9d77079
parent05cff8a558fda0e974ea7d00f26f8f4ff6e1195f

socketpair: posix wrapper, void on windows

socketpair is something like a pipe2() for sockets, and generally only works for AF_UNIX sockets for most platforms. Winsock2 explicitly does not support this call, even though it does have AF_UNIX sockets.

2 files changed, 47 insertions(+), 1 deletions(-)

lib/std/c.zig+7-1
...@@ -10599,6 +10599,12 @@ pub const socket = switch (native_os) {...@@ -10599,6 +10599,12 @@ pub const socket = switch (native_os) {
10599 else => private.socket,10599 else => private.socket,
10600};10600};
1060110601
10602pub const socketpair = switch (native_os) {
10603 // https://devblogs.microsoft.com/commandline/af_unix-comes-to-windows/#unsupported\unavailable:
10604 .windows => void,
10605 else => private.socketpair,
10606};
10607
10602pub const stat = switch (native_os) {10608pub const stat = switch (native_os) {
10603 .macos => switch (native_arch) {10609 .macos => switch (native_arch) {
10604 .x86_64 => private.@"stat$INODE64",10610 .x86_64 => private.@"stat$INODE64",
...@@ -10740,7 +10746,6 @@ pub extern "c" fn uname(buf: *utsname) c_int;...@@ -10740,7 +10746,6 @@ pub extern "c" fn uname(buf: *utsname) c_int;
10740pub extern "c" fn gethostname(name: [*]u8, len: usize) c_int;10746pub extern "c" fn gethostname(name: [*]u8, len: usize) c_int;
10741pub extern "c" fn shutdown(socket: fd_t, how: c_int) c_int;10747pub extern "c" fn shutdown(socket: fd_t, how: c_int) c_int;
10742pub extern "c" fn bind(socket: fd_t, address: ?*const sockaddr, address_len: socklen_t) c_int;10748pub extern "c" fn bind(socket: fd_t, address: ?*const sockaddr, address_len: socklen_t) c_int;
10743pub extern "c" fn socketpair(domain: c_uint, sock_type: c_uint, protocol: c_uint, sv: *[2]fd_t) c_int;
10744pub extern "c" fn listen(sockfd: fd_t, backlog: c_uint) c_int;10749pub extern "c" fn listen(sockfd: fd_t, backlog: c_uint) c_int;
10745pub extern "c" fn getsockname(sockfd: fd_t, noalias addr: *sockaddr, noalias addrlen: *socklen_t) c_int;10750pub extern "c" fn getsockname(sockfd: fd_t, noalias addr: *sockaddr, noalias addrlen: *socklen_t) c_int;
10746pub extern "c" fn getpeername(sockfd: fd_t, noalias addr: *sockaddr, noalias addrlen: *socklen_t) c_int;10751pub extern "c" fn getpeername(sockfd: fd_t, noalias addr: *sockaddr, noalias addrlen: *socklen_t) c_int;
...@@ -11429,6 +11434,7 @@ const private = struct {...@@ -11429,6 +11434,7 @@ const private = struct {
11429 extern "c" fn sigismember(set: ?*const sigset_t, signo: c_int) c_int;11434 extern "c" fn sigismember(set: ?*const sigset_t, signo: c_int) c_int;
11430 extern "c" fn sigprocmask(how: c_int, noalias set: ?*const sigset_t, noalias oset: ?*sigset_t) c_int;11435 extern "c" fn sigprocmask(how: c_int, noalias set: ?*const sigset_t, noalias oset: ?*sigset_t) c_int;
11431 extern "c" fn socket(domain: c_uint, sock_type: c_uint, protocol: c_uint) c_int;11436 extern "c" fn socket(domain: c_uint, sock_type: c_uint, protocol: c_uint) c_int;
11437 extern "c" fn socketpair(domain: c_uint, sock_type: c_uint, protocol: c_uint, sv: *[2]fd_t) c_int;
11432 extern "c" fn stat(noalias path: [*:0]const u8, noalias buf: *Stat) c_int;11438 extern "c" fn stat(noalias path: [*:0]const u8, noalias buf: *Stat) c_int;
11433 extern "c" fn sigaltstack(ss: ?*stack_t, old_ss: ?*stack_t) c_int;11439 extern "c" fn sigaltstack(ss: ?*stack_t, old_ss: ?*stack_t) c_int;
11434 extern "c" fn sysconf(sc: c_int) c_long;11440 extern "c" fn sysconf(sc: c_int) c_long;
lib/std/posix.zig+40
...@@ -3671,6 +3671,46 @@ pub fn socket(domain: u32, socket_type: u32, protocol: u32) SocketError!socket_t...@@ -3671,6 +3671,46 @@ pub fn socket(domain: u32, socket_type: u32, protocol: u32) SocketError!socket_t
3671 }3671 }
3672}3672}
36733673
3674pub fn socketpair(domain: u32, socket_type: u32, protocol: u32) SocketError![2]socket_t {
3675 // Note to the future: we could provide a shim here for e.g. windows which
3676 // creates a listening socket, then creates a second socket and connects it
3677 // to the listening socket, and then returns the two.
3678 if (@TypeOf(system.socketpair) == void)
3679 @compileError("socketpair() not supported by this OS");
3680
3681 // I'm not really sure if haiku supports flags here. I'm following the
3682 // existing filter here from pipe2(), because it sure seems like it
3683 // supports flags there too, but haiku can be hard to understand.
3684 const have_sock_flags = !builtin.target.os.tag.isDarwin() and native_os != .haiku;
3685 const filtered_sock_type = if (!have_sock_flags)
3686 socket_type & ~@as(u32, SOCK.NONBLOCK | SOCK.CLOEXEC)
3687 else
3688 socket_type;
3689 var socks: [2]socket_t = undefined;
3690 const rc = system.socketpair(domain, filtered_sock_type, protocol, &socks);
3691 switch (errno(rc)) {
3692 .SUCCESS => {
3693 errdefer close(socks[0]);
3694 errdefer close(socks[1]);
3695 if (!have_sock_flags) {
3696 try setSockFlags(socks[0], socket_type);
3697 try setSockFlags(socks[1], socket_type);
3698 }
3699 return socks;
3700 },
3701 .ACCES => return error.AccessDenied,
3702 .AFNOSUPPORT => return error.AddressFamilyNotSupported,
3703 .INVAL => return error.ProtocolFamilyNotAvailable,
3704 .MFILE => return error.ProcessFdQuotaExceeded,
3705 .NFILE => return error.SystemFdQuotaExceeded,
3706 .NOBUFS => return error.SystemResources,
3707 .NOMEM => return error.SystemResources,
3708 .PROTONOSUPPORT => return error.ProtocolNotSupported,
3709 .PROTOTYPE => return error.SocketTypeNotSupported,
3710 else => |err| return unexpectedErrno(err),
3711 }
3712}
3713
3674pub const ShutdownError = error{3714pub const ShutdownError = error{
3675 ConnectionAborted,3715 ConnectionAborted,
36763716