dope-uring 0.44.0

Owned io_uring backend for dope
Documentation
use std::{
    mem,
    os::fd::{AsRawFd as _, BorrowedFd},
    ptr,
};

use dope_sys::io::socket::route::{
    Attach, Plan, Source,
    count::Index,
    install::{Error, Operation},
};

use crate::Uring;

mod program;

pub struct Installer<'a> {
    plan: Plan,
    filter: &'a mut [libc::sock_filter],
}

impl Attach for Installer<'_> {
    fn try_attach(&self, socket: BorrowedFd<'_>) -> Result<(), Error> {
        let mut code = [program::EMPTY; program::MAX];
        attach(
            socket,
            program::build(&mut code, self.plan, None),
            Operation::ProgramAttach,
        )
    }

    fn try_filter(&mut self, key: Index, socket: BorrowedFd<'_>) -> Result<(), Error> {
        let index = self.filter.len() - 3;
        self.filter[index].k = key.into_raw() as u32;
        attach(socket, self.filter, Operation::FilterAttach)
    }
}

impl Source for Uring {
    type Storage = [libc::sock_filter; program::MAX];
    type Install<'a> = Installer<'a>;
    type Ready = ();
    type Lease<'a> = BorrowedFd<'a>;

    const STORAGE: Self::Storage = [program::EMPTY; program::MAX];

    #[inline]
    fn try_prepare(
        filter: &mut Self::Storage,
        plan: Plan,
    ) -> Result<(Self::Install<'_>, Self::Ready), Plan> {
        let installer = Installer {
            plan,
            filter: program::build(filter, plan, Some(Index::ZERO)),
        };
        Ok((installer, ()))
    }

    fn lease<'a>((): &(), socket: BorrowedFd<'a>) -> Self::Lease<'a> {
        socket
    }
}

fn attach(
    socket: BorrowedFd<'_>,
    code: &[libc::sock_filter],
    operation: Operation,
) -> Result<(), Error> {
    let program = libc::sock_fprog {
        len: code.len() as u16,
        filter: code.as_ptr().cast_mut(),
    };
    let option = match operation {
        Operation::ProgramAttach => libc::SO_ATTACH_REUSEPORT_CBPF,
        Operation::FilterAttach => libc::SO_ATTACH_FILTER,
    };
    // SAFETY: the program and its complete instruction array outlive setsockopt.
    let result = unsafe {
        libc::setsockopt(
            socket.as_raw_fd(),
            libc::SOL_SOCKET,
            option,
            ptr::from_ref(&program).cast(),
            mem::size_of_val(&program) as libc::socklen_t,
        )
    };
    // SAFETY: setsockopt returned zero or -1; errno has not been changed.
    unsafe { dope_sys::kernel::raw::Status::new(result).try_zero::<Uring, dope_sys::Errno>() }
        .map_err(|errno| Error { operation, errno })
}