os/linux/io_uring: add recvmsg and sendmsg (#10212)
* os/linux/io_uring: add recvmsg and sendmsg * Use std.os.iovec and std.os.iovec_const * Remove msg_ prefix in msghdr and msghdr_const in arm64 etc * Strip msg_ prefix in msghdr and msghdr_const for linux arm-eabi * Copy msghdr and msghdr_const from i386 to mips * Add sockaddr to lib/std/os/linux/mips.zig * Copy msghdr and msghdr_const from x86_64 to riscv64
This commit is contained in:
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user