Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add sendmmsg syscall wrapper #2326

Merged
merged 3 commits into from
May 4, 2019
Merged

Add sendmmsg syscall wrapper #2326

merged 3 commits into from
May 4, 2019

Conversation

daurnimator
Copy link
Contributor

@daurnimator daurnimator commented Apr 21, 2019

Includes some cleanups of msghdr definition.

Open questions:

  • is working around kernel bugs/oddities in syscall wrappers as I've done expected/wanted?
  • having e.g. both iovec and iovec_const; both msghdr and msghdr_const gets messy. What can the zig language do to make this less annoying?

Tested with this snippet:

test "sendmmsg" {
    const fd = try std.os.posixSocket(linux.AF_INET, linux.SOCK_DGRAM, 0);
    defer std.os.close(fd);

    std.debug.warn("sendmmsg {}\n", linux.sendmmsg(fd, &[]linux.mmsghdr_const{}, 0, 0));

    const name = std.net.Address.initIp4(try std.net.parseIp4("192.0.2.1"), 80).os_addr; // part of TEST-NET-1 see RFC 5737
    const namelen = @sizeOf(linux.sockaddr_in);

    const iovecs1 = []linux.iovec_const{linux.iovec_const{ .iov_base = &"hello", .iov_len = 2 }};
    const iovecs2 = blk: {
        const mmap_len = 1<<30;
        const mmap_addr = linux.mmap(null, mmap_len, linux.PROT_READ, linux.MAP_PRIVATE | linux.MAP_ANONYMOUS, -1, 0);
        if (mmap_addr == linux.MAP_FAILED) unreachable;
        const mmap_ptr = @intToPtr([*]u8, mmap_addr);
        break :blk []linux.iovec_const{
            linux.iovec_const{ .iov_base = mmap_ptr, .iov_len = mmap_len },
            linux.iovec_const{ .iov_base = mmap_ptr, .iov_len = mmap_len },
            linux.iovec_const{ .iov_base = mmap_ptr, .iov_len = mmap_len },
        };
    };
    const iovecs3 = []linux.iovec_const{linux.iovec_const{ .iov_base = &("world"**(1<<20)), .iov_len = 5*(1<<20) }};
    const msgvec = []linux.mmsghdr_const{
        linux.mmsghdr_const{
            .msg_hdr = linux.msghdr_const{
                .msg_name = &name,
                .msg_namelen = namelen,
                .msg_iov = &iovecs1,
                .msg_iovlen = iovecs1.len,
                .__pad1 = 0,
                .msg_control = null,
                .msg_controllen = 0,
                .__pad2 = 0,
                .msg_flags = 0,
            },
            .msg_len = undefined,
        },
        linux.mmsghdr_const{
            .msg_hdr = linux.msghdr_const{
                .msg_name = &name,
                .msg_namelen = namelen,
                .msg_iov = &iovecs2,
                .msg_iovlen = iovecs2.len,
                .__pad1 = 0,
                .msg_control = null,
                .msg_controllen = 0,
                .__pad2 = 0,
                .msg_flags = 0,
            },
            .msg_len = undefined,
        },
        linux.mmsghdr_const{
            .msg_hdr = linux.msghdr_const{
                .msg_name = &name,
                .msg_namelen = namelen,
                .msg_iov = &iovecs3,
                .msg_iovlen = iovecs3.len,
                .__pad1 = 0,
                .msg_control = null,
                .msg_controllen = 0,
                .__pad2 = 0,
                .msg_flags = 0,
            },
            .msg_len = undefined,
        },
    };
    std.debug.warn("sendmmsg {}\n", linux.sendmmsg(fd, &msgvec, msgvec.len, 0));
}

As `iovec_const` is to `iovec`, `msghdr_const` is to `msghdr`
msg_iovlen: i32,
__pad1: i32,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Did you remove this padding field? Doesn't that break the ABI?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This padding field isn't present in freebsd headers. It looked like someone just copy/pasted the linux definition without checking.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Argh. That's a problem. Now the entire freebsd.zig file needs to be audited.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

likewise netbsd.zig; which seems to have been copied from freebsd....

return syscall3(SYS_sendmsg, @bitCast(usize, isize(fd)), @ptrToInt(msg), flags);
}

pub fn sendmmsg(fd: i32, msgvec: [*]mmsghdr_const, vlen: u32, flags: u32) usize {
if (@typeInfo(usize).Int.bits > @typeInfo(@typeOf(mmsghdr(undefined).msg_len)).Int.bits) {
// workaround kernel brokenness:
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I opened #2380 to address this. I'd like to resolve that issue before merging this pull request. It's not a particularly big time investment for me to do that, so I can prioritize it to unblock you.

Copy link
Contributor Author

@daurnimator daurnimator Apr 30, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure #2380 is related :P
sendmmsg is not a posix API (see my comment here)

This is an oversight in the linux kernel when introducing 64bit support to code originally written for 32bit that has now resulted in a broken kernel ABI forever.
But it does of course bring up the question of: where does this wrapper belong?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Instead of std.os.posix mapping directly to OS-specific files, it will provide a "zig flavored POSIX" API on top of the native OS API. This is where kernel limitations will be worked around; fork might call clone on Linux, etc.

I think this applies to the sendmmsg workaround. std.os.linux.sendmmsg is meant to be completely raw. std.os.posix.sendmmsg will be a compile error on systems that don't have it, that's fine. Zig is using std.os.posix to mean a specific, slightly different thing than it means in C and that's OK.

@daurnimator
Copy link
Contributor Author

daurnimator commented Apr 29, 2019

@andrewrk any thoughts on:

having e.g. both iovec and iovec_const; both msghdr and msghdr_const gets messy. What can the zig language do to make this less annoying?

@andrewrk
Copy link
Member

Oops, meant to address that - thanks for the reminder. That's a problem that has come up in several different contexts and I don't have a good answer for it yet. I think it would be worth opening up an issue to discuss potential solutions.

@daurnimator
Copy link
Contributor Author

daurnimator commented Apr 30, 2019

I think it would be worth opening up an issue to discuss potential solutions.

Opened #2383 to track

@andrewrk
Copy link
Member

andrewrk commented May 3, 2019

I'm OK with merging this and doing #2380 later. Is this ready to merge @daurnimator? Can you confirm where you got the msghdr struct layouts for arm64, netbsd, and freebsd?

@daurnimator
Copy link
Contributor Author

Is this ready to merge @daurnimator?

Yes.

Can you confirm where you got the msghdr struct layouts for arm64, netbsd, and freebsd?

Checked headers of each OS. comments are directly from each OS.

@andrewrk andrewrk merged commit 21c8d57 into ziglang:master May 4, 2019
@daurnimator daurnimator deleted the sendmmsg branch May 6, 2019 02:09
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants