diff --git a/lib/std/os/linux/arm-eabi.zig b/lib/std/os/linux/arm-eabi.zig index cea3188b3d..287c61c49d 100644 --- a/lib/std/os/linux/arm-eabi.zig +++ b/lib/std/os/linux/arm-eabi.zig @@ -648,23 +648,23 @@ pub const Flock = extern struct { }; pub const msghdr = extern struct { - msg_name: ?*sockaddr, - msg_namelen: socklen_t, - msg_iov: [*]iovec, - msg_iovlen: i32, - msg_control: ?*anyopaque, - msg_controllen: socklen_t, - msg_flags: i32, + name: ?*sockaddr, + namelen: socklen_t, + iov: [*]iovec, + iovlen: i32, + control: ?*anyopaque, + controllen: socklen_t, + flags: i32, }; pub const msghdr_const = extern struct { - msg_name: ?*const sockaddr, - msg_namelen: socklen_t, - msg_iov: [*]iovec_const, - msg_iovlen: i32, - msg_control: ?*anyopaque, - msg_controllen: socklen_t, - msg_flags: i32, + name: ?*const sockaddr, + namelen: socklen_t, + iov: [*]iovec_const, + iovlen: i32, + control: ?*anyopaque, + controllen: socklen_t, + flags: i32, }; pub const blksize_t = i32; diff --git a/lib/std/os/linux/arm64.zig b/lib/std/os/linux/arm64.zig index 815a640b79..9cb66c3fcf 100644 --- a/lib/std/os/linux/arm64.zig +++ b/lib/std/os/linux/arm64.zig @@ -3,8 +3,8 @@ const maxInt = std.math.maxInt; const linux = std.os.linux; const socklen_t = linux.socklen_t; const sockaddr = linux.sockaddr; -const iovec = linux.iovec; -const iovec_const = linux.iovec_const; +const iovec = std.os.iovec; +const iovec_const = std.os.iovec_const; const uid_t = linux.uid_t; const gid_t = linux.gid_t; const pid_t = linux.pid_t; @@ -499,27 +499,27 @@ pub const Flock = extern struct { }; pub const msghdr = extern struct { - msg_name: ?*sockaddr, - msg_namelen: socklen_t, - msg_iov: [*]iovec, - msg_iovlen: i32, + name: ?*sockaddr, + namelen: socklen_t, + iov: [*]iovec, + iovlen: i32, __pad1: i32 = 0, - msg_control: ?*anyopaque, - msg_controllen: socklen_t, + control: ?*anyopaque, + controllen: socklen_t, __pad2: socklen_t = 0, - msg_flags: i32, + flags: i32, }; pub const msghdr_const = extern struct { - msg_name: ?*const sockaddr, - msg_namelen: socklen_t, - msg_iov: [*]iovec_const, - msg_iovlen: i32, + name: ?*const sockaddr, + namelen: socklen_t, + iov: [*]iovec_const, + iovlen: i32, __pad1: i32 = 0, - msg_control: ?*anyopaque, - msg_controllen: socklen_t, + control: ?*anyopaque, + controllen: socklen_t, __pad2: socklen_t = 0, - msg_flags: i32, + flags: i32, }; pub const blksize_t = i32; diff --git a/lib/std/os/linux/i386.zig b/lib/std/os/linux/i386.zig index 0b9a05c7c7..f5768aed71 100644 --- a/lib/std/os/linux/i386.zig +++ b/lib/std/os/linux/i386.zig @@ -2,8 +2,8 @@ const std = @import("../../std.zig"); const maxInt = std.math.maxInt; const linux = std.os.linux; const socklen_t = linux.socklen_t; -const iovec = linux.iovec; -const iovec_const = linux.iovec_const; +const iovec = std.os.iovec; +const iovec_const = std.os.iovec_const; const uid_t = linux.uid_t; const gid_t = linux.gid_t; const pid_t = linux.pid_t; diff --git a/lib/std/os/linux/io_uring.zig b/lib/std/os/linux/io_uring.zig index fc32508cf5..b67b616bca 100644 --- a/lib/std/os/linux/io_uring.zig +++ b/lib/std/os/linux/io_uring.zig @@ -537,6 +537,36 @@ pub const IO_Uring = struct { return sqe; } + /// Queues (but does not submit) an SQE to perform a `recvmsg(2)`. + /// Returns a pointer to the SQE. + pub fn recvmsg( + self: *IO_Uring, + user_data: u64, + fd: os.fd_t, + msg: *os.msghdr, + flags: u32, + ) !*io_uring_sqe { + const sqe = try self.get_sqe(); + io_uring_prep_recvmsg(sqe, fd, msg, flags); + sqe.user_data = user_data; + return sqe; + } + + /// Queues (but does not submit) an SQE to perform a `sendmsg(2)`. + /// Returns a pointer to the SQE. + pub fn sendmsg( + self: *IO_Uring, + user_data: u64, + fd: os.fd_t, + msg: *const os.msghdr_const, + flags: u32, + ) !*io_uring_sqe { + const sqe = try self.get_sqe(); + io_uring_prep_sendmsg(sqe, fd, msg, flags); + sqe.user_data = user_data; + return sqe; + } + /// Queues (but does not submit) an SQE to perform an `openat(2)`. /// Returns a pointer to the SQE. pub fn openat( @@ -1237,6 +1267,26 @@ pub fn io_uring_prep_send(sqe: *io_uring_sqe, fd: os.fd_t, buffer: []const u8, f sqe.rw_flags = flags; } +pub fn io_uring_prep_recvmsg( + sqe: *io_uring_sqe, + fd: os.fd_t, + msg: *os.msghdr, + flags: u32, +) void { + linux.io_uring_prep_rw(.RECVMSG, sqe, fd, @ptrToInt(msg), 1, 0); + sqe.rw_flags = flags; +} + +pub fn io_uring_prep_sendmsg( + sqe: *io_uring_sqe, + fd: os.fd_t, + msg: *const os.msghdr_const, + flags: u32, +) void { + linux.io_uring_prep_rw(.SENDMSG, sqe, fd, @ptrToInt(msg), 1, 0); + sqe.rw_flags = flags; +} + pub fn io_uring_prep_openat( sqe: *io_uring_sqe, fd: os.fd_t, @@ -1908,6 +1958,88 @@ test "accept/connect/send/recv" { try testing.expectEqualSlices(u8, buffer_send[0..buffer_recv.len], buffer_recv[0..]); } +test "sendmsg/recvmsg" { + if (builtin.os.tag != .linux) return error.SkipZigTest; + + var ring = IO_Uring.init(2, 0) catch |err| switch (err) { + error.SystemOutdated => return error.SkipZigTest, + error.PermissionDenied => return error.SkipZigTest, + else => return err, + }; + defer ring.deinit(); + + const address_server = try net.Address.parseIp4("127.0.0.1", 3131); + + const server = try os.socket(address_server.any.family, os.SOCK.DGRAM, 0); + defer os.close(server); + try os.setsockopt(server, os.SOL.SOCKET, os.SO.REUSEPORT, &mem.toBytes(@as(c_int, 1))); + try os.setsockopt(server, os.SOL.SOCKET, os.SO.REUSEADDR, &mem.toBytes(@as(c_int, 1))); + try os.bind(server, &address_server.any, address_server.getOsSockLen()); + + const client = try os.socket(address_server.any.family, os.SOCK.DGRAM, 0); + defer os.close(client); + + const buffer_send = [_]u8{42} ** 128; + var iovecs_send = [_]os.iovec_const{ + os.iovec_const{ .iov_base = &buffer_send, .iov_len = buffer_send.len }, + }; + const msg_send = os.msghdr_const{ + .name = &address_server.any, + .namelen = address_server.getOsSockLen(), + .iov = &iovecs_send, + .iovlen = 1, + .control = null, + .controllen = 0, + .flags = 0, + }; + const sqe_sendmsg = try ring.sendmsg(0x11111111, client, &msg_send, 0); + sqe_sendmsg.flags |= linux.IOSQE_IO_LINK; + try testing.expectEqual(linux.IORING_OP.SENDMSG, sqe_sendmsg.opcode); + try testing.expectEqual(client, sqe_sendmsg.fd); + + var buffer_recv = [_]u8{0} ** 128; + var iovecs_recv = [_]os.iovec{ + os.iovec{ .iov_base = &buffer_recv, .iov_len = buffer_recv.len }, + }; + var addr = [_]u8{0} ** 4; + var address_recv = net.Address.initIp4(addr, 0); + var msg_recv: os.msghdr = os.msghdr{ + .name = &address_recv.any, + .namelen = address_recv.getOsSockLen(), + .iov = &iovecs_recv, + .iovlen = 1, + .control = null, + .controllen = 0, + .flags = 0, + }; + const sqe_recvmsg = try ring.recvmsg(0x22222222, server, &msg_recv, 0); + try testing.expectEqual(linux.IORING_OP.RECVMSG, sqe_recvmsg.opcode); + try testing.expectEqual(server, sqe_recvmsg.fd); + + try testing.expectEqual(@as(u32, 2), ring.sq_ready()); + try testing.expectEqual(@as(u32, 2), try ring.submit_and_wait(2)); + try testing.expectEqual(@as(u32, 0), ring.sq_ready()); + try testing.expectEqual(@as(u32, 2), ring.cq_ready()); + + const cqe_sendmsg = try ring.copy_cqe(); + if (cqe_sendmsg.res == -@as(i32, @enumToInt(linux.E.INVAL))) return error.SkipZigTest; + try testing.expectEqual(linux.io_uring_cqe{ + .user_data = 0x11111111, + .res = buffer_send.len, + .flags = 0, + }, cqe_sendmsg); + + const cqe_recvmsg = try ring.copy_cqe(); + if (cqe_recvmsg.res == -@as(i32, @enumToInt(linux.E.INVAL))) return error.SkipZigTest; + try testing.expectEqual(linux.io_uring_cqe{ + .user_data = 0x22222222, + .res = buffer_recv.len, + .flags = 0, + }, cqe_recvmsg); + + try testing.expectEqualSlices(u8, buffer_send[0..buffer_recv.len], buffer_recv[0..]); +} + test "timeout (after a relative time)" { if (builtin.os.tag != .linux) return error.SkipZigTest; diff --git a/lib/std/os/linux/mips.zig b/lib/std/os/linux/mips.zig index ef586cba19..f9e760babe 100644 --- a/lib/std/os/linux/mips.zig +++ b/lib/std/os/linux/mips.zig @@ -2,11 +2,12 @@ const std = @import("../../std.zig"); const maxInt = std.math.maxInt; const linux = std.os.linux; const socklen_t = linux.socklen_t; -const iovec = linux.iovec; -const iovec_const = linux.iovec_const; +const iovec = std.os.iovec; +const iovec_const = std.os.iovec_const; const uid_t = linux.uid_t; const gid_t = linux.gid_t; const pid_t = linux.pid_t; +const sockaddr = linux.sockaddr; const timespec = linux.timespec; pub fn syscall0(number: SYS) usize { @@ -716,6 +717,26 @@ pub const Flock = extern struct { __unused: [4]u8, }; +pub const msghdr = extern struct { + name: ?*sockaddr, + namelen: socklen_t, + iov: [*]iovec, + iovlen: i32, + control: ?*anyopaque, + controllen: socklen_t, + flags: i32, +}; + +pub const msghdr_const = extern struct { + name: ?*const sockaddr, + namelen: socklen_t, + iov: [*]iovec_const, + iovlen: i32, + control: ?*anyopaque, + controllen: socklen_t, + flags: i32, +}; + pub const blksize_t = i32; pub const nlink_t = u32; pub const time_t = i32; diff --git a/lib/std/os/linux/powerpc.zig b/lib/std/os/linux/powerpc.zig index 5decf83a50..d1ef2b4a21 100644 --- a/lib/std/os/linux/powerpc.zig +++ b/lib/std/os/linux/powerpc.zig @@ -2,8 +2,8 @@ const std = @import("../../std.zig"); const maxInt = std.math.maxInt; const linux = std.os.linux; const socklen_t = linux.socklen_t; -const iovec = linux.iovec; -const iovec_const = linux.iovec_const; +const iovec = std.os.iovec; +const iovec_const = std.os.iovec_const; const uid_t = linux.uid_t; const gid_t = linux.gid_t; const pid_t = linux.pid_t; @@ -651,23 +651,23 @@ pub const Flock = extern struct { }; pub const msghdr = extern struct { - msg_name: ?*sockaddr, - msg_namelen: socklen_t, - msg_iov: [*]iovec, - msg_iovlen: usize, - msg_control: ?*anyopaque, - msg_controllen: socklen_t, - msg_flags: i32, + name: ?*sockaddr, + namelen: socklen_t, + iov: [*]iovec, + iovlen: usize, + control: ?*anyopaque, + controllen: socklen_t, + flags: i32, }; pub const msghdr_const = extern struct { - msg_name: ?*const sockaddr, - msg_namelen: socklen_t, - msg_iov: [*]iovec_const, - msg_iovlen: usize, - msg_control: ?*anyopaque, - msg_controllen: socklen_t, - msg_flags: i32, + name: ?*const sockaddr, + namelen: socklen_t, + iov: [*]iovec_const, + iovlen: usize, + control: ?*anyopaque, + controllen: socklen_t, + flags: i32, }; pub const blksize_t = i32; diff --git a/lib/std/os/linux/powerpc64.zig b/lib/std/os/linux/powerpc64.zig index 74caa71f3d..f1758c2b02 100644 --- a/lib/std/os/linux/powerpc64.zig +++ b/lib/std/os/linux/powerpc64.zig @@ -2,8 +2,8 @@ const std = @import("../../std.zig"); const maxInt = std.math.maxInt; const linux = std.os.linux; const socklen_t = linux.socklen_t; -const iovec = linux.iovec; -const iovec_const = linux.iovec_const; +const iovec = std.os.iovec; +const iovec_const = std.os.iovec_const; const uid_t = linux.uid_t; const gid_t = linux.gid_t; const pid_t = linux.pid_t; @@ -626,23 +626,23 @@ pub const Flock = extern struct { }; pub const msghdr = extern struct { - msg_name: ?*sockaddr, - msg_namelen: socklen_t, - msg_iov: [*]iovec, - msg_iovlen: usize, - msg_control: ?*anyopaque, - msg_controllen: usize, - msg_flags: i32, + name: ?*sockaddr, + namelen: socklen_t, + iov: [*]iovec, + iovlen: usize, + control: ?*anyopaque, + controllen: usize, + flags: i32, }; pub const msghdr_const = extern struct { - msg_name: ?*const sockaddr, - msg_namelen: socklen_t, - msg_iov: [*]iovec_const, - msg_iovlen: usize, - msg_control: ?*anyopaque, - msg_controllen: usize, - msg_flags: i32, + name: ?*const sockaddr, + namelen: socklen_t, + iov: [*]iovec_const, + iovlen: usize, + control: ?*anyopaque, + controllen: usize, + flags: i32, }; pub const blksize_t = i64; diff --git a/lib/std/os/linux/riscv64.zig b/lib/std/os/linux/riscv64.zig index 1ce3bed4e2..a2a50ddef4 100644 --- a/lib/std/os/linux/riscv64.zig +++ b/lib/std/os/linux/riscv64.zig @@ -1,7 +1,12 @@ const std = @import("../../std.zig"); +const iovec = std.os.iovec; +const iovec_const = std.os.iovec_const; +const linux = std.os.linux; const uid_t = std.os.linux.uid_t; const gid_t = std.os.linux.gid_t; const pid_t = std.os.linux.pid_t; +const sockaddr = linux.sockaddr; +const socklen_t = linux.socklen_t; const timespec = std.os.linux.timespec; pub fn syscall0(number: SYS) usize { @@ -488,6 +493,30 @@ pub const Flock = extern struct { __unused: [4]u8, }; +pub const msghdr = extern struct { + name: ?*sockaddr, + namelen: socklen_t, + iov: [*]iovec, + iovlen: i32, + __pad1: i32 = 0, + control: ?*anyopaque, + controllen: socklen_t, + __pad2: socklen_t = 0, + flags: i32, +}; + +pub const msghdr_const = extern struct { + name: ?*const sockaddr, + namelen: socklen_t, + iov: [*]iovec_const, + iovlen: i32, + __pad1: i32 = 0, + control: ?*anyopaque, + controllen: socklen_t, + __pad2: socklen_t = 0, + flags: i32, +}; + // The `stat` definition used by the Linux kernel. pub const Stat = extern struct { dev: dev_t, diff --git a/lib/std/os/linux/sparc64.zig b/lib/std/os/linux/sparc64.zig index 146ac8d2ee..231cd0a283 100644 --- a/lib/std/os/linux/sparc64.zig +++ b/lib/std/os/linux/sparc64.zig @@ -9,8 +9,8 @@ const sigset_t = linux.sigset_t; const linux = std.os.linux; const sockaddr = linux.sockaddr; const socklen_t = linux.socklen_t; -const iovec = linux.iovec; -const iovec_const = linux.iovec_const; +const iovec = std.os.iovec; +const iovec_const = std.os.iovec_const; const timespec = linux.timespec; pub fn syscall_pipe(fd: *[2]i32) usize { @@ -656,23 +656,23 @@ pub const Flock = extern struct { }; pub const msghdr = extern struct { - msg_name: ?*sockaddr, - msg_namelen: socklen_t, - msg_iov: [*]iovec, - msg_iovlen: u64, - msg_control: ?*anyopaque, - msg_controllen: u64, - msg_flags: i32, + name: ?*sockaddr, + namelen: socklen_t, + iov: [*]iovec, + iovlen: u64, + control: ?*anyopaque, + controllen: u64, + flags: i32, }; pub const msghdr_const = extern struct { - msg_name: ?*const sockaddr, - msg_namelen: socklen_t, - msg_iov: [*]iovec_const, - msg_iovlen: u64, - msg_control: ?*anyopaque, - msg_controllen: u64, - msg_flags: i32, + name: ?*const sockaddr, + namelen: socklen_t, + iov: [*]iovec_const, + iovlen: u64, + control: ?*anyopaque, + controllen: u64, + flags: i32, }; pub const off_t = i64;