Expand description
Rendezvous handshake engine — draft-sharabayko-srt-01 §4.3.2 (Rendezvous
Handshake), curated at specs/rules/srt-rendezvous.md. Line cites below
(LNNNN) are the source draft’s line numbers, exactly as recorded in that
curation.
RendezvousHandshake is symmetric: both peers run the same engine
(unlike crate::caller::CallerHandshake / crate::listener::ListenerHandshake,
which run different code for different roles). Which of the two logical
roles — Initiator or Responder — a given instance ends up playing
is decided at runtime by the cookie contest (§4.3.2, L2107-2135):
each side supplies its own 32-bit cookie to RendezvousHandshake::new
(this crate never reads a clock or a socket address — see
crate::handshake_sm::derive_cookie for a ready-made, non-standardized
derivation helper, exactly as for crate::listener::ListenerHandshake),
and the greater cookie value wins (“becomes Initiator”, L2133-2135).
§State machine
States are named exactly as the draft’s Parallel Handshake Flow diagram
(§4.3.2.2, L2280, quoted verbatim): Waving → Attention → Initiated →
Connected (plus Idle before RendezvousHandshake::start is called —
not spec-named, mirrors crate::caller::CallerHandshakeState::Idle — and
Rejected/TimedOut terminal states, also not spec-named). Every
transition below is the Initiator table (L2301-2334) or Responder table
(L2336-2382), or a missing-packet recovery rule (L2383-2432).
§Serial vs Parallel flow: one engine, not two
The draft narrates two “flows” (§4.3.2.1 Serial, L2140-2269; §4.3.2.2
Parallel, L2270-2432) that differ only in message interleaving, not in
any new transition rule: the Parallel flow’s Initiator/Responder tables are
complete state × received-message tables, driven purely by message
content — so they already cover the Serial flow’s crossing case. That case
is: a peer still in Waving (having sent its own WAVEAHAND but never
having received the other side’s) receives a CONCLUSION directly
instead of a WAVEAHAND (§4.3.2.1 step 3, L2203-2219 — the draft calls the
resulting state “fine”). Tracing the draft’s own worked example confirms
the action taken is identical to applying the Parallel Attention row to
that CONCLUSION: an Initiator receiving an extension-less CONCLUSION here
behaves exactly like the Initiator-Attention-row “no extensions” case
(L2312-2318); a Responder receiving a CONCLUSION+HSREQ here behaves
exactly like the Responder-Attention-row HSREQ case (L2360-2364) — because
by this point in the exchange the peer’s role-appropriate first CONCLUSION
already carries whatever extension its role dictates (Initiator: HSREQ
immediately, L2286-2287; Responder: none until it has seen HSREQ,
L2357-2360/L2287-2288). This implementation therefore has no separate
“Fine” state — a received CONCLUSION while still in Waving dispatches
straight into the same Attention-row logic used when genuinely in
Attention, rather than inventing a fourth, behaviourally-divergent state
the tables do not define.
§Resolved ambiguities (not explicit in the curated rules)
- Cookie collision → rejection. The draft says only “the connection
will not be made until new, unique cookies are generated” (L2119-2124),
describing an out-of-band retry, not a wire action. This engine surfaces
it as
RejectionReason::RdvCookie(Table 7 code1009, “rendezvous cookie collision” — an exact fit) rather than blocking or retrying internally; a driver that wants the “regenerate and retry” behaviour builds a freshRendezvousHandshakewith a new cookie. - CONCLUSION
SYN Cookiefield. The draft specifies WAVEAHAND’s SYN Cookie (L2156-2165) but not what later CONCLUSION/AGREEMENT messages carry in that field. Every message this engine sends after WAVEAHAND continues to carry this side’s own cookie (never an echo of the peer’s, unlike the Caller-Listener flood-protection cookie) — consistent with the cookie’s role here being mutual identification/contest, not a flood-protection echo-token. - No Stream ID / Group Membership exchange. Neither extension is
mentioned anywhere in §4.3.2; unlike
crate::handshake_sm::NegotiatedParamsfrom the Caller-Listener flow, this engine never sends them and always reportsstream_id: None,group: None— flagged rather than fabricated. - Latency/flags reconciliation. §4.3.2 does not restate the
greater-latency / AND-flags rule from §4.3.1.2, but it is a property of
the Handshake Extension Message itself (§3.2.1.1), not of the flow that
carried it, so the same shared
handshake_smreconciliation helper used by the Caller-Listener flow is reused unchanged. - Duplicate WAVEAHAND while already
Attention. Not covered by either table (which only fire on the first WAVEAHAND). Treated as a benign duplicate: resend the last message, no state change. - Recovery rule 3 (data packet promotes a stuck Responder, L2413-2422)
is exposed as
RendezvousHandshake::on_recovery_trigger, since this engine’sfeedtakes aControlPacket(matchingcrate::caller::CallerHandshake/crate::listener::ListenerHandshake), not the data-planecrate::packet::SrtPacket; a driver that receives aSrtPacket::Data(or any Control packet normally only sent between connected parties —RendezvousHandshake::feedalready treats any inbound non-HandshakeControlPacketthis way for exactly this reason) calls it directly.
Explicit non-goals, unchanged from the crate root: ARQ/loss, TSBPD
delivery, congestion control, AES key-wrap/unwrap crypto, a tokio socket
adapter, and the Version-4 legacy Rendezvous path (L2101-2105, out of
scope of the draft excerpt this crate implements against).
Structs§
- Rendezvous
Handshake - A driveable, symmetric SRT Rendezvous handshake
(
draft-sharabayko-srt-01§4.3.2). See the module docs for the state machine and the design decisions not explicit in the curated rules.
Enums§
- Rendezvous
Handshake State - Rendezvous handshake lifecycle state (
draft-sharabayko-srt-01§4.3.2). State names are exactly the Parallel Handshake Flow diagram (§4.3.2.2, L2280):Waving -> Attention -> Initiated -> Connected. See the module doc “Serial vs Parallel flow” note for why there is no separate state for the Serial flow’s “fine”. - Rendezvous
Role - The role a
RendezvousHandshakeplays, resolved by the cookie contest (draft-sharabayko-srt-01§4.3.2, L2107-2135): “When one party’s cookie value is greater than its peer’s, it wins the cookie contest and becomes Initiator (the other party becomes the Responder).”