#![doc = simple_mermaid::mermaid!("../../pocketscion/src/util/topologies/diagrams/minimal.mmd")]
mod common;
use std::time::Duration;
use pocketscion::util::topologies::{IA132, IA212, UnderlayType, minimal::minimal_topology};
use scion_stack::stack::UdpScionSocket;
use sciparse::address::ip_socket_addr::ScionSocketIpAddr;
use tokio::time::timeout;
const MAX_DATAGRAM: usize = 2048;
#[tokio::main]
async fn main() -> anyhow::Result<()> {
run().await
}
async fn run() -> anyhow::Result<()> {
scion_sdk_utils::rustls::select_ring_crypto_provider();
let ps = minimal_topology(UnderlayType::Snap).await;
let server_stack = common::build_stack(&ps, IA212).await?;
let server_socket = server_stack.bind(None).await?;
let server_addr = server_socket.local_addr();
println!("echo server listening on {server_addr}");
let server = tokio::spawn(echo_server(server_socket));
let client_stack = common::build_stack(&ps, IA132).await?;
let client_socket = client_stack.bind(None).await?;
let reply = ping(&client_socket, server_addr, b"Hello, SCION!").await?;
println!("client received echo: {}", String::from_utf8_lossy(&reply));
server.abort();
Ok(())
}
async fn echo_server(socket: UdpScionSocket) -> anyhow::Result<()> {
let mut buffer = [0u8; MAX_DATAGRAM];
loop {
let (len, from) = socket.recv_from(&mut buffer).await?;
socket.send_to(&buffer[..len], from).await?;
}
}
async fn ping(
socket: &UdpScionSocket,
destination: ScionSocketIpAddr,
payload: &[u8],
) -> anyhow::Result<Vec<u8>> {
let mut buffer = [0u8; MAX_DATAGRAM];
for attempt in 1..=5 {
socket.send_to(payload, destination).await?;
match timeout(Duration::from_millis(500), socket.recv_from(&mut buffer)).await {
Ok(result) => {
let (len, _from) = result?;
return Ok(buffer[..len].to_vec());
}
Err(_elapsed) => tracing::debug!(attempt, "no echo yet, resending"),
}
}
anyhow::bail!("no echo received from {destination} after 5 attempts")
}
#[cfg(test)]
mod tests {
use test_log::test;
#[test(tokio::test)]
#[ntest::timeout(30_000)]
async fn udp_echo_roundtrip() {
super::run().await.expect("udp_echo example should succeed");
}
}