updates muxer legs select, buf sizes and constantsa
This commit is contained in:
@@ -1,5 +1,4 @@
|
||||
use bytes::{Buf, Bytes};
|
||||
use std::collections::VecDeque;
|
||||
use netrunner_core::{
|
||||
net::{NetworkConfig, UDP_IDLE_TIMEOUT},
|
||||
rawcast::{LocalProtocol, RawCastFrame},
|
||||
@@ -12,6 +11,7 @@ use smoltcp::{
|
||||
Ipv6Address,
|
||||
},
|
||||
};
|
||||
use std::collections::VecDeque;
|
||||
use tokio::sync::{mpsc, oneshot};
|
||||
|
||||
use netrunner_logger::{debug, info};
|
||||
@@ -165,9 +165,9 @@ impl TcpConnection {
|
||||
|
||||
if !self.server_eof {
|
||||
loop {
|
||||
|
||||
let pending_size: usize = self.pending_data.iter().map(|b| b.len()).sum();
|
||||
if pending_size >= 4 * NetworkConfig::global().mtu {
|
||||
let max_pending = 128 * 1024;
|
||||
if pending_size >= max_pending {
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -413,4 +413,4 @@ impl IcmpResponder {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,14 +1,19 @@
|
||||
use dashmap::DashMap;
|
||||
use netrunner_core::{
|
||||
net::{DNS_PORT, GLOBAL_IDLE_TIMEOUT, HTTPS_PORT, MAX_SOCKETS, NETBIOS_PORTS, TCP_HANDSHAKE_TIMEOUT},
|
||||
net::{
|
||||
DNS_PORT, GLOBAL_IDLE_TIMEOUT, HTTPS_PORT, MAX_SOCKETS, NETBIOS_PORTS,
|
||||
TCP_HANDSHAKE_TIMEOUT,
|
||||
},
|
||||
rawcast::{RawCastEvent, RawCastFrame},
|
||||
};
|
||||
use netrunner_logger::{info, trace};
|
||||
use netrunner_logger::{info, trace, warn};
|
||||
use smoltcp::{
|
||||
iface::{SocketHandle, SocketSet},
|
||||
socket::{Socket, tcp, udp},
|
||||
wire::{IpAddress, IpListenEndpoint, IpProtocol, Ipv4Packet, Ipv6Packet, TcpPacket, UdpPacket},
|
||||
};
|
||||
use std::{sync::Arc};
|
||||
use std::sync::Arc;
|
||||
use std::time::Instant; // Используем DashMap для потокобезопасного трекинга
|
||||
|
||||
use tokio::sync::mpsc;
|
||||
|
||||
@@ -19,6 +24,9 @@ use crate::net::{
|
||||
socket_factory::SocketProvider,
|
||||
};
|
||||
|
||||
// Ключ для идентификации уникального потока (4-tuple)
|
||||
type FlowKey = (IpAddress, u16, IpAddress, u16);
|
||||
|
||||
struct Flow {
|
||||
src: IpAddress,
|
||||
dst: IpAddress,
|
||||
@@ -26,6 +34,12 @@ struct Flow {
|
||||
dst_p: u16,
|
||||
}
|
||||
|
||||
impl Flow {
|
||||
fn to_key(&self) -> FlowKey {
|
||||
(self.src, self.src_p, self.dst, self.dst_p)
|
||||
}
|
||||
}
|
||||
|
||||
struct TargetResolver {
|
||||
dns_handler: DnsHandler,
|
||||
fake_ip_store: FakeIpStore,
|
||||
@@ -66,6 +80,8 @@ pub struct ConnectionManager {
|
||||
resolver: TargetResolver,
|
||||
tx_to_tunnel: mpsc::Sender<RawCastFrame>,
|
||||
factory: Arc<dyn SocketProvider>,
|
||||
// 🔥 ТРЕКЕР ОЖИДАЮЩИХ СОЕДИНЕНИЙ: предотвращает SYN-шторм
|
||||
pending_connects: DashMap<FlowKey, Instant>,
|
||||
}
|
||||
|
||||
impl ConnectionManager {
|
||||
@@ -79,6 +95,7 @@ impl ConnectionManager {
|
||||
resolver: TargetResolver::new(dns_handler),
|
||||
tx_to_tunnel,
|
||||
factory,
|
||||
pending_connects: DashMap::new(),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -114,7 +131,6 @@ impl ConnectionManager {
|
||||
for (_, socket) in socket_set.iter_mut() {
|
||||
match socket {
|
||||
Socket::Tcp(tcp) => {
|
||||
// 🛡️ ИСПРАВЛЕНО: Только пустые базовые сокеты слушают 443
|
||||
if !tcp.is_open() && tcp.local_endpoint().is_none() {
|
||||
let _ = tcp.listen(IpListenEndpoint {
|
||||
addr: None,
|
||||
@@ -123,7 +139,6 @@ impl ConnectionManager {
|
||||
}
|
||||
}
|
||||
Socket::Udp(udp) => {
|
||||
// 🛡️ ИСПРАВЛЕНО: Только пустые базовые сокеты биндят 53
|
||||
if !udp.is_open() && udp.endpoint().port == 0 {
|
||||
let _ = udp.bind(IpListenEndpoint {
|
||||
addr: None,
|
||||
@@ -163,7 +178,10 @@ impl ConnectionManager {
|
||||
if let Ok(p) = TcpPacket::new_checked(ip.payload()) {
|
||||
flow.src_p = p.src_port();
|
||||
flow.dst_p = p.dst_port();
|
||||
self.intercept_tcp(flow, socket_set);
|
||||
// Игнорируем пакеты, если это не SYN (новое соединение)
|
||||
if p.syn() && !p.ack() {
|
||||
self.intercept_tcp(flow, socket_set);
|
||||
}
|
||||
}
|
||||
}
|
||||
IpProtocol::Udp => {
|
||||
@@ -193,7 +211,9 @@ impl ConnectionManager {
|
||||
if let Ok(p) = TcpPacket::new_checked(ip.payload()) {
|
||||
flow.src_p = p.src_port();
|
||||
flow.dst_p = p.dst_port();
|
||||
self.intercept_tcp(flow, socket_set);
|
||||
if p.syn() && !p.ack() {
|
||||
self.intercept_tcp(flow, socket_set);
|
||||
}
|
||||
}
|
||||
}
|
||||
IpProtocol::Udp => {
|
||||
@@ -208,12 +228,22 @@ impl ConnectionManager {
|
||||
}
|
||||
|
||||
fn intercept_tcp(&mut self, f: Flow, socket_set: &mut SocketSet) {
|
||||
let key = f.to_key();
|
||||
|
||||
// 🔥 ФИКС 1: Проверка в таблице ожидающих соединений
|
||||
if self.pending_connects.contains_key(&key) {
|
||||
return;
|
||||
}
|
||||
|
||||
if !self.tracker.has_connection_from(f.src, f.src_p, socket_set) {
|
||||
if socket_set.iter().count() >= 2048 {
|
||||
netrunner_logger::warn!("🔥 TCP Socket limit reached! Dropping SYN.");
|
||||
warn!("🔥 TCP Socket limit reached! Dropping SYN.");
|
||||
return;
|
||||
}
|
||||
|
||||
// Помечаем поток как "в процессе создания"
|
||||
self.pending_connects.insert(key, Instant::now());
|
||||
|
||||
let socket = self.factory.create_listening_tcp(Some(f.dst), f.dst_p);
|
||||
let handle = socket_set.add(socket);
|
||||
self.tracker.add_pending_tcp(handle);
|
||||
@@ -221,16 +251,16 @@ impl ConnectionManager {
|
||||
}
|
||||
|
||||
fn intercept_udp(&mut self, f: Flow, socket_set: &mut SocketSet) {
|
||||
if f.dst_p == 0
|
||||
|| f.dst_p == DNS_PORT
|
||||
|| NETBIOS_PORTS.contains(&f.dst_p) // 👈 Используй массив
|
||||
|| self.tracker.is_client_known(f.src_p)
|
||||
if f.dst_p == 0
|
||||
|| f.dst_p == DNS_PORT
|
||||
|| NETBIOS_PORTS.contains(&f.dst_p)
|
||||
|| self.tracker.is_client_known(f.src_p)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if socket_set.iter().count() >= MAX_SOCKETS {
|
||||
netrunner_logger::warn!("🔥 UDP Socket limit reached! Dropping packet.");
|
||||
warn!("🔥 UDP Socket limit reached! Dropping packet.");
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -255,7 +285,13 @@ impl ConnectionManager {
|
||||
}
|
||||
|
||||
pub fn process_sockets(&mut self, socket_set: &mut SocketSet) {
|
||||
for (handle, socket) in socket_set.iter_mut() {
|
||||
// Собираем хендлы, чтобы избежать конфликтов заимствования (borrow checker)
|
||||
let handles: Vec<SocketHandle> = socket_set.iter().map(|(h, _)| h).collect();
|
||||
|
||||
for handle in handles {
|
||||
// 🔥 ИСПРАВЛЕНИЕ: get_mut возвращает &mut Socket, а не Option<&mut Socket>
|
||||
let socket = socket_set.get_mut(handle);
|
||||
|
||||
match socket {
|
||||
Socket::Tcp(s) => self.handle_tcp(handle, s),
|
||||
Socket::Udp(s) => self.handle_udp(handle, s),
|
||||
@@ -263,46 +299,26 @@ impl ConnectionManager {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn handle_tcp(&mut self, handle: SocketHandle, socket: &mut tcp::Socket) {
|
||||
self.tracker.update_activity(handle);
|
||||
|
||||
let state = socket.state();
|
||||
|
||||
// 1. Терминальные состояния (уже закрыты)
|
||||
if state == tcp::State::Closed || state == tcp::State::TimeWait {
|
||||
self.tracker.queue_removal(handle);
|
||||
return;
|
||||
}
|
||||
|
||||
// 🛡️ ИСПРАВЛЕНИЕ: Мы не считаем сокет "мертвым", если он в процессе Handshake
|
||||
let is_handshaking = state == tcp::State::SynSent || state == tcp::State::SynReceived;
|
||||
|
||||
// 🚨 Логика очистки Half-Close (CloseWait/FinWait2)
|
||||
// Убиваем сокет ТОЛЬКО если он не слушает, не коннектится И при этом не может передавать данные
|
||||
if !is_handshaking && state != tcp::State::Listen {
|
||||
if !socket.may_recv() && !socket.may_send() {
|
||||
trace!(%handle, ?state, "💀 Cleaning up dead half-closed socket");
|
||||
socket.abort();
|
||||
self.tracker.queue_removal(handle);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Тайм-аут на установку соединения (если SYN висит слишком долго)
|
||||
if self
|
||||
.tracker
|
||||
.check_pending_timeout(handle, TCP_HANDSHAKE_TIMEOUT)
|
||||
{
|
||||
socket.abort();
|
||||
self.tracker.queue_removal(handle);
|
||||
return;
|
||||
}
|
||||
|
||||
// Инициализация туннеля при успешном коннекте
|
||||
if state == tcp::State::Established && self.tracker.should_init_tcp(handle) {
|
||||
if let Some(ep) = socket.local_endpoint() {
|
||||
if let (Some(local), Some(remote)) = (socket.local_endpoint(), socket.remote_endpoint())
|
||||
{
|
||||
// 🔥 ФИКС 2: Удаляем из pending при установке соединения
|
||||
let key = (remote.addr, remote.port, local.addr, local.port);
|
||||
self.pending_connects.remove(&key);
|
||||
|
||||
let socket_id = self.tracker.next_id();
|
||||
let (dst_ip, target) = self.resolver.resolve_destination(ep.addr, ep.port);
|
||||
let (dst_ip, target) = self.resolver.resolve_destination(local.addr, local.port);
|
||||
|
||||
let (conn, rx_smol, tx_smol, handshake_tx) = TcpConnection::new(handle);
|
||||
self.tracker.register_tcp(handle, socket_id, conn, tx_smol);
|
||||
@@ -310,7 +326,7 @@ impl ConnectionManager {
|
||||
TcpConnection::spawn(
|
||||
socket_id,
|
||||
dst_ip,
|
||||
ep.port,
|
||||
local.port,
|
||||
target,
|
||||
rx_smol,
|
||||
handshake_tx,
|
||||
@@ -319,10 +335,27 @@ impl ConnectionManager {
|
||||
}
|
||||
}
|
||||
|
||||
// Прокачка данных
|
||||
// Очистка мертвых сокетов
|
||||
if state != tcp::State::Listen && !is_handshaking(state) {
|
||||
if !socket.may_recv() && !socket.may_send() {
|
||||
socket.abort();
|
||||
self.tracker.queue_removal(handle);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if self
|
||||
.tracker
|
||||
.check_pending_timeout(handle, TCP_HANDSHAKE_TIMEOUT)
|
||||
{
|
||||
// Если таймаут, нужно тоже попытаться очистить pending_connects (по возрасту в cleanup)
|
||||
socket.abort();
|
||||
self.tracker.queue_removal(handle);
|
||||
return;
|
||||
}
|
||||
|
||||
if let Some(conn) = self.tracker.get_tcp_mut(handle) {
|
||||
if !conn.tick(socket) {
|
||||
// Если tick вернул false (ошибка в каналах или Close от туннеля)
|
||||
socket.abort();
|
||||
self.tracker.queue_removal(handle);
|
||||
}
|
||||
@@ -331,7 +364,6 @@ impl ConnectionManager {
|
||||
|
||||
fn handle_udp(&mut self, handle: SocketHandle, socket: &mut udp::Socket) {
|
||||
self.tracker.update_activity(handle);
|
||||
|
||||
if socket.endpoint().port == 53 {
|
||||
while let Ok((data, meta)) = socket.recv() {
|
||||
if let Some(res) = self.resolver.process_dns_query(data) {
|
||||
@@ -340,7 +372,6 @@ impl ConnectionManager {
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if let Some(conn) = self.tracker.get_udp_mut(handle) {
|
||||
if !conn.tick(socket) {
|
||||
self.tracker.queue_removal(handle);
|
||||
@@ -349,7 +380,15 @@ impl ConnectionManager {
|
||||
}
|
||||
|
||||
pub fn cleanup(&mut self, socket_set: &mut SocketSet) {
|
||||
// 🔥 ФИКС 3: Очистка зависших pending_connects (например, если SYN потерялся)
|
||||
self.pending_connects
|
||||
.retain(|_, timestamp| timestamp.elapsed() < TCP_HANDSHAKE_TIMEOUT);
|
||||
|
||||
self.tracker.enforce_idle_timeouts(GLOBAL_IDLE_TIMEOUT);
|
||||
self.tracker.cleanup(socket_set);
|
||||
}
|
||||
}
|
||||
|
||||
fn is_handshaking(state: tcp::State) -> bool {
|
||||
matches!(state, tcp::State::SynSent | tcp::State::SynReceived)
|
||||
}
|
||||
|
||||
+23
-26
@@ -8,7 +8,6 @@ use smoltcp::{
|
||||
iface::{Config, Interface, SocketSet},
|
||||
phy::DeviceCapabilities,
|
||||
};
|
||||
use tokio::sync::mpsc::UnboundedReceiver;
|
||||
use std::net::Ipv4Addr;
|
||||
use std::sync::atomic::Ordering;
|
||||
use std::{
|
||||
@@ -16,6 +15,7 @@ use std::{
|
||||
time::Instant as StdInstant,
|
||||
};
|
||||
use tokio::io::{AsyncReadExt, AsyncWriteExt};
|
||||
use tokio::sync::mpsc::UnboundedReceiver;
|
||||
use tokio::sync::mpsc::{self, Receiver, Sender};
|
||||
use tokio::time::{Duration, sleep};
|
||||
use tun::{DeviceReader, DeviceWriter};
|
||||
@@ -40,6 +40,7 @@ pub struct Engine {
|
||||
from_smoltcp_rx: Option<UnboundedReceiver<TokenBuffer>>,
|
||||
avail: Arc<AtomicBool>,
|
||||
rx_from_tunnel: mpsc::Receiver<RawCastFrame>,
|
||||
factory: Arc<dyn SocketProvider>, // 🔥 Сохраняем фабрику для доступа к логам статистики
|
||||
}
|
||||
|
||||
impl Engine {
|
||||
@@ -69,6 +70,7 @@ impl Engine {
|
||||
avail,
|
||||
manager,
|
||||
rx_from_tunnel,
|
||||
factory,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -76,7 +78,6 @@ impl Engine {
|
||||
info!("Current routes: {:?}", self.interface.routes());
|
||||
let (writer, reader) = tun.split().expect("Failed to split TUN");
|
||||
|
||||
// 🚨 ПРАВИЛО 1: ОГРАНИЧИВАЕМ КАНАЛ ОТ TUN, чтобы ОС не затопила нас памятью!
|
||||
let (tun_to_engine_tx, mut tun_to_engine_rx) =
|
||||
mpsc::channel(NetworkConfig::global().client_tun_capacity);
|
||||
|
||||
@@ -84,7 +85,10 @@ impl Engine {
|
||||
|
||||
let from_smoltcp_rx = self.from_smoltcp_rx.take().expect("Engine started twice");
|
||||
Self::spawn_tun_writer(writer, from_smoltcp_rx);
|
||||
|
||||
|
||||
// 🔥 Таймер для периодического вывода статистики буферов
|
||||
let mut last_stats_log = StdInstant::now();
|
||||
|
||||
loop {
|
||||
// 1. Сначала обрабатываем всё, что накопилось в стеке
|
||||
let mut repeat_poll = true;
|
||||
@@ -92,10 +96,15 @@ impl Engine {
|
||||
self.manager.process_sockets(&mut self.socket_set);
|
||||
let poll_res = self.poll();
|
||||
self.manager.cleanup(&mut self.socket_set);
|
||||
// Если сокеты изменились, крутим еще раз, пока не вытолкнем всё
|
||||
repeat_poll = matches!(poll_res, PollResult::SocketStateChanged);
|
||||
}
|
||||
|
||||
// 🔥 Логируем состояние буферов раз в 5 секунд
|
||||
if last_stats_log.elapsed() >= Duration::from_secs(5) {
|
||||
self.factory.log_stats(&self.socket_set);
|
||||
last_stats_log = StdInstant::now();
|
||||
}
|
||||
|
||||
// 2. Считаем задержку
|
||||
let delay = self
|
||||
.interface
|
||||
@@ -110,7 +119,6 @@ impl Engine {
|
||||
msg = self.rx_from_tunnel.recv() => {
|
||||
if let Some(frame) = msg {
|
||||
let _ = self.manager.try_inject_inbound(frame);
|
||||
// Читаем по чуть-чуть (max 32), чтобы чаще делать poll()
|
||||
let mut count = 0;
|
||||
while let Ok(frame) = self.rx_from_tunnel.try_recv() {
|
||||
let _ = self.manager.try_inject_inbound(frame);
|
||||
@@ -124,15 +132,9 @@ impl Engine {
|
||||
if let Some(token) = msg {
|
||||
self.manager.try_create_socket_from_packet(&token, &mut self.socket_set);
|
||||
|
||||
// 🔥 ФИКС 1: Используем .send().await.
|
||||
// Мы не имеем права терять пакеты внутри системы.
|
||||
// Если smoltcp занят, TUN Reader просто подождет.
|
||||
if self.to_smoltcp_tx.send(token).await.is_ok() {
|
||||
self.device.mark_rx_available();
|
||||
}
|
||||
|
||||
// Пакетную обработку Ok(token) = try_recv лучше убрать или
|
||||
// тоже заменить на логику, которая не дропает данные.
|
||||
} else { break; }
|
||||
}
|
||||
}
|
||||
@@ -144,36 +146,34 @@ impl Engine {
|
||||
self.interface
|
||||
.poll(now, &mut self.device, &mut self.socket_set)
|
||||
}
|
||||
|
||||
|
||||
fn spawn_tun_reader(
|
||||
mut reader: DeviceReader,
|
||||
to_engine: mpsc::Sender<TokenBuffer>,
|
||||
to_engine: mpsc::Sender<TokenBuffer>,
|
||||
is_avail: Arc<AtomicBool>,
|
||||
) {
|
||||
tokio::spawn(async move {
|
||||
debug!("TUN Reader task started");
|
||||
let mut buf = [0u8; 65536];
|
||||
while let Ok(n) = reader.read(&mut buf).await {
|
||||
if n == 0 { break; }
|
||||
// ... (фильтрация IP) ...
|
||||
|
||||
if n == 0 {
|
||||
break;
|
||||
}
|
||||
let mut token = TokenBuffer::with_capacity(n);
|
||||
token.extend_from_slice(&buf[..n]);
|
||||
|
||||
// 🔥 ФИКС 2: Возвращаем .send().await!
|
||||
// Это заставит ОС притормозить отправку пакетов,
|
||||
// если туннель перегружен. Пинг упадет, так как пакеты
|
||||
// будут стоять в очереди ОС, а не дропаться.
|
||||
if to_engine.send(token).await.is_ok() {
|
||||
is_avail.store(true, Ordering::Release);
|
||||
} else { break; }
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
fn spawn_tun_writer(
|
||||
mut writer: DeviceWriter,
|
||||
mut from_smoltcp: UnboundedReceiver<TokenBuffer>, // 🔥 Обновили тип
|
||||
mut from_smoltcp: UnboundedReceiver<TokenBuffer>,
|
||||
) {
|
||||
tokio::spawn(async move {
|
||||
debug!("TUN Writer task started");
|
||||
@@ -265,7 +265,6 @@ impl EngineConfig {
|
||||
pub struct EngineBuilder {
|
||||
config: EngineConfig,
|
||||
tun_device: Option<Tun>,
|
||||
|
||||
socket_factory: Option<Arc<dyn SocketProvider>>,
|
||||
}
|
||||
|
||||
@@ -321,9 +320,7 @@ impl EngineBuilder {
|
||||
|
||||
let factory = self.socket_factory.unwrap_or_else(|| {
|
||||
let config_owned = (*NetworkConfig::global()).clone();
|
||||
|
||||
let config = Arc::new(config_owned);
|
||||
|
||||
Arc::new(SmolSocketFactory::new(config))
|
||||
});
|
||||
|
||||
@@ -351,4 +348,4 @@ impl EngineBuilder {
|
||||
|
||||
Ok((engine, tun))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
use netrunner_core::net::NetworkConfig;
|
||||
use netrunner_logger::info;
|
||||
use smoltcp::{
|
||||
iface::SocketSet,
|
||||
socket::{
|
||||
@@ -34,17 +35,17 @@ impl TrafficProfile {
|
||||
}
|
||||
|
||||
pub trait SocketProvider: Send + Sync {
|
||||
// Убрали <'static> у tcp::Socket
|
||||
fn create_tcp(&self, profile: TrafficProfile) -> tcp::Socket;
|
||||
fn create_tcp(&self, profile: TrafficProfile) -> tcp::Socket;
|
||||
fn create_udp(&self, profile: TrafficProfile) -> udp::Socket<'static>;
|
||||
fn create_icmp(&self) -> icmp::Socket<'static>;
|
||||
|
||||
// Убрали <'static> у tcp::Socket
|
||||
fn create_listening_tcp(&self, addr: Option<IpAddress>, port: u16) -> tcp::Socket;
|
||||
|
||||
fn create_icmp(&self, profile: TrafficProfile) -> icmp::Socket<'static>;
|
||||
|
||||
fn create_listening_tcp(&self, addr: Option<IpAddress>, port: u16) -> tcp::Socket;
|
||||
fn create_bound_udp(&self, addr: Option<IpAddress>, port: u16) -> udp::Socket<'static>;
|
||||
fn create_base_set(&self, n_icmp: usize) -> SocketSet<'static>;
|
||||
fn reconfigure_tcp(&self, socket: &mut tcp::Socket, profile: TrafficProfile);
|
||||
|
||||
// 🔥 НОВЫЙ МЕТОД: Логирование статистики всех сокетов в сете
|
||||
fn log_stats(&self, sockets: &SocketSet);
|
||||
}
|
||||
|
||||
pub struct SmolSocketFactory {
|
||||
@@ -57,24 +58,25 @@ impl SmolSocketFactory {
|
||||
}
|
||||
|
||||
fn alloc_buf(&self, size: usize) -> Vec<u8> {
|
||||
// Убрали пул памяти, так как 1MB RX буферы раздуют оперативку (128MB+).
|
||||
// Выделение памяти через vec! при старте сокета работает достаточно быстро.
|
||||
vec![0u8; size]
|
||||
}
|
||||
}
|
||||
|
||||
impl SocketProvider for SmolSocketFactory {
|
||||
// Убрали <'static>
|
||||
fn create_tcp(&self, profile: TrafficProfile) -> tcp::Socket {
|
||||
// 👈 Асимметричные буферы: RX большой (Download), TX маленький (Upload)
|
||||
let (rx_size, tx_size) = match profile {
|
||||
TrafficProfile::Bulk => (self.config.tcp_rx_heavy, self.config.tcp_tx_heavy),
|
||||
TrafficProfile::Interactive => (self.config.tcp_rx_light, self.config.tcp_tx_light),
|
||||
_ => (self.config.tcp_rx_light * 2, self.config.tcp_tx_light * 2),
|
||||
};
|
||||
|
||||
// 🔥 ИСПОЛЬЗУЕМ НАШИ НОВЫЕ ДИНАМИЧЕСКИЕ БУФЕРЫ 🔥
|
||||
// Мы больше не аллоцируем векторы снаружи, буфер сам управляет памятью
|
||||
info!(
|
||||
"🚀 TCP Socket Created | Profile: {:?} | Initial RX: {} KB, TX: {} KB",
|
||||
profile,
|
||||
rx_size / 1024,
|
||||
tx_size / 1024
|
||||
);
|
||||
|
||||
let rx_buffer = tcp::DynamicSocketBuffer::new(rx_size);
|
||||
let tx_buffer = tcp::DynamicSocketBuffer::new(tx_size);
|
||||
let mut socket = tcp::Socket::new(rx_buffer, tx_buffer);
|
||||
@@ -87,28 +89,41 @@ impl SocketProvider for SmolSocketFactory {
|
||||
}
|
||||
|
||||
fn reconfigure_tcp(&self, socket: &mut tcp::Socket, profile: TrafficProfile) {
|
||||
// Выключаем Nagle везде, так как внутри Netrunner мы сами батчим данные в чанки (tcp_chunk_size),
|
||||
// а BBR сам управляет плавностью отправки (Pacing). Nagle здесь будет только мешать.
|
||||
socket.set_nagle_enabled(false);
|
||||
|
||||
match profile {
|
||||
TrafficProfile::Interactive | TrafficProfile::Dns => {
|
||||
// Для интерактивного трафика (SSH, RDP, DNS) нам нужна минимальная задержка.
|
||||
// Отвечаем ACK'ами мгновенно.
|
||||
socket.set_ack_delay(None);
|
||||
}
|
||||
TrafficProfile::Bulk | TrafficProfile::Default => {
|
||||
// Для тяжелого трафика ставим крошечный delay (1 мс).
|
||||
// Это снизит нагрузку на CPU (будет меньше syscall-ов на отправку голых ACK),
|
||||
// но при этом 1 мс не испортит расчеты RTT и RateSample для BBR.
|
||||
socket.set_ack_delay(Some(Duration::from_millis(1)));
|
||||
}
|
||||
}
|
||||
|
||||
// Включаем нашу ракету
|
||||
|
||||
socket.set_congestion_control(CongestionControl::Bbr);
|
||||
}
|
||||
|
||||
fn log_stats(&self, sockets: &SocketSet) {
|
||||
for (handle, socket) in sockets.iter() {
|
||||
if let smoltcp::socket::Socket::Tcp(tcp_socket) = socket {
|
||||
if tcp_socket.is_active() {
|
||||
// Извлекаем текущие емкости динамических буферов
|
||||
let rx_cap = tcp_socket.recv_capacity();
|
||||
let tx_cap = tcp_socket.send_capacity();
|
||||
let state = tcp_socket.state();
|
||||
|
||||
info!(
|
||||
"📊 [TCP {}] Buffers: RX: {:>4} KB, TX: {:>4} KB | State: {:?}",
|
||||
handle,
|
||||
rx_cap / 1024,
|
||||
tx_cap / 1024,
|
||||
state
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn create_udp(&self, profile: TrafficProfile) -> udp::Socket<'static> {
|
||||
let (buf_size, meta_count) = match profile {
|
||||
TrafficProfile::Bulk => (self.config.udp_buf_heavy, self.config.udp_meta_heavy),
|
||||
@@ -131,20 +146,20 @@ impl SocketProvider for SmolSocketFactory {
|
||||
)
|
||||
}
|
||||
|
||||
fn create_icmp(&self) -> icmp::Socket<'static> {
|
||||
fn create_icmp(&self, _profile: TrafficProfile) -> icmp::Socket<'static> {
|
||||
icmp::Socket::new(
|
||||
icmp::PacketBuffer::new(vec![icmp::PacketMetadata::EMPTY; 4], vec![0; 512]),
|
||||
icmp::PacketBuffer::new(vec![icmp::PacketMetadata::EMPTY; 4], vec![0; 512]),
|
||||
)
|
||||
}
|
||||
|
||||
fn create_listening_tcp(&self, addr: Option<IpAddress>, port: u16) -> tcp::Socket {
|
||||
fn create_listening_tcp(&self, addr: Option<IpAddress>, port: u16) -> tcp::Socket {
|
||||
let profile = TrafficProfile::guess_from_port(port, true);
|
||||
let mut socket = self.create_tcp(profile);
|
||||
let _ = socket.listen(IpListenEndpoint { addr, port });
|
||||
socket
|
||||
}
|
||||
|
||||
|
||||
fn create_bound_udp(&self, addr: Option<IpAddress>, port: u16) -> udp::Socket<'static> {
|
||||
let profile = TrafficProfile::guess_from_port(port, false);
|
||||
let mut socket = self.create_udp(profile);
|
||||
@@ -156,7 +171,7 @@ impl SocketProvider for SmolSocketFactory {
|
||||
let mut sockets = SocketSet::new(Vec::with_capacity(128));
|
||||
sockets.add(self.create_bound_udp(None, 53));
|
||||
for _ in 0..n_icmp {
|
||||
sockets.add(self.create_icmp());
|
||||
sockets.add(self.create_icmp(TrafficProfile::Default));
|
||||
}
|
||||
sockets
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user