Add TCP ping utility

This commit is contained in:
Erik 2023-05-31 16:33:32 +02:00
parent 7a40908543
commit eb35683748
4 changed files with 144 additions and 0 deletions

View File

@ -5,9 +5,24 @@ edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
default-run = "proxy"
[[bin]]
name = "proxy"
path = "src/bin/proxy.rs"
[[bin]]
name = "ping-server"
path = "src/bin/ping_server.rs"
[[bin]]
name = "ping-client"
path = "src/bin/ping_client.rs"
[dependencies] [dependencies]
anyhow = "1.0.69" anyhow = "1.0.69"
axum = { version = "0.6.11", features = ["json"] } axum = { version = "0.6.11", features = ["json"] }
clap = { version = "4.3.0", features = ["derive"] }
p384 = { version = "0.13.0", features = ["ecdsa", "serde"] } p384 = { version = "0.13.0", features = ["ecdsa", "serde"] }
serde = { version = "1.0.155", features = ["derive"] } serde = { version = "1.0.155", features = ["derive"] }
serde_json = "1.0.94" serde_json = "1.0.94"

96
src/bin/ping_client.rs Normal file
View File

@ -0,0 +1,96 @@
use clap::Parser;
use std::net::SocketAddrV4;
use std::str::FromStr;
use std::sync::{
atomic::{AtomicBool, AtomicU32, Ordering},
Arc, Mutex,
};
use std::time::{Duration, Instant};
use tokio::{
io::{AsyncReadExt, AsyncWriteExt},
net::TcpStream,
time::sleep,
};
#[tokio::main]
async fn main() {
let args = Args::parse();
let in_transit = Arc::new(AtomicBool::new(false));
let in_transit2 = in_transit.clone();
let out_timestamp = Arc::new(Mutex::new(Instant::now()));
let out_timestamp2 = out_timestamp.clone();
let count = AtomicU32::new(args.count);
let addr = SocketAddrV4::from_str(&args.address).unwrap();
let stream = TcpStream::connect(addr).await.unwrap();
if !args.csv {
println!("Ping {addr}");
}
let (mut si, mut so) = stream.into_split();
let ping_in = async move {
let mut read_buf = [0; 1024];
while count.load(Ordering::Relaxed) > 0 {
let bytes = si.read(&mut read_buf).await.unwrap();
if bytes > 0 {
let in_timestamp = Instant::now();
// println!("Received {bytes} bytes");
let duration = in_timestamp.duration_since(*out_timestamp.lock().unwrap());
let i = u32::from_be_bytes(read_buf[0..bytes].try_into().unwrap());
let rtt = duration.as_micros();
if !args.csv {
println!("Ping {i} arrived with RTT of {rtt}us");
} else {
println!("{rtt},");
}
// let old = count.fetch_sub(1, Ordering::Relaxed);
// println!("Old count value: {old}");
count.fetch_sub(1, Ordering::Relaxed);
in_transit2.store(false, Ordering::Relaxed);
}
}
if !args.csv {
println!("Done receiving");
}
};
let ping_out = async move {
for i in 1..=args.count {
if let Ok(false) =
in_transit.compare_exchange_weak(false, true, Ordering::Relaxed, Ordering::Relaxed)
{
*out_timestamp2.lock().unwrap() = Instant::now();
so.write_u32(i).await.unwrap();
}
if !args.csv {
println!("Sending ping {i}");
}
sleep(Duration::from_millis(1)).await;
}
if !args.csv {
println!("Done sending pings");
}
};
tokio::join!(ping_out, ping_in);
}
#[derive(Parser, Debug)]
struct Args {
/// Socket address to ping
#[arg(long)]
address: String,
/// Amount of pings to send
#[arg(short, long)]
count: u32,
/// CSV mode
#[arg(long)]
csv: bool,
}

33
src/bin/ping_server.rs Normal file
View File

@ -0,0 +1,33 @@
use clap::Parser;
use std::error::Error;
use std::net::SocketAddrV4;
use std::str::FromStr;
use tokio::io::AsyncWriteExt;
use tokio::{io, net::TcpListener};
#[tokio::main]
async fn main() -> Result<(), Box<dyn Error>> {
let args = Args::parse();
let addr = SocketAddrV4::from_str(&args.address).unwrap();
let listener = TcpListener::bind(&addr).await?;
println!("Listening on: {addr}");
loop {
let (mut socket, _) = listener.accept().await?;
tokio::spawn(async move {
let (mut si, mut so) = socket.split();
io::copy(&mut si, &mut so).await?;
so.shutdown().await
});
}
}
#[derive(Parser, Debug)]
struct Args {
/// Socket address to listen on
#[arg(long)]
address: String,
}