authorgravatar for bblack@wikimedia.orgBrandon Black <bblack@wikimedia.org> 2025-09-08 14:30:13-05:00
committergravatar for bblack@wikimedia.orgBrandon Black <bblack@wikimedia.org> 2025-09-08 14:45:51-05:00
logc4c6c01cc5b89a2647702b6849979572dcb74eab
treea23fa7f794548676a520053dd356bf637ce4075d
parent79313d844f96f9f661cd2621a33890cefa8fb859

recvmsg: posix wrapper, void on windows

Also, added EPIPE to recvfrom() error set (it's a documented error for unix and tcp sockets, at least), which recvmsg() largely shares. Windows has an odd, callback-based form of recvmsg() that doesn't fit the normal interface here.

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

lib/std/c.zig+10-1
...@@ -10779,7 +10779,15 @@ pub extern "c" fn recvfrom(...@@ -10779,7 +10779,15 @@ pub extern "c" fn recvfrom(
10779 noalias src_addr: ?*sockaddr,10779 noalias src_addr: ?*sockaddr,
10780 noalias addrlen: ?*socklen_t,10780 noalias addrlen: ?*socklen_t,
10781) if (native_os == .windows) c_int else isize;10781) if (native_os == .windows) c_int else isize;
10782pub extern "c" fn recvmsg(sockfd: fd_t, msg: *msghdr, flags: u32) isize;10782
10783pub 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};
1078310791
10784pub extern "c" fn kill(pid: pid_t, sig: c_int) c_int;10792pub extern "c" fn kill(pid: pid_t, sig: c_int) c_int;
1078510793
...@@ -11424,6 +11432,7 @@ const private = struct {...@@ -11424,6 +11432,7 @@ const private = struct {
11424 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;
11425 extern "c" fn readdir(dir: *DIR) ?*dirent;11433 extern "c" fn readdir(dir: *DIR) ?*dirent;
11426 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;
11427 extern "c" fn sched_yield() c_int;11436 extern "c" fn sched_yield() c_int;
11428 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;
11429 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;
lib/std/posix.zig+53
...@@ -6644,6 +6644,9 @@ pub const RecvFromError = error{...@@ -6644,6 +6644,9 @@ pub const RecvFromError = error{
66446644
6645 /// The socket is not connected (connection-oriented sockets only).6645 /// The socket is not connected (connection-oriented sockets only).
6646 SocketNotConnected,6646 SocketNotConnected,
6647
6648 /// The other end closed the socket unexpectedly or a read is executed on a shut down socket
6649 BrokenPipe,
6647} || UnexpectedError;6650} || UnexpectedError;
66486651
6649pub fn recv(sock: socket_t, buf: []u8, flags: u32) RecvFromError!usize {6652pub fn recv(sock: socket_t, buf: []u8, flags: u32) RecvFromError!usize {
...@@ -6692,12 +6695,62 @@ pub fn recvfrom(...@@ -6692,12 +6695,62 @@ pub fn recvfrom(
6692 .CONNREFUSED => return error.ConnectionRefused,6695 .CONNREFUSED => return error.ConnectionRefused,
6693 .CONNRESET => return error.ConnectionResetByPeer,6696 .CONNRESET => return error.ConnectionResetByPeer,
6694 .TIMEDOUT => return error.ConnectionTimedOut,6697 .TIMEDOUT => return error.ConnectionTimedOut,
6698 .PIPE => return error.BrokenPipe,
6695 else => |err| return unexpectedErrno(err),6699 else => |err| return unexpectedErrno(err),
6696 }6700 }
6697 }6701 }
6698 }6702 }
6699}6703}
67006704
6705pub 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.
6719pub 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
6701pub const DnExpandError = error{InvalidDnsPacket};6754pub const DnExpandError = error{InvalidDnsPacket};
67026755
6703pub fn dn_expand(6756pub fn dn_expand(