bufferbloat fixes, deadlocks and buf sizes change
This commit is contained in:
@@ -136,78 +136,22 @@ impl TcpConnection {
|
||||
socket.set_tunnel_rtt(rtt);
|
||||
|
||||
// Читаем из браузера в Туннель
|
||||
if self.core.tx.capacity() > 200 {
|
||||
while socket.can_recv() {
|
||||
if let Ok(n) = socket.peek_slice(&mut self.chunk_buf) {
|
||||
if n == 0 {
|
||||
break;
|
||||
}
|
||||
let chunk = Bytes::copy_from_slice(&self.chunk_buf[..n]);
|
||||
|
||||
match self.core.tx.try_send(chunk) {
|
||||
Ok(_) => {
|
||||
socket.recv_slice(&mut self.chunk_buf[..n]).unwrap();
|
||||
}
|
||||
Err(mpsc::error::TrySendError::Full(_)) => {
|
||||
break;
|
||||
}
|
||||
Err(mpsc::error::TrySendError::Closed(_)) => {
|
||||
self.server_eof = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
while socket.can_recv() && self.core.tx.capacity() > 0 {
|
||||
if let Ok(n) = socket.peek_slice(&mut self.chunk_buf) {
|
||||
if n == 0 {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
let chunk = Bytes::copy_from_slice(&self.chunk_buf[..n]);
|
||||
|
||||
// Читаем из Туннеля в браузер
|
||||
if !self.server_eof {
|
||||
// 🔥 ДИНАМИЧЕСКИЙ BACKPRESSURE (Auto-Scaling Buffer)
|
||||
// В зависимости от текущего пинга всей системы, мы разрешаем
|
||||
// локальному сокету буферизовать разное количество данных.
|
||||
let dynamic_limit = if current_rtt < 50 {
|
||||
2 * 1024 * 1024 // 2 MB: Отличный Wi-Fi, качаем на максимум
|
||||
} else if current_rtt < 150 {
|
||||
1024 * 1024 // 1 MB: Хороший LTE
|
||||
} else if current_rtt < 300 {
|
||||
256 * 1024 // 256 KB: Загруженный 3G/LTE, начинаем зажимать
|
||||
} else {
|
||||
128 * 1024 // 128 KB: Сеть умирает (или сменилась вышка), спасаем пинг
|
||||
};
|
||||
|
||||
while self.pending_bytes < dynamic_limit {
|
||||
match self.core.rx.try_recv() {
|
||||
Ok(data) => {
|
||||
self.pending_bytes += data.len();
|
||||
self.pending_data.push_back(data);
|
||||
match self.core.tx.try_send(chunk) {
|
||||
Ok(_) => {
|
||||
socket.recv_slice(&mut self.chunk_buf[..n]).unwrap();
|
||||
}
|
||||
Err(mpsc::error::TryRecvError::Empty) => break,
|
||||
Err(mpsc::error::TryRecvError::Disconnected) => {
|
||||
debug!(%self.core.handle, "Tunnel channel closed (Server EOF)");
|
||||
self.server_eof = true;
|
||||
Err(mpsc::error::TrySendError::Full(_)) => {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Отправляем из очереди в smoltcp
|
||||
while socket.can_send() {
|
||||
if let Some(mut chunk) = self.pending_data.pop_front() {
|
||||
match socket.send_slice(&chunk) {
|
||||
Ok(n) => {
|
||||
self.pending_bytes -= n;
|
||||
if n < chunk.len() {
|
||||
chunk.advance(n);
|
||||
self.pending_data.push_front(chunk);
|
||||
break;
|
||||
}
|
||||
}
|
||||
Err(e) => {
|
||||
debug!(%self.core.handle, "Smoltcp send error: {:?}", e);
|
||||
self.pending_data.push_front(chunk);
|
||||
Err(mpsc::error::TrySendError::Closed(_)) => {
|
||||
self.server_eof = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -216,6 +160,43 @@ impl TcpConnection {
|
||||
}
|
||||
}
|
||||
|
||||
if !self.server_eof {
|
||||
while socket.can_send() {
|
||||
// Если есть недоотправленный кусок - берем его первым
|
||||
if let Some(mut chunk) = self.pending_data.pop_front() {
|
||||
match socket.send_slice(&chunk) {
|
||||
Ok(n) => {
|
||||
self.pending_bytes -= n;
|
||||
if n < chunk.len() {
|
||||
chunk.advance(n);
|
||||
self.pending_data.push_front(chunk);
|
||||
break; // Сокет заполнился
|
||||
}
|
||||
}
|
||||
Err(e) => {
|
||||
debug!(%self.core.handle, "Smoltcp send error: {:?}", e);
|
||||
self.pending_data.push_front(chunk);
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Очередь пуста, пытаемся прочитать из канала туннеля
|
||||
match self.core.rx.try_recv() {
|
||||
Ok(data) => {
|
||||
self.pending_bytes += data.len();
|
||||
self.pending_data.push_back(data);
|
||||
}
|
||||
Err(mpsc::error::TryRecvError::Empty) => break,
|
||||
Err(mpsc::error::TryRecvError::Disconnected) => {
|
||||
debug!(%self.core.handle, "Tunnel channel closed (Server EOF)");
|
||||
self.server_eof = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if self.server_eof && self.pending_data.is_empty() {
|
||||
let state = socket.state();
|
||||
if state == tcp::State::Established || state == tcp::State::CloseWait {
|
||||
@@ -224,6 +205,7 @@ impl TcpConnection {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn app_pending_out_size(&self) -> usize {
|
||||
self.pending_bytes
|
||||
}
|
||||
@@ -269,7 +251,7 @@ impl TcpConnection {
|
||||
});
|
||||
}
|
||||
}
|
||||
// ... остальной код (UdpConnection и IcmpResponder без изменений) ...
|
||||
|
||||
pub type UdpPacketTarget = (Bytes, std::net::Ipv4Addr, u16);
|
||||
|
||||
pub struct UdpConnection {
|
||||
|
||||
@@ -4,9 +4,9 @@ use netrunner_core::{
|
||||
DNS_PORT, GLOBAL_IDLE_TIMEOUT, HTTPS_PORT, MAX_SOCKETS, NETBIOS_PORTS,
|
||||
TCP_HANDSHAKE_TIMEOUT,
|
||||
},
|
||||
rawcast::{RawCastEvent, RawCastFrame},
|
||||
rawcast::RawCastFrame,
|
||||
};
|
||||
use netrunner_logger::{info, trace, warn};
|
||||
use netrunner_logger::warn;
|
||||
use smoltcp::{
|
||||
iface::{SocketHandle, SocketSet},
|
||||
socket::{Socket, tcp, udp},
|
||||
|
||||
@@ -85,10 +85,6 @@ impl Engine {
|
||||
|
||||
let mut last_stats_log = StdInstant::now();
|
||||
|
||||
// 🔥 ФИКС: Выносим чтение из туннеля в отдельную изолированную задачу!
|
||||
// Это позволяет использовать `.await` при отправке данных в локальный сокет smoltcp.
|
||||
// Если локальный сокет забит, эта задача мягко "засыпает", создавая идеальный Backpressure,
|
||||
// при этом НЕ БЛОКИРУЯ основной цикл обработки интерфейсов Engine.
|
||||
let inbound_map = self.manager.tracker.inbound_tx.clone();
|
||||
let mut rx_tunnel = self.rx_from_tunnel.take().unwrap();
|
||||
|
||||
@@ -97,9 +93,13 @@ impl Engine {
|
||||
if frame.event == RawCastEvent::Close {
|
||||
inbound_map.remove(&frame.socket_id);
|
||||
} else if frame.event == RawCastEvent::Data {
|
||||
if let Some(tx) = inbound_map.get(&frame.socket_id) {
|
||||
// ZERO DROP, PERFECT BACKPRESSURE.
|
||||
// Ожидаем, пока локальный сокет не освободит место.
|
||||
// 1. Берем лок, клонируем Sender, СРАЗУ отпускаем лок (конец scope `tx_opt`)
|
||||
let tx_opt = inbound_map
|
||||
.get(&frame.socket_id)
|
||||
.map(|ref_tx| ref_tx.clone());
|
||||
|
||||
// 2. Теперь спокойно ждем (Backpressure), не блокируя остальную систему
|
||||
if let Some(tx) = tx_opt {
|
||||
let _ = tx.send(frame.payload).await;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user