| 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 | 42 | }; |
| 43 | 43 | |
| 44 | 44 | pub const msghdr = extern struct { |
| 45 | msg_name: *u8, | |
| 45 | /// optional address | |
| 46 | msg_name: ?*sockaddr, | |
| 47 | /// size of address | |
| 46 | 48 | msg_namelen: socklen_t, |
| 47 | msg_iov: *iovec, | |
| 49 | /// scatter/gather array | |
| 50 | msg_iov: [*]iovec, | |
| 51 | /// # elements in msg_iov | |
| 48 | 52 | msg_iovlen: i32, |
| 49 | __pad1: i32, | |
| 50 | msg_control: *u8, | |
| 53 | /// ancillary data | |
| 54 | msg_control: ?*c_void, | |
| 55 | /// ancillary data buffer len | |
| 51 | 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 | 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 | 42 | }; |
| 43 | 43 | |
| 44 | 44 | pub const msghdr = extern struct { |
| 45 | msg_name: *u8, | |
| 45 | /// optional address | |
| 46 | msg_name: ?*sockaddr, | |
| 47 | /// size of address | |
| 46 | 48 | msg_namelen: socklen_t, |
| 47 | msg_iov: *iovec, | |
| 49 | /// scatter/gather array | |
| 50 | msg_iov: [*]iovec, | |
| 51 | /// # elements in msg_iov | |
| 48 | 52 | msg_iovlen: i32, |
| 49 | __pad1: i32, | |
| 50 | msg_control: *u8, | |
| 53 | /// ancillary data | |
| 54 | msg_control: ?*c_void, | |
| 55 | /// ancillary data buffer len | |
| 51 | 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 | 75 | msg_flags: i32, |
| 54 | 76 | }; |
| 55 | 77 |
std/os/linux.zig+52-1| ... | ... | @@ -12,6 +12,7 @@ pub use switch (builtin.arch) { |
| 12 | 12 | pub use @import("linux/errno.zig"); |
| 13 | 13 | |
| 14 | 14 | pub const PATH_MAX = 4096; |
| 15 | pub const IOV_MAX = 1024; | |
| 15 | 16 | |
| 16 | 17 | pub const STDIN_FILENO = 0; |
| 17 | 18 | pub const STDOUT_FILENO = 1; |
| ... | ... | @@ -1193,6 +1194,16 @@ pub const iovec_const = extern struct { |
| 1193 | 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 | 1207 | pub fn getsockname(fd: i32, noalias addr: *sockaddr, noalias len: *socklen_t) usize { |
| 1197 | 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 | 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 | 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 | 1271 | pub fn connect(fd: i32, addr: *const c_void, len: socklen_t) usize { |
| 1221 | 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 | 2 | const linux = std.os.linux; |
| 3 | 3 | const socklen_t = linux.socklen_t; |
| 4 | 4 | const iovec = linux.iovec; |
| 5 | const iovec_const = linux.iovec_const; | |
| 5 | 6 | |
| 6 | 7 | pub const SYS_io_setup = 0; |
| 7 | 8 | pub const SYS_io_destroy = 1; |
| ... | ... | @@ -415,12 +416,24 @@ pub fn syscall6( |
| 415 | 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 | 418 | pub const msghdr = extern struct { |
| 418 | msg_name: *u8, | |
| 419 | msg_name: ?*sockaddr, | |
| 419 | 420 | msg_namelen: socklen_t, |
| 420 | msg_iov: *iovec, | |
| 421 | msg_iov: [*]iovec, | |
| 421 | 422 | msg_iovlen: i32, |
| 422 | 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 | 437 | msg_controllen: socklen_t, |
| 425 | 438 | __pad2: socklen_t, |
| 426 | 439 | msg_flags: i32, |
std/os/linux/x86_64.zig+17-3| ... | ... | @@ -1,7 +1,9 @@ |
| 1 | 1 | const std = @import("../../std.zig"); |
| 2 | 2 | const linux = std.os.linux; |
| 3 | const sockaddr = linux.sockaddr; | |
| 3 | 4 | const socklen_t = linux.socklen_t; |
| 4 | 5 | const iovec = linux.iovec; |
| 6 | const iovec_const = linux.iovec_const; | |
| 5 | 7 | |
| 6 | 8 | pub const SYS_read = 0; |
| 7 | 9 | pub const SYS_write = 1; |
| ... | ... | @@ -483,12 +485,24 @@ pub nakedcc fn restore_rt() void { |
| 483 | 485 | } |
| 484 | 486 | |
| 485 | 487 | pub const msghdr = extern struct { |
| 486 | msg_name: *u8, | |
| 488 | msg_name: ?*sockaddr, | |
| 487 | 489 | msg_namelen: socklen_t, |
| 488 | msg_iov: *iovec, | |
| 490 | msg_iov: [*]iovec, | |
| 489 | 491 | msg_iovlen: i32, |
| 490 | 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 | 506 | msg_controllen: socklen_t, |
| 493 | 507 | __pad2: socklen_t, |
| 494 | 508 | msg_flags: i32, |