mirror of
https://mirror.suhoan.cn/https://github.com/EasyTier/EasyTier.git
synced 2025-12-13 05:07:23 +08:00
fix 202 bugs (#418)
* fix peer rpc stop working because of mpsc tunnel close unexpectedly * fix gui: 1. allow set network prefix for virtual ipv4 2. fix android crash 3. fix subnet proxy cannot be set on android
This commit is contained in:
@@ -93,7 +93,7 @@ impl PeerConn {
|
||||
let peer_conn_tunnel_filter = StatsRecorderTunnelFilter::new();
|
||||
let throughput = peer_conn_tunnel_filter.filter_output();
|
||||
let peer_conn_tunnel = TunnelWithFilter::new(tunnel, peer_conn_tunnel_filter);
|
||||
let mut mpsc_tunnel = MpscTunnel::new(peer_conn_tunnel);
|
||||
let mut mpsc_tunnel = MpscTunnel::new(peer_conn_tunnel, Some(Duration::from_secs(7)));
|
||||
|
||||
let (recv, sink) = (mpsc_tunnel.get_stream(), mpsc_tunnel.get_sink());
|
||||
|
||||
|
||||
@@ -1387,7 +1387,9 @@ impl PeerRouteServiceImpl {
|
||||
if resp.error.is_some() {
|
||||
let err = resp.error.unwrap();
|
||||
if err == Error::DuplicatePeerId as i32 {
|
||||
panic!("duplicate peer id");
|
||||
if !self.global_ctx.get_feature_flags().is_public_server {
|
||||
panic!("duplicate peer id");
|
||||
}
|
||||
} else {
|
||||
tracing::error!(?ret, ?my_peer_id, ?dst_peer_id, "sync_route_info failed");
|
||||
session
|
||||
|
||||
@@ -61,8 +61,8 @@ impl Client {
|
||||
pub fn new() -> Self {
|
||||
let (ring_a, ring_b) = create_ring_tunnel_pair();
|
||||
Self {
|
||||
mpsc: Mutex::new(MpscTunnel::new(ring_a)),
|
||||
transport: Mutex::new(MpscTunnel::new(ring_b)),
|
||||
mpsc: Mutex::new(MpscTunnel::new(ring_a, None)),
|
||||
transport: Mutex::new(MpscTunnel::new(ring_b, None)),
|
||||
inflight_requests: Arc::new(DashMap::new()),
|
||||
tasks: Arc::new(Mutex::new(JoinSet::new())),
|
||||
}
|
||||
|
||||
@@ -56,8 +56,8 @@ impl Server {
|
||||
|
||||
Self {
|
||||
registry,
|
||||
mpsc: Mutex::new(Some(MpscTunnel::new(ring_a))),
|
||||
transport: Mutex::new(MpscTunnel::new(ring_b)),
|
||||
mpsc: Mutex::new(Some(MpscTunnel::new(ring_a, None))),
|
||||
transport: Mutex::new(MpscTunnel::new(ring_b, None)),
|
||||
tasks: Arc::new(Mutex::new(JoinSet::new())),
|
||||
packet_mergers: Arc::new(DashMap::new()),
|
||||
}
|
||||
|
||||
@@ -175,6 +175,83 @@ async fn rpc_timeout_test() {
|
||||
assert_eq!(0, ctx.server.inflight_count());
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn rpc_tunnel_stuck_test() {
|
||||
use crate::proto::rpc_types;
|
||||
use crate::tunnel::ring::RING_TUNNEL_CAP;
|
||||
|
||||
let rpc_server = Server::new();
|
||||
rpc_server.run();
|
||||
let server = GreetingServer::new(GreetingService {
|
||||
delay_ms: 0,
|
||||
prefix: "Hello".to_string(),
|
||||
});
|
||||
rpc_server.registry().register(server, "test");
|
||||
|
||||
let client = Client::new();
|
||||
client.run();
|
||||
|
||||
let rpc_tasks = Arc::new(Mutex::new(JoinSet::new()));
|
||||
let (mut rx, tx) = (
|
||||
rpc_server.get_transport_stream(),
|
||||
client.get_transport_sink(),
|
||||
);
|
||||
|
||||
rpc_tasks.lock().unwrap().spawn(async move {
|
||||
while let Some(Ok(packet)) = rx.next().await {
|
||||
if let Err(err) = tx.send(packet).await {
|
||||
println!("{:?}", err);
|
||||
break;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// mock server is stuck (no task to do forwards)
|
||||
|
||||
let mut tasks = JoinSet::new();
|
||||
for _ in 0..RING_TUNNEL_CAP + 15 {
|
||||
let out =
|
||||
client.scoped_client::<GreetingClientFactory<RpcController>>(1, 1, "test".to_string());
|
||||
tasks.spawn(async move {
|
||||
let mut ctrl = RpcController::default();
|
||||
ctrl.timeout_ms = 1000;
|
||||
|
||||
let input = SayHelloRequest {
|
||||
name: "world".to_string(),
|
||||
};
|
||||
|
||||
out.say_hello(ctrl, input).await
|
||||
});
|
||||
}
|
||||
while let Some(ret) = tasks.join_next().await {
|
||||
assert!(matches!(ret, Ok(Err(rpc_types::error::Error::Timeout(_)))));
|
||||
}
|
||||
|
||||
// start server consumer, new requests should be processed
|
||||
let (mut rx, tx) = (
|
||||
client.get_transport_stream(),
|
||||
rpc_server.get_transport_sink(),
|
||||
);
|
||||
rpc_tasks.lock().unwrap().spawn(async move {
|
||||
while let Some(Ok(packet)) = rx.next().await {
|
||||
if let Err(err) = tx.send(packet).await {
|
||||
println!("{:?}", err);
|
||||
break;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
let out =
|
||||
client.scoped_client::<GreetingClientFactory<RpcController>>(1, 1, "test".to_string());
|
||||
let mut ctrl = RpcController::default();
|
||||
ctrl.timeout_ms = 1000;
|
||||
let input = SayHelloRequest {
|
||||
name: "fuck world".to_string(),
|
||||
};
|
||||
let ret = out.say_hello(ctrl, input).await.unwrap();
|
||||
assert_eq!(ret.greeting, "Hello fuck world!");
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn standalone_rpc_test() {
|
||||
use crate::proto::rpc_impl::standalone::{StandAloneClient, StandAloneServer};
|
||||
|
||||
@@ -41,13 +41,13 @@ pub struct MpscTunnel<T> {
|
||||
}
|
||||
|
||||
impl<T: Tunnel> MpscTunnel<T> {
|
||||
pub fn new(tunnel: T) -> Self {
|
||||
pub fn new(tunnel: T, send_timeout: Option<Duration>) -> Self {
|
||||
let (tx, mut rx) = channel(32);
|
||||
let (stream, mut sink) = tunnel.split();
|
||||
|
||||
let task = tokio::spawn(async move {
|
||||
loop {
|
||||
if let Err(e) = Self::forward_one_round(&mut rx, &mut sink).await {
|
||||
if let Err(e) = Self::forward_one_round(&mut rx, &mut sink, send_timeout).await {
|
||||
tracing::error!(?e, "forward error");
|
||||
break;
|
||||
}
|
||||
@@ -68,21 +68,44 @@ impl<T: Tunnel> MpscTunnel<T> {
|
||||
async fn forward_one_round(
|
||||
rx: &mut Receiver<ZCPacket>,
|
||||
sink: &mut Pin<Box<dyn ZCPacketSink>>,
|
||||
send_timeout_ms: Option<Duration>,
|
||||
) -> Result<(), TunnelError> {
|
||||
let item = rx.recv().await.with_context(|| "recv error")?;
|
||||
if let Some(timeout_ms) = send_timeout_ms {
|
||||
Self::forward_one_round_with_timeout(rx, sink, item, timeout_ms).await
|
||||
} else {
|
||||
Self::forward_one_round_no_timeout(rx, sink, item).await
|
||||
}
|
||||
}
|
||||
|
||||
match timeout(Duration::from_secs(10), async move {
|
||||
sink.feed(item).await?;
|
||||
while let Ok(item) = rx.try_recv() {
|
||||
match sink.feed(item).await {
|
||||
Err(e) => {
|
||||
tracing::error!(?e, "feed error");
|
||||
return Err(e);
|
||||
}
|
||||
Ok(_) => {}
|
||||
async fn forward_one_round_no_timeout(
|
||||
rx: &mut Receiver<ZCPacket>,
|
||||
sink: &mut Pin<Box<dyn ZCPacketSink>>,
|
||||
initial_item: ZCPacket,
|
||||
) -> Result<(), TunnelError> {
|
||||
sink.feed(initial_item).await?;
|
||||
|
||||
while let Ok(item) = rx.try_recv() {
|
||||
match sink.feed(item).await {
|
||||
Err(e) => {
|
||||
tracing::error!(?e, "feed error");
|
||||
return Err(e);
|
||||
}
|
||||
Ok(_) => {}
|
||||
}
|
||||
sink.flush().await
|
||||
}
|
||||
|
||||
sink.flush().await
|
||||
}
|
||||
|
||||
async fn forward_one_round_with_timeout(
|
||||
rx: &mut Receiver<ZCPacket>,
|
||||
sink: &mut Pin<Box<dyn ZCPacketSink>>,
|
||||
initial_item: ZCPacket,
|
||||
timeout_ms: Duration,
|
||||
) -> Result<(), TunnelError> {
|
||||
match timeout(timeout_ms, async move {
|
||||
Self::forward_one_round_no_timeout(rx, sink, initial_item).await
|
||||
})
|
||||
.await
|
||||
{
|
||||
@@ -112,17 +135,12 @@ impl<T: Tunnel> MpscTunnel<T> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Tunnel> From<T> for MpscTunnel<T> {
|
||||
fn from(tunnel: T) -> Self {
|
||||
Self::new(tunnel)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use futures::StreamExt;
|
||||
|
||||
use crate::tunnel::{
|
||||
ring::{create_ring_tunnel_pair, RING_TUNNEL_CAP},
|
||||
tcp::{TcpTunnelConnector, TcpTunnelListener},
|
||||
TunnelConnector, TunnelListener,
|
||||
};
|
||||
@@ -162,7 +180,7 @@ mod tests {
|
||||
});
|
||||
|
||||
let tunnel = connector.connect().await.unwrap();
|
||||
let mpsc_tunnel = MpscTunnel::from(tunnel);
|
||||
let mpsc_tunnel = MpscTunnel::new(tunnel, None);
|
||||
|
||||
let sink1 = mpsc_tunnel.get_sink();
|
||||
let t2 = tokio::spawn(async move {
|
||||
@@ -213,4 +231,24 @@ mod tests {
|
||||
|
||||
let _ = tokio::join!(t1, t2, t3, t4);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn mpsc_slow_receiver_with_send_timeout() {
|
||||
let (a, _b) = create_ring_tunnel_pair();
|
||||
let mpsc_tunnel = MpscTunnel::new(a, Some(Duration::from_secs(1)));
|
||||
let s = mpsc_tunnel.get_sink();
|
||||
for _ in 0..RING_TUNNEL_CAP {
|
||||
s.send(ZCPacket::new_with_payload(&[0; 1024]))
|
||||
.await
|
||||
.unwrap();
|
||||
}
|
||||
tokio::time::sleep(Duration::from_millis(1500)).await;
|
||||
let e = s.send(ZCPacket::new_with_payload(&[0; 1024])).await;
|
||||
assert!(e.is_ok());
|
||||
|
||||
tokio::time::sleep(Duration::from_millis(1500)).await;
|
||||
|
||||
let e = s.send(ZCPacket::new_with_payload(&[0; 1024])).await;
|
||||
assert!(e.is_err());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -26,7 +26,7 @@ use super::{
|
||||
StreamItem, Tunnel, TunnelConnector, TunnelError, TunnelInfo, TunnelListener,
|
||||
};
|
||||
|
||||
static RING_TUNNEL_CAP: usize = 128;
|
||||
pub static RING_TUNNEL_CAP: usize = 128;
|
||||
static RING_TUNNEL_RESERVERD_CAP: usize = 4;
|
||||
|
||||
type RingLock = parking_lot::Mutex<()>;
|
||||
|
||||
@@ -81,7 +81,7 @@ impl WireGuardImpl {
|
||||
wg_peer_ip_table: WgPeerIpTable,
|
||||
) {
|
||||
let info = t.info().unwrap_or_default();
|
||||
let mut mpsc_tunnel = MpscTunnel::new(t);
|
||||
let mut mpsc_tunnel = MpscTunnel::new(t, None);
|
||||
let mut stream = mpsc_tunnel.get_stream();
|
||||
let mut ip_registered = false;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user