use std::str::FromStr;
use anyhow::{Context, Ok};
use chrono::Utc;
use ntest::timeout;
use pocketscion::{
network::scion::topology::{ScionAs, ScionTopologyBuilder},
runtime::builder::PocketScionRuntimeBuilder,
state::PocketScionState,
};
use scion_stack::stack::ScionStackBuilder;
use sciparse::identifier::isd_asn::IsdAsn;
use snap_tokens::v0::dummy_snap_token;
use url::Url;
#[tokio::test]
#[timeout(10_000)]
async fn should_send_receive_with_topology() -> anyhow::Result<()> {
scion_sdk_utils::rustls::select_ring_crypto_provider();
let server_ia = IsdAsn::from_str("1-3")?;
let client_ia = IsdAsn::from_str("2-3")?;
const MESSAGE_LEN: usize = 64;
let mut state = PocketScionState::new(Utc::now());
let mut topo = ScionTopologyBuilder::new();
topo.add_as(ScionAs::new_core("1-1".parse()?))?
.add_as(ScionAs::new_core("1-2".parse()?))?
.add_as(ScionAs::new("1-3".parse()?))?
.add_as(ScionAs::new_core("2-1".parse()?))?
.add_as(ScionAs::new("2-2".parse()?))?
.add_as(ScionAs::new("2-3".parse()?))?
.add_link("1-1#1 core 1-2#2".parse()?)?
.add_link("1-2#1 down_to 1-3#1".parse()?)?
.add_link("1-1#2 down_to 1-3#2".parse()?)?
.add_link("1-1#3 core 2-1#1".parse()?)?
.add_link("2-1#2 down_to 2-2#1".parse()?)?
.add_link("2-2#2 down_to 2-3#1".parse()?)?;
state.set_topology(topo.build()?);
let server_snap_id = state.add_snap(server_ia)?;
let client_snap_id = state.add_snap(client_ia)?;
let _server_eh = state.add_endhost_api(vec![server_ia]);
let _client_eh = state.add_endhost_api(vec![client_ia]);
let ps_rt = PocketScionRuntimeBuilder::new()
.with_system_state(state)
.start()
.await
.context("starting runtime")?;
let client_cp_addr = ps_rt
.snap_control_addr(client_snap_id)
.context("client snap not found")?;
let client_cp_url: Url = format!("http://{client_cp_addr}").parse().unwrap();
let server_cp_addr = ps_rt
.snap_control_addr(server_snap_id)
.context("server snap not found")?;
let server_cp_url: Url = format!("http://{server_cp_addr}").parse().unwrap();
let server_stack = ScionStackBuilder::new()
.with_endhost_api(server_cp_url)
.with_auth_token(dummy_snap_token())
.build()
.await?;
let server_socket = server_stack.bind(None).await?;
let server_addr = server_socket.local_addr();
let client_stack = ScionStackBuilder::new()
.with_endhost_api(client_cp_url)
.with_auth_token(dummy_snap_token())
.build()
.await?;
let client_socket = client_stack.bind(None).await?;
let mut recv_buf = [0u8; MESSAGE_LEN];
let random_message = rand::random::<[u8; MESSAGE_LEN]>();
client_socket
.send_to(&random_message, server_addr)
.await
.context("error client sending essage")?;
let (_, client_addr) = server_socket
.recv_from(&mut recv_buf)
.await
.context("error server receiving message")?;
assert_eq!(recv_buf, random_message, "Message mismatch");
let random_message = rand::random::<[u8; MESSAGE_LEN]>();
server_socket
.send_to(&random_message, client_addr)
.await
.context("error server echoing message")?;
client_socket
.recv_from(&mut recv_buf)
.await
.context("error client receiving echo")?;
assert_eq!(recv_buf, random_message, "Message mismatch");
Ok(())
}