[mio] 增加模拟弱网参数
This commit is contained in:
@@ -37,6 +37,8 @@ pub struct FileConfig {
|
|||||||
pub cmd: bool,
|
pub cmd: bool,
|
||||||
pub first_latency: bool,
|
pub first_latency: bool,
|
||||||
pub device_name: Option<String>,
|
pub device_name: Option<String>,
|
||||||
|
pub packet_loss: Option<f64>,
|
||||||
|
pub packet_delay: u32,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for FileConfig {
|
impl Default for FileConfig {
|
||||||
@@ -71,6 +73,8 @@ impl Default for FileConfig {
|
|||||||
cmd: false,
|
cmd: false,
|
||||||
first_latency: false,
|
first_latency: false,
|
||||||
device_name: None,
|
device_name: None,
|
||||||
|
packet_loss: None,
|
||||||
|
packet_delay: 0,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -166,6 +170,8 @@ pub fn read_config(file_path: &str) -> io::Result<(Config, bool)> {
|
|||||||
file_conf.first_latency,
|
file_conf.first_latency,
|
||||||
file_conf.device_name,
|
file_conf.device_name,
|
||||||
use_channel_type,
|
use_channel_type,
|
||||||
|
file_conf.packet_loss,
|
||||||
|
file_conf.packet_delay
|
||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
Ok((config, file_conf.cmd))
|
Ok((config, file_conf.cmd))
|
||||||
|
|||||||
+13
-6
@@ -68,12 +68,9 @@ fn main() {
|
|||||||
opts.optflag("", "cmd", "开启窗口输入");
|
opts.optflag("", "cmd", "开启窗口输入");
|
||||||
opts.optflag("", "no-proxy", "关闭内置代理");
|
opts.optflag("", "no-proxy", "关闭内置代理");
|
||||||
opts.optflag("", "first-latency", "优先延迟");
|
opts.optflag("", "first-latency", "优先延迟");
|
||||||
opts.optopt(
|
opts.optopt("", "use-channel", "使用通道 relay/p2p", "<use-channel>");
|
||||||
"",
|
opts.optopt("", "packet-loss", "丢包率", "<packet-loss>");
|
||||||
"use-channel",
|
opts.optopt("", "packet-delay", "延迟", "<packet-delay>");
|
||||||
"使用通道 relay/p2p,默认两者都使用",
|
|
||||||
"<use-channel>",
|
|
||||||
);
|
|
||||||
opts.optopt("f", "", "配置文件", "<conf>");
|
opts.optopt("f", "", "配置文件", "<conf>");
|
||||||
//"后台运行时,查看其他设备列表"
|
//"后台运行时,查看其他设备列表"
|
||||||
opts.optflag("", "list", "后台运行时,查看其他设备列表");
|
opts.optflag("", "list", "后台运行时,查看其他设备列表");
|
||||||
@@ -294,6 +291,12 @@ fn main() {
|
|||||||
#[cfg(feature = "ip_proxy")]
|
#[cfg(feature = "ip_proxy")]
|
||||||
let no_proxy = matches.opt_present("no-proxy");
|
let no_proxy = matches.opt_present("no-proxy");
|
||||||
let first_latency = matches.opt_present("first-latency");
|
let first_latency = matches.opt_present("first-latency");
|
||||||
|
let packet_loss = matches
|
||||||
|
.opt_get::<f64>("packet-loss")
|
||||||
|
.expect("--packet-loss");
|
||||||
|
let packet_delay = matches
|
||||||
|
.opt_get::<u32>("packet-delay")
|
||||||
|
.expect("--packet-delay").unwrap_or(0);
|
||||||
let config = Config::new(
|
let config = Config::new(
|
||||||
#[cfg(any(target_os = "windows", target_os = "linux"))]
|
#[cfg(any(target_os = "windows", target_os = "linux"))]
|
||||||
tap,
|
tap,
|
||||||
@@ -320,6 +323,8 @@ fn main() {
|
|||||||
first_latency,
|
first_latency,
|
||||||
device_name,
|
device_name,
|
||||||
use_channel_type,
|
use_channel_type,
|
||||||
|
packet_loss,
|
||||||
|
packet_delay
|
||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
(config, cmd)
|
(config, cmd)
|
||||||
@@ -461,6 +466,8 @@ fn print_usage(program: &str, _opts: Options) {
|
|||||||
println!(" --first-latency 优先低延迟的通道,默认情况优先使用p2p通道");
|
println!(" --first-latency 优先低延迟的通道,默认情况优先使用p2p通道");
|
||||||
println!(" --use-channel <p2p> 使用通道 relay/p2p/all,默认两者都使用");
|
println!(" --use-channel <p2p> 使用通道 relay/p2p/all,默认两者都使用");
|
||||||
println!(" --nic <tun0> 指定虚拟网卡名称");
|
println!(" --nic <tun0> 指定虚拟网卡名称");
|
||||||
|
println!(" --packet-loss <0> 模拟丢包,取值0~1之间的小数,程序会按设定的概率主动丢包,可用于模拟弱网");
|
||||||
|
println!(" --packet-delay <0> 模拟延迟,整数,单位毫秒(ms),程序会按设定的值延迟发包,可用于模拟弱网");
|
||||||
|
|
||||||
println!();
|
println!();
|
||||||
println!(
|
println!(
|
||||||
|
|||||||
@@ -132,6 +132,8 @@ pub fn new_config(env: &mut JNIEnv, config: JObject) -> Result<Config, Error> {
|
|||||||
#[cfg(target_os = "android")]
|
#[cfg(target_os = "android")]
|
||||||
device_fd,
|
device_fd,
|
||||||
UseChannelType::from_str(&use_channel.unwrap_or_default()).unwrap_or_default(),
|
UseChannelType::from_str(&use_channel.unwrap_or_default()).unwrap_or_default(),
|
||||||
|
None,
|
||||||
|
0,
|
||||||
) {
|
) {
|
||||||
Ok(config) => config,
|
Ok(config) => config,
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ use std::time::{Duration, Instant};
|
|||||||
|
|
||||||
use crossbeam_utils::atomic::AtomicCell;
|
use crossbeam_utils::atomic::AtomicCell;
|
||||||
use parking_lot::RwLock;
|
use parking_lot::RwLock;
|
||||||
|
use rand::Rng;
|
||||||
|
|
||||||
use crate::channel::punch::NatType;
|
use crate::channel::punch::NatType;
|
||||||
use crate::channel::sender::{AcceptSocketSender, ChannelSender, PacketSender};
|
use crate::channel::sender::{AcceptSocketSender, ChannelSender, PacketSender};
|
||||||
@@ -26,9 +27,21 @@ impl Context {
|
|||||||
use_channel_type: UseChannelType,
|
use_channel_type: UseChannelType,
|
||||||
first_latency: bool,
|
first_latency: bool,
|
||||||
is_tcp: bool,
|
is_tcp: bool,
|
||||||
|
packet_loss_rate: Option<f64>,
|
||||||
|
packet_delay: u32,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
let channel_num = main_udp_socket.len();
|
let channel_num = main_udp_socket.len();
|
||||||
assert_ne!(channel_num, 0, "not channel");
|
assert_ne!(channel_num, 0, "not channel");
|
||||||
|
let packet_loss_rate = packet_loss_rate
|
||||||
|
.map(|v| {
|
||||||
|
let v = (v * PACKET_LOSS_RATE_DENOMINATOR as f64) as u32;
|
||||||
|
if v > PACKET_LOSS_RATE_DENOMINATOR {
|
||||||
|
PACKET_LOSS_RATE_DENOMINATOR
|
||||||
|
} else {
|
||||||
|
v
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.unwrap_or(0);
|
||||||
let inner = ContextInner {
|
let inner = ContextInner {
|
||||||
main_udp_socket,
|
main_udp_socket,
|
||||||
sub_udp_socket: RwLock::new(Vec::with_capacity(64)),
|
sub_udp_socket: RwLock::new(Vec::with_capacity(64)),
|
||||||
@@ -36,6 +49,8 @@ impl Context {
|
|||||||
route_table: RouteTable::new(use_channel_type, first_latency, channel_num),
|
route_table: RouteTable::new(use_channel_type, first_latency, channel_num),
|
||||||
is_tcp,
|
is_tcp,
|
||||||
state: AtomicBool::new(true),
|
state: AtomicBool::new(true),
|
||||||
|
packet_loss_rate,
|
||||||
|
packet_delay,
|
||||||
};
|
};
|
||||||
Self {
|
Self {
|
||||||
inner: Arc::new(inner),
|
inner: Arc::new(inner),
|
||||||
@@ -56,7 +71,7 @@ impl Deref for Context {
|
|||||||
|
|
||||||
/// 对称网络增加的udp socket数目,有助于增加打洞成功率
|
/// 对称网络增加的udp socket数目,有助于增加打洞成功率
|
||||||
pub const SYMMETRIC_CHANNEL_NUM: usize = 64;
|
pub const SYMMETRIC_CHANNEL_NUM: usize = 64;
|
||||||
|
const PACKET_LOSS_RATE_DENOMINATOR: u32 = 100_0000;
|
||||||
pub struct ContextInner {
|
pub struct ContextInner {
|
||||||
// 核心udp socket
|
// 核心udp socket
|
||||||
pub(crate) main_udp_socket: Vec<UdpSocket>,
|
pub(crate) main_udp_socket: Vec<UdpSocket>,
|
||||||
@@ -70,6 +85,10 @@ pub struct ContextInner {
|
|||||||
is_tcp: bool,
|
is_tcp: bool,
|
||||||
//状态
|
//状态
|
||||||
state: AtomicBool,
|
state: AtomicBool,
|
||||||
|
//控制丢包率,取值v=[0,100_0000] 丢包率r=v/100_0000
|
||||||
|
packet_loss_rate: u32,
|
||||||
|
//控制延迟
|
||||||
|
packet_delay: u32,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ContextInner {
|
impl ContextInner {
|
||||||
@@ -230,6 +249,27 @@ impl ContextInner {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
/// 发送网络数据
|
||||||
|
pub fn send_ipv4_by_id(
|
||||||
|
&self,
|
||||||
|
buf: &[u8],
|
||||||
|
id: &Ipv4Addr,
|
||||||
|
server_addr: SocketAddr,
|
||||||
|
) -> io::Result<()> {
|
||||||
|
if self.packet_loss_rate > 0 {
|
||||||
|
if rand::thread_rng().gen_ratio(self.packet_loss_rate, PACKET_LOSS_RATE_DENOMINATOR) {
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if self.packet_delay > 0 {
|
||||||
|
std::thread::sleep(Duration::from_millis(self.packet_delay as _));
|
||||||
|
}
|
||||||
|
if self.send_by_id(buf, id).is_err() && !self.route_table.use_channel_type.is_only_p2p() {
|
||||||
|
self.send_default(buf, server_addr)
|
||||||
|
} else {
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
/// 将数据发到指定id
|
/// 将数据发到指定id
|
||||||
pub fn send_by_id(&self, buf: &[u8], id: &Ipv4Addr) -> io::Result<()> {
|
pub fn send_by_id(&self, buf: &[u8], id: &Ipv4Addr) -> io::Result<()> {
|
||||||
let route = self.route_table.get_route_by_id(id)?;
|
let route = self.route_table.get_route_by_id(id)?;
|
||||||
|
|||||||
+10
-1
@@ -141,6 +141,8 @@ pub fn init_context(
|
|||||||
use_channel_type: UseChannelType,
|
use_channel_type: UseChannelType,
|
||||||
first_latency: bool,
|
first_latency: bool,
|
||||||
is_tcp: bool,
|
is_tcp: bool,
|
||||||
|
packet_loss_rate: Option<f64>,
|
||||||
|
packet_delay: u32,
|
||||||
) -> io::Result<(Context, mio::net::TcpListener)> {
|
) -> io::Result<(Context, mio::net::TcpListener)> {
|
||||||
assert!(!ports.is_empty(), "not channel");
|
assert!(!ports.is_empty(), "not channel");
|
||||||
let mut udps = Vec::with_capacity(ports.len());
|
let mut udps = Vec::with_capacity(ports.len());
|
||||||
@@ -158,7 +160,14 @@ pub fn init_context(
|
|||||||
main_channel.set_write_timeout(Some(Duration::from_secs(5)))?;
|
main_channel.set_write_timeout(Some(Duration::from_secs(5)))?;
|
||||||
udps.push(main_channel);
|
udps.push(main_channel);
|
||||||
}
|
}
|
||||||
let context = Context::new(udps, use_channel_type, first_latency, is_tcp);
|
let context = Context::new(
|
||||||
|
udps,
|
||||||
|
use_channel_type,
|
||||||
|
first_latency,
|
||||||
|
is_tcp,
|
||||||
|
packet_loss_rate,
|
||||||
|
packet_delay,
|
||||||
|
);
|
||||||
|
|
||||||
let port = context.main_local_udp_port()?[0];
|
let port = context.main_local_udp_port()?[0];
|
||||||
//监听v6+v4双栈,tcp通道使用异步io
|
//监听v6+v4双栈,tcp通道使用异步io
|
||||||
|
|||||||
@@ -93,6 +93,8 @@ impl Vnt {
|
|||||||
config.use_channel_type,
|
config.use_channel_type,
|
||||||
config.first_latency,
|
config.first_latency,
|
||||||
config.tcp,
|
config.tcp,
|
||||||
|
config.packet_loss_rate,
|
||||||
|
config.packet_delay,
|
||||||
)?;
|
)?;
|
||||||
let local_ipv4 = nat::local_ipv4();
|
let local_ipv4 = nat::local_ipv4();
|
||||||
let local_ipv6 = nat::local_ipv6();
|
let local_ipv6 = nat::local_ipv6();
|
||||||
|
|||||||
@@ -39,6 +39,9 @@ pub struct Config {
|
|||||||
#[cfg(target_os = "android")]
|
#[cfg(target_os = "android")]
|
||||||
pub device_fd: i32,
|
pub device_fd: i32,
|
||||||
pub use_channel_type: UseChannelType,
|
pub use_channel_type: UseChannelType,
|
||||||
|
//控制丢包率
|
||||||
|
pub packet_loss_rate: Option<f64>,
|
||||||
|
pub packet_delay: u32,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Config {
|
impl Config {
|
||||||
@@ -67,6 +70,8 @@ impl Config {
|
|||||||
#[cfg(not(target_os = "android"))] device_name: Option<String>,
|
#[cfg(not(target_os = "android"))] device_name: Option<String>,
|
||||||
#[cfg(target_os = "android")] device_fd: i32,
|
#[cfg(target_os = "android")] device_fd: i32,
|
||||||
use_channel_type: UseChannelType,
|
use_channel_type: UseChannelType,
|
||||||
|
packet_loss_rate: Option<f64>,
|
||||||
|
packet_delay: u32,
|
||||||
) -> io::Result<Self> {
|
) -> io::Result<Self> {
|
||||||
for x in stun_server.iter_mut() {
|
for x in stun_server.iter_mut() {
|
||||||
if !x.contains(":") {
|
if !x.contains(":") {
|
||||||
@@ -111,6 +116,8 @@ impl Config {
|
|||||||
#[cfg(target_os = "android")]
|
#[cfg(target_os = "android")]
|
||||||
device_fd,
|
device_fd,
|
||||||
use_channel_type,
|
use_channel_type,
|
||||||
|
packet_loss_rate,
|
||||||
|
packet_delay,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -150,10 +150,5 @@ pub fn base_handle(
|
|||||||
}
|
}
|
||||||
client_cipher.encrypt_ipv4(&mut net_packet)?;
|
client_cipher.encrypt_ipv4(&mut net_packet)?;
|
||||||
//优先发到直连到地址
|
//优先发到直连到地址
|
||||||
if context.send_by_id(net_packet.buffer(), &dest_ip).is_err() {
|
context.send_ipv4_by_id(net_packet.buffer(), &dest_ip, current_device.connect_server)
|
||||||
if !context.use_channel_type().is_only_p2p() {
|
|
||||||
context.send_default(net_packet.buffer(), current_device.connect_server)?;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return Ok(());
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -47,11 +47,11 @@ fn handle(
|
|||||||
client_cipher: &Cipher,
|
client_cipher: &Cipher,
|
||||||
server_cipher: &Cipher,
|
server_cipher: &Cipher,
|
||||||
) -> io::Result<()> {
|
) -> io::Result<()> {
|
||||||
if len > 12 && data[12] >> 4 != 4 {
|
//忽略掉结构不对的情况(ipv6数据、win tap会读到空数据),不然日志打印太多了
|
||||||
//忽略非ipv4包
|
let ipv4_packet = match IpV4Packet::new(&mut data[12..len]) {
|
||||||
return Ok(());
|
Ok(packet) => packet,
|
||||||
}
|
Err(_) => return Ok(()),
|
||||||
let ipv4_packet = IpV4Packet::new(&mut data[12..len])?;
|
};
|
||||||
let src_ip = ipv4_packet.source_ip();
|
let src_ip = ipv4_packet.source_ip();
|
||||||
let dest_ip = ipv4_packet.destination_ip();
|
let dest_ip = ipv4_packet.destination_ip();
|
||||||
if src_ip == dest_ip {
|
if src_ip == dest_ip {
|
||||||
|
|||||||
Reference in New Issue
Block a user