mirror of https://github.com/ospab/ostp.git
fix(client): stop leaking a socket+task per bypassed UDP flow
start_udp_bypass_session (the TUN-mode path for UDP from apps/IPs the user has excluded from the tunnel) spawned a separate task to read from the physical-interface-bound socket, holding its own Arc<UdpSocket> clone. Nothing ever cancelled that task when the outer function returned (e.g. once session_rx closed) - it just kept running, and its socket clone kept the OS fd alive, for the lifetime of the process. Every distinct bypassed UDP flow (any excluded app's DNS query, game session, etc.) leaked one socket and one task permanently. The sibling function right below it, start_udp_session, already does this correctly: one tokio::select! loop combining both directions in a single task that exits (and drops the socket) as soon as either side closes. Rewrote start_udp_bypass_session to match that pattern instead of spawning a detached reader task.
This commit is contained in:
parent
51b947e6ff
commit
dbf923fb16
|
|
@ -138,27 +138,34 @@ async fn start_udp_bypass_session(
|
||||||
let _ = crate::tunnel::proxy::bind_socket_to_interface(&socket, name);
|
let _ = crate::tunnel::proxy::bind_socket_to_interface(&socket, name);
|
||||||
}
|
}
|
||||||
|
|
||||||
let socket = Arc::new(socket);
|
// A single select! loop over both directions, rather than spawning a
|
||||||
let socket_rx = socket.clone();
|
// separate task for the read side, so the whole session - physical
|
||||||
|
// socket included - is torn down the moment this function returns
|
||||||
// Spawn a task to read from physical socket and send back to smoltcp
|
// (e.g. when session_rx closes). The previous spawned-task version left
|
||||||
let tx_clone = smoltcp_tx.clone();
|
// that task (and its Arc<UdpSocket> clone, keeping the OS socket fd
|
||||||
tokio::spawn(async move {
|
// alive) running forever after this function returned: nothing ever
|
||||||
use futures::SinkExt;
|
// cancelled it, so every bypassed UDP flow (any excluded app/IP in TUN
|
||||||
let mut buf = [0u8; 65536];
|
// mode) leaked one socket + one task for the lifetime of the process.
|
||||||
loop {
|
use futures::SinkExt;
|
||||||
match socket_rx.recv_from(&mut buf).await {
|
let mut buf = [0u8; 65536];
|
||||||
Ok((n, peer)) => {
|
loop {
|
||||||
let mut lock = tx_clone.lock().await;
|
tokio::select! {
|
||||||
let _ = lock.send((buf[..n].to_vec(), peer, client_src)).await;
|
outbound = session_rx.recv() => {
|
||||||
|
match outbound {
|
||||||
|
Some((payload, dst)) => { socket.send_to(&payload, dst).await?; }
|
||||||
|
None => break,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
inbound = socket.recv_from(&mut buf) => {
|
||||||
|
match inbound {
|
||||||
|
Ok((n, peer)) => {
|
||||||
|
let mut lock = smoltcp_tx.lock().await;
|
||||||
|
let _ = lock.send((buf[..n].to_vec(), peer, client_src)).await;
|
||||||
|
}
|
||||||
|
Err(_) => break,
|
||||||
}
|
}
|
||||||
Err(_) => break,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
|
||||||
|
|
||||||
while let Some((payload, dst)) = session_rx.recv().await {
|
|
||||||
socket.send_to(&payload, dst).await?;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue