dope_uring/sockets/reuse/
mod.rs1use 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; program::MAX],
20 length: usize,
21}
22
23impl Attach for Installer<'_> {
24 fn try_attach(&self, socket: BorrowedFd<'_>) -> Result<(), Error> {
25 let mut code = [program::EMPTY; program::MAX];
26 let length = program::build(&mut code, self.plan, None);
27 attach(socket, &code[..length], Operation::ProgramAttach)
28 }
29
30 fn try_filter(&mut self, key: Index, socket: BorrowedFd<'_>) -> Result<(), Error> {
31 self.filter[self.length - 3].k = key.into_raw() as u32;
32 attach(socket, &self.filter[..self.length], Operation::FilterAttach)
33 }
34}
35
36impl Source for Uring {
37 type Storage = [libc::sock_filter; program::MAX];
38 type Install<'a> = Installer<'a>;
39 type Ready = ();
40 type Lease<'a> = BorrowedFd<'a>;
41
42 const STORAGE: Self::Storage = [program::EMPTY; program::MAX];
43
44 #[inline]
45 fn try_prepare(
46 filter: &mut Self::Storage,
47 plan: Plan,
48 ) -> Result<(Self::Install<'_>, Self::Ready), Plan> {
49 let length = program::build(filter, plan, Some(Index::ZERO));
50 let installer = Installer {
51 plan,
52 filter,
53 length,
54 };
55 Ok((installer, ()))
56 }
57
58 fn lease<'a>((): &(), socket: BorrowedFd<'a>) -> Self::Lease<'a> {
59 socket
60 }
61}
62
63fn attach(
64 socket: BorrowedFd<'_>,
65 code: &[libc::sock_filter],
66 operation: Operation,
67) -> Result<(), Error> {
68 let program = libc::sock_fprog {
69 len: code.len() as u16,
70 filter: code.as_ptr().cast_mut(),
71 };
72 let option = match operation {
73 Operation::ProgramAttach => libc::SO_ATTACH_REUSEPORT_CBPF,
74 Operation::FilterAttach => libc::SO_ATTACH_FILTER,
75 };
76 let result = unsafe {
78 libc::setsockopt(
79 socket.as_raw_fd(),
80 libc::SOL_SOCKET,
81 option,
82 ptr::from_ref(&program).cast(),
83 mem::size_of_val(&program) as libc::socklen_t,
84 )
85 };
86 unsafe { dope_sys::kernel::raw::Status::new(result).try_zero::<Uring, dope_sys::Errno>() }
88 .map_err(|errno| Error { operation, errno })
89}