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:
Hiroaki Nakamura
2022-03-04 05:13:54 +09:00
committed by GitHub
parent e91c16e38b
commit 3605dd307f
9 changed files with 264 additions and 82 deletions

View File

@@ -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;

View File

@@ -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;

View File

@@ -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;

View File

@@ -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;

View File

@@ -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;

View File

@@ -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;

View File

@@ -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;

View File

@@ -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,

View File

@@ -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;