| ... | @@ -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 | } |
| ... | @@ -1217,6 +1228,46 @@ pub fn sendmsg(fd: i32, msg: *msghdr_const, flags: u32) usize { | ... | @@ -1217,6 +1228,46 @@ 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 | } |