| author | |
| committer | |
| log | 21c8d57fca6bad5c9573679c2f7b40e584bd597c |
| tree | cbf8ed80c1438398ec1b845ebeb453bf4f7b6483 |
| parent | f4798297ded2d05f4e1919fb27a9cdb9981a5e11 |
| parent | fd056752daf6b6841ce06061072f092d9c7f8513 |
| signature |
Add sendmmsg syscall wrapper5 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 | }; |
| 43 | 43 | ||
| 44 | pub const msghdr = extern struct { | 44 | pub 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 | |||
| 61 | pub 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 | }; |
| 55 | 77 |
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 | }; |
| 43 | 43 | ||
| 44 | pub const msghdr = extern struct { | 44 | pub 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 | |||
| 61 | pub 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 | }; |
| 55 | 77 |
std/os/linux.zig+52-1| ... | @@ -12,6 +12,7 @@ pub use switch (builtin.arch) { | ... | @@ -12,6 +12,7 @@ pub use switch (builtin.arch) { |
| 12 | pub use @import("linux/errno.zig"); | 12 | pub use @import("linux/errno.zig"); |
| 13 | 13 | ||
| 14 | pub const PATH_MAX = 4096; | 14 | pub const PATH_MAX = 4096; |
| 15 | pub const IOV_MAX = 1024; | ||
| 15 | 16 | ||
| 16 | pub const STDIN_FILENO = 0; | 17 | pub const STDIN_FILENO = 0; |
| 17 | pub const STDOUT_FILENO = 1; | 18 | pub 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 | }; |
| 1195 | 1196 | ||
| 1197 | pub const mmsghdr = extern struct { | ||
| 1198 | msg_hdr: msghdr, | ||
| 1199 | msg_len: u32, | ||
| 1200 | }; | ||
| 1201 | |||
| 1202 | pub const mmsghdr_const = extern struct { | ||
| 1203 | msg_hdr: msghdr_const, | ||
| 1204 | msg_len: u32, | ||
| 1205 | }; | ||
| 1206 | |||
| 1196 | pub fn getsockname(fd: i32, noalias addr: *sockaddr, noalias len: *socklen_t) usize { | 1207 | pub 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 | } |
| 1215 | 1226 | ||
| 1216 | pub fn sendmsg(fd: i32, msg: *const msghdr, flags: u32) usize { | 1227 | pub 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 | } |
| 1219 | 1230 | ||
| 1231 | pub 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 | |||
| 1220 | pub fn connect(fd: i32, addr: *const c_void, len: socklen_t) usize { | 1271 | pub 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"); |
| 2 | const linux = std.os.linux; | 2 | const linux = std.os.linux; |
| 3 | const socklen_t = linux.socklen_t; | 3 | const socklen_t = linux.socklen_t; |
| 4 | const iovec = linux.iovec; | 4 | const iovec = linux.iovec; |
| 5 | const iovec_const = linux.iovec_const; | ||
| 5 | 6 | ||
| 6 | pub const SYS_io_setup = 0; | 7 | pub const SYS_io_setup = 0; |
| 7 | pub const SYS_io_destroy = 1; | 8 | pub const SYS_io_destroy = 1; |
| ... | @@ -415,12 +416,24 @@ pub fn syscall6( | ... | @@ -415,12 +416,24 @@ pub fn syscall6( |
| 415 | pub extern fn clone(func: extern fn (arg: usize) u8, stack: usize, flags: u32, arg: usize, ptid: *i32, tls: usize, ctid: *i32) usize; | 416 | pub extern fn clone(func: extern fn (arg: usize) u8, stack: usize, flags: u32, arg: usize, ptid: *i32, tls: usize, ctid: *i32) usize; |
| 416 | 417 | ||
| 417 | pub const msghdr = extern struct { | 418 | pub 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 | |||
| 430 | pub 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 @@ |
| 1 | const std = @import("../../std.zig"); | 1 | const std = @import("../../std.zig"); |
| 2 | const linux = std.os.linux; | 2 | const linux = std.os.linux; |
| 3 | const sockaddr = linux.sockaddr; | ||
| 3 | const socklen_t = linux.socklen_t; | 4 | const socklen_t = linux.socklen_t; |
| 4 | const iovec = linux.iovec; | 5 | const iovec = linux.iovec; |
| 6 | const iovec_const = linux.iovec_const; | ||
| 5 | 7 | ||
| 6 | pub const SYS_read = 0; | 8 | pub const SYS_read = 0; |
| 7 | pub const SYS_write = 1; | 9 | pub 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 | } |
| 484 | 486 | ||
| 485 | pub const msghdr = extern struct { | 487 | pub 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 | |||
| 499 | pub 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, |