zig

fork of https://codeberg.org/ziglang/zig
Log | Files | Refs | README | LICENSE

commit 79313d844f96f9f661cd2621a33890cefa8fb859 (tree)
parent 05cff8a558fda0e974ea7d00f26f8f4ff6e1195f
Author: Brandon Black <bblack@wikimedia.org>
Date:   Mon,  8 Sep 2025 13:33:00 -0500

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.

Diffstat:
Mlib/std/c.zig | 8+++++++-
Mlib/std/posix.zig | 40++++++++++++++++++++++++++++++++++++++++
2 files changed, 47 insertions(+), 1 deletion(-)

diff --git a/lib/std/c.zig b/lib/std/c.zig @@ -10599,6 +10599,12 @@ pub const socket = switch (native_os) { else => private.socket, }; +pub const socketpair = switch (native_os) { + // https://devblogs.microsoft.com/commandline/af_unix-comes-to-windows/#unsupported\unavailable: + .windows => void, + else => private.socketpair, +}; + pub const stat = switch (native_os) { .macos => switch (native_arch) { .x86_64 => private.@"stat$INODE64", @@ -10740,7 +10746,6 @@ pub extern "c" fn uname(buf: *utsname) c_int; pub extern "c" fn gethostname(name: [*]u8, len: usize) c_int; pub extern "c" fn shutdown(socket: fd_t, how: c_int) c_int; pub extern "c" fn bind(socket: fd_t, address: ?*const sockaddr, address_len: socklen_t) c_int; -pub extern "c" fn socketpair(domain: c_uint, sock_type: c_uint, protocol: c_uint, sv: *[2]fd_t) c_int; pub extern "c" fn listen(sockfd: fd_t, backlog: c_uint) c_int; pub extern "c" fn getsockname(sockfd: fd_t, noalias addr: *sockaddr, noalias addrlen: *socklen_t) c_int; pub extern "c" fn getpeername(sockfd: fd_t, noalias addr: *sockaddr, noalias addrlen: *socklen_t) c_int; @@ -11429,6 +11434,7 @@ const private = struct { extern "c" fn sigismember(set: ?*const sigset_t, signo: c_int) c_int; extern "c" fn sigprocmask(how: c_int, noalias set: ?*const sigset_t, noalias oset: ?*sigset_t) c_int; extern "c" fn socket(domain: c_uint, sock_type: c_uint, protocol: c_uint) c_int; + extern "c" fn socketpair(domain: c_uint, sock_type: c_uint, protocol: c_uint, sv: *[2]fd_t) c_int; extern "c" fn stat(noalias path: [*:0]const u8, noalias buf: *Stat) c_int; extern "c" fn sigaltstack(ss: ?*stack_t, old_ss: ?*stack_t) c_int; extern "c" fn sysconf(sc: c_int) c_long; diff --git a/lib/std/posix.zig b/lib/std/posix.zig @@ -3671,6 +3671,46 @@ pub fn socket(domain: u32, socket_type: u32, protocol: u32) SocketError!socket_t } } +pub fn socketpair(domain: u32, socket_type: u32, protocol: u32) SocketError![2]socket_t { + // Note to the future: we could provide a shim here for e.g. windows which + // creates a listening socket, then creates a second socket and connects it + // to the listening socket, and then returns the two. + if (@TypeOf(system.socketpair) == void) + @compileError("socketpair() not supported by this OS"); + + // I'm not really sure if haiku supports flags here. I'm following the + // existing filter here from pipe2(), because it sure seems like it + // supports flags there too, but haiku can be hard to understand. + const have_sock_flags = !builtin.target.os.tag.isDarwin() and native_os != .haiku; + const filtered_sock_type = if (!have_sock_flags) + socket_type & ~@as(u32, SOCK.NONBLOCK | SOCK.CLOEXEC) + else + socket_type; + var socks: [2]socket_t = undefined; + const rc = system.socketpair(domain, filtered_sock_type, protocol, &socks); + switch (errno(rc)) { + .SUCCESS => { + errdefer close(socks[0]); + errdefer close(socks[1]); + if (!have_sock_flags) { + try setSockFlags(socks[0], socket_type); + try setSockFlags(socks[1], socket_type); + } + return socks; + }, + .ACCES => return error.AccessDenied, + .AFNOSUPPORT => return error.AddressFamilyNotSupported, + .INVAL => return error.ProtocolFamilyNotAvailable, + .MFILE => return error.ProcessFdQuotaExceeded, + .NFILE => return error.SystemFdQuotaExceeded, + .NOBUFS => return error.SystemResources, + .NOMEM => return error.SystemResources, + .PROTONOSUPPORT => return error.ProtocolNotSupported, + .PROTOTYPE => return error.SocketTypeNotSupported, + else => |err| return unexpectedErrno(err), + } +} + pub const ShutdownError = error{ ConnectionAborted,