fixed handshake retry

This commit is contained in:
Jędrzej Stuczyński
2026-03-04 13:03:07 +00:00
parent 8f376d1b9b
commit 86aec84697
3 changed files with 37 additions and 38 deletions
+12 -18
View File
@@ -5,7 +5,7 @@
use super::config::LpRegistrationConfig;
use super::error::{LpClientError, Result};
use crate::lp_client::helpers::{LpDataDeliverExt, LpDataSendExt};
use crate::lp_client::helpers::{LpDataDeliverExt, LpDataSendExt, exponential_backoff_with_jitter};
use crate::lp_client::nested_session::connection::NestedConnection;
use crate::lp_client::session_helpers::{extract_forwarded_response, prepare_send_packet};
use nym_bandwidth_controller::{BandwidthTicketProvider, DEFAULT_TICKETS_TO_SPEND};
@@ -23,12 +23,12 @@ use nym_registration_common::{
WireguardRegistrationData,
};
use nym_wireguard_types::PeerPublicKey;
use rand09::{CryptoRng, Rng, RngCore};
use rand09::{CryptoRng, RngCore};
use std::net::SocketAddr;
use std::sync::Arc;
use std::time::Duration;
use tokio::net::TcpStream;
use tracing::warn;
use tracing::{debug, warn};
/// LP (Lewes Protocol) registration client for direct gateway connections.
///
@@ -649,27 +649,21 @@ where
let mut last_error = None;
for attempt in 0..=max_retries {
let attempt_display = attempt + 1;
debug!("registration attempt {attempt_display}");
if attempt > 0 {
// Exponential backoff with jitter: 100ms, 200ms, 400ms, 800ms, 1600ms (capped)
let base_delay_ms = 100u64 * (1 << attempt.min(4));
let jitter_ms: u64 = rand09::rng().random_range(0..(base_delay_ms / 4 + 1));
let delay = std::time::Duration::from_millis(base_delay_ms + jitter_ms);
tracing::info!("Retrying registration (attempt {attempt_display}) after {delay:?}");
tokio::time::sleep(delay).await;
// Clear any stale state before re-handshaking
self.transport_session = None;
self.close();
exponential_backoff_with_jitter(attempt).await
}
// Ensure fresh connection and handshake for each attempt
// (On retry, the old connection/session may be dead)
if self.stream.is_none() || attempt > 0 {
// Clear any stale state before re-handshaking
self.close();
self.transport_session = None;
if let Err(e) = self.perform_handshake().await {
match self.perform_handshake().await {
Ok(_) => break,
Err(e) => {
tracing::warn!("Handshake failed on attempt {attempt_display}: {e}");
last_error = Some(e);
continue;
}
}
}
@@ -11,6 +11,7 @@ use nym_lp::session::{LpAction, LpInput};
use nym_registration_common::{
LpRegistrationRequest, LpRegistrationResponse, NymNodeLPInformation,
};
use rand09::Rng;
pub(crate) trait LpDataSendExt {
fn to_lp_data(&self) -> Result<LpMessage, LpClientError>;
@@ -83,3 +84,12 @@ pub(crate) fn try_convert_forward_response(action: LpAction) -> Result<Vec<u8>,
pub(crate) fn to_lp_remote_peer(data: NymNodeLPInformation) -> LpRemotePeer {
LpRemotePeer::new(data.x25519).with_key_digests(data.expected_kem_key_hashes)
}
pub(crate) async fn exponential_backoff_with_jitter(attempt: u32) {
// Exponential backoff with jitter: 100ms, 200ms, 400ms, 800ms, 1600ms (capped)
let base_delay_ms = 100u64 * (1 << attempt.min(4));
let jitter_ms: u64 = rand09::rng().random_range(0..(base_delay_ms / 4 + 1));
let delay = std::time::Duration::from_millis(base_delay_ms + jitter_ms);
tracing::info!("Retrying registration after the following delay {delay:?}");
tokio::time::sleep(delay).await;
}
@@ -20,7 +20,7 @@
use super::client::LpRegistrationClient;
use super::error::{LpClientError, Result};
use crate::lp_client::helpers::{LpDataDeliverExt, LpDataSendExt};
use crate::lp_client::helpers::{LpDataDeliverExt, LpDataSendExt, exponential_backoff_with_jitter};
use crate::lp_client::session_helpers::{extract_forwarded_response, prepare_send_packet};
use nym_bandwidth_controller::{BandwidthTicketProvider, DEFAULT_TICKETS_TO_SPEND};
use nym_credentials_interface::TicketType;
@@ -37,7 +37,7 @@ use nym_registration_common::{
WireguardRegistrationData,
};
use nym_wireguard_types::PeerPublicKey;
use rand09::{CryptoRng, Rng, RngCore};
use rand09::{CryptoRng, RngCore};
use std::net::SocketAddr;
use std::sync::Arc;
use tracing::{debug, warn};
@@ -513,31 +513,26 @@ impl NestedLpSession {
let mut last_error = None;
for attempt in 0..=max_retries {
let attempt_display = attempt + 1;
debug!("registration attempt {attempt_display}");
// Verify outer session is still usable before retry
if !outer_client.is_handshake_complete() {
return Err(LpClientError::Other(
"Outer session lost during retry - caller must re-establish entry gateway connection".to_string()
));
}
if attempt > 0 {
// Verify outer session is still usable before retry
if !outer_client.is_handshake_complete() {
return Err(LpClientError::Other(
"Outer session lost during retry - caller must re-establish entry gateway connection".to_string()
));
}
// Exponential backoff with jitter: 100ms, 200ms, 400ms, 800ms, 1600ms (capped)
let base_delay_ms = 100u64 * (1 << attempt.min(4));
let jitter_ms: u64 = rand09::rng().random_range(0..(base_delay_ms / 4 + 1));
let delay = std::time::Duration::from_millis(base_delay_ms + jitter_ms);
tracing::info!(
"Retrying exit registration (attempt {attempt_display}) after {delay:?}",
);
tokio::time::sleep(delay).await;
// Clear state machine before retry - handshake needs fresh start
self.transport_session = None;
exponential_backoff_with_jitter(attempt).await
}
if let Err(e) = self.perform_handshake(outer_client).await {
match self.perform_handshake(outer_client).await {
Ok(_) => break,
Err(e) => {
warn!("Handshake failed on attempt {attempt_display}: {e}");
last_error = Some(e);
continue;
}
}
}