增加命令
This commit is contained in:
+2
-16
@@ -1,5 +1,5 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "virtual_network"
|
name = "switch"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
|
|
||||||
@@ -18,7 +18,7 @@ parking_lot = "0.12.1"
|
|||||||
rsa = "0.7.2"
|
rsa = "0.7.2"
|
||||||
rand = "0.8.5"
|
rand = "0.8.5"
|
||||||
sha2 = { version = "0.10.6", features = ["oid"] }
|
sha2 = { version = "0.10.6", features = ["oid"] }
|
||||||
colored = "2.0.0"
|
#colored = "2.0.0"
|
||||||
|
|
||||||
thiserror = "1.0.37"
|
thiserror = "1.0.37"
|
||||||
chrono = "0.4.23"
|
chrono = "0.4.23"
|
||||||
@@ -29,7 +29,6 @@ protobuf = "3.2.0"
|
|||||||
console = "0.15.2"
|
console = "0.15.2"
|
||||||
mac_address = "1.1.4"
|
mac_address = "1.1.4"
|
||||||
clap = { version = "4.0.32", features = ["derive"] }
|
clap = { version = "4.0.32", features = ["derive"] }
|
||||||
#clap_derive = "4.0.21"
|
|
||||||
[target.'cfg(any(unix))'.dependencies]
|
[target.'cfg(any(unix))'.dependencies]
|
||||||
tun = { version = "0.5" }
|
tun = { version = "0.5" }
|
||||||
sudo = "0.6.0"
|
sudo = "0.6.0"
|
||||||
@@ -40,19 +39,6 @@ wintun = "0.2.1"
|
|||||||
libloading = "0.7.4"
|
libloading = "0.7.4"
|
||||||
runas = "0.2.1"
|
runas = "0.2.1"
|
||||||
|
|
||||||
#[dependencies.windows]
|
|
||||||
#
|
|
||||||
#libloading = "0.7.4"
|
|
||||||
#
|
|
||||||
#version = "0.37.0"
|
|
||||||
#features = [
|
|
||||||
# "alloc",
|
|
||||||
# "Win32_Foundation",
|
|
||||||
# "Win32_NetworkManagement_IpHelper",
|
|
||||||
# "Win32_Networking_WinSock",
|
|
||||||
# "Win32_UI_WindowsAndMessaging",
|
|
||||||
# "Win32_System_IO"
|
|
||||||
#]
|
|
||||||
[build-dependencies]
|
[build-dependencies]
|
||||||
protobuf-codegen = "3.2.0"
|
protobuf-codegen = "3.2.0"
|
||||||
protoc-bin-vendored = "3.0.0"
|
protoc-bin-vendored = "3.0.0"
|
||||||
@@ -4,15 +4,15 @@ use std::time::Duration;
|
|||||||
|
|
||||||
use chrono::Local;
|
use chrono::Local;
|
||||||
|
|
||||||
|
use crate::DEVICE_LIST;
|
||||||
use crate::error::*;
|
use crate::error::*;
|
||||||
use crate::handle::DIRECT_ROUTE_TABLE;
|
use crate::handle::DIRECT_ROUTE_TABLE;
|
||||||
use crate::protocol::control_packet::PingPacket;
|
|
||||||
use crate::protocol::{control_packet, NetPacket, Protocol, Version};
|
use crate::protocol::{control_packet, NetPacket, Protocol, Version};
|
||||||
use crate::DEVICE_LIST;
|
use crate::protocol::control_packet::PingPacket;
|
||||||
|
|
||||||
pub fn handle_loop(udp: UdpSocket, server_addr: SocketAddr) -> Result<()> {
|
pub fn handle_loop(udp: UdpSocket, server_addr: SocketAddr) -> Result<()> {
|
||||||
const INTERVAL: u64 = 3000;
|
const INTERVAL: u64 = 3000;
|
||||||
const MAX_INTERVAL: i64 = 3000 * 5;
|
const MAX_INTERVAL: i64 = 3000 * 3;
|
||||||
let mut buf = [0u8; (4 + 8 + 4)];
|
let mut buf = [0u8; (4 + 8 + 4)];
|
||||||
let mut net_packet = NetPacket::new(&mut buf)?;
|
let mut net_packet = NetPacket::new(&mut buf)?;
|
||||||
net_packet.set_version(Version::V1);
|
net_packet.set_version(Version::V1);
|
||||||
@@ -20,23 +20,23 @@ pub fn handle_loop(udp: UdpSocket, server_addr: SocketAddr) -> Result<()> {
|
|||||||
net_packet.set_transport_protocol(control_packet::Protocol::Ping.into());
|
net_packet.set_transport_protocol(control_packet::Protocol::Ping.into());
|
||||||
net_packet.set_ttl(255);
|
net_packet.set_ttl(255);
|
||||||
loop {
|
loop {
|
||||||
let current_time = Local::now().timestamp();
|
let current_time = Local::now().timestamp_millis();
|
||||||
{
|
{
|
||||||
let mut ping = PingPacket::new(net_packet.payload_mut())?;
|
let mut ping = PingPacket::new(net_packet.payload_mut())?;
|
||||||
ping.set_time(current_time);
|
ping.set_time(current_time);
|
||||||
let epoch = { DEVICE_LIST.lock().0 };
|
let epoch = { DEVICE_LIST.lock().0 };
|
||||||
ping.set_epoch(epoch);
|
ping.set_epoch(epoch);
|
||||||
}
|
}
|
||||||
udp.send_to(net_packet.buffer(), server_addr)?;
|
let _ = udp.send_to(net_packet.buffer(), server_addr);
|
||||||
for x in DIRECT_ROUTE_TABLE.iter() {
|
for x in DIRECT_ROUTE_TABLE.iter() {
|
||||||
let virtual_ip = x.key().clone();
|
let virtual_ip = x.key().clone();
|
||||||
let route = x.value().clone();
|
let route = x.value().clone();
|
||||||
drop(x);
|
drop(x);
|
||||||
if current_time - route.recv_time <= MAX_INTERVAL {
|
if current_time - route.recv_time <= MAX_INTERVAL {
|
||||||
udp.send_to(net_packet.buffer(), route.address)?;
|
let _ = udp.send_to(net_packet.buffer(), route.address);
|
||||||
} else {
|
} else {
|
||||||
DIRECT_ROUTE_TABLE.remove_if(&virtual_ip, |_, route| {
|
DIRECT_ROUTE_TABLE.remove_if(&virtual_ip, |_, route| {
|
||||||
current_time - route.recv_time > MAX_INTERVAL
|
current_time - route.recv_time <= MAX_INTERVAL
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+10
-10
@@ -82,15 +82,15 @@ pub fn init_nat_info(public_ip: u32, public_port: u16) {
|
|||||||
|
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub struct CurrentDeviceInfo {
|
pub struct CurrentDeviceInfo {
|
||||||
virtual_ip: Ipv4Addr,
|
pub(crate) virtual_ip: Ipv4Addr,
|
||||||
virtual_gateway: Ipv4Addr,
|
pub(crate) virtual_gateway: Ipv4Addr,
|
||||||
virtual_netmask: Ipv4Addr,
|
pub(crate) virtual_netmask: Ipv4Addr,
|
||||||
//网络地址
|
//网络地址
|
||||||
virtual_network: Ipv4Addr,
|
pub(crate) virtual_network: Ipv4Addr,
|
||||||
//直接广播地址
|
//直接广播地址
|
||||||
broadcast_address: Ipv4Addr,
|
pub(crate) broadcast_address: Ipv4Addr,
|
||||||
//链接的服务器地址
|
//链接的服务器地址
|
||||||
connect_server: SocketAddr,
|
pub(crate) connect_server: SocketAddr,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl CurrentDeviceInfo {
|
impl CurrentDeviceInfo {
|
||||||
@@ -114,11 +114,11 @@ impl CurrentDeviceInfo {
|
|||||||
|
|
||||||
#[derive(Clone,Debug)]
|
#[derive(Clone,Debug)]
|
||||||
pub struct Route {
|
pub struct Route {
|
||||||
address: SocketAddr,
|
pub(crate) address: SocketAddr,
|
||||||
//用心跳探测延迟,收包时更新
|
//用心跳探测延迟,收包时更新
|
||||||
delay: i64,
|
pub(crate) delay: i64,
|
||||||
//收包时更新,如果太久没有收到消息则剔除
|
//收包时更新,如果太久没有收到消息则剔除
|
||||||
recv_time: i64,
|
pub(crate) recv_time: i64,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Route {
|
impl Route {
|
||||||
@@ -126,7 +126,7 @@ impl Route {
|
|||||||
Self {
|
Self {
|
||||||
address,
|
address,
|
||||||
delay: -1,
|
delay: -1,
|
||||||
recv_time: Local::now().timestamp(),
|
recv_time: Local::now().timestamp_millis(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -91,7 +91,7 @@ fn registration_request_packet(token: String, mac_address: String) -> Result<Net
|
|||||||
|
|
||||||
pub fn fast_registration(udp: &UdpSocket, server_address: SocketAddr) -> Result<()> {
|
pub fn fast_registration(udp: &UdpSocket, server_address: SocketAddr) -> Result<()> {
|
||||||
let last = REGISTRATION_TIME.load(Ordering::Relaxed);
|
let last = REGISTRATION_TIME.load(Ordering::Relaxed);
|
||||||
let new = Local::now().timestamp();
|
let new = Local::now().timestamp_millis();
|
||||||
if new - last < 2000
|
if new - last < 2000
|
||||||
|| REGISTRATION_TIME
|
|| REGISTRATION_TIME
|
||||||
.compare_exchange(last, new, Ordering::Relaxed, Ordering::Relaxed)
|
.compare_exchange(last, new, Ordering::Relaxed, Ordering::Relaxed)
|
||||||
@@ -106,7 +106,7 @@ pub fn fast_registration(udp: &UdpSocket, server_address: SocketAddr) -> Result<
|
|||||||
if let Some((token, mac_address)) = option {
|
if let Some((token, mac_address)) = option {
|
||||||
let request_packet = registration_request_packet(token, mac_address)?;
|
let request_packet = registration_request_packet(token, mac_address)?;
|
||||||
udp.send_to(request_packet.buffer(), server_address)?;
|
udp.send_to(request_packet.buffer(), server_address)?;
|
||||||
REGISTRATION_TIME.store(Local::now().timestamp(), Ordering::Relaxed);
|
REGISTRATION_TIME.store(Local::now().timestamp_millis(), Ordering::Relaxed);
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
return Err(Error::Stop("注册信息不存在".to_string()));
|
return Err(Error::Stop("注册信息不存在".to_string()));
|
||||||
|
|||||||
@@ -71,7 +71,7 @@ fn handle(
|
|||||||
ipv4_turn_packet.set_payload(ipv4_packet.buffer);
|
ipv4_turn_packet.set_payload(ipv4_packet.buffer);
|
||||||
//优先发到直连到地址
|
//优先发到直连到地址
|
||||||
if let Some(route) = DIRECT_ROUTE_TABLE.get(&dest_ip) {
|
if let Some(route) = DIRECT_ROUTE_TABLE.get(&dest_ip) {
|
||||||
let current_time = Local::now().timestamp();
|
let current_time = Local::now().timestamp_millis();
|
||||||
if current_time - route.recv_time < 3_000 {
|
if current_time - route.recv_time < 3_000 {
|
||||||
udp.send_to(&net_packet.buffer()[..(4 + 8 + data_len)], route.address)?;
|
udp.send_to(&net_packet.buffer()[..(4 + 8 + data_len)], route.address)?;
|
||||||
return Ok(());
|
return Ok(());
|
||||||
|
|||||||
@@ -200,12 +200,12 @@ fn other_handle(
|
|||||||
}
|
}
|
||||||
Protocol::Control => {
|
Protocol::Control => {
|
||||||
match ControlPacket::new(net_packet.transport_protocol(), net_packet.payload())? {
|
match ControlPacket::new(net_packet.transport_protocol(), net_packet.payload())? {
|
||||||
ControlPacket::PingPacket(_) => {
|
ControlPacket::PingPacket(ping) => {
|
||||||
net_packet.set_transport_protocol(control_packet::Protocol::Pong.into());
|
net_packet.set_transport_protocol(control_packet::Protocol::Pong.into());
|
||||||
udp.send_to(&net_packet.buffer()[..12], peer_addr)?;
|
udp.send_to(&net_packet.buffer()[..12], peer_addr)?;
|
||||||
}
|
}
|
||||||
ControlPacket::PongPacket(pong_packet) => {
|
ControlPacket::PongPacket(pong_packet) => {
|
||||||
let current_time = Local::now().timestamp();
|
let current_time = Local::now().timestamp_millis();
|
||||||
let rt = current_time - pong_packet.time();
|
let rt = current_time - pong_packet.time();
|
||||||
if rt >= 0 {
|
if rt >= 0 {
|
||||||
if peer_addr == server_addr {
|
if peer_addr == server_addr {
|
||||||
|
|||||||
+76
-13
@@ -1,11 +1,11 @@
|
|||||||
use std::{io, thread};
|
use std::{io, thread};
|
||||||
use std::net::{IpAddr, Ipv4Addr, SocketAddr, SocketAddrV4, UdpSocket};
|
use std::net::{IpAddr, Ipv4Addr, SocketAddr, SocketAddrV4, UdpSocket};
|
||||||
|
use std::sync::atomic::Ordering;
|
||||||
|
|
||||||
use clap::Parser;
|
use clap::Parser;
|
||||||
use console::style;
|
use console::style;
|
||||||
use crossbeam::sync::Parker;
|
|
||||||
|
|
||||||
use crate::handle::{CurrentDeviceInfo, DEVICE_LIST, NAT_INFO, NatInfo};
|
use crate::handle::{CurrentDeviceInfo, DEVICE_LIST, DIRECT_ROUTE_TABLE, NAT_INFO, NatInfo, SERVER_RT};
|
||||||
use crate::handle::registration_handler::registration;
|
use crate::handle::registration_handler::registration;
|
||||||
use crate::tun_device::create_tun;
|
use crate::tun_device::create_tun;
|
||||||
|
|
||||||
@@ -96,16 +96,14 @@ fn main() {
|
|||||||
println!("virtual_gateway:{:?}", virtual_gateway);
|
println!("virtual_gateway:{:?}", virtual_gateway);
|
||||||
println!("virtual_netmask:{:?}", virtual_netmask);
|
println!("virtual_netmask:{:?}", virtual_netmask);
|
||||||
println!("当前设备ip(virtual_ip):{}", style(virtual_ip).green());
|
println!("当前设备ip(virtual_ip):{}", style(virtual_ip).green());
|
||||||
let parker = Parker::new();
|
|
||||||
//心跳线程
|
//心跳线程
|
||||||
{
|
{
|
||||||
let un_parker = parker.unparker().clone();
|
|
||||||
let udp = udp.try_clone().unwrap();
|
let udp = udp.try_clone().unwrap();
|
||||||
let _ = thread::spawn(move || {
|
let _ = thread::spawn(move || {
|
||||||
if let Err(e) = handle::heartbeat_handler::handle_loop(udp, server_address) {
|
if let Err(e) = handle::heartbeat_handler::handle_loop(udp, server_address) {
|
||||||
println!("心跳线程停止:{:?}", e);
|
println!("心跳线程停止:{:?}", e);
|
||||||
}
|
}
|
||||||
un_parker.unpark();
|
std::process::exit(1);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
//初始化nat数据
|
//初始化nat数据
|
||||||
@@ -117,7 +115,6 @@ fn main() {
|
|||||||
let (punch_sender, cone_receiver, req_symmetric_receiver, res_symmetric_receiver) = handle::punch_handler::bounded();
|
let (punch_sender, cone_receiver, req_symmetric_receiver, res_symmetric_receiver) = handle::punch_handler::bounded();
|
||||||
//udp数据处理
|
//udp数据处理
|
||||||
{
|
{
|
||||||
let un_parker = parker.unparker().clone();
|
|
||||||
// 低优先级的udp数据通道
|
// 低优先级的udp数据通道
|
||||||
let (sender, receiver) = crossbeam::channel::bounded(100);
|
let (sender, receiver) = crossbeam::channel::bounded(100);
|
||||||
let udp1 = udp.try_clone().unwrap();
|
let udp1 = udp.try_clone().unwrap();
|
||||||
@@ -132,16 +129,15 @@ fn main() {
|
|||||||
) {
|
) {
|
||||||
println!("udp数据处理线程停止:{:?}", e);
|
println!("udp数据处理线程停止:{:?}", e);
|
||||||
}
|
}
|
||||||
un_parker.unpark();
|
std::process::exit(1);
|
||||||
});
|
});
|
||||||
let udp1 = udp.try_clone().unwrap();
|
let udp1 = udp.try_clone().unwrap();
|
||||||
let un_parker = parker.unparker().clone();
|
|
||||||
let _ = thread::spawn(move || {
|
let _ = thread::spawn(move || {
|
||||||
let current_device = CurrentDeviceInfo::new(virtual_ip, virtual_gateway, virtual_netmask, server_address);
|
let current_device = CurrentDeviceInfo::new(virtual_ip, virtual_gateway, virtual_netmask, server_address);
|
||||||
if let Err(e) = handle::udp_recv_handler::other_loop(udp1, receiver, current_device, punch_sender) {
|
if let Err(e) = handle::udp_recv_handler::other_loop(udp1, receiver, current_device, punch_sender) {
|
||||||
println!("udp数据处理线程停止:{:?}", e);
|
println!("udp数据处理线程停止:{:?}", e);
|
||||||
}
|
}
|
||||||
un_parker.unpark();
|
std::process::exit(1);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
//打洞处理
|
//打洞处理
|
||||||
@@ -171,15 +167,82 @@ fn main() {
|
|||||||
//tun数据处理
|
//tun数据处理
|
||||||
{
|
{
|
||||||
let udp = udp.try_clone().unwrap();
|
let udp = udp.try_clone().unwrap();
|
||||||
let un_parker = parker.unparker().clone();
|
|
||||||
let _ = thread::spawn(move || {
|
let _ = thread::spawn(move || {
|
||||||
let current_device = CurrentDeviceInfo::new(virtual_ip, virtual_gateway, virtual_netmask, server_address);
|
let current_device = CurrentDeviceInfo::new(virtual_ip, virtual_gateway, virtual_netmask, server_address);
|
||||||
if let Err(e) = handle::tun_handler::handle_loop(udp, tun_reader, current_device) {
|
if let Err(e) = handle::tun_handler::handle_loop(udp, tun_reader, current_device) {
|
||||||
println!("tun数据处理线程停止:{:?}", e);
|
println!("tun数据处理线程停止:{:?}", e);
|
||||||
}
|
}
|
||||||
un_parker.unpark();
|
std::process::exit(1);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
parker.park();
|
use console::Term;
|
||||||
std::process::exit(1);
|
let term = Term::stdout();
|
||||||
|
let current_device = CurrentDeviceInfo::new(virtual_ip, virtual_gateway, virtual_netmask, server_address);
|
||||||
|
loop {
|
||||||
|
println!("{}", style("Please enter the command (Usage: list,status,exit,help):").color256(102));
|
||||||
|
match term.read_line() {
|
||||||
|
Ok(cmd) => {
|
||||||
|
command(cmd.trim(), ¤t_device);
|
||||||
|
}
|
||||||
|
Err(e) => {
|
||||||
|
println!("read_line:{:?}", e);
|
||||||
|
std::process::exit(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn command(cmd: &str, current_device: &CurrentDeviceInfo) {
|
||||||
|
match cmd {
|
||||||
|
"list" => {
|
||||||
|
let server_delay = SERVER_RT.load(Ordering::Relaxed);
|
||||||
|
let device_list_lock = DEVICE_LIST.lock();
|
||||||
|
let (_epoch, device_list) = device_list_lock.clone();
|
||||||
|
drop(device_list_lock);
|
||||||
|
if device_list.is_empty() {
|
||||||
|
println!("No other devices found");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
for ip in device_list {
|
||||||
|
if let Some(route_ref) = DIRECT_ROUTE_TABLE.get(&ip) {
|
||||||
|
let str = if route_ref.value().delay >= 0 {
|
||||||
|
format!("{}(p2p delay:{}ms)", ip, route_ref.value().delay)
|
||||||
|
} else {
|
||||||
|
format!("{}(p2p)", ip)
|
||||||
|
};
|
||||||
|
drop(route_ref);
|
||||||
|
println!("{}", style(str).green());
|
||||||
|
} else {
|
||||||
|
let str = if server_delay >= 0 {
|
||||||
|
format!("{}(relay delay:{}ms)", ip, server_delay * 2)
|
||||||
|
} else {
|
||||||
|
format!("{}(relay)", ip)
|
||||||
|
};
|
||||||
|
println!("{}", style(str).blue());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"status" => {
|
||||||
|
let server_delay = SERVER_RT.load(Ordering::Relaxed);
|
||||||
|
println!("Virtual ip:{}", style(current_device.virtual_ip).green());
|
||||||
|
println!("Virtual gateway:{}", style(current_device.virtual_gateway).green());
|
||||||
|
println!("Relay server :{}", style(current_device.connect_server).green());
|
||||||
|
if server_delay >= 0 {
|
||||||
|
println!("Delay of relay server :{}", style(server_delay).green());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"help" | "h" => {
|
||||||
|
println!("Options: ");
|
||||||
|
println!("{} , Query the virtual IP of other devices", style("list").green());
|
||||||
|
println!("{} , View current device status", style("status").green());
|
||||||
|
println!("{} , Exit the program", style("exit").green());
|
||||||
|
}
|
||||||
|
"exit" => {
|
||||||
|
std::process::exit(1);
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
println!("command {} not fount. ", style(cmd).red());
|
||||||
|
println!("Try to enter: '{}'", style("help").green());
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -70,6 +70,7 @@ pub struct PongPacket<B> {
|
|||||||
buffer: B,
|
buffer: B,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
impl<B: AsRef<[u8]>> PingPacket<B> {
|
impl<B: AsRef<[u8]>> PingPacket<B> {
|
||||||
pub fn new(buffer: B) -> Result<PingPacket<B>> {
|
pub fn new(buffer: B) -> Result<PingPacket<B>> {
|
||||||
let len = buffer.as_ref().len();
|
let len = buffer.as_ref().len();
|
||||||
@@ -98,6 +99,15 @@ impl<B: AsRef<[u8]> + AsMut<[u8]>> PingPacket<B> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<B: AsRef<[u8]>> fmt::Debug for PingPacket<B> {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
f.debug_struct("PingPacket")
|
||||||
|
.field("time", &self.time())
|
||||||
|
.field("epoch", &self.epoch())
|
||||||
|
.finish()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl<B: AsRef<[u8]>> PongPacket<B> {
|
impl<B: AsRef<[u8]>> PongPacket<B> {
|
||||||
pub fn new(buffer: B) -> Result<PongPacket<B>> {
|
pub fn new(buffer: B) -> Result<PongPacket<B>> {
|
||||||
let len = buffer.as_ref().len();
|
let len = buffer.as_ref().len();
|
||||||
@@ -120,6 +130,14 @@ impl<B: AsRef<[u8]> + AsMut<[u8]>> PongPacket<B> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<B: AsRef<[u8]>> fmt::Debug for PongPacket<B> {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
f.debug_struct("PongPacket")
|
||||||
|
.field("time", &self.time())
|
||||||
|
.finish()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub type TurnPongPacket<B> = TurnPingPacket<B>;
|
pub type TurnPongPacket<B> = TurnPingPacket<B>;
|
||||||
|
|
||||||
/// 探测目标延迟
|
/// 探测目标延迟
|
||||||
|
|||||||
@@ -51,6 +51,7 @@ pub fn create_tun(
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
|
println!("{}", console::style("wintun.dll not found").red());
|
||||||
return Err(Error::Stop(format!("{:?}", e)));
|
return Err(Error::Stop(format!("{:?}", e)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user