Add lazy P2P demand tracking and need_p2p override (#2003)

- add lazy_p2p so nodes only start background P2P for peers that actually have recent business traffic
- add need_p2p so specific peers can still request eager background P2P even when other nodes enable lazy mode
- cover the new behavior with focused connector/peer-manager tests plus three-node integration tests that verify relay-to-direct route transition
This commit is contained in:
KKRainbow
2026-03-23 09:38:57 +08:00
committed by GitHub
parent 2bfdd44759
commit 1d89ddbb16
22 changed files with 876 additions and 91 deletions
+75
View File
@@ -15,6 +15,7 @@ use crate::tunnel::unix::UnixSocketTunnelConnector;
use crate::tunnel::wireguard::{WgConfig, WgTunnelConnector};
use crate::{
common::{error::Error, global_ctx::ArcGlobalCtx, idn, network::IPCollector},
proto::common::PeerFeatureFlag,
tunnel::{
check_scheme_and_get_socket_addr, ring::RingTunnelConnector, tcp::TcpTunnelConnector,
udp::UdpTunnelConnector, IpVersion, TunnelConnector,
@@ -29,6 +30,24 @@ pub mod udp_hole_punch;
pub mod dns_connector;
pub mod http_connector;
pub(crate) fn should_try_p2p_with_peer(
feature_flag: Option<&PeerFeatureFlag>,
allow_public_server: bool,
) -> bool {
feature_flag
.map(|flag| allow_public_server || !flag.is_public_server)
.unwrap_or(true)
}
pub(crate) fn should_background_p2p_with_peer(
feature_flag: Option<&PeerFeatureFlag>,
allow_public_server: bool,
lazy_p2p: bool,
) -> bool {
should_try_p2p_with_peer(feature_flag, allow_public_server)
&& (!lazy_p2p || feature_flag.map(|flag| flag.need_p2p).unwrap_or(false))
}
async fn set_bind_addr_for_peer_connector(
connector: &mut (impl TunnelConnector + ?Sized),
is_ipv4: bool,
@@ -197,3 +216,59 @@ pub async fn create_connector_by_url(
Ok(connector)
}
#[cfg(test)]
mod tests {
use crate::proto::common::PeerFeatureFlag;
use super::{should_background_p2p_with_peer, should_try_p2p_with_peer};
#[test]
fn lazy_background_p2p_requires_need_p2p() {
let no_need_p2p = PeerFeatureFlag {
need_p2p: false,
..Default::default()
};
let need_p2p = PeerFeatureFlag {
need_p2p: true,
..Default::default()
};
assert!(should_background_p2p_with_peer(
Some(&no_need_p2p),
false,
false
));
assert!(!should_background_p2p_with_peer(
Some(&no_need_p2p),
false,
true
));
assert!(should_background_p2p_with_peer(
Some(&need_p2p),
false,
true
));
}
#[test]
fn p2p_policy_respects_public_server_setting() {
let public_server = PeerFeatureFlag {
is_public_server: true,
..Default::default()
};
assert!(!should_try_p2p_with_peer(Some(&public_server), false));
assert!(should_try_p2p_with_peer(Some(&public_server), true));
assert!(!should_background_p2p_with_peer(
Some(&public_server),
false,
false
));
assert!(should_background_p2p_with_peer(
Some(&public_server),
true,
false
));
}
}