fips_core/upper/
tun_write.rs1use std::collections::VecDeque;
2use std::sync::{Arc, Condvar, Mutex, MutexGuard, mpsc};
3
4use crate::transport::PacketBuffer;
5
6#[derive(Debug)]
7struct TunWriteQueue {
8 state: Mutex<TunWriteState>,
9 ready: Condvar,
10}
11
12#[derive(Debug)]
13struct TunWriteState {
14 priority: VecDeque<TunWritePacket>,
15 senders: usize,
16 receiver_alive: bool,
17}
18
19#[derive(Debug)]
20#[cfg_attr(
21 not(any(test, target_os = "linux", target_os = "macos", windows)),
22 allow(dead_code)
23)]
24pub(crate) enum TunWritePacket {
25 Vec(Vec<u8>),
26 Pooled(PacketBuffer),
27}
28
29impl TunWritePacket {
30 #[cfg_attr(
31 not(any(test, target_os = "linux", target_os = "macos", windows)),
32 allow(dead_code)
33 )]
34 pub(crate) fn as_slice(&self) -> &[u8] {
35 match self {
36 Self::Vec(packet) => packet,
37 Self::Pooled(packet) => packet.as_slice(),
38 }
39 }
40
41 #[cfg(any(test, target_os = "linux", target_os = "macos", windows))]
42 pub(crate) fn as_mut_slice(&mut self) -> &mut [u8] {
43 match self {
44 Self::Vec(packet) => packet,
45 Self::Pooled(packet) => packet.as_mut_slice(),
46 }
47 }
48
49 #[cfg(any(test, target_os = "linux", target_os = "macos", windows))]
50 pub(crate) fn len(&self) -> usize {
51 self.as_slice().len()
52 }
53}
54
55impl From<Vec<u8>> for TunWritePacket {
56 fn from(packet: Vec<u8>) -> Self {
57 Self::Vec(packet)
58 }
59}
60
61impl From<PacketBuffer> for TunWritePacket {
62 fn from(packet: PacketBuffer) -> Self {
63 Self::Pooled(packet)
64 }
65}
66
67#[derive(Debug)]
69pub struct TunTx {
70 queue: Arc<TunWriteQueue>,
71}
72
73#[derive(Debug)]
75#[cfg(any(test, target_os = "linux", target_os = "macos", windows))]
76pub(crate) struct TunRx {
77 queue: Arc<TunWriteQueue>,
78}
79
80impl Clone for TunTx {
81 fn clone(&self) -> Self {
82 {
83 let mut state = self.queue.lock();
84 state.senders = state.senders.saturating_add(1);
85 }
86 Self {
87 queue: Arc::clone(&self.queue),
88 }
89 }
90}
91
92impl Drop for TunTx {
93 fn drop(&mut self) {
94 let should_notify = {
95 let mut state = self.queue.lock();
96 state.senders = state.senders.saturating_sub(1);
97 state.senders == 0
98 };
99 if should_notify {
100 self.queue.ready.notify_all();
101 }
102 }
103}
104
105impl TunTx {
106 pub fn send(&self, packet: Vec<u8>) -> Result<(), mpsc::SendError<Vec<u8>>> {
108 let mut state = self.queue.lock();
109 if !state.receiver_alive {
110 return Err(mpsc::SendError(packet));
111 }
112
113 state.priority.push_back(TunWritePacket::Vec(packet));
114 drop(state);
115 self.queue.ready.notify_one();
116 Ok(())
117 }
118
119 pub(crate) fn send_batch<I, P>(&self, packets: I) -> usize
122 where
123 I: IntoIterator<Item = P>,
124 P: Into<TunWritePacket>,
125 {
126 let packets = packets.into_iter();
127 let mut state = self.queue.lock();
128 if !state.receiver_alive {
129 return packets.count();
130 }
131
132 let mut sent = 0;
133 for packet in packets {
134 state.priority.push_back(packet.into());
135 sent += 1;
136 }
137 drop(state);
138 if sent > 0 {
139 self.queue.ready.notify_one();
140 }
141 0
142 }
143}
144
145#[cfg(any(test, target_os = "linux", target_os = "macos", windows))]
146impl TunRx {
147 pub(crate) fn recv(&self) -> Option<TunWritePacket> {
148 let mut state = self.queue.lock();
149 loop {
150 if let Some(packet) = state.priority.pop_front() {
151 return Some(packet);
152 }
153 if state.senders == 0 {
154 state.receiver_alive = false;
155 return None;
156 }
157 state = self
158 .queue
159 .ready
160 .wait(state)
161 .unwrap_or_else(|poisoned| poisoned.into_inner());
162 }
163 }
164
165 #[cfg(any(test, target_os = "linux"))]
166 pub(crate) fn try_recv_packet(&self) -> Result<TunWritePacket, mpsc::TryRecvError> {
167 let mut state = self.queue.lock();
168 if let Some(packet) = state.priority.pop_front() {
169 return Ok(packet);
170 }
171 if state.senders == 0 {
172 state.receiver_alive = false;
173 Err(mpsc::TryRecvError::Disconnected)
174 } else {
175 Err(mpsc::TryRecvError::Empty)
176 }
177 }
178}
179
180#[cfg(any(test, target_os = "linux", target_os = "macos", windows))]
181impl Drop for TunRx {
182 fn drop(&mut self) {
183 let mut state = self.queue.lock();
184 state.receiver_alive = false;
185 state.priority.clear();
186 drop(state);
187 self.queue.ready.notify_all();
188 }
189}
190
191impl TunWriteQueue {
192 fn lock(&self) -> MutexGuard<'_, TunWriteState> {
193 self.state
194 .lock()
195 .unwrap_or_else(|poisoned| poisoned.into_inner())
196 }
197}
198
199#[cfg(any(test, target_os = "linux", target_os = "macos", windows))]
200pub(crate) fn write_channel() -> (TunTx, TunRx) {
201 let queue = Arc::new(TunWriteQueue {
202 state: Mutex::new(TunWriteState {
203 priority: VecDeque::new(),
204 senders: 1,
205 receiver_alive: true,
206 }),
207 ready: Condvar::new(),
208 });
209 (
210 TunTx {
211 queue: Arc::clone(&queue),
212 },
213 TunRx { queue },
214 )
215}