1use std::collections::HashMap;
49use std::io;
50use std::net::{Ipv4Addr, SocketAddr};
51use std::sync::atomic::{AtomicU64, AtomicUsize, Ordering};
52use std::sync::{Arc, Mutex, MutexGuard};
53use std::time::Duration;
54
55use tokio::io::{AsyncReadExt, AsyncWriteExt};
56use tokio::net::tcp::{OwnedReadHalf, OwnedWriteHalf};
57use tokio::net::{TcpListener, TcpStream};
58use tokio::sync::watch;
59use tokio::task::{JoinHandle, JoinSet};
60
61#[derive(Clone, Copy, Debug, PartialEq, Eq)]
63#[non_exhaustive]
64pub enum Cut {
65 Up(usize),
68 Down(usize),
72 After(Duration),
74 Now,
76}
77
78#[derive(Clone, Copy, Debug, PartialEq, Eq)]
80pub enum Direction {
81 Up,
83 Down,
85}
86
87pub struct Tear {
91 addr: SocketAddr,
92 shared: Arc<Shared>,
93 accept: JoinHandle<()>,
94}
95
96struct Shared {
97 upstream: SocketAddr,
98 rules: Mutex<Rules>,
99 flowing: watch::Sender<bool>,
101 open: Mutex<HashMap<u64, watch::Sender<bool>>>,
103 next: AtomicU64,
104 accepted: AtomicUsize,
105 torn: AtomicUsize,
106 passed_up: AtomicUsize,
107 passed_down: AtomicUsize,
108}
109
110#[derive(Default)]
111struct Rules {
112 up: Option<usize>,
114 down: Option<usize>,
116 offline: bool,
117}
118
119impl Tear {
120 pub async fn start(upstream: SocketAddr) -> io::Result<Self> {
127 let listener = TcpListener::bind((Ipv4Addr::LOCALHOST, 0)).await?;
128 let addr = listener.local_addr()?;
129 let shared = Arc::new(Shared {
130 upstream,
131 rules: Mutex::new(Rules::default()),
132 flowing: watch::Sender::new(true),
133 open: Mutex::new(HashMap::new()),
134 next: AtomicU64::new(0),
135 accepted: AtomicUsize::new(0),
136 torn: AtomicUsize::new(0),
137 passed_up: AtomicUsize::new(0),
138 passed_down: AtomicUsize::new(0),
139 });
140 let accept = tokio::spawn(accept(listener, shared.clone()));
141 Ok(Self { addr, shared, accept })
142 }
143
144 pub fn addr(&self) -> SocketAddr {
146 self.addr
147 }
148
149 pub fn upstream(&self) -> SocketAddr {
151 self.shared.upstream
152 }
153
154 pub fn cut(&self, cut: Cut) {
157 match cut {
158 Cut::Up(bytes) => self.shared.rules().up = Some(bytes),
159 Cut::Down(bytes) => self.shared.rules().down = Some(bytes),
160 Cut::Now => self.shared.tear_open(),
161 Cut::After(delay) => {
162 let shared = Arc::downgrade(&self.shared);
163 tokio::spawn(async move {
164 tokio::time::sleep(delay).await;
165 if let Some(shared) = shared.upgrade() {
166 shared.tear_open();
167 }
168 });
169 }
170 }
171 }
172
173 pub fn disarm(&self) {
175 let mut rules = self.shared.rules();
176 rules.up = None;
177 rules.down = None;
178 }
179
180 pub fn offline(&self) {
183 self.shared.rules().offline = true;
184 self.shared.tear_open();
185 }
186
187 pub fn online(&self) {
189 self.shared.rules().offline = false;
190 }
191
192 pub fn stall(&self) {
195 self.shared.flowing.send_replace(false);
196 }
197
198 pub fn flow(&self) {
200 self.shared.flowing.send_replace(true);
201 }
202
203 pub fn connections(&self) -> usize {
205 self.shared.accepted.load(Ordering::SeqCst)
206 }
207
208 pub fn torn(&self) -> usize {
211 self.shared.torn.load(Ordering::SeqCst)
212 }
213
214 pub fn passed(&self, direction: Direction) -> usize {
217 match direction {
218 Direction::Up => self.shared.passed_up.load(Ordering::SeqCst),
219 Direction::Down => self.shared.passed_down.load(Ordering::SeqCst),
220 }
221 }
222}
223
224impl Drop for Tear {
225 fn drop(&mut self) {
226 self.accept.abort();
229 }
230}
231
232impl std::fmt::Debug for Tear {
233 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
234 f.debug_struct("Tear").field("addr", &self.addr).field("upstream", &self.shared.upstream).finish()
235 }
236}
237
238impl Shared {
239 fn rules(&self) -> MutexGuard<'_, Rules> {
240 lock(&self.rules)
241 }
242
243 fn tear_open(&self) {
244 for switch in lock(&self.open).values() {
245 switch.send_replace(true);
246 }
247 }
248
249 fn take(&self, direction: Direction, len: usize) -> (usize, bool) {
252 let mut rules = self.rules();
253 let budget = match direction {
254 Direction::Up => &mut rules.up,
255 Direction::Down => &mut rules.down,
256 };
257 match budget {
258 None => (len, false),
259 Some(left) if len <= *left => {
260 *left -= len;
261 (len, false)
262 }
263 Some(left) => {
264 let pass = *left;
265 *budget = None;
266 (pass, true)
267 }
268 }
269 }
270
271 fn passed(&self, direction: Direction, len: usize) {
272 let counter = match direction {
273 Direction::Up => &self.passed_up,
274 Direction::Down => &self.passed_down,
275 };
276 counter.fetch_add(len, Ordering::SeqCst);
277 }
278}
279
280async fn accept(listener: TcpListener, shared: Arc<Shared>) {
281 let mut connections = JoinSet::new();
282 loop {
283 while connections.try_join_next().is_some() {}
286 let Ok((client, _)) = listener.accept().await else {
287 continue;
288 };
289 shared.accepted.fetch_add(1, Ordering::SeqCst);
290 connections.spawn(serve(client, shared.clone()));
291 }
292}
293
294enum Flow {
296 Ended,
298 Cut,
300 Failed,
302}
303
304async fn serve(client: TcpStream, shared: Arc<Shared>) {
305 if shared.rules().offline {
306 shared.torn.fetch_add(1, Ordering::SeqCst);
307 reset(&client);
308 return;
309 }
310 let Ok(server) = TcpStream::connect(shared.upstream).await else {
311 reset(&client);
312 return;
313 };
314 let _ = client.set_nodelay(true);
317 let _ = server.set_nodelay(true);
318
319 let id = shared.next.fetch_add(1, Ordering::SeqCst);
320 let (switch, mut torn) = watch::channel(false);
321 lock(&shared.open).insert(id, switch);
322 let (mut client_read, mut client_write) = client.into_split();
323 let (mut server_read, mut server_write) = server.into_split();
324
325 let end = {
326 let up = pump(&mut client_read, &mut server_write, Direction::Up, &shared);
327 let down = pump(&mut server_read, &mut client_write, Direction::Down, &shared);
328 tokio::pin!(up, down);
329 let (mut up_done, mut down_done) = (false, false);
330 loop {
331 let flow = tokio::select! {
332 flow = &mut up, if !up_done => { up_done = true; flow }
333 flow = &mut down, if !down_done => { down_done = true; flow }
334 _ = torn.wait_for(|torn| *torn) => Flow::Cut,
335 };
336 match flow {
337 Flow::Ended if up_done && down_done => break Flow::Ended,
338 Flow::Ended => {}
339 end => break end,
340 }
341 }
342 };
343 lock(&shared.open).remove(&id);
344 if matches!(end, Flow::Ended) {
345 return;
346 }
347 if matches!(end, Flow::Cut) {
348 shared.torn.fetch_add(1, Ordering::SeqCst);
349 }
350 for (read, write) in [(client_read, client_write), (server_read, server_write)] {
354 if let Ok(socket) = read.reunite(write) {
355 reset(&socket);
356 }
357 }
358}
359
360async fn pump(from: &mut OwnedReadHalf, to: &mut OwnedWriteHalf, direction: Direction, shared: &Shared) -> Flow {
362 let mut flowing = shared.flowing.subscribe();
363 let mut buffer = vec![0u8; 16 * 1024];
364 loop {
365 let len = match from.read(&mut buffer).await {
366 Ok(0) => {
367 return match to.shutdown().await {
368 Ok(()) => Flow::Ended,
369 Err(_) => Flow::Failed,
370 };
371 }
372 Ok(len) => len,
373 Err(_) => return Flow::Failed,
374 };
375 if flowing.wait_for(|flowing| *flowing).await.is_err() {
376 return Flow::Failed;
377 }
378 let (pass, cut) = shared.take(direction, len);
379 if pass > 0 {
380 if to.write_all(&buffer[..pass]).await.is_err() {
381 return Flow::Failed;
382 }
383 shared.passed(direction, pass);
384 }
385 if cut {
386 return Flow::Cut;
387 }
388 }
389}
390
391fn reset(socket: &TcpStream) {
394 let _ = socket.set_zero_linger();
397}
398
399fn lock<T>(mutex: &Mutex<T>) -> MutexGuard<'_, T> {
400 mutex.lock().unwrap_or_else(|poisoned| poisoned.into_inner())
401}