authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2019-05-04 14:05:55-04:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2019-05-04 14:05:55-04:00
log21c8d57fca6bad5c9573679c2f7b40e584bd597c
treecbf8ed80c1438398ec1b845ebeb453bf4f7b6483
parentf4798297ded2d05f4e1919fb27a9cdb9981a5e11
parentfd056752daf6b6841ce06061072f092d9c7f8513
signaturebadge-question-mark Signed by PGP key 4AEE18F83AFDEB23

Merge pull request #2326 from daurnimator/sendmmsg

Add sendmmsg syscall wrapper

5 files changed, 139 insertions(+), 17 deletions(-)

std/c/freebsd.zig+27-5
......@@ -42,14 +42,36 @@ pub const pthread_attr_t = extern struct {
4242};
4343
4444pub const msghdr = extern struct {
45 msg_name: *u8,
45 /// optional address
46 msg_name: ?*sockaddr,
47 /// size of address
4648 msg_namelen: socklen_t,
47 msg_iov: *iovec,
49 /// scatter/gather array
50 msg_iov: [*]iovec,
51 /// # elements in msg_iov
4852 msg_iovlen: i32,
49 __pad1: i32,
50 msg_control: *u8,
53 /// ancillary data
54 msg_control: ?*c_void,
55 /// ancillary data buffer len
5156 msg_controllen: socklen_t,
52 __pad2: socklen_t,
57 /// flags on received message
58 msg_flags: i32,
59};
60
61pub const msghdr_const = extern struct {
62 /// optional address
63 msg_name: ?*const sockaddr,
64 /// size of address
65 msg_namelen: socklen_t,
66 /// scatter/gather array
67 msg_iov: [*]iovec_const,
68 /// # elements in msg_iov
69 msg_iovlen: i32,
70 /// ancillary data
71 msg_control: ?*c_void,
72 /// ancillary data buffer len
73 msg_controllen: socklen_t,
74 /// flags on received message
5375 msg_flags: i32,
5476};
5577
std/c/netbsd.zig+27-5
......@@ -42,14 +42,36 @@ pub const pthread_attr_t = extern struct {
4242};
4343
4444pub const msghdr = extern struct {
45 msg_name: *u8,
45 /// optional address
46 msg_name: ?*sockaddr,
47 /// size of address
4648 msg_namelen: socklen_t,
47 msg_iov: *iovec,
49 /// scatter/gather array
50 msg_iov: [*]iovec,
51 /// # elements in msg_iov
4852 msg_iovlen: i32,
49 __pad1: i32,
50 msg_control: *u8,
53 /// ancillary data
54 msg_control: ?*c_void,
55 /// ancillary data buffer len
5156 msg_controllen: socklen_t,
52 __pad2: socklen_t,
57 /// flags on received message
58 msg_flags: i32,
59};
60
61pub const msghdr_const = extern struct {
62 /// optional address
63 msg_name: ?*const sockaddr,
64 /// size of address
65 msg_namelen: socklen_t,
66 /// scatter/gather array
67 msg_iov: [*]iovec_const,
68 /// # elements in msg_iov
69 msg_iovlen: i32,
70 /// ancillary data
71 msg_control: ?*c_void,
72 /// ancillary data buffer len
73 msg_controllen: socklen_t,
74 /// flags on received message
5375 msg_flags: i32,
5476};
5577
std/os/linux.zig+52-1
......@@ -12,6 +12,7 @@ pub use switch (builtin.arch) {
1212pub use @import("linux/errno.zig");
1313
1414pub const PATH_MAX = 4096;
15pub const IOV_MAX = 1024;
1516
1617pub const STDIN_FILENO = 0;
1718pub const STDOUT_FILENO = 1;
......@@ -1193,6 +1194,16 @@ pub const iovec_const = extern struct {
11931194 iov_len: usize,
11941195};
11951196
1197pub const mmsghdr = extern struct {
1198 msg_hdr: msghdr,
1199 msg_len: u32,
1200};
1201
1202pub const mmsghdr_const = extern struct {
1203 msg_hdr: msghdr_const,
1204 msg_len: u32,
1205};
1206
11961207pub fn getsockname(fd: i32, noalias addr: *sockaddr, noalias len: *socklen_t) usize {
11971208 return syscall3(SYS_getsockname, @bitCast(usize, isize(fd)), @ptrToInt(addr), @ptrToInt(len));
11981209}
......@@ -1213,10 +1224,50 @@ pub fn getsockopt(fd: i32, level: u32, optname: u32, noalias optval: [*]u8, noal
12131224 return syscall5(SYS_getsockopt, @bitCast(usize, isize(fd)), level, optname, @ptrToInt(optval), @ptrToInt(optlen));
12141225}
12151226
1216pub fn sendmsg(fd: i32, msg: *const msghdr, flags: u32) usize {
1227pub fn sendmsg(fd: i32, msg: *msghdr_const, flags: u32) usize {
12171228 return syscall3(SYS_sendmsg, @bitCast(usize, isize(fd)), @ptrToInt(msg), flags);
12181229}
12191230
1231pub fn sendmmsg(fd: i32, msgvec: [*]mmsghdr_const, vlen: u32, flags: u32) usize {
1232 if (@typeInfo(usize).Int.bits > @typeInfo(@typeOf(mmsghdr(undefined).msg_len)).Int.bits) {
1233 // workaround kernel brokenness:
1234 // if adding up all iov_len overflows a i32 then split into multiple calls
1235 // see https://www.openwall.com/lists/musl/2014/06/07/5
1236 const kvlen = if (vlen > IOV_MAX) IOV_MAX else vlen; // matches kernel
1237 var next_unsent: usize = 0;
1238 for (msgvec[0..kvlen]) |*msg, i| {
1239 var size: i32 = 0;
1240 const msg_iovlen = @intCast(usize, msg.msg_hdr.msg_iovlen); // kernel side this is treated as unsigned
1241 for (msg.msg_hdr.msg_iov[0..msg_iovlen]) |iov, j| {
1242 if (iov.iov_len > std.math.maxInt(i32) or @addWithOverflow(i32, size, @intCast(i32, iov.iov_len), &size)) {
1243 // batch-send all messages up to the current message
1244 if (next_unsent < i) {
1245 const batch_size = i - next_unsent;
1246 const r = syscall4(SYS_sendmmsg, @bitCast(usize, isize(fd)), @ptrToInt(&msgvec[next_unsent]), batch_size, flags);
1247 if (getErrno(r) != 0) return next_unsent;
1248 if (r < batch_size) return next_unsent + r;
1249 }
1250 // send current message as own packet
1251 const r = sendmsg(fd, &msg.msg_hdr, flags);
1252 if (getErrno(r) != 0) return r;
1253 // Linux limits the total bytes sent by sendmsg to INT_MAX, so this cast is safe.
1254 msg.msg_len = @intCast(u32, r);
1255 next_unsent = i + 1;
1256 break;
1257 }
1258 }
1259 }
1260 if (next_unsent < kvlen or next_unsent == 0) { // want to make sure at least one syscall occurs (e.g. to trigger MSG_EOR)
1261 const batch_size = kvlen - next_unsent;
1262 const r = syscall4(SYS_sendmmsg, @bitCast(usize, isize(fd)), @ptrToInt(&msgvec[next_unsent]), batch_size, flags);
1263 if (getErrno(r) != 0) return r;
1264 return next_unsent + r;
1265 }
1266 return kvlen;
1267 }
1268 return syscall4(SYS_sendmmsg, @bitCast(usize, isize(fd)), @ptrToInt(msgvec), vlen, flags);
1269}
1270
12201271pub fn connect(fd: i32, addr: *const c_void, len: socklen_t) usize {
12211272 return syscall3(SYS_connect, @bitCast(usize, isize(fd)), @ptrToInt(addr), len);
12221273}
std/os/linux/arm64.zig+16-3
......@@ -2,6 +2,7 @@ const std = @import("../../std.zig");
22const linux = std.os.linux;
33const socklen_t = linux.socklen_t;
44const iovec = linux.iovec;
5const iovec_const = linux.iovec_const;
56
67pub const SYS_io_setup = 0;
78pub const SYS_io_destroy = 1;
......@@ -415,12 +416,24 @@ pub fn syscall6(
415416pub extern fn clone(func: extern fn (arg: usize) u8, stack: usize, flags: u32, arg: usize, ptid: *i32, tls: usize, ctid: *i32) usize;
416417
417418pub const msghdr = extern struct {
418 msg_name: *u8,
419 msg_name: ?*sockaddr,
419420 msg_namelen: socklen_t,
420 msg_iov: *iovec,
421 msg_iov: [*]iovec,
421422 msg_iovlen: i32,
422423 __pad1: i32,
423 msg_control: *u8,
424 msg_control: ?*c_void,
425 msg_controllen: socklen_t,
426 __pad2: socklen_t,
427 msg_flags: i32,
428};
429
430pub const msghdr_const = extern struct {
431 msg_name: ?*const sockaddr,
432 msg_namelen: socklen_t,
433 msg_iov: [*]iovec_const,
434 msg_iovlen: i32,
435 __pad1: i32,
436 msg_control: ?*c_void,
424437 msg_controllen: socklen_t,
425438 __pad2: socklen_t,
426439 msg_flags: i32,
std/os/linux/x86_64.zig+17-3
......@@ -1,7 +1,9 @@
11const std = @import("../../std.zig");
22const linux = std.os.linux;
3const sockaddr = linux.sockaddr;
34const socklen_t = linux.socklen_t;
45const iovec = linux.iovec;
6const iovec_const = linux.iovec_const;
57
68pub const SYS_read = 0;
79pub const SYS_write = 1;
......@@ -483,12 +485,24 @@ pub nakedcc fn restore_rt() void {
483485}
484486
485487pub const msghdr = extern struct {
486 msg_name: *u8,
488 msg_name: ?*sockaddr,
487489 msg_namelen: socklen_t,
488 msg_iov: *iovec,
490 msg_iov: [*]iovec,
489491 msg_iovlen: i32,
490492 __pad1: i32,
491 msg_control: *u8,
493 msg_control: ?*c_void,
494 msg_controllen: socklen_t,
495 __pad2: socklen_t,
496 msg_flags: i32,
497};
498
499pub const msghdr_const = extern struct {
500 msg_name: ?*const sockaddr,
501 msg_namelen: socklen_t,
502 msg_iov: [*]iovec_const,
503 msg_iovlen: i32,
504 __pad1: i32,
505 msg_control: ?*c_void,
492506 msg_controllen: socklen_t,
493507 __pad2: socklen_t,
494508 msg_flags: i32,