| author | |
| committer | |
| log | 3071ba4272c2a89e892c6a48090496ec0ba46d8c |
| tree | d6e2b78d0f9bfeb0797c9188206e8284f0705d88 |
| parent | 1872c85ac25146036119387d1f376e2cba3ff7be |
| parent | c4c6c01cc5b89a2647702b6849979572dcb74eab |
| signature |
Add missing posix wrappers for socketpair() and recvmsg()2 files changed, 110 insertions(+), 2 deletions(-)
lib/std/c.zig+17-2| ... | @@ -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 | }; |
| 10601 | 10601 | ||
| 10602 | pub 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 | |||
| 10602 | pub const stat = switch (native_os) { | 10608 | pub 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; |
| 10740 | pub extern "c" fn gethostname(name: [*]u8, len: usize) c_int; | 10746 | pub extern "c" fn gethostname(name: [*]u8, len: usize) c_int; |
| 10741 | pub extern "c" fn shutdown(socket: fd_t, how: c_int) c_int; | 10747 | pub extern "c" fn shutdown(socket: fd_t, how: c_int) c_int; |
| 10742 | pub extern "c" fn bind(socket: fd_t, address: ?*const sockaddr, address_len: socklen_t) c_int; | 10748 | pub extern "c" fn bind(socket: fd_t, address: ?*const sockaddr, address_len: socklen_t) c_int; |
| 10743 | pub extern "c" fn socketpair(domain: c_uint, sock_type: c_uint, protocol: c_uint, sv: *[2]fd_t) c_int; | ||
| 10744 | pub extern "c" fn listen(sockfd: fd_t, backlog: c_uint) c_int; | 10749 | pub extern "c" fn listen(sockfd: fd_t, backlog: c_uint) c_int; |
| 10745 | pub extern "c" fn getsockname(sockfd: fd_t, noalias addr: *sockaddr, noalias addrlen: *socklen_t) c_int; | 10750 | pub extern "c" fn getsockname(sockfd: fd_t, noalias addr: *sockaddr, noalias addrlen: *socklen_t) c_int; |
| 10746 | pub extern "c" fn getpeername(sockfd: fd_t, noalias addr: *sockaddr, noalias addrlen: *socklen_t) c_int; | 10751 | pub extern "c" fn getpeername(sockfd: fd_t, noalias addr: *sockaddr, noalias addrlen: *socklen_t) c_int; |
| ... | @@ -10774,7 +10779,15 @@ pub extern "c" fn recvfrom( | ... | @@ -10774,7 +10779,15 @@ pub extern "c" fn recvfrom( |
| 10774 | noalias src_addr: ?*sockaddr, | 10779 | noalias src_addr: ?*sockaddr, |
| 10775 | noalias addrlen: ?*socklen_t, | 10780 | noalias addrlen: ?*socklen_t, |
| 10776 | ) if (native_os == .windows) c_int else isize; | 10781 | ) if (native_os == .windows) c_int else isize; |
| 10777 | pub extern "c" fn recvmsg(sockfd: fd_t, msg: *msghdr, flags: u32) isize; | 10782 | |
| 10783 | pub const recvmsg = switch (native_os) { | ||
| 10784 | // Windows: Technically, a form of recvmsg() exists for Windows, but the | ||
| 10785 | // user has to install some kind of callback for it. I'm not sure if/how | ||
| 10786 | // we can map this to normal recvmsg() interface use. | ||
| 10787 | // https://learn.microsoft.com/en-us/windows/win32/api/mswsock/nc-mswsock-lpfn_wsarecvmsg | ||
| 10788 | .windows => void, | ||
| 10789 | else => private.recvmsg, | ||
| 10790 | }; | ||
| 10778 | 10791 | ||
| 10779 | pub extern "c" fn kill(pid: pid_t, sig: c_int) c_int; | 10792 | pub extern "c" fn kill(pid: pid_t, sig: c_int) c_int; |
| 10780 | 10793 | ||
| ... | @@ -11419,6 +11432,7 @@ const private = struct { | ... | @@ -11419,6 +11432,7 @@ const private = struct { |
| 11419 | extern "c" fn pipe2(fds: *[2]fd_t, flags: O) c_int; | 11432 | extern "c" fn pipe2(fds: *[2]fd_t, flags: O) c_int; |
| 11420 | extern "c" fn readdir(dir: *DIR) ?*dirent; | 11433 | extern "c" fn readdir(dir: *DIR) ?*dirent; |
| 11421 | extern "c" fn realpath(noalias file_name: [*:0]const u8, noalias resolved_name: [*]u8) ?[*:0]u8; | 11434 | extern "c" fn realpath(noalias file_name: [*:0]const u8, noalias resolved_name: [*]u8) ?[*:0]u8; |
| 11435 | extern "c" fn recvmsg(sockfd: fd_t, msg: *msghdr, flags: u32) isize; | ||
| 11422 | extern "c" fn sched_yield() c_int; | 11436 | extern "c" fn sched_yield() c_int; |
| 11423 | extern "c" fn sendfile(out_fd: fd_t, in_fd: fd_t, offset: ?*off_t, count: usize) isize; | 11437 | extern "c" fn sendfile(out_fd: fd_t, in_fd: fd_t, offset: ?*off_t, count: usize) isize; |
| 11424 | extern "c" fn sigaction(sig: c_int, noalias act: ?*const Sigaction, noalias oact: ?*Sigaction) c_int; | 11438 | extern "c" fn sigaction(sig: c_int, noalias act: ?*const Sigaction, noalias oact: ?*Sigaction) c_int; |
| ... | @@ -11429,6 +11443,7 @@ const private = struct { | ... | @@ -11429,6 +11443,7 @@ const private = struct { |
| 11429 | extern "c" fn sigismember(set: ?*const sigset_t, signo: c_int) c_int; | 11443 | 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; | 11444 | 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; | 11445 | extern "c" fn socket(domain: c_uint, sock_type: c_uint, protocol: c_uint) c_int; |
| 11446 | 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; | 11447 | 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; | 11448 | extern "c" fn sigaltstack(ss: ?*stack_t, old_ss: ?*stack_t) c_int; |
| 11434 | extern "c" fn sysconf(sc: c_int) c_long; | 11449 | extern "c" fn sysconf(sc: c_int) c_long; |
lib/std/posix.zig+93| ... | @@ -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 | } |
| 3673 | 3673 | ||
| 3674 | pub 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 | |||
| 3674 | pub const ShutdownError = error{ | 3714 | pub const ShutdownError = error{ |
| 3675 | ConnectionAborted, | 3715 | ConnectionAborted, |
| 3676 | 3716 | ||
| ... | @@ -6604,6 +6644,9 @@ pub const RecvFromError = error{ | ... | @@ -6604,6 +6644,9 @@ pub const RecvFromError = error{ |
| 6604 | 6644 | ||
| 6605 | /// The socket is not connected (connection-oriented sockets only). | 6645 | /// The socket is not connected (connection-oriented sockets only). |
| 6606 | SocketNotConnected, | 6646 | SocketNotConnected, |
| 6647 | |||
| 6648 | /// The other end closed the socket unexpectedly or a read is executed on a shut down socket | ||
| 6649 | BrokenPipe, | ||
| 6607 | } || UnexpectedError; | 6650 | } || UnexpectedError; |
| 6608 | 6651 | ||
| 6609 | pub fn recv(sock: socket_t, buf: []u8, flags: u32) RecvFromError!usize { | 6652 | pub fn recv(sock: socket_t, buf: []u8, flags: u32) RecvFromError!usize { |
| ... | @@ -6652,12 +6695,62 @@ pub fn recvfrom( | ... | @@ -6652,12 +6695,62 @@ pub fn recvfrom( |
| 6652 | .CONNREFUSED => return error.ConnectionRefused, | 6695 | .CONNREFUSED => return error.ConnectionRefused, |
| 6653 | .CONNRESET => return error.ConnectionResetByPeer, | 6696 | .CONNRESET => return error.ConnectionResetByPeer, |
| 6654 | .TIMEDOUT => return error.ConnectionTimedOut, | 6697 | .TIMEDOUT => return error.ConnectionTimedOut, |
| 6698 | .PIPE => return error.BrokenPipe, | ||
| 6655 | else => |err| return unexpectedErrno(err), | 6699 | else => |err| return unexpectedErrno(err), |
| 6656 | } | 6700 | } |
| 6657 | } | 6701 | } |
| 6658 | } | 6702 | } |
| 6659 | } | 6703 | } |
| 6660 | 6704 | ||
| 6705 | pub const RecvMsgError = RecvFromError || error{ | ||
| 6706 | /// Reception of SCM_RIGHTS fds via ancillary data in msg.control would | ||
| 6707 | /// exceed some system limit (generally this is retryable by trying to | ||
| 6708 | /// receive fewer fds or closing some existing fds) | ||
| 6709 | SystemFdQuotaExceeded, | ||
| 6710 | |||
| 6711 | /// Reception of SCM_RIGHTS fds via ancillary data in msg.control would | ||
| 6712 | /// exceed some process limit (generally this is retryable by trying to | ||
| 6713 | /// receive fewer fds, closing some existing fds, or changing the ulimit) | ||
| 6714 | ProcessFdQuotaExceeded, | ||
| 6715 | }; | ||
| 6716 | |||
| 6717 | /// If `sockfd` is opened in non blocking mode, the function will | ||
| 6718 | /// return error.WouldBlock when EAGAIN is received. | ||
| 6719 | pub fn recvmsg( | ||
| 6720 | /// The file descriptor of the sending socket. | ||
| 6721 | sockfd: socket_t, | ||
| 6722 | /// Message header and iovecs | ||
| 6723 | msg: *msghdr, | ||
| 6724 | flags: u32, | ||
| 6725 | ) RecvMsgError!usize { | ||
| 6726 | if (@TypeOf(system.recvmsg) == void) | ||
| 6727 | @compileError("recvmsg() not supported on this OS"); | ||
| 6728 | while (true) { | ||
| 6729 | const rc = system.recvmsg(sockfd, msg, flags); | ||
| 6730 | switch (errno(rc)) { | ||
| 6731 | .SUCCESS => return @intCast(rc), | ||
| 6732 | .AGAIN => return error.WouldBlock, | ||
| 6733 | .BADF => unreachable, // always a race condition | ||
| 6734 | .NFILE => return error.SystemFdQuotaExceeded, | ||
| 6735 | .MFILE => return error.ProcessFdQuotaExceeded, | ||
| 6736 | .INTR => continue, | ||
| 6737 | .FAULT => unreachable, // An invalid user space address was specified for an argument. | ||
| 6738 | .INVAL => unreachable, // Invalid argument passed. | ||
| 6739 | .ISCONN => unreachable, // connection-mode socket was connected already but a recipient was specified | ||
| 6740 | .NOBUFS => return error.SystemResources, | ||
| 6741 | .NOMEM => return error.SystemResources, | ||
| 6742 | .NOTCONN => return error.SocketNotConnected, | ||
| 6743 | .NOTSOCK => unreachable, // The file descriptor sockfd does not refer to a socket. | ||
| 6744 | .MSGSIZE => return error.MessageTooBig, | ||
| 6745 | .PIPE => return error.BrokenPipe, | ||
| 6746 | .OPNOTSUPP => unreachable, // Some bit in the flags argument is inappropriate for the socket type. | ||
| 6747 | .CONNRESET => return error.ConnectionResetByPeer, | ||
| 6748 | .NETDOWN => return error.NetworkSubsystemFailed, | ||
| 6749 | else => |err| return unexpectedErrno(err), | ||
| 6750 | } | ||
| 6751 | } | ||
| 6752 | } | ||
| 6753 | |||
| 6661 | pub const DnExpandError = error{InvalidDnsPacket}; | 6754 | pub const DnExpandError = error{InvalidDnsPacket}; |
| 6662 | 6755 | ||
| 6663 | pub fn dn_expand( | 6756 | pub fn dn_expand( |