9db748e8dd
* Improve SDK rustdoc and add ARCHITECTURE.md files - Rewrite lib.rs module docs with quick-start example and module overview - Add stream example and include_str! ARCHITECTURE.md to mixnet module - Add ARCHITECTURE.md for mixnet, client_pool, and stream modules - Add rustdoc to MixnetClientBuilder, MixnetClientSender, MixnetMessageSender - Add cancel safety and drop behavior annotations to async methods - Add TcpProxy deprecation notice pointing to stream module * Fix rustdoc errors and add stepwise comments to remaining examples Rustdoc fixes: - Add missing .unwrap() on connect_new example - Replace broken turbofish intra-doc link in MixnetClientBuilder - Fix NymProxyServer::new args in tcp_proxy example - Wrap BandwidthImporter example in scoped block to fix borrow-then-move - Change misleading "5-hop routing" to "multi-hop routing" - Fix copy-paste "forget me" in send_remember_me error message - Fix wrong cargo run command in stream_simple_read_write - Fix DecayWrapper description * Cut down doc comment length * Trimmed down SDK ARCHITECTURE files * Slim Rust SDK docs and rename opener to dialer - Merge tour page into SDK landing page, delete tour.mdx - Trim all three tutorials: cut boilerplate, duplicated code, and misplaced content - Make FFI page evergreen with Go and C++ snippets, link to repo examples - Rename "opener" to "dialer" in stream docs, source ARCHITECTURE.md, and rustdoc - Add reply-to-open arrow in stream mermaid diagram - Replace remaining Unicode dashes in mermaid flowchart * - elevate streams in rustdoc: examples on lib.rs, MixnetClient, open_stream, listener - add stream quick reference to mixnet ARCHITECTURE.md - add stream types to key types list in ARCHITECTURE.md - add docs.rs links for AsyncRead/AsyncWrite and stream submodule - tcp_proxy: replace bold deprecation with warning box * - replace individual example doc pages with GitHub-linked tables - add step-by-step inline comments to all SDK example source files - add doc comments to examples missing them (simple, surb_reply, builder, etc.) - expand mixnet tutorial with persistent identity and split_sender sections - add tcpproxy tutorial - rename "API Reference" to "TypeDoc Reference" in TS SDK sidebar - rename "Misc" to "Extras" in developer sidebar, move VPN CLI up - remove echo server from tools - update message-queue callout to reference actual modules - fix mixnet/examples redirect collision * Add missing mut to example code * Update ARCHITECTURE.md with LP Framing + stream examples with sequencing * Update doc comment in utils.rs * Standardise commenting style across Rust SDK examples * Fix inline doc examples and trim re-export boilerplate * Update sdk/rust/nym-sdk/examples/bandwidth.rs Co-authored-by: Simon Wicky <simon@nymtech.net> * Fix review comments --------- Co-authored-by: Simon Wicky <simon@nymtech.net>
90 lines
3.1 KiB
Rust
90 lines
3.1 KiB
Rust
// Copyright 2025 - Nym Technologies SA <contact@nymtech.net>
|
|
// SPDX-License-Identifier: Apache-2.0
|
|
|
|
//! Smoke test for `IpMixStream`: connect to an IPR, send a ping, check we get a reply.
|
|
//!
|
|
//! Tests both IPv4 and IPv6 paths.
|
|
//!
|
|
//! Run with: `cargo run --example ipr_tunnel -- --ipr <IPR_ADDRESS>`
|
|
|
|
use std::net::{Ipv4Addr, Ipv6Addr};
|
|
use std::time::Duration;
|
|
|
|
use nym_ip_packet_requests::codec::MultiIpPacketCodec;
|
|
use nym_ip_packet_requests::icmp_utils::{
|
|
build_icmp_ping, build_icmpv6_ping, is_echo_reply_v4, is_echo_reply_v6,
|
|
};
|
|
use nym_sdk::ipr_wrapper::IpMixStream;
|
|
|
|
const PING4_TARGET: Ipv4Addr = Ipv4Addr::new(8, 8, 8, 8);
|
|
const PING6_TARGET: Ipv6Addr = Ipv6Addr::new(0x2001, 0x4860, 0x4860, 0, 0, 0, 0, 0x8888);
|
|
|
|
#[tokio::main]
|
|
async fn main() -> anyhow::Result<()> {
|
|
nym_bin_common::logging::setup_tracing_logger();
|
|
|
|
let args: Vec<String> = std::env::args().collect();
|
|
let ipr_addr = args
|
|
.iter()
|
|
.position(|a| a == "--ipr")
|
|
.and_then(|i| args.get(i + 1));
|
|
|
|
let mut tunnel = if let Some(addr) = ipr_addr {
|
|
let recipient = addr.parse().expect("invalid IPR address");
|
|
IpMixStream::new_with_ipr(recipient).await?
|
|
} else {
|
|
IpMixStream::new().await?
|
|
};
|
|
|
|
let ips = tunnel.allocated_ips();
|
|
let src4 = ips.ipv4;
|
|
let src6 = ips.ipv6;
|
|
println!("Tunnel up — IPv4: {src4}, IPv6: {src6}");
|
|
|
|
// Send IPv4 ping (ICMP seq=0, unrelated to LP Stream sequence numbers)
|
|
let pkt4 = build_icmp_ping(src4, PING4_TARGET, 0).expect("failed to build ICMP packet");
|
|
let bundled = MultiIpPacketCodec::bundle_one_packet(pkt4.into());
|
|
tunnel.send_ip_packet(&bundled).await?;
|
|
println!("Sent ping → {PING4_TARGET}");
|
|
|
|
// Send IPv6 ping
|
|
let pkt6 = build_icmpv6_ping(src6, PING6_TARGET, 0).expect("failed to build ICMPv6 packet");
|
|
let bundled = MultiIpPacketCodec::bundle_one_packet(pkt6.into());
|
|
tunnel.send_ip_packet(&bundled).await?;
|
|
println!("Sent ping → {PING6_TARGET}");
|
|
|
|
let mut got_v4 = false;
|
|
let mut got_v6 = false;
|
|
let deadline = tokio::time::sleep(Duration::from_secs(30));
|
|
tokio::pin!(deadline);
|
|
|
|
loop {
|
|
tokio::select! {
|
|
_ = &mut deadline => {
|
|
if !got_v4 { println!("FAIL — no IPv4 reply within 30s"); }
|
|
if !got_v6 { println!("FAIL — no IPv6 reply within 30s"); }
|
|
break;
|
|
}
|
|
result = tunnel.handle_incoming() => {
|
|
for pkt in result? {
|
|
if !got_v4 && is_echo_reply_v4(&pkt, src4) {
|
|
println!("OK — got IPv4 echo reply");
|
|
got_v4 = true;
|
|
}
|
|
if !got_v6 && is_echo_reply_v6(&pkt, src6) {
|
|
println!("OK — got IPv6 echo reply");
|
|
got_v6 = true;
|
|
}
|
|
if got_v4 && got_v6 {
|
|
tunnel.disconnect().await;
|
|
return Ok(());
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
tunnel.disconnect().await;
|
|
Ok(())
|
|
}
|