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:
Sijie.Sun
2024-10-13 11:59:16 +08:00
committed by GitHub
parent 55efd62798
commit d87a440c04
13 changed files with 181 additions and 35 deletions

View File

@@ -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());

View File

@@ -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

View File

@@ -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())),
}

View File

@@ -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()),
}

View File

@@ -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};

View File

@@ -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());
}
}

View File

@@ -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<()>;

View File

@@ -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;