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, install_channel: &str, server_ip: String, hostname: Option, connecting_chan: Option>, // start_stop_sender: Sender, // start_stop_receiver: Receiver, ) -> 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 { 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) { 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::() 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, } #[derive(Debug, Deserialize, Serialize)] pub struct NetworkResp { pub result: NetworkRespNetworks, } pub async fn get_my_networks(url: &str) -> Result>{ 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::().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], } ] ) } }