292 lines
8.0 KiB
Rust
Executable File
292 lines
8.0 KiB
Rust
Executable File
mod config;
|
|
mod network;
|
|
mod pb;
|
|
mod tcp;
|
|
mod utils;
|
|
|
|
use std::sync::Arc;
|
|
use std::{sync::atomic::AtomicU8, time::Duration};
|
|
|
|
use std::net::{SocketAddr, ToSocketAddrs};
|
|
|
|
pub use network::get_edge;
|
|
pub use network::get_install_channel;
|
|
pub use network::{async_main, init_arp, init_edge, NodeConfig, restore_dns};
|
|
use sdlan_sn_rs::utils::save_to_file;
|
|
use serde::{Deserialize, Serialize};
|
|
use tokio::net::UdpSocket;
|
|
use tokio::sync::mpsc::{channel, Sender};
|
|
use tokio_util::sync::CancellationToken;
|
|
use tracing::{debug, error};
|
|
pub use utils::{CommandLine, CommandLineInput, mod_hostname};
|
|
|
|
pub use config::{get_base_dir, set_base_dir};
|
|
|
|
use sdlan_sn_rs::{
|
|
peer::SdlanSock,
|
|
utils::{create_or_load_uuid, get_sdlan_sock_from_socketaddr, Result, SDLanError},
|
|
};
|
|
|
|
|
|
#[derive(Clone)]
|
|
pub enum ConnectionInfo {
|
|
ConnState(ConnectionState),
|
|
IPInfo(String),
|
|
}
|
|
|
|
#[derive(Clone)]
|
|
#[repr(u8)]
|
|
pub enum ConnectionState {
|
|
NotConnected = 0,
|
|
Connecting = 1,
|
|
Connected = 2,
|
|
}
|
|
|
|
pub async fn run_sdlan(
|
|
args: CommandLine,
|
|
sender: std::sync::mpsc::Sender<bool>,
|
|
install_channel: &str,
|
|
|
|
server_ip: String,
|
|
|
|
hostname: Option<String>,
|
|
connecting_chan: Option<Sender<ConnectionInfo>>, // start_stop_sender: Sender<String>,
|
|
// start_stop_receiver: Receiver<String>,
|
|
) -> Result<()> {
|
|
let (start_stop_sender, start_stop_chan) = channel(20);
|
|
let edge_uuid = create_or_load_uuid(&format!("{}/.id", get_base_dir()), None)?;
|
|
let node_conf = parse_config(edge_uuid, &args).await?;
|
|
|
|
let hostfile = format!("{}/.host", get_base_dir());
|
|
let host = create_or_load_uuid(&hostfile, Some(8))?;
|
|
|
|
init_arp();
|
|
|
|
let hostname = hostname.unwrap_or(host);
|
|
let _ = save_to_file(&hostfile, &hostname);
|
|
|
|
let sock = Arc::new(UdpSocket::bind("0.0.0.0:0").await?);
|
|
|
|
if let Err(e) = init_edge(
|
|
&args.token,
|
|
&args.network_code,
|
|
node_conf,
|
|
args.tos,
|
|
start_stop_sender,
|
|
args.mtu,
|
|
connecting_chan.clone(),
|
|
sock,
|
|
hostname,
|
|
server_ip,
|
|
)
|
|
.await
|
|
{
|
|
panic!("failed to init edge: {:?}", e);
|
|
}
|
|
let _ = sender.send(true);
|
|
debug!("edge inited");
|
|
|
|
let cancel = CancellationToken::new();
|
|
let install_chan = install_channel.to_owned();
|
|
tokio::spawn(async move {
|
|
if let Err(e) =
|
|
async_main(install_chan, args, start_stop_chan, cancel, connecting_chan).await
|
|
{
|
|
error!("failed to run async main: {}", e.as_str());
|
|
}
|
|
});
|
|
|
|
Ok(())
|
|
}
|
|
|
|
async fn parse_config(uuid: String, args: &CommandLine) -> Result<NodeConfig> {
|
|
if args.sn.len() == 0 {
|
|
return Err(SDLanError::NormalError("no sn is specified"));
|
|
}
|
|
// node_conf.allow_p2p = args.allow_p2p;
|
|
|
|
let Ok(addr1) = args.nat_server1.to_socket_addrs() else {
|
|
return Err(SDLanError::NormalError("nat_server1 format error"));
|
|
};
|
|
let Some(nat1) = addr1.into_iter().next() else {
|
|
return Err(SDLanError::NormalError("get nat_server1 failed"));
|
|
};
|
|
|
|
let Ok(addr2) = args.nat_server2.to_socket_addrs() else {
|
|
return Err(SDLanError::NormalError("nat_server2 format error"));
|
|
};
|
|
let Some(nat2) = addr2.into_iter().next() else {
|
|
return Err(SDLanError::NormalError("get nat_server2 failed"));
|
|
};
|
|
|
|
let sns: Vec<&str> = args.sn.split(",").collect();
|
|
let mut correct_sns: Vec<_>;
|
|
let mut sockaddr: Vec<_>;
|
|
|
|
loop {
|
|
debug!("parsing sns");
|
|
(correct_sns, sockaddr) = parse_sns(&sns);
|
|
if sockaddr.len() < 1 {
|
|
if correct_sns.len() > 0 {
|
|
tokio::time::sleep(Duration::from_millis(500)).await;
|
|
continue;
|
|
// (correct_sns, sockaddr) = parse_sns(&correct_sns);
|
|
} else {
|
|
// correct_sns == 0, just error
|
|
panic!("no correct sns specified");
|
|
}
|
|
}
|
|
|
|
// node_conf.super_nodes = sockaddr;
|
|
break;
|
|
}
|
|
|
|
let mut register_ttl = 1;
|
|
if args.register_ttl > 1 {
|
|
register_ttl = args.register_ttl;
|
|
}
|
|
|
|
let node_conf = NodeConfig {
|
|
name: args.name.to_owned(),
|
|
allow_routing: true,
|
|
_drop_multicast: true,
|
|
allow_p2p: args.allow_p2p,
|
|
mtu: args.mtu,
|
|
_tos: 0,
|
|
_register_super_interval: config::REGISTER_SUPER_INTERVAL,
|
|
register_ttl,
|
|
_local_port: args.local_port as u16,
|
|
node_uuid: uuid,
|
|
super_nodes: sockaddr,
|
|
super_node_index: AtomicU8::new(0),
|
|
nat_server1: nat1,
|
|
nat_server2: nat2,
|
|
};
|
|
|
|
Ok(node_conf)
|
|
}
|
|
|
|
fn parse_sns<'a>(sns: &'a Vec<&'a str>) -> (Vec<&'a str>, Vec<SdlanSock>) {
|
|
let mut correct_sns = vec![];
|
|
let mut result = vec![];
|
|
for sn in sns {
|
|
let addr: Vec<_> = sn.split(":").collect();
|
|
if addr.len() != 2 {
|
|
error!("sn format error: [host:port] => {}", sn);
|
|
continue;
|
|
}
|
|
|
|
let Ok(port) = addr[1].parse::<u16>() else {
|
|
continue;
|
|
};
|
|
// store correct format sns
|
|
correct_sns.push(*sn);
|
|
|
|
// node_conf.super_nodes.push(sock);
|
|
if let Ok(ipaddr) = dns_lookup::lookup_host(addr[0]) {
|
|
for ip in ipaddr {
|
|
let sockaddr = SocketAddr::new(ip, port);
|
|
let Ok(sock) = get_sdlan_sock_from_socketaddr(sockaddr) else {
|
|
error!("failed to parse sn: {}", sn);
|
|
continue;
|
|
};
|
|
result.push(sock);
|
|
}
|
|
} else {
|
|
error!("failed to parse host: {}", sn);
|
|
continue;
|
|
}
|
|
}
|
|
(correct_sns, result)
|
|
}
|
|
|
|
#[derive(Debug, Serialize)]
|
|
struct NetworkReq<'a> {
|
|
client_id: &'a str,
|
|
}
|
|
|
|
#[derive(Debug, Deserialize, Serialize)]
|
|
pub struct NetworkRespSingleNetwork {
|
|
pub name: String,
|
|
pub code: String,
|
|
}
|
|
|
|
#[derive(Debug, Deserialize, Serialize)]
|
|
pub struct NetworkRespNetworks {
|
|
pub network: Vec<NetworkRespSingleNetwork>,
|
|
}
|
|
|
|
#[derive(Debug, Deserialize, Serialize)]
|
|
pub struct NetworkResp {
|
|
pub result: NetworkRespNetworks,
|
|
}
|
|
|
|
pub async fn get_my_networks(url: &str) -> Result<Vec<NetworkRespSingleNetwork>>{
|
|
let edge_uuid = create_or_load_uuid(&format!("{}/.id", get_base_dir()), None)?;
|
|
|
|
let req_data = NetworkReq {
|
|
client_id: &edge_uuid,
|
|
};
|
|
|
|
let Ok(client) = reqwest::Client::builder()
|
|
.timeout(Duration::from_secs(5)).build() else {
|
|
return Err(SDLanError::NormalError("failed to create client"));
|
|
};
|
|
// match client.post("https://punchnet.s5s8.com/api/get_user_network")
|
|
match client.post(url)
|
|
.json(&req_data)
|
|
.send().await {
|
|
|
|
Ok(response) => {
|
|
let Ok(network) = response.json::<NetworkResp>().await else {
|
|
return Err(SDLanError::NormalError("failed to jsonify get_user_network "));
|
|
};
|
|
|
|
Ok(network.result.network)
|
|
|
|
}
|
|
Err(e) => {
|
|
error!("failed to send get_user_network: {}", e);
|
|
return Err(SDLanError::NormalError("failed to get_user_network"));
|
|
}
|
|
}
|
|
|
|
// let Ok(response) = client.post("https://punchnet.aioe.tech/api/get_all_networks")
|
|
// .json(&req_data)
|
|
// .send().await else {
|
|
// return Err(SDLanError::NormalError("failed to send get_all_networks"));
|
|
// };
|
|
}
|
|
|
|
#[cfg(test)]
|
|
mod test {
|
|
use sdlan_sn_rs::config::AF_INET;
|
|
|
|
use super::*;
|
|
|
|
#[test]
|
|
#[ignore]
|
|
fn test_parse_dns() {
|
|
let sns = vec!["git.asxalex.pw:80", "121.4.79.234:81"];
|
|
let (correct, res) = parse_sns(&sns);
|
|
assert_eq!(correct, sns);
|
|
assert_eq!(
|
|
res,
|
|
vec![
|
|
SdlanSock {
|
|
family: AF_INET,
|
|
port: 80,
|
|
v4: [10, 167, 69, 157],
|
|
v6: [0; 16],
|
|
},
|
|
SdlanSock {
|
|
family: AF_INET,
|
|
port: 81,
|
|
v4: [121, 4, 79, 234],
|
|
v6: [0; 16],
|
|
}
|
|
]
|
|
)
|
|
}
|
|
}
|