| ... | @@ -3498,6 +3498,121 @@ pub fn send( | ... | @@ -3498,6 +3498,121 @@ pub fn send( |
| 3498 | return sendto(sockfd, buf, flags, null, 0); | 3498 | return sendto(sockfd, buf, flags, null, 0); |
| 3499 | } | 3499 | } |
| 3500 | | 3500 | |
| | 3501 | pub const SendFileError = error{ |
| | 3502 | /// There was an unspecified error while reading from infd. |
| | 3503 | InputOutput, |
| | 3504 | |
| | 3505 | /// There was insufficient resources for processing. |
| | 3506 | SystemResources, |
| | 3507 | |
| | 3508 | /// The value provided for count overflows the maximum size of either |
| | 3509 | /// infd or outfd. |
| | 3510 | Overflow, |
| | 3511 | |
| | 3512 | /// Offset was provided, but infd is not seekable. |
| | 3513 | Unseekable, |
| | 3514 | |
| | 3515 | /// The outfd is marked nonblocking and the requested operation would block, and |
| | 3516 | /// there is no global event loop configured. |
| | 3517 | WouldBlock, |
| | 3518 | } || WriteError || UnexpectedError; |
| | 3519 | |
| | 3520 | pub const sf_hdtr = struct { |
| | 3521 | headers: []iovec_const, |
| | 3522 | trailers: []iovec_const, |
| | 3523 | }; |
| | 3524 | |
| | 3525 | /// Transfer data between file descriptors. |
| | 3526 | /// |
| | 3527 | /// The `sendfile` call copies `count` bytes from one file descriptor to another within the kernel. This can |
| | 3528 | /// be more performant than transferring data from the kernel to user space and back, such as with |
| | 3529 | /// `read` and `write` calls. |
| | 3530 | /// |
| | 3531 | /// The `infd` should be a file descriptor opened for reading, and `outfd` should be a file descriptor |
| | 3532 | /// opened for writing. Copying will begin at `offset`, if not null, which will be updated to reflect |
| | 3533 | /// the number of bytes read. If `offset` is null, the copying will begin at the current seek position, |
| | 3534 | /// and the file position will be updated. |
| | 3535 | pub fn sendfile(infd: fd_t, outfd: fd_t, offset: u64, count: usize, optional_hdtr: ?*const sf_hdtr, flags: u32) SendFileError!usize { |
| | 3536 | // XXX: check if offset is > length of file, return 0 bytes written |
| | 3537 | // XXX: document systems where headers are sent atomically. |
| | 3538 | // XXX: compute new offset on EINTR/EAGAIN |
| | 3539 | var rc: usize = undefined; |
| | 3540 | var err: usize = undefined; |
| | 3541 | if (builtin.os == .linux) { |
| | 3542 | while (true) { |
| | 3543 | try lseek_SET(infd, offset); |
| | 3544 | |
| | 3545 | if (optional_hdtr) |hdtr| { |
| | 3546 | try writev(outfd, hdtr.headers); |
| | 3547 | } |
| | 3548 | |
| | 3549 | rc = system.sendfile(outfd, infd, null, count); |
| | 3550 | err = errno(rc); |
| | 3551 | |
| | 3552 | if (optional_hdtr) |hdtr| { |
| | 3553 | try writev(outfd, hdtr.trailers); |
| | 3554 | } |
| | 3555 | |
| | 3556 | switch (err) { |
| | 3557 | 0 => return @intCast(usize, rc), |
| | 3558 | else => return unexpectedErrno(err), |
| | 3559 | |
| | 3560 | EBADF => unreachable, |
| | 3561 | EINVAL => unreachable, |
| | 3562 | EFAULT => unreachable, |
| | 3563 | EAGAIN => if (std.event.Loop.instance) |loop| { |
| | 3564 | loop.waitUntilFdWritable(outfd); |
| | 3565 | continue; |
| | 3566 | } else { |
| | 3567 | return error.WouldBlock; |
| | 3568 | }, |
| | 3569 | EIO => return error.InputOutput, |
| | 3570 | ENOMEM => return error.SystemResources, |
| | 3571 | EOVERFLOW => return error.Overflow, |
| | 3572 | ESPIPE => return error.Unseekable, |
| | 3573 | } |
| | 3574 | } |
| | 3575 | } else if (builtin.os == .freebsd) { |
| | 3576 | while (true) { |
| | 3577 | var rcount: u64 = 0; |
| | 3578 | var hdtr: std.c.sf_hdtr = undefined; |
| | 3579 | if (optional_hdtr) |h| { |
| | 3580 | hdtr = std.c.sf_hdtr{ |
| | 3581 | .headers = h.headers.ptr, |
| | 3582 | .hdr_cnt = @intCast(c_int, h.headers.len), |
| | 3583 | .trailers = h.trailers.ptr, |
| | 3584 | .trl_cnt = @intCast(c_int, h.trailers.len), |
| | 3585 | }; |
| | 3586 | } |
| | 3587 | err = errno(system.sendfile(infd, outfd, offset, count, &hdtr, &rcount, @intCast(c_int, flags))); |
| | 3588 | switch (err) { |
| | 3589 | 0 => return @intCast(usize, rcount), |
| | 3590 | else => return unexpectedErrno(err), |
| | 3591 | |
| | 3592 | EBADF => unreachable, |
| | 3593 | EFAULT => unreachable, |
| | 3594 | EINVAL => unreachable, |
| | 3595 | ENOTCAPABLE => unreachable, |
| | 3596 | ENOTCONN => unreachable, |
| | 3597 | ENOTSOCK => unreachable, |
| | 3598 | EAGAIN => if (std.event.Loop.instance) |loop| { |
| | 3599 | loop.waitUntilFdWritable(outfd); |
| | 3600 | continue; |
| | 3601 | } else { |
| | 3602 | return error.WouldBlock; |
| | 3603 | }, |
| | 3604 | EBUSY => return error.DeviceBusy, |
| | 3605 | EINTR => continue, |
| | 3606 | EIO => return error.InputOutput, |
| | 3607 | ENOBUFS => return error.SystemResources, |
| | 3608 | EPIPE => return error.BrokenPipe, |
| | 3609 | } |
| | 3610 | } |
| | 3611 | } else { |
| | 3612 | @compileError("sendfile unimplemented for this target"); |
| | 3613 | } |
| | 3614 | } |
| | 3615 | |
| 3501 | pub const PollError = error{ | 3616 | pub const PollError = error{ |
| 3502 | /// The kernel had no space to allocate file descriptor tables. | 3617 | /// The kernel had no space to allocate file descriptor tables. |
| 3503 | SystemResources, | 3618 | SystemResources, |