T1.5: Migrate emit/parse sites to v2 wire format

This commit is contained in:
Siavash Sameni
2026-05-11 12:36:45 +04:00
parent 9680b6ff34
commit c93d302656
120 changed files with 5953 additions and 2888 deletions

View File

@@ -94,9 +94,10 @@ fn relay_a_handle_offer(reg_a: &mut CallRegistry, offer: &SignalMessage) -> Sign
/// reproduced here for the test.
fn relay_b_handle_forwarded_offer(reg_b: &mut CallRegistry, forward: &SignalMessage) {
let (inner, origin_relay_fp) = match forward {
SignalMessage::FederatedSignalForward { inner, origin_relay_fp } => {
(inner.as_ref().clone(), origin_relay_fp.clone())
}
SignalMessage::FederatedSignalForward {
inner,
origin_relay_fp,
} => (inner.as_ref().clone(), origin_relay_fp.clone()),
_ => panic!("not a forward"),
};
// Loop-prevention: drop self-sourced.
@@ -114,11 +115,7 @@ fn relay_b_handle_forwarded_offer(reg_b: &mut CallRegistry, forward: &SignalMess
};
// Simulated: target is local to B (Bob is registered here).
reg_b.create_call(
call_id.clone(),
caller_fingerprint,
target_fingerprint,
);
reg_b.create_call(call_id.clone(), caller_fingerprint, target_fingerprint);
reg_b.set_caller_reflexive_addr(&call_id, caller_reflexive_addr);
reg_b.set_peer_relay_fp(&call_id, Some(origin_relay_fp));
}
@@ -194,9 +191,10 @@ fn relay_a_handle_forwarded_answer(
forward: &SignalMessage,
) -> SignalMessage {
let (inner, origin_relay_fp) = match forward {
SignalMessage::FederatedSignalForward { inner, origin_relay_fp } => {
(inner.as_ref().clone(), origin_relay_fp.clone())
}
SignalMessage::FederatedSignalForward {
inner,
origin_relay_fp,
} => (inner.as_ref().clone(), origin_relay_fp.clone()),
_ => panic!("not a forward"),
};
assert_ne!(origin_relay_fp, RELAY_A_TLS_FP);
@@ -270,12 +268,15 @@ fn cross_relay_answer_crosswires_peer_direct_addrs() {
// Bob answers on Relay B.
let answer = bob_answer("c-xrelay-2");
let (answer_forward, setup_for_bob) =
relay_b_handle_local_answer(&mut reg_b, &answer);
let (answer_forward, setup_for_bob) = relay_b_handle_local_answer(&mut reg_b, &answer);
// Bob's CallSetup carries Alice's addr.
match setup_for_bob {
SignalMessage::CallSetup { peer_direct_addr, relay_addr, .. } => {
SignalMessage::CallSetup {
peer_direct_addr,
relay_addr,
..
} => {
assert_eq!(peer_direct_addr.as_deref(), Some(ALICE_ADDR));
assert_eq!(relay_addr, RELAY_B_ADDR);
}
@@ -286,7 +287,11 @@ fn cross_relay_answer_crosswires_peer_direct_addrs() {
// her CallSetup.
let setup_for_alice = relay_a_handle_forwarded_answer(&mut reg_a, &answer_forward);
match setup_for_alice {
SignalMessage::CallSetup { peer_direct_addr, relay_addr, .. } => {
SignalMessage::CallSetup {
peer_direct_addr,
relay_addr,
..
} => {
assert_eq!(peer_direct_addr.as_deref(), Some(BOB_ADDR));
assert_eq!(relay_addr, RELAY_A_ADDR);
}
@@ -313,9 +318,14 @@ fn cross_relay_loop_prevention_drops_self_sourced_forward() {
// The dispatcher in main.rs calls this explicit check before
// doing any work. Reproduce it inline.
let origin = match &forward {
SignalMessage::FederatedSignalForward { origin_relay_fp, .. } => origin_relay_fp.clone(),
SignalMessage::FederatedSignalForward {
origin_relay_fp, ..
} => origin_relay_fp.clone(),
_ => unreachable!(),
};
// Relay B sees origin == its own fp → drop.
assert_eq!(origin, RELAY_B_TLS_FP, "loop-prevention triggers on self-fp");
assert_eq!(
origin, RELAY_B_TLS_FP,
"loop-prevention triggers on self-fp"
);
}

View File

@@ -21,10 +21,10 @@ use bytes::Bytes;
use wzp_proto::{MediaTransport, SignalMessage};
use wzp_relay::config::{PeerConfig, TrustedConfig};
use wzp_relay::event_log::EventLogger;
use wzp_relay::federation::{room_hash, FederationManager};
use wzp_relay::federation::{FederationManager, room_hash};
use wzp_relay::metrics::RelayMetrics;
use wzp_relay::room::RoomManager;
use wzp_transport::{client_config, create_endpoint, server_config, QuinnTransport};
use wzp_transport::{QuinnTransport, client_config, create_endpoint, server_config};
// ───────────────────────────── helpers ──────────────────────────────
@@ -41,8 +41,7 @@ fn create_test_fm_full(
) -> Arc<FederationManager> {
let _ = rustls::crypto::ring::default_provider().install_default();
let (sc, _cert) = server_config();
let ep = create_endpoint((Ipv4Addr::LOCALHOST, 0).into(), Some(sc))
.expect("test endpoint");
let ep = create_endpoint((Ipv4Addr::LOCALHOST, 0).into(), Some(sc)).expect("test endpoint");
let room_mgr = Arc::new(RoomManager::new());
let metrics = Arc::new(RelayMetrics::new());
let event_log = EventLogger::Noop;
@@ -219,7 +218,10 @@ async fn forward_to_peers_empty_returns_immediately() {
fm.forward_to_peers("room", &hash, &data),
)
.await;
assert!(result.is_ok(), "forward_to_peers should return immediately with no peers");
assert!(
result.is_ok(),
"forward_to_peers should return immediately with no peers"
);
}
// ─────────── 4. forward_to_peers with live QUIC peer links ──────────
@@ -339,20 +341,20 @@ async fn broadcast_signal_sends_to_all_peers() {
.expect("FM should connect to mock peer within 5s");
// The FM sends FederationHello as the first signal. Read it.
let hello = tokio::time::timeout(
Duration::from_secs(2),
peer_transport.recv_signal(),
)
.await
.expect("hello timeout")
.expect("recv ok")
.expect("some message");
let hello = tokio::time::timeout(Duration::from_secs(2), peer_transport.recv_signal())
.await
.expect("hello timeout")
.expect("recv ok")
.expect("some message");
match hello {
SignalMessage::FederationHello { tls_fingerprint } => {
assert_eq!(tls_fingerprint, "test-relay-fp-abc123");
}
other => panic!("expected FederationHello, got: {:?}", std::mem::discriminant(&other)),
other => panic!(
"expected FederationHello, got: {:?}",
std::mem::discriminant(&other)
),
}
// Now the FM's run_federation_link registered the peer in peer_links
@@ -372,20 +374,22 @@ async fn broadcast_signal_sends_to_all_peers() {
assert_eq!(count, 1, "should have broadcast to exactly 1 peer");
// Read the signal on the peer side
let received = tokio::time::timeout(
Duration::from_secs(2),
peer_transport.recv_signal(),
)
.await
.expect("broadcast signal timeout")
.expect("recv ok")
.expect("some message");
let received = tokio::time::timeout(Duration::from_secs(2), peer_transport.recv_signal())
.await
.expect("broadcast signal timeout")
.expect("recv ok")
.expect("some message");
match received {
SignalMessage::FederatedSignalForward { origin_relay_fp, .. } => {
SignalMessage::FederatedSignalForward {
origin_relay_fp, ..
} => {
assert_eq!(origin_relay_fp, "other-relay-fp");
}
other => panic!("expected FederatedSignalForward, got: {:?}", std::mem::discriminant(&other)),
other => panic!(
"expected FederatedSignalForward, got: {:?}",
std::mem::discriminant(&other)
),
}
drop(peer_transport);
@@ -585,14 +589,11 @@ async fn federation_media_egress_forwards_to_peer() {
.expect("FM should connect within 5s");
// Read the FederationHello
let _hello = tokio::time::timeout(
Duration::from_secs(2),
peer_transport.recv_signal(),
)
.await
.expect("hello timeout")
.expect("recv ok")
.expect("some message");
let _hello = tokio::time::timeout(Duration::from_secs(2), peer_transport.recv_signal())
.await
.expect("hello timeout")
.expect("recv ok")
.expect("some message");
// Wait for link setup
tokio::time::sleep(Duration::from_millis(100)).await;

View File

@@ -11,14 +11,18 @@ use wzp_client::perform_handshake;
use wzp_crypto::{KeyExchange, WarzoneKeyExchange};
use wzp_proto::{MediaTransport, SignalMessage};
use wzp_relay::handshake::accept_handshake;
use wzp_transport::{client_config, create_endpoint, server_config, QuinnTransport};
use wzp_transport::{QuinnTransport, client_config, create_endpoint, server_config};
/// Establish a QUIC connection and wrap both sides in `QuinnTransport`.
///
/// Returns (client_transport, server_transport, _endpoints) where the endpoint
/// tuple must be kept alive for the duration of the test to avoid premature
/// connection teardown.
async fn connected_pair() -> (Arc<QuinnTransport>, Arc<QuinnTransport>, (quinn::Endpoint, quinn::Endpoint)) {
async fn connected_pair() -> (
Arc<QuinnTransport>,
Arc<QuinnTransport>,
(quinn::Endpoint, quinn::Endpoint),
) {
let _ = rustls::crypto::ring::default_provider().install_default();
let (sc, _cert_der) = server_config();
@@ -31,7 +35,9 @@ async fn connected_pair() -> (Arc<QuinnTransport>, Arc<QuinnTransport>, (quinn::
let server_ep_clone = server_ep.clone();
let accept_fut = tokio::spawn(async move {
let conn = wzp_transport::accept(&server_ep_clone).await.expect("accept");
let conn = wzp_transport::accept(&server_ep_clone)
.await
.expect("accept");
Arc::new(QuinnTransport::new(conn))
});
@@ -59,9 +65,8 @@ async fn handshake_succeeds() {
// Clone Arc so the server transport stays alive in the main task too.
let server_t = Arc::clone(&server_transport);
let callee_handle = tokio::spawn(async move {
accept_handshake(server_t.as_ref(), &callee_seed).await
});
let callee_handle =
tokio::spawn(async move { accept_handshake(server_t.as_ref(), &callee_seed).await });
let caller_session = perform_handshake(client_transport.as_ref(), &caller_seed, None)
.await
@@ -120,9 +125,8 @@ async fn handshake_verifies_identity() {
);
let server_t = Arc::clone(&server_transport);
let callee_handle = tokio::spawn(async move {
accept_handshake(server_t.as_ref(), &callee_seed).await
});
let callee_handle =
tokio::spawn(async move { accept_handshake(server_t.as_ref(), &callee_seed).await });
let caller_session = perform_handshake(client_transport.as_ref(), &caller_seed, None)
.await
@@ -179,13 +183,17 @@ async fn auth_then_handshake() {
let token = match auth_msg {
SignalMessage::AuthToken { token } => token,
other => panic!("expected AuthToken, got {:?}", std::mem::discriminant(&other)),
other => panic!(
"expected AuthToken, got {:?}",
std::mem::discriminant(&other)
),
};
// 2. Run the cryptographic handshake
let (session, profile, _caller_fp, _caller_alias) = accept_handshake(server_t.as_ref(), &callee_seed)
.await
.expect("accept_handshake after auth");
let (session, profile, _caller_fp, _caller_alias) =
accept_handshake(server_t.as_ref(), &callee_seed)
.await
.expect("accept_handshake after auth");
(token, session, profile)
});
@@ -203,9 +211,7 @@ async fn auth_then_handshake() {
.await
.expect("perform_handshake after auth");
let (received_token, callee_session, _profile) = callee_handle
.await
.expect("join callee task");
let (received_token, callee_session, _profile) = callee_handle.await.expect("join callee task");
// Verify the auth token was received correctly.
assert_eq!(received_token, "bearer-test-token-12345");
@@ -246,9 +252,8 @@ async fn handshake_rejects_bad_signature() {
// Spawn callee -- it should reject the tampered CallOffer.
let server_t = Arc::clone(&server_transport);
let callee_handle = tokio::spawn(async move {
accept_handshake(server_t.as_ref(), &callee_seed).await
});
let callee_handle =
tokio::spawn(async move { accept_handshake(server_t.as_ref(), &callee_seed).await });
// Manually build a CallOffer with a corrupted signature.
let mut kx = WarzoneKeyExchange::from_identity_seed(&caller_seed);

View File

@@ -151,12 +151,13 @@ fn both_peers_advertise_reflex_addrs_cross_wire_in_setup() {
);
let answer = mk_answer("c1", CallAcceptMode::AcceptTrusted, Some(callee_addr));
let (setup_caller, setup_callee) =
handle_answer_and_build_setups(&mut reg, &answer);
let (setup_caller, setup_callee) = handle_answer_and_build_setups(&mut reg, &answer);
// The CALLER's setup should carry the CALLEE's addr as peer_direct_addr.
match setup_caller {
SignalMessage::CallSetup { peer_direct_addr, .. } => {
SignalMessage::CallSetup {
peer_direct_addr, ..
} => {
assert_eq!(
peer_direct_addr.as_deref(),
Some(callee_addr),
@@ -168,7 +169,9 @@ fn both_peers_advertise_reflex_addrs_cross_wire_in_setup() {
// The CALLEE's setup should carry the CALLER's addr.
match setup_callee {
SignalMessage::CallSetup { peer_direct_addr, .. } => {
SignalMessage::CallSetup {
peer_direct_addr, ..
} => {
assert_eq!(
peer_direct_addr.as_deref(),
Some(caller_addr),
@@ -193,12 +196,13 @@ fn privacy_mode_answer_omits_callee_addr_from_setup() {
// AcceptGeneric explicitly passes None for callee_reflexive_addr —
// the whole point is to hide the callee's IP from the caller.
let answer = mk_answer("c2", CallAcceptMode::AcceptGeneric, None);
let (setup_caller, setup_callee) =
handle_answer_and_build_setups(&mut reg, &answer);
let (setup_caller, setup_callee) = handle_answer_and_build_setups(&mut reg, &answer);
// CALLER should see peer_direct_addr = None (privacy preserved).
match setup_caller {
SignalMessage::CallSetup { peer_direct_addr, .. } => {
SignalMessage::CallSetup {
peer_direct_addr, ..
} => {
assert!(
peer_direct_addr.is_none(),
"privacy mode must not leak callee addr to caller"
@@ -210,7 +214,9 @@ fn privacy_mode_answer_omits_callee_addr_from_setup() {
// CALLEE still gets the caller's addr — only the callee opted for
// privacy, the caller already volunteered its addr in the offer.
match setup_callee {
SignalMessage::CallSetup { peer_direct_addr, .. } => {
SignalMessage::CallSetup {
peer_direct_addr, ..
} => {
assert_eq!(
peer_direct_addr.as_deref(),
Some(caller_addr),
@@ -242,11 +248,12 @@ fn pre_phase3_caller_leaves_both_setups_relay_only() {
CallAcceptMode::AcceptTrusted,
Some("198.51.100.9:4433"),
);
let (setup_caller, setup_callee) =
handle_answer_and_build_setups(&mut reg, &answer);
let (setup_caller, setup_callee) = handle_answer_and_build_setups(&mut reg, &answer);
match setup_caller {
SignalMessage::CallSetup { peer_direct_addr, .. } => {
SignalMessage::CallSetup {
peer_direct_addr, ..
} => {
// Phase 3 relay behavior: we always inject whatever
// addrs are in the registry, regardless of who
// advertised. The caller here gets the callee's addr
@@ -258,7 +265,9 @@ fn pre_phase3_caller_leaves_both_setups_relay_only() {
// The callee's setup has no caller addr (pre-Phase-3 offer).
match setup_callee {
SignalMessage::CallSetup { peer_direct_addr, .. } => {
SignalMessage::CallSetup {
peer_direct_addr, ..
} => {
assert!(
peer_direct_addr.is_none(),
"callee should see no caller addr when offer was pre-Phase-3"
@@ -278,12 +287,15 @@ fn neither_peer_advertises_both_setups_are_relay_only() {
handle_offer(&mut reg, &mk_offer("c4", None));
let answer = mk_answer("c4", CallAcceptMode::AcceptTrusted, None);
let (setup_caller, setup_callee) =
handle_answer_and_build_setups(&mut reg, &answer);
let (setup_caller, setup_callee) = handle_answer_and_build_setups(&mut reg, &answer);
for (label, setup) in [("caller", setup_caller), ("callee", setup_callee)] {
match setup {
SignalMessage::CallSetup { peer_direct_addr, relay_addr, .. } => {
SignalMessage::CallSetup {
peer_direct_addr,
relay_addr,
..
} => {
assert!(
peer_direct_addr.is_none(),
"{label}'s CallSetup must have no peer_direct_addr"

View File

@@ -24,9 +24,9 @@ use std::net::{Ipv4Addr, SocketAddr};
use std::sync::Arc;
use std::time::Duration;
use wzp_client::reflect::{detect_nat_type, probe_reflect_addr, NatType};
use wzp_client::reflect::{NatType, detect_nat_type, probe_reflect_addr};
use wzp_proto::{MediaTransport, SignalMessage};
use wzp_transport::{create_endpoint, server_config, QuinnTransport};
use wzp_transport::{QuinnTransport, create_endpoint, server_config};
/// Minimal mock relay that loops accepting connections, handles
/// RegisterPresence + Reflect, and responds correctly. Mirrors the
@@ -136,10 +136,7 @@ async fn detect_nat_type_two_loopback_relays_probes_work_but_classify_unknown()
let (addr_b, _h_b) = spawn_mock_relay().await;
let detection = detect_nat_type(
vec![
("RelayA".into(), addr_a),
("RelayB".into(), addr_b),
],
vec![("RelayA".into(), addr_a), ("RelayB".into(), addr_b)],
2000,
None,
)
@@ -194,10 +191,7 @@ async fn detect_nat_type_dead_relay_is_unknown() {
let dead_addr: SocketAddr = "127.0.0.1:1".parse().unwrap();
let detection = detect_nat_type(
vec![
("Alive".into(), alive_addr),
("Dead".into(), dead_addr),
],
vec![("Alive".into(), alive_addr), ("Dead".into(), dead_addr)],
600, // tight timeout so the dead probe fails fast
None,
)
@@ -207,8 +201,16 @@ async fn detect_nat_type_dead_relay_is_unknown() {
// Find the alive and dead probes by name (order of JoinSet
// completions is not guaranteed).
let alive = detection.probes.iter().find(|p| p.relay_name == "Alive").unwrap();
let dead = detection.probes.iter().find(|p| p.relay_name == "Dead").unwrap();
let alive = detection
.probes
.iter()
.find(|p| p.relay_name == "Alive")
.unwrap();
let dead = detection
.probes
.iter()
.find(|p| p.relay_name == "Dead")
.unwrap();
assert!(
alive.observed_addr.is_some(),

View File

@@ -31,7 +31,7 @@ use std::sync::Arc;
use std::time::Duration;
use wzp_proto::{MediaTransport, SignalMessage};
use wzp_transport::{client_config, create_endpoint, server_config, QuinnTransport};
use wzp_transport::{QuinnTransport, client_config, create_endpoint, server_config};
/// Spawn a minimal mock relay that loops over `recv_signal`,
/// matches on `Reflect`, and responds with `ReflectResponse` using
@@ -94,7 +94,11 @@ async fn spawn_mock_relay_without_reflect(
/// distinct-ports test).
async fn connected_pair_with_port(
_client_port_hint: u16,
) -> (Arc<QuinnTransport>, Arc<QuinnTransport>, (quinn::Endpoint, quinn::Endpoint)) {
) -> (
Arc<QuinnTransport>,
Arc<QuinnTransport>,
(quinn::Endpoint, quinn::Endpoint),
) {
let _ = rustls::crypto::ring::default_provider().install_default();
let (sc, _cert_der) = server_config();
@@ -109,7 +113,9 @@ async fn connected_pair_with_port(
let server_ep_clone = server_ep.clone();
let accept_fut = tokio::spawn(async move {
let conn = wzp_transport::accept(&server_ep_clone).await.expect("accept");
let conn = wzp_transport::accept(&server_ep_clone)
.await
.expect("accept");
Arc::new(QuinnTransport::new(conn))
});
@@ -134,10 +140,7 @@ async fn reflect_happy_path() {
// Grab the client's actual bound port so we can cross-check
// against the reflected response.
let client_port = client_ep
.local_addr()
.expect("client local addr")
.port();
let client_port = client_ep.local_addr().expect("client local addr").port();
assert_ne!(client_port, 0, "client must have a real bound port");
// Start the mock relay's reflect handler.
@@ -162,7 +165,10 @@ async fn reflect_happy_path() {
let observed_addr = match resp {
SignalMessage::ReflectResponse { observed_addr } => observed_addr,
other => panic!("expected ReflectResponse, got {:?}", std::mem::discriminant(&other)),
other => panic!(
"expected ReflectResponse, got {:?}",
std::mem::discriminant(&other)
),
};
let parsed: SocketAddr = observed_addr
@@ -210,19 +216,17 @@ async fn reflect_two_clients_distinct_ports() {
// Client A
let client_ep_a = create_endpoint((Ipv4Addr::LOCALHOST, 0).into(), None).expect("ep A");
let conn_a =
wzp_transport::connect(&client_ep_a, server_listen, "localhost", client_config())
.await
.expect("connect A");
let conn_a = wzp_transport::connect(&client_ep_a, server_listen, "localhost", client_config())
.await
.expect("connect A");
let client_a = Arc::new(QuinnTransport::new(conn_a));
let port_a = client_ep_a.local_addr().unwrap().port();
// Client B
let client_ep_b = create_endpoint((Ipv4Addr::LOCALHOST, 0).into(), None).expect("ep B");
let conn_b =
wzp_transport::connect(&client_ep_b, server_listen, "localhost", client_config())
.await
.expect("connect B");
let conn_b = wzp_transport::connect(&client_ep_b, server_listen, "localhost", client_config())
.await
.expect("connect B");
let client_b = Arc::new(QuinnTransport::new(conn_b));
let port_b = client_ep_b.local_addr().unwrap().port();
@@ -252,7 +256,8 @@ async fn reflect_two_clients_distinct_ports() {
}
};
let (addr_a, addr_b) = tokio::join!(reflect_for(client_a.clone()), reflect_for(client_b.clone()));
let (addr_a, addr_b) =
tokio::join!(reflect_for(client_a.clone()), reflect_for(client_b.clone()));
let parsed_a: SocketAddr = addr_a.parse().unwrap();
let parsed_b: SocketAddr = addr_b.parse().unwrap();
@@ -277,12 +282,10 @@ async fn reflect_two_clients_distinct_ports() {
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn reflect_old_relay_times_out() {
let (client_transport, server_transport, _endpoints) =
connected_pair_with_port(0).await;
let (client_transport, server_transport, _endpoints) = connected_pair_with_port(0).await;
// Mock relay that ignores Reflect — simulates a pre-Phase-1 build.
let _relay_handle =
spawn_mock_relay_without_reflect(Arc::clone(&server_transport)).await;
let _relay_handle = spawn_mock_relay_without_reflect(Arc::clone(&server_transport)).await;
client_transport
.send_signal(&SignalMessage::Reflect)