Skip to main content

dope_uring/sockets/reuse/
mod.rs

1use std::{
2    mem,
3    os::fd::{AsRawFd as _, BorrowedFd},
4    ptr,
5};
6
7use dope_sys::io::socket::route::{
8    Attach, Plan, Source,
9    count::Index,
10    install::{Error, Operation},
11};
12
13use crate::Uring;
14
15mod program;
16
17pub struct Installer<'a> {
18    plan: Plan,
19    filter: &'a mut [libc::sock_filter],
20}
21
22impl Attach for Installer<'_> {
23    fn try_attach(&self, socket: BorrowedFd<'_>) -> Result<(), Error> {
24        let mut code = [program::EMPTY; program::MAX];
25        attach(
26            socket,
27            program::build(&mut code, self.plan, None),
28            Operation::ProgramAttach,
29        )
30    }
31
32    fn try_filter(&mut self, key: Index, socket: BorrowedFd<'_>) -> Result<(), Error> {
33        let index = self.filter.len() - 3;
34        self.filter[index].k = key.into_raw() as u32;
35        attach(socket, self.filter, Operation::FilterAttach)
36    }
37}
38
39impl Source for Uring {
40    type Storage = [libc::sock_filter; program::MAX];
41    type Install<'a> = Installer<'a>;
42    type Ready = ();
43    type Lease<'a> = BorrowedFd<'a>;
44
45    const STORAGE: Self::Storage = [program::EMPTY; program::MAX];
46
47    #[inline]
48    fn try_prepare(
49        filter: &mut Self::Storage,
50        plan: Plan,
51    ) -> Result<(Self::Install<'_>, Self::Ready), Plan> {
52        let installer = Installer {
53            plan,
54            filter: program::build(filter, plan, Some(Index::ZERO)),
55        };
56        Ok((installer, ()))
57    }
58
59    fn lease<'a>((): &(), socket: BorrowedFd<'a>) -> Self::Lease<'a> {
60        socket
61    }
62}
63
64fn attach(
65    socket: BorrowedFd<'_>,
66    code: &[libc::sock_filter],
67    operation: Operation,
68) -> Result<(), Error> {
69    let program = libc::sock_fprog {
70        len: code.len() as u16,
71        filter: code.as_ptr().cast_mut(),
72    };
73    let option = match operation {
74        Operation::ProgramAttach => libc::SO_ATTACH_REUSEPORT_CBPF,
75        Operation::FilterAttach => libc::SO_ATTACH_FILTER,
76    };
77    // SAFETY: the program and its complete instruction array outlive setsockopt.
78    let result = unsafe {
79        libc::setsockopt(
80            socket.as_raw_fd(),
81            libc::SOL_SOCKET,
82            option,
83            ptr::from_ref(&program).cast(),
84            mem::size_of_val(&program) as libc::socklen_t,
85        )
86    };
87    // SAFETY: setsockopt returned zero or -1; errno has not been changed.
88    unsafe { dope_sys::kernel::raw::Status::new(result).try_zero::<Uring, dope_sys::Errno>() }
89        .map_err(|errno| Error { operation, errno })
90}