new rust demo + cleanup of build

This commit is contained in:
Lennon Day-Reynolds
2023-06-05 19:14:12 -07:00
parent 8d21a265cc
commit 787dd6efc1
6 changed files with 662 additions and 26 deletions

View File

@@ -0,0 +1,170 @@
use std::{
error::Error,
fmt, fs,
io::{self, Read, Write},
net::{self, Shutdown},
sync::Arc,
thread,
time::Duration,
};
use anyhow::Result;
use clap::Parser;
use parking_lot::FairMutex;
use libzt::{node::ZeroTierNode, tcp as zt_tcp};
const BUF_SIZE: usize = 1024;
const SOCKET_IO_TIMEOUT: Duration = Duration::new(1, 0);
const DEFAULT_LISTEN_PORT: u16 = 9080;
#[derive(Debug)]
enum ForwardingError {
BindFailed(String),
ConnectFailed(String),
}
impl Error for ForwardingError {}
#[derive(Parser, Debug)]
struct Args {
#[arg(short, long, value_parser=clap_num::maybe_hex::<u64>)]
network_id: u64,
#[arg(short, long)]
connect: String,
#[arg(short, long, default_value_t = DEFAULT_LISTEN_PORT)]
port: u16,
}
fn setup_node(network_id: u64) -> Result<ZeroTierNode> {
log::info!("joining network: {:#x}", network_id);
let mut storage_path = dirs::data_local_dir().unwrap();
storage_path.push("libzt");
storage_path.push("forwarding");
fs::create_dir_all(&storage_path)?;
log::debug!(
"initializing from state dir: {}",
storage_path.to_string_lossy()
);
let node = ZeroTierNode {};
node.init_set_port(0);
node.init_from_storage(&storage_path.join("libzt-examples").to_string_lossy());
node.start();
log::debug!("waiting for node to come online...");
while !node.is_online() {
node.delay(250);
}
log::info!("node id: {:#x}", node.id());
node.net_join(network_id);
log::debug!("waiting for transport...");
while !node.net_transport_is_ready(network_id) {
node.delay(250);
}
let addr = node.addr_get(network_id).unwrap();
log::info!("got ZT addr: {}", addr.to_string());
Ok(node)
}
impl fmt::Display for ForwardingError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{:?}", self)
}
}
fn main() -> Result<()> {
env_logger::init();
let Args {
connect: remote_addr,
network_id,
port: local_port,
} = Args::parse();
let _node = setup_node(network_id)?;
let local_addr = format!("localhost:{}", local_port);
let listener = net::TcpListener::bind(&local_addr)
.map_err(|_| ForwardingError::BindFailed(local_addr.clone()))?;
log::info!("listener bound to {}", local_addr);
for conn in listener.incoming() {
log::debug!("incoming: {:?}", conn);
if let Ok(client) = conn {
client.set_read_timeout(Some(SOCKET_IO_TIMEOUT))?;
client.set_write_timeout(Some(SOCKET_IO_TIMEOUT))?;
let client = Arc::new(FairMutex::new(client));
log::info!("connecting to remote: {}", remote_addr);
let remote = zt_tcp::TcpStream::connect(&remote_addr)
.map_err(|_| ForwardingError::ConnectFailed(remote_addr.clone()))?;
remote.set_read_timeout(Some(SOCKET_IO_TIMEOUT))?;
remote.set_write_timeout(Some(SOCKET_IO_TIMEOUT))?;
let remote = Arc::new(FairMutex::new(remote));
log::info!("connected");
thread::spawn(move || {
let mut buf = [0u8; BUF_SIZE];
loop {
let mut client = client.lock();
let mut remote = remote.lock();
match client.read(&mut buf) {
Ok(n) if n > 0 => {
log::debug!("got {} bytes from client", n);
remote.write(&buf).unwrap();
remote.flush().unwrap();
}
Err(e) if e.kind() == io::ErrorKind::WouldBlock => {
thread::sleep(Duration::new(0, 5000));
}
other => {
log::debug!("closing client connection: {:?}", other);
let _ = client.shutdown(Shutdown::Read);
let _ = remote.shutdown(Shutdown::Write);
break;
}
}
buf.fill(0);
match remote.read(&mut buf) {
Ok(n) if n > 0 => {
log::debug!("got {} bytes from remote", n);
client.write(&buf).unwrap();
client.flush().unwrap();
}
other => {
log::debug!("closing remote connection: {:?}", other);
let _ = remote.shutdown(Shutdown::Read);
let _ = client.shutdown(Shutdown::Write);
break;
}
}
buf.fill(0);
}
});
}
}
Ok(())
}

