mirror of
https://codeberg.org/ziglang/zig.git
synced 2025-12-06 13:54:21 +00:00
Merge pull request #25190 from blblack/netcalls
Add missing posix wrappers for socketpair() and recvmsg()
This commit is contained in:
commit
3071ba4272
2 changed files with 110 additions and 2 deletions
|
|
@ -10599,6 +10599,12 @@ pub const socket = switch (native_os) {
|
||||||
else => private.socket,
|
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) {
|
pub const stat = switch (native_os) {
|
||||||
.macos => switch (native_arch) {
|
.macos => switch (native_arch) {
|
||||||
.x86_64 => private.@"stat$INODE64",
|
.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 gethostname(name: [*]u8, len: usize) c_int;
|
||||||
pub extern "c" fn shutdown(socket: fd_t, how: c_int) 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 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 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 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;
|
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(
|
||||||
noalias src_addr: ?*sockaddr,
|
noalias src_addr: ?*sockaddr,
|
||||||
noalias addrlen: ?*socklen_t,
|
noalias addrlen: ?*socklen_t,
|
||||||
) if (native_os == .windows) c_int else isize;
|
) if (native_os == .windows) c_int else isize;
|
||||||
pub extern "c" fn recvmsg(sockfd: fd_t, msg: *msghdr, flags: u32) isize;
|
|
||||||
|
pub const recvmsg = switch (native_os) {
|
||||||
|
// Windows: Technically, a form of recvmsg() exists for Windows, but the
|
||||||
|
// user has to install some kind of callback for it. I'm not sure if/how
|
||||||
|
// we can map this to normal recvmsg() interface use.
|
||||||
|
// https://learn.microsoft.com/en-us/windows/win32/api/mswsock/nc-mswsock-lpfn_wsarecvmsg
|
||||||
|
.windows => void,
|
||||||
|
else => private.recvmsg,
|
||||||
|
};
|
||||||
|
|
||||||
pub extern "c" fn kill(pid: pid_t, sig: c_int) c_int;
|
pub extern "c" fn kill(pid: pid_t, sig: c_int) c_int;
|
||||||
|
|
||||||
|
|
@ -11419,6 +11432,7 @@ const private = struct {
|
||||||
extern "c" fn pipe2(fds: *[2]fd_t, flags: O) c_int;
|
extern "c" fn pipe2(fds: *[2]fd_t, flags: O) c_int;
|
||||||
extern "c" fn readdir(dir: *DIR) ?*dirent;
|
extern "c" fn readdir(dir: *DIR) ?*dirent;
|
||||||
extern "c" fn realpath(noalias file_name: [*:0]const u8, noalias resolved_name: [*]u8) ?[*:0]u8;
|
extern "c" fn realpath(noalias file_name: [*:0]const u8, noalias resolved_name: [*]u8) ?[*:0]u8;
|
||||||
|
extern "c" fn recvmsg(sockfd: fd_t, msg: *msghdr, flags: u32) isize;
|
||||||
extern "c" fn sched_yield() c_int;
|
extern "c" fn sched_yield() c_int;
|
||||||
extern "c" fn sendfile(out_fd: fd_t, in_fd: fd_t, offset: ?*off_t, count: usize) isize;
|
extern "c" fn sendfile(out_fd: fd_t, in_fd: fd_t, offset: ?*off_t, count: usize) isize;
|
||||||
extern "c" fn sigaction(sig: c_int, noalias act: ?*const Sigaction, noalias oact: ?*Sigaction) c_int;
|
extern "c" fn sigaction(sig: c_int, noalias act: ?*const Sigaction, noalias oact: ?*Sigaction) c_int;
|
||||||
|
|
@ -11429,6 +11443,7 @@ const private = struct {
|
||||||
extern "c" fn sigismember(set: ?*const sigset_t, signo: c_int) c_int;
|
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 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 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 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 sigaltstack(ss: ?*stack_t, old_ss: ?*stack_t) c_int;
|
||||||
extern "c" fn sysconf(sc: c_int) c_long;
|
extern "c" fn sysconf(sc: c_int) c_long;
|
||||||
|
|
|
||||||
|
|
@ -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{
|
pub const ShutdownError = error{
|
||||||
ConnectionAborted,
|
ConnectionAborted,
|
||||||
|
|
||||||
|
|
@ -6604,6 +6644,9 @@ pub const RecvFromError = error{
|
||||||
|
|
||||||
/// The socket is not connected (connection-oriented sockets only).
|
/// The socket is not connected (connection-oriented sockets only).
|
||||||
SocketNotConnected,
|
SocketNotConnected,
|
||||||
|
|
||||||
|
/// The other end closed the socket unexpectedly or a read is executed on a shut down socket
|
||||||
|
BrokenPipe,
|
||||||
} || UnexpectedError;
|
} || UnexpectedError;
|
||||||
|
|
||||||
pub fn recv(sock: socket_t, buf: []u8, flags: u32) RecvFromError!usize {
|
pub fn recv(sock: socket_t, buf: []u8, flags: u32) RecvFromError!usize {
|
||||||
|
|
@ -6652,12 +6695,62 @@ pub fn recvfrom(
|
||||||
.CONNREFUSED => return error.ConnectionRefused,
|
.CONNREFUSED => return error.ConnectionRefused,
|
||||||
.CONNRESET => return error.ConnectionResetByPeer,
|
.CONNRESET => return error.ConnectionResetByPeer,
|
||||||
.TIMEDOUT => return error.ConnectionTimedOut,
|
.TIMEDOUT => return error.ConnectionTimedOut,
|
||||||
|
.PIPE => return error.BrokenPipe,
|
||||||
else => |err| return unexpectedErrno(err),
|
else => |err| return unexpectedErrno(err),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub const RecvMsgError = RecvFromError || error{
|
||||||
|
/// Reception of SCM_RIGHTS fds via ancillary data in msg.control would
|
||||||
|
/// exceed some system limit (generally this is retryable by trying to
|
||||||
|
/// receive fewer fds or closing some existing fds)
|
||||||
|
SystemFdQuotaExceeded,
|
||||||
|
|
||||||
|
/// Reception of SCM_RIGHTS fds via ancillary data in msg.control would
|
||||||
|
/// exceed some process limit (generally this is retryable by trying to
|
||||||
|
/// receive fewer fds, closing some existing fds, or changing the ulimit)
|
||||||
|
ProcessFdQuotaExceeded,
|
||||||
|
};
|
||||||
|
|
||||||
|
/// If `sockfd` is opened in non blocking mode, the function will
|
||||||
|
/// return error.WouldBlock when EAGAIN is received.
|
||||||
|
pub fn recvmsg(
|
||||||
|
/// The file descriptor of the sending socket.
|
||||||
|
sockfd: socket_t,
|
||||||
|
/// Message header and iovecs
|
||||||
|
msg: *msghdr,
|
||||||
|
flags: u32,
|
||||||
|
) RecvMsgError!usize {
|
||||||
|
if (@TypeOf(system.recvmsg) == void)
|
||||||
|
@compileError("recvmsg() not supported on this OS");
|
||||||
|
while (true) {
|
||||||
|
const rc = system.recvmsg(sockfd, msg, flags);
|
||||||
|
switch (errno(rc)) {
|
||||||
|
.SUCCESS => return @intCast(rc),
|
||||||
|
.AGAIN => return error.WouldBlock,
|
||||||
|
.BADF => unreachable, // always a race condition
|
||||||
|
.NFILE => return error.SystemFdQuotaExceeded,
|
||||||
|
.MFILE => return error.ProcessFdQuotaExceeded,
|
||||||
|
.INTR => continue,
|
||||||
|
.FAULT => unreachable, // An invalid user space address was specified for an argument.
|
||||||
|
.INVAL => unreachable, // Invalid argument passed.
|
||||||
|
.ISCONN => unreachable, // connection-mode socket was connected already but a recipient was specified
|
||||||
|
.NOBUFS => return error.SystemResources,
|
||||||
|
.NOMEM => return error.SystemResources,
|
||||||
|
.NOTCONN => return error.SocketNotConnected,
|
||||||
|
.NOTSOCK => unreachable, // The file descriptor sockfd does not refer to a socket.
|
||||||
|
.MSGSIZE => return error.MessageTooBig,
|
||||||
|
.PIPE => return error.BrokenPipe,
|
||||||
|
.OPNOTSUPP => unreachable, // Some bit in the flags argument is inappropriate for the socket type.
|
||||||
|
.CONNRESET => return error.ConnectionResetByPeer,
|
||||||
|
.NETDOWN => return error.NetworkSubsystemFailed,
|
||||||
|
else => |err| return unexpectedErrno(err),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub const DnExpandError = error{InvalidDnsPacket};
|
pub const DnExpandError = error{InvalidDnsPacket};
|
||||||
|
|
||||||
pub fn dn_expand(
|
pub fn dn_expand(
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue