netlink_socket2/
chained.rs1use std::{
2 fmt,
3 io::{self, IoSlice},
4 marker::{Send, Sync},
5 sync::Arc,
6};
7
8use netlink_bindings::traits::NetlinkChained;
9
10use super::{sock::NetlinkReplyInner, NetlinkSocket, Socket};
11use crate::{ReplyError, RECV_BUF_SIZE};
12
13impl NetlinkSocket {
14 #[super::strip_async]
22 pub async fn request_chained<'a, Chained>(
23 &'a mut self,
24 request: &'a Chained,
25 ) -> io::Result<NetlinkReplyChained<'a>>
26 where
27 Chained: NetlinkChained + Send + Sync,
28 {
29 let sock = Self::get_socket_cached(&mut self.sock, request.protonum())?;
30
31 Self::write_buf(sock, &[IoSlice::new(request.payload())]).await?;
32
33 let mut done = Bits::with_len(request.chain_len());
34 for i in 0..request.chain_len() {
35 let Some(has_ack) = request.supports_ack(i) else {
36 break;
37 };
38 if !has_ack {
39 done.set(i);
40 }
41 }
42
43 Ok(NetlinkReplyChained {
44 sock,
45 buf: &mut self.buf,
46 request,
47 inner: NetlinkReplyInner {
48 buf_offset: 0,
49 buf_read: 0,
50 },
51 done,
52 })
53 }
54}
55
56pub struct NetlinkReplyChained<'sock> {
57 inner: NetlinkReplyInner,
58 request: &'sock (dyn NetlinkChained + Send + Sync),
59 sock: &'sock mut Socket,
60 buf: &'sock mut Arc<[u8; RECV_BUF_SIZE]>,
61 done: Bits,
62}
63
64impl NetlinkReplyChained<'_> {
65 #[super::strip_async]
66 pub async fn recv_all(&mut self) -> Result<(), ReplyError> {
67 while let Some(res) = self.recv().await {
68 res?;
69 }
70 Ok(())
71 }
72
73 #[super::strip_async]
74 pub async fn recv(&mut self) -> Option<Result<(), ReplyError>> {
75 if self.done.is_all() {
76 return None;
77 }
78
79 let buf = Arc::make_mut(self.buf);
80
81 loop {
82 match self.inner.recv(self.sock, buf).await {
83 Err(io_err) => {
84 self.done.set_all();
85 return Some(Err(io_err.into()));
86 }
87 Ok((seq, _type, res)) => {
88 let Some(index) = self.request.get_index(seq) else {
89 continue;
90 };
91 match res {
92 Ok(_) => return Some(Ok(())),
93 Err(mut err) => {
94 if err.code.raw_os_error().unwrap() == 0 {
95 self.done.set(index);
96 return Some(Ok(()));
97 } else {
98 self.done.set_all();
99 err.chained_name = Some(self.request.name(index));
100 if err.has_context() {
101 err.lookup = Some(self.request.lookup(index));
102 err.reply_buf = Some(self.buf.clone());
103 }
104 return Some(Err(err));
105 };
106 }
107 }
108 }
109 };
110 }
111 }
112}
113
114#[derive(Clone)]
115enum Bits {
116 Inline(u64),
117 Vec(Vec<u64>),
118}
119
120impl fmt::Debug for Bits {
121 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
122 let n = self.count_zeros();
123 write!(f, "{n} replies pending")
124 }
125}
126
127impl Bits {
128 fn with_len(len: usize) -> Self {
129 if len < 64 {
130 Self::Inline(u64::MAX << (len % 64))
131 } else {
132 let mut vec = vec![0; len.div_ceil(64)];
133 *vec.last_mut().unwrap() |= u64::MAX << (len % 64);
134 Self::Vec(vec)
135 }
136 }
137
138 fn set(&mut self, index: usize) {
139 match self {
140 Self::Inline(w) => *w |= 1u64 << index,
141 Self::Vec(bits) => bits[index / 64] |= 1u64 << (index % 64),
142 }
143 }
144
145 fn is_all(&self) -> bool {
146 match self {
147 Self::Inline(w) => *w == u64::MAX,
148 Self::Vec(bits) => bits.iter().all(|w| *w == u64::MAX),
149 }
150 }
151
152 fn set_all(&mut self) {
153 match self {
154 Self::Inline(w) => *w = u64::MAX,
155 Self::Vec(bits) => bits.iter_mut().for_each(|w| *w = u64::MAX),
156 }
157 }
158
159 fn count_zeros(&self) -> usize {
160 match self {
161 Self::Inline(w) => w.count_zeros() as usize,
162 Self::Vec(bits) => bits.iter().map(|s| s.count_zeros() as usize).sum(),
163 }
164 }
165}
166
167#[cfg(test)]
168mod test {
169 use super::*;
170
171 #[allow(unused)]
172 trait SpawnCompatible: Send {}
173 impl<'a> SpawnCompatible for NetlinkReplyChained<'a> {}
174}