mirror of
https://github.com/jmcorgan/fips.git
synced 2026-08-12 01:27:32 +00:00
Session-layer handshake message retry with exponential backoff
Add resend logic for SessionSetup/SessionAck messages routed through the mesh. Stores the encoded payload on SessionEntry for resend in a fresh SessionDatagram (so routing can adapt to topology changes). Uses the same config parameters as link-layer retry. Also fixes a latent bug: Initiating/Responding sessions previously had no timeout — a stuck handshake would live forever. Now cleaned up after handshake_timeout_secs (default 30s). Responder idempotency: duplicate SessionSetup triggers resend of stored SessionAck instead of being silently dropped. Initiator-side duplicate SessionAck already handled safely (entry.take_state() sees Established, puts it back and returns). Handshake payload cleared on Established transition at both initiator (handle_session_ack) and responder (handle_encrypted_session_msg).
This commit is contained in:
@@ -70,6 +70,15 @@ pub(crate) struct SessionEntry {
|
||||
is_initiator: bool,
|
||||
/// Session-layer MMP state. Initialized on Established transition.
|
||||
mmp: Option<MmpSessionState>,
|
||||
|
||||
// === Handshake Resend ===
|
||||
/// Encoded session-layer payload for resend (SessionSetup or SessionAck).
|
||||
/// Cleared on Established transition.
|
||||
handshake_payload: Option<Vec<u8>>,
|
||||
/// Number of resends performed.
|
||||
resend_count: u32,
|
||||
/// When the next resend should fire (Unix ms). 0 = no resend scheduled.
|
||||
next_resend_at_ms: u64,
|
||||
}
|
||||
|
||||
impl SessionEntry {
|
||||
@@ -91,6 +100,9 @@ impl SessionEntry {
|
||||
coords_warmup_remaining: 0,
|
||||
is_initiator,
|
||||
mmp: None,
|
||||
handshake_payload: None,
|
||||
resend_count: 0,
|
||||
next_resend_at_ms: 0,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -193,4 +205,45 @@ impl SessionEntry {
|
||||
pub(crate) fn init_mmp(&mut self, config: &SessionMmpConfig) {
|
||||
self.mmp = Some(MmpSessionState::new(config, self.is_initiator));
|
||||
}
|
||||
|
||||
// === Handshake Resend ===
|
||||
|
||||
/// Store the encoded session-layer payload for potential resend.
|
||||
///
|
||||
/// For initiators, this is the SessionSetup payload bytes.
|
||||
/// For responders, this is the SessionAck payload bytes.
|
||||
/// The payload is re-wrapped in a fresh SessionDatagram on each resend
|
||||
/// so routing can adapt to topology changes.
|
||||
pub(crate) fn set_handshake_payload(&mut self, payload: Vec<u8>, next_resend_at_ms: u64) {
|
||||
self.handshake_payload = Some(payload);
|
||||
self.resend_count = 0;
|
||||
self.next_resend_at_ms = next_resend_at_ms;
|
||||
}
|
||||
|
||||
/// Get the stored handshake payload for resend.
|
||||
pub(crate) fn handshake_payload(&self) -> Option<&[u8]> {
|
||||
self.handshake_payload.as_deref()
|
||||
}
|
||||
|
||||
/// Clear the stored handshake payload (called on Established transition).
|
||||
pub(crate) fn clear_handshake_payload(&mut self) {
|
||||
self.handshake_payload = None;
|
||||
self.next_resend_at_ms = 0;
|
||||
}
|
||||
|
||||
/// Number of resends performed so far.
|
||||
pub(crate) fn resend_count(&self) -> u32 {
|
||||
self.resend_count
|
||||
}
|
||||
|
||||
/// When the next resend should fire (Unix ms). 0 = no resend scheduled.
|
||||
pub(crate) fn next_resend_at_ms(&self) -> u64 {
|
||||
self.next_resend_at_ms
|
||||
}
|
||||
|
||||
/// Record a resend and schedule the next one.
|
||||
pub(crate) fn record_resend(&mut self, next_resend_at_ms: u64) {
|
||||
self.resend_count += 1;
|
||||
self.next_resend_at_ms = next_resend_at_ms;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user