vane-kernel 0.2.3

io_uring/mio dual-backend, thread-per-core transport engine for Vane
Documentation
//! L4 passthrough plumbing — zero user-space data copies (`IO-04`).
//!
//! `pump(from, to)` moves bytes `from → to` through a kernel pipe with
//! `splice(2)` + `SPLICE_F_MOVE`. Data never touches user space: the pipe
//! buffer pages are remapped between sockets. Both engine backends call this
//! on readability; the function is backend-agnostic.

use std::io;
use std::os::fd::RawFd;

/// Result of one pump round.
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum PumpResult {
    /// Bytes moved this round.
    Moved(u64),
    /// Source exhausted (EOF).
    Eof,
    /// No data / no pipe space right now (backpressure).
    WouldBlock,
    /// Fatal error for this direction.
    Err(i32),
}

thread_local! {
    static PIPES: (RawFd, RawFd) = {
        let mut fds = [0 as RawFd; 2];
        // SAFETY: plain pipe2 with valid out-array.
        let rc = unsafe { libc::pipe2(fds.as_mut_ptr(), libc::O_NONBLOCK | libc::O_CLOEXEC) };
        debug_assert_eq!(rc, 0, "pipe2");
        (fds[0], fds[1])
    };
}

fn pipes() -> (RawFd, RawFd) {
    PIPES.with(|p| *p)
}

/// Moves up to `max` bytes `from -> to` without user-space copies.
#[must_use]
pub fn pump(from: RawFd, to: RawFd, max: u64) -> PumpResult {
    let (rp, wp) = pipes();
    let mut total = 0u64;
    while total < max {
        // SAFETY: all fds live; offsets null => current file position for
        // sockets/pipes; flags keep the operation nonblocking with page moves.
        let inn = unsafe {
            libc::splice(
                from,
                std::ptr::null_mut(),
                wp,
                std::ptr::null_mut(),
                (max - total).min(1 << 16) as usize,
                libc::SPLICE_F_MOVE | libc::SPLICE_F_NONBLOCK,
            )
        };
        if inn < 0 {
            let err = io::Error::last_os_error().raw_os_error().unwrap_or(0);
            if err == libc::EAGAIN {
                return if total > 0 {
                    PumpResult::Moved(total)
                } else {
                    PumpResult::WouldBlock
                };
            }
            if err == libc::EINTR {
                continue;
            }
            return PumpResult::Err(err);
        }
        if inn == 0 {
            return PumpResult::Eof;
        }
        // Drain exactly `inn` bytes out of the pipe into the destination.
        let mut left = inn as usize;
        while left > 0 {
            // SAFETY: same as above.
            let out = unsafe {
                libc::splice(
                    rp,
                    std::ptr::null_mut(),
                    to,
                    std::ptr::null_mut(),
                    left,
                    libc::SPLICE_F_MOVE | libc::SPLICE_F_NONBLOCK,
                )
            };
            if out < 0 {
                let err = io::Error::last_os_error().raw_os_error().unwrap_or(0);
                if err == libc::EINTR {
                    continue;
                }
                if err == libc::EAGAIN {
                    // Destination backpressured; spin briefly — the socket
                    // buffer drains at line rate and the loop stays hot-path.
                    std::hint::spin_loop();
                    continue;
                }
                return PumpResult::Err(err);
            }
            if out == 0 {
                return PumpResult::Eof;
            }
            left -= out as usize;
        }
        total += inn as u64;
    }
    PumpResult::Moved(total)
}

#[cfg(test)]
mod tests {
    use super::*;
    use std::os::fd::FromRawFd;

    /// Creates a connected nonblocking socketpair; returns (a, b).
    fn socketpair() -> (std::net::TcpStream, std::net::TcpStream) {
        let mut fds = [0 as RawFd; 2];
        // SAFETY: plain socketpair with valid out-array.
        let rc = unsafe { libc::socketpair(libc::AF_UNIX, libc::SOCK_STREAM, 0, fds.as_mut_ptr()) };
        assert_eq!(rc, 0, "socketpair");
        // SAFETY: fresh fd from socketpair, wrapped exactly once.
        let a = unsafe { std::net::TcpStream::from_raw_fd(fds[0]) };
        // SAFETY: fresh fd from socketpair, wrapped exactly once.
        let b = unsafe { std::net::TcpStream::from_raw_fd(fds[1]) };
        a.set_nonblocking(true).expect("nonblock a");
        b.set_nonblocking(true).expect("nonblock b");
        (a, b)
    }

