summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTerin Stock <terinjokes@gmail.com>2020-01-10 01:18:43 -0800
committerTerin Stock <terinjokes@gmail.com>2020-01-10 01:18:43 -0800
commit87d8282897d31c39339ad4059a217fdde064983e (patch)
tree303f6c950c417a56ebf6cf048926c173d87ae8fa
parent5df29709c87654a45585fea07672df51eb9d1050 (diff)
architecture portable version of sendfile
Removes the custom thunking for `sendfile(2)` in favor of using the standard library yscall function and constants. This allows ziggetty to be portable across architectures. Where available, the 64-bit compatible `sendfile64(2)` is called. This changeset also wraps the sendfile implementation to turn errno-style errors into Zig errors.
-rw-r--r--main.zig66
1 files changed, 50 insertions, 16 deletions
diff --git a/main.zig b/main.zig
index 0c1e15c..c1b78dd 100644
--- a/main.zig
+++ b/main.zig
@@ -3,13 +3,12 @@
// file, You can obtain one at https://mozilla.org/MPL/2.0/.
const std = @import("std");
+const builtin = @import("builtin");
const net = std.net;
const os = std.os;
const fs = std.fs;
const heap = std.heap;
-const SYS_sendfile = 40;
-
pub fn main() !void {
var act = os.Sigaction{
.sigaction = os.SIG_IGN,
@@ -42,9 +41,12 @@ pub fn main() !void {
"HTTP/1.1 200 OK\r\nServer: ziggetty\r\nConnection: closed\r\nContent-Length: {}\r\n\r\n",
.{stat.size},
) catch unreachable;
-
+ errdefer allocator.free(hdr);
try conn.file.write(hdr);
- _ = sendfile(conn.file.handle, f.handle, 0, stat.size);
+
+ // TODO: remove this cast
+ const size = @intCast(usize, stat.size);
+ const sent = try sendfile(conn.file.handle, f.handle, null, size);
conn.file.close();
os.exit(0);
},
@@ -55,18 +57,50 @@ pub fn main() !void {
}
}
-fn sendfile(outfd: i32, infd: i32, offset: u64, count: usize) usize {
- return syscall4(SYS_sendfile, @bitCast(usize, @as(isize, outfd)), @bitCast(usize, @as(isize, infd)), offset, count);
+const SendFileError = error{
+ InputOutput,
+ NoMem,
+ Overflow,
+ Unseekable,
+ WouldBlock,
+} || os.UnexpectedError;
+
+fn sendfile(outfd: os.fd_t, infd: os.fd_t, offset: ?*u64, count: usize) SendFileError!usize {
+ while (true) {
+ var rc: usize = undefined;
+ var err: usize = undefined;
+ if (builtin.os == .linux) {
+ rc = _sendfile(outfd, infd, offset, count);
+ err = os.errno(rc);
+ } else {
+ @compileError("sendfile unimplemented for this target");
+ }
+
+ switch (err) {
+ 0 => return @intCast(usize, rc),
+ else => return os.unexpectedErrno(err),
+
+ os.EBADF => unreachable,
+ os.EINVAL => unreachable,
+ os.EFAULT => unreachable,
+ os.EAGAIN => if (std.event.Loop.instance) |loop| {
+ loop.waitUntilFdWritable(outfd);
+ continue;
+ } else {
+ return error.WouldBlock;
+ },
+ os.EIO => return error.InputOutput,
+ os.ENOMEM => return error.NoMem,
+ os.EOVERFLOW => return error.Overflow,
+ os.ESPIPE => return error.Unseekable,
+ }
+ }
}
-fn syscall4(number: usize, arg1: usize, arg2: usize, arg3: usize, arg4: usize) usize {
- return asm volatile ("syscall"
- : [ret] "={rax}" (-> usize)
- : [number] "{rax}" (number),
- [arg1] "{rdi}" (arg1),
- [arg2] "{rsi}" (arg2),
- [arg3] "{rdx}" (arg3),
- [arg4] "{r10}" (arg4)
- : "rcx", "r11", "memory"
- );
+fn _sendfile(outfd: i32, infd: i32, offset: ?*u64, count: usize) usize {
+ if (@hasDecl(os, "SYS_sendfile64")) {
+ return std.os.linux.syscall4(os.SYS_sendfile64, @bitCast(usize, @as(isize, outfd)), @bitCast(usize, @as(isize, infd)), @ptrToInt(offset), count);
+ } else {
+ return std.os.linux.syscall4(os.SYS_sendfile, @bitCast(usize, @as(isize, outfd)), @bitCast(usize, @as(isize, infd)), @ptrToInt(offset), count);
+ }
}