View File

@@ -0,0 +1,146 @@
use libzt;
use std::env;
use libzt::tcp::{TcpListener, TcpStream};
use std::io::{Read, Write};
use std::net::Shutdown;
use std::str::from_utf8;
use std::thread;
// (Optional) Notify application of ZeroTier events, some with context
fn user_event_handler(event_code: i16) -> () {
println!("user_event {}", event_code);
}
fn handle_client(mut stream: TcpStream) {
let mut data = [0 as u8; 50]; // using 50 byte buffer
while match stream.read(&mut data) {
Ok(size) => {
// echo everything!
stream.write(&data[0..size]).unwrap();
true
}
Err(_) => {
println!(
"An error occurred, terminating connection with {}",
stream.peer_addr().unwrap()
);
stream.shutdown(Shutdown::Both).unwrap();
false
}
} {}
}
fn main() -> std::io::Result<()> {
let args: Vec<String> = env::args().collect();
println!("{:?}", args);
if args.len() != 5 && args.len() != 6 {
println!("Incorrect number of arguments.");
println!(" Usage: libzt-test-app server <storage_path> <net_id> <local_ip> <local_port>");
println!(" Usage: libzt-test-app client <storage_path> <net_id> <remote_ip> <remote_port>");
return Ok(())
}
let storage_path = &args[2];
let net_id = u64::from_str_radix(&args[3], 16).unwrap();
println!("path = {}", storage_path);
println!("net_id = {:x}", net_id);
// SET UP ZEROTIER
let node = libzt::node::ZeroTierNode {};
// (Optional) initialization
node.init_set_port(0);
node.init_set_event_handler(user_event_handler);
node.init_from_storage(&storage_path);
// Start the node
node.start();
println!("Waiting for node to come online...");
while !node.is_online() {
node.delay(50);
}
println!("Node ID = {:#06x}", node.id());
println!("Joining network");
node.net_join(net_id);
println!("Waiting for network to assign addresses...");
while !node.net_transport_is_ready(net_id) {
node.delay(50);
}
let addr = node.addr_get(net_id).unwrap();
println!("Assigned addr = {}", addr);
// Server
if &args[1] == "server" {
println!("server mode");
let mut addr_str: String = "".to_owned();
addr_str.push_str(&args[4]);
addr_str.push_str(":");
addr_str.push_str(&args[5]);
let server: std::net::SocketAddr =
addr_str.parse().expect("Unable to parse socket address");
let listener = TcpListener::bind(&server).unwrap();
for stream in listener.incoming() {
match stream {
Ok(stream) => {
println!("New connection: {}", stream.peer_addr().unwrap());
thread::spawn(move || {
// connection succeeded
handle_client(stream)
});
}
Err(e) => {
println!("Error: {}", e);
// connection failed
}
}
}
drop(listener);
}
// Client
if &args[1] == "client" {
println!("client mode");
let mut addr_str: String = "".to_owned();
addr_str.push_str(&args[4]);
addr_str.push_str(":");
addr_str.push_str(&args[5]);
match TcpStream::connect(addr_str) {
Ok(mut stream) => {
println!("Successfully connected to server");
let msg = b"Hello, network!";
stream.write(msg).unwrap();
let mut data = [0 as u8; 15];
match stream.read_exact(&mut data) {
Ok(_) => {
if &data == msg {
println!("Reply is ok!");
} else {
let text = from_utf8(&data).unwrap();
println!("Unexpected reply: {}", text);
}
}
Err(e) => {
println!("Failed to receive data: {}", e);
}
}
}
Err(e) => {
println!("Failed to connect: {}", e);
}
}
println!("Terminated.");
}
node.stop();
Ok(())
}