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 {...@@ -42,14 +42,36 @@ pub const pthread_attr_t = extern struct {
42};42};
4343
44pub const msghdr = extern struct {44pub const msghdr = extern struct {
45 msg_name: *u8,45 /// optional address
46 msg_name: ?*sockaddr,
47 /// size of address
46 msg_namelen: socklen_t,48 msg_namelen: socklen_t,
47 msg_iov: *iovec,49 /// scatter/gather array
50 msg_iov: [*]iovec,
51 /// # elements in msg_iov
48 msg_iovlen: i32,52 msg_iovlen: i32,
49 __pad1: i32,53 /// ancillary data
50 msg_control: *u8,54 msg_control: ?*c_void,
55 /// ancillary data buffer len
51 msg_controllen: socklen_t,56 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
53 msg_flags: i32,75 msg_flags: i32,
54};76};
5577
std/c/netbsd.zig+27-5
...@@ -42,14 +42,36 @@ pub const pthread_attr_t = extern struct {...@@ -42,14 +42,36 @@ pub const pthread_attr_t = extern struct {
42};42};
4343
44pub const msghdr = extern struct {44pub const msghdr = extern struct {
45 msg_name: *u8,45 /// optional address
46 msg_name: ?*sockaddr,
47 /// size of address
46 msg_namelen: socklen_t,48 msg_namelen: socklen_t,
47 msg_iov: *iovec,49 /// scatter/gather array
50 msg_iov: [*]iovec,
51 /// # elements in msg_iov
48 msg_iovlen: i32,52 msg_iovlen: i32,
49 __pad1: i32,53 /// ancillary data
50 msg_control: *u8,54 msg_control: ?*c_void,
55 /// ancillary data buffer len
51 msg_controllen: socklen_t,56 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
53 msg_flags: i32,75 msg_flags: i32,
54};76};
5577
std/os/linux.zig+52-1
...@@ -12,6 +12,7 @@ pub use switch (builtin.arch) {...@@ -12,6 +12,7 @@ pub use switch (builtin.arch) {
12pub use @import("linux/errno.zig");12pub use @import("linux/errno.zig");
1313
14pub const PATH_MAX = 4096;14pub const PATH_MAX = 4096;
15pub const IOV_MAX = 1024;
1516
16pub const STDIN_FILENO = 0;17pub const STDIN_FILENO = 0;
17pub const STDOUT_FILENO = 1;18pub const STDOUT_FILENO = 1;
...@@ -1193,6 +1194,16 @@ pub const iovec_const = extern struct {...@@ -1193,6 +1194,16 @@ pub const iovec_const = extern struct {
1193 iov_len: usize,1194 iov_len: usize,
1194};1195};
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
1196pub fn getsockname(fd: i32, noalias addr: *sockaddr, noalias len: *socklen_t) usize {1207pub fn getsockname(fd: i32, noalias addr: *sockaddr, noalias len: *socklen_t) usize {
1197 return syscall3(SYS_getsockname, @bitCast(usize, isize(fd)), @ptrToInt(addr), @ptrToInt(len));1208 return syscall3(SYS_getsockname, @bitCast(usize, isize(fd)), @ptrToInt(addr), @ptrToInt(len));
1198}1209}
...@@ -1213,10 +1224,50 @@ pub fn getsockopt(fd: i32, level: u32, optname: u32, noalias optval: [*]u8, noal...@@ -1213,10 +1224,50 @@ pub fn getsockopt(fd: i32, level: u32, optname: u32, noalias optval: [*]u8, noal
1213 return syscall5(SYS_getsockopt, @bitCast(usize, isize(fd)), level, optname, @ptrToInt(optval), @ptrToInt(optlen));1224 return syscall5(SYS_getsockopt, @bitCast(usize, isize(fd)), level, optname, @ptrToInt(optval), @ptrToInt(optlen));
1214}1225}
12151226
1216pub fn sendmsg(fd: i32, msg: *const msghdr, flags: u32) usize {1227pub fn sendmsg(fd: i32, msg: *msghdr_const, flags: u32) usize {
1217 return syscall3(SYS_sendmsg, @bitCast(usize, isize(fd)), @ptrToInt(msg), flags);1228 return syscall3(SYS_sendmsg, @bitCast(usize, isize(fd)), @ptrToInt(msg), flags);
1218}1229}
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
1220pub fn connect(fd: i32, addr: *const c_void, len: socklen_t) usize {1271pub fn connect(fd: i32, addr: *const c_void, len: socklen_t) usize {
1221 return syscall3(SYS_connect, @bitCast(usize, isize(fd)), @ptrToInt(addr), len);1272 return syscall3(SYS_connect, @bitCast(usize, isize(fd)), @ptrToInt(addr), len);
1222}1273}
std/os/linux/arm64.zig+16-3
...@@ -2,6 +2,7 @@ const std = @import("../../std.zig");...@@ -2,6 +2,7 @@ const std = @import("../../std.zig");
2const linux = std.os.linux;2const linux = std.os.linux;
3const socklen_t = linux.socklen_t;3const socklen_t = linux.socklen_t;
4const iovec = linux.iovec;4const iovec = linux.iovec;
5const iovec_const = linux.iovec_const;
56
6pub const SYS_io_setup = 0;7pub const SYS_io_setup = 0;
7pub const SYS_io_destroy = 1;8pub const SYS_io_destroy = 1;
...@@ -415,12 +416,24 @@ pub fn syscall6(...@@ -415,12 +416,24 @@ pub fn syscall6(
415pub extern fn clone(func: extern fn (arg: usize) u8, stack: usize, flags: u32, arg: usize, ptid: *i32, tls: usize, ctid: *i32) usize;416pub extern fn clone(func: extern fn (arg: usize) u8, stack: usize, flags: u32, arg: usize, ptid: *i32, tls: usize, ctid: *i32) usize;
416417
417pub const msghdr = extern struct {418pub const msghdr = extern struct {
418 msg_name: *u8,419 msg_name: ?*sockaddr,
419 msg_namelen: socklen_t,420 msg_namelen: socklen_t,
420 msg_iov: *iovec,421 msg_iov: [*]iovec,
421 msg_iovlen: i32,422 msg_iovlen: i32,
422 __pad1: i32,423 __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,
424 msg_controllen: socklen_t,437 msg_controllen: socklen_t,
425 __pad2: socklen_t,438 __pad2: socklen_t,
426 msg_flags: i32,439 msg_flags: i32,
std/os/linux/x86_64.zig+17-3
...@@ -1,7 +1,9 @@...@@ -1,7 +1,9 @@
1const std = @import("../../std.zig");1const std = @import("../../std.zig");
2const linux = std.os.linux;2const linux = std.os.linux;
3const sockaddr = linux.sockaddr;
3const socklen_t = linux.socklen_t;4const socklen_t = linux.socklen_t;
4const iovec = linux.iovec;5const iovec = linux.iovec;
6const iovec_const = linux.iovec_const;
57
6pub const SYS_read = 0;8pub const SYS_read = 0;
7pub const SYS_write = 1;9pub const SYS_write = 1;
...@@ -483,12 +485,24 @@ pub nakedcc fn restore_rt() void {...@@ -483,12 +485,24 @@ pub nakedcc fn restore_rt() void {
483}485}
484486
485pub const msghdr = extern struct {487pub const msghdr = extern struct {
486 msg_name: *u8,488 msg_name: ?*sockaddr,
487 msg_namelen: socklen_t,489 msg_namelen: socklen_t,
488 msg_iov: *iovec,490 msg_iov: [*]iovec,
489 msg_iovlen: i32,491 msg_iovlen: i32,
490 __pad1: i32,492 __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,
492 msg_controllen: socklen_t,506 msg_controllen: socklen_t,
493 __pad2: socklen_t,507 __pad2: socklen_t,
494 msg_flags: i32,508 msg_flags: i32,