mirror of
https://mirror.suhoan.cn/https://github.com/EasyTier/EasyTier.git
synced 2025-12-14 05:37:23 +08:00
nat4-nat4 punch (#388)
this patch optimize the udp hole punch logic: 1. allow start punch hole before stun test complete. 2. add lock to symmetric punch, avoid conflict between concurrent hole punching task. 3. support punching hole for predictable nat4-nat4. 4. make backoff of retry reasonable
This commit is contained in:
@@ -94,7 +94,7 @@ pub trait Tunnel: Send {
|
||||
|
||||
#[auto_impl::auto_impl(Arc)]
|
||||
pub trait TunnelConnCounter: 'static + Send + Sync + Debug {
|
||||
fn get(&self) -> u32;
|
||||
fn get(&self) -> Option<u32>;
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq)]
|
||||
@@ -114,8 +114,8 @@ pub trait TunnelListener: Send {
|
||||
#[derive(Debug)]
|
||||
struct FakeTunnelConnCounter {}
|
||||
impl TunnelConnCounter for FakeTunnelConnCounter {
|
||||
fn get(&self) -> u32 {
|
||||
0
|
||||
fn get(&self) -> Option<u32> {
|
||||
None
|
||||
}
|
||||
}
|
||||
Arc::new(Box::new(FakeTunnelConnCounter {}))
|
||||
|
||||
@@ -43,6 +43,10 @@ impl TunnelListener for TcpTunnelListener {
|
||||
setup_sokcet2(&socket2_socket, &addr)?;
|
||||
let socket = TcpSocket::from_std_stream(socket2_socket.into());
|
||||
|
||||
if let Err(e) = socket.set_nodelay(true) {
|
||||
tracing::warn!(?e, "set_nodelay fail in listen");
|
||||
}
|
||||
|
||||
self.addr
|
||||
.set_port(Some(socket.local_addr()?.port()))
|
||||
.unwrap();
|
||||
@@ -54,7 +58,11 @@ impl TunnelListener for TcpTunnelListener {
|
||||
async fn accept(&mut self) -> Result<Box<dyn Tunnel>, super::TunnelError> {
|
||||
let listener = self.listener.as_ref().unwrap();
|
||||
let (stream, _) = listener.accept().await?;
|
||||
stream.set_nodelay(true).unwrap();
|
||||
|
||||
if let Err(e) = stream.set_nodelay(true) {
|
||||
tracing::warn!(?e, "set_nodelay fail in accept");
|
||||
}
|
||||
|
||||
let info = TunnelInfo {
|
||||
tunnel_type: "tcp".to_owned(),
|
||||
local_addr: Some(self.local_url().into()),
|
||||
@@ -80,7 +88,9 @@ fn get_tunnel_with_tcp_stream(
|
||||
stream: TcpStream,
|
||||
remote_url: url::Url,
|
||||
) -> Result<Box<dyn Tunnel>, super::TunnelError> {
|
||||
stream.set_nodelay(true).unwrap();
|
||||
if let Err(e) = stream.set_nodelay(true) {
|
||||
tracing::warn!(?e, "set_nodelay fail in get_tunnel_with_tcp_stream");
|
||||
}
|
||||
|
||||
let info = TunnelInfo {
|
||||
tunnel_type: "tcp".to_owned(),
|
||||
|
||||
@@ -1,4 +1,7 @@
|
||||
use std::{fmt::Debug, sync::Arc};
|
||||
use std::{
|
||||
fmt::Debug,
|
||||
sync::{Arc, Weak},
|
||||
};
|
||||
|
||||
use async_trait::async_trait;
|
||||
use bytes::BytesMut;
|
||||
@@ -445,25 +448,25 @@ impl TunnelListener for UdpTunnelListener {
|
||||
|
||||
fn get_conn_counter(&self) -> Arc<Box<dyn TunnelConnCounter>> {
|
||||
struct UdpTunnelConnCounter {
|
||||
sock_map: Arc<DashMap<SocketAddr, UdpConnection>>,
|
||||
sock_map: Weak<DashMap<SocketAddr, UdpConnection>>,
|
||||
}
|
||||
|
||||
impl TunnelConnCounter for UdpTunnelConnCounter {
|
||||
fn get(&self) -> Option<u32> {
|
||||
self.sock_map.upgrade().map(|x| x.len() as u32)
|
||||
}
|
||||
}
|
||||
|
||||
impl Debug for UdpTunnelConnCounter {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
f.debug_struct("UdpTunnelConnCounter")
|
||||
.field("sock_map_len", &self.sock_map.len())
|
||||
.field("sock_map_len", &self.get())
|
||||
.finish()
|
||||
}
|
||||
}
|
||||
|
||||
impl TunnelConnCounter for UdpTunnelConnCounter {
|
||||
fn get(&self) -> u32 {
|
||||
self.sock_map.len() as u32
|
||||
}
|
||||
}
|
||||
|
||||
Arc::new(Box::new(UdpTunnelConnCounter {
|
||||
sock_map: self.data.sock_map.clone(),
|
||||
sock_map: Arc::downgrade(&self.data.sock_map.clone()),
|
||||
}))
|
||||
}
|
||||
}
|
||||
@@ -942,14 +945,22 @@ mod tests {
|
||||
|
||||
listener.listen().await.unwrap();
|
||||
let c1 = listener.accept().await.unwrap();
|
||||
assert_eq!(conn_counter.get(), 1);
|
||||
assert_eq!(conn_counter.get(), Some(1));
|
||||
let c2 = listener.accept().await.unwrap();
|
||||
assert_eq!(conn_counter.get(), 2);
|
||||
assert_eq!(conn_counter.get(), Some(2));
|
||||
|
||||
drop(c2);
|
||||
wait_for_condition(|| async { conn_counter.get() == 1 }, Duration::from_secs(1)).await;
|
||||
wait_for_condition(
|
||||
|| async { conn_counter.get() == Some(1) },
|
||||
Duration::from_secs(1),
|
||||
)
|
||||
.await;
|
||||
|
||||
drop(c1);
|
||||
wait_for_condition(|| async { conn_counter.get() == 0 }, Duration::from_secs(1)).await;
|
||||
wait_for_condition(
|
||||
|| async { conn_counter.get().unwrap_or(0) == 0 },
|
||||
Duration::from_secs(1),
|
||||
)
|
||||
.await;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user