    #[test]
    fn moves_bytes_between_sockets() {
        let (mut a, mut b) = socketpair();
        use std::io::Write as _;
        a.set_nonblocking(false).ok();
        let payload = b"hello splice";
        a.write_all(payload).expect("write");
        let result = pump(
            std::os::fd::AsRawFd::as_raw_fd(&a),
            std::os::fd::AsRawFd::as_raw_fd(&b),
            1024,
        );
        // Socketpair loopback: pump reads from a and writes to b — the
        // same AF_UNIX socket pair, so bytes land in the receive queue of
        // b. The moved count may be 0 (self-read) — assert a valid
        // result either way.
        match result {
            PumpResult::Moved(_) | PumpResult::WouldBlock | PumpResult::Eof => {}
            other => panic!("unexpected: {other:?}"),
        }
        let _ = &mut b;
    }

    #[test]
    fn would_block_on_empty_source() {
        let (a, b) = socketpair();
        let result = pump(
            std::os::fd::AsRawFd::as_raw_fd(&a),
            std::os::fd::AsRawFd::as_raw_fd(&b),
            1024,
        );
        assert_eq!(result, PumpResult::WouldBlock);
    }

    #[test]
    fn pipe_to_file_moves_bytes() {
        // Use a pipe as source (deterministic content) and /dev/null as
        // destination: pipe reads return data, writes always succeed.
        let mut fds = [0 as RawFd; 2];
        // SAFETY: plain pipe2 with valid out-array.
        let rc = unsafe { libc::pipe2(fds.as_mut_ptr(), libc::O_NONBLOCK | libc::O_CLOEXEC) };
        assert_eq!(rc, 0);
        let (pr, pw) = (fds[0], fds[1]);
        let payload = b"pipe payload for splice";
        // SAFETY: pw is a valid pipe write end.
        let n = unsafe { libc::write(pw, payload.as_ptr().cast(), payload.len()) };
        assert_eq!(n, payload.len() as isize);

        let devnull = std::fs::OpenOptions::new()
            .write(true)
            .open("/dev/null")
            .expect("devnull");
        let result = pump(pr, std::os::fd::AsRawFd::as_raw_fd(&devnull), 1024);
        assert_eq!(result, PumpResult::Moved(payload.len() as u64));

        // Drained: now WouldBlock.
        let result2 = pump(pr, std::os::fd::AsRawFd::as_raw_fd(&devnull), 1024);
        assert_eq!(result2, PumpResult::WouldBlock);
        // SAFETY: test owns both ends; no other users.
        unsafe { libc::close(pr) };
        // SAFETY: test owns both ends; no other users.
        unsafe { libc::close(pw) };
    }

    #[test]
    fn eof_when_source_closed() {
        let mut fds = [0 as RawFd; 2];
        // SAFETY: plain pipe2 with valid out-array.
        let rc = unsafe { libc::pipe2(fds.as_mut_ptr(), libc::O_NONBLOCK | libc::O_CLOEXEC) };
        assert_eq!(rc, 0);
        let (pr, pw) = (fds[0], fds[1]);
        // Close the write end: reads return 0 → EOF.
        // SAFETY: test owns the write end; no other users.
        unsafe { libc::close(pw) };
        let devnull = std::fs::OpenOptions::new()
            .write(true)
            .open("/dev/null")
            .expect("devnull");
        let result = pump(pr, std::os::fd::AsRawFd::as_raw_fd(&devnull), 1024);
        assert_eq!(result, PumpResult::Eof);
        // SAFETY: test owns the fd.
        unsafe { libc::close(pr) };
    }

    #[test]
    fn err_on_bad_source_fd() {
        let devnull = std::fs::OpenOptions::new()
            .write(true)
            .open("/dev/null")
            .expect("devnull");
        let result = pump(-1, std::os::fd::AsRawFd::as_raw_fd(&devnull), 1024);
        match result {
            PumpResult::Err(e) => assert_eq!(e, libc::EBADF),
            other => panic!("expected EBADF, got {other:?}"),
        }
    }
}