From 314595e8f0b47e1b68e9c512442655dec4a2acc0 Mon Sep 17 00:00:00 2001 From: Hirek193 Date: Thu, 17 Sep 2026 15:01:58 +0000 Subject: [PATCH] hardware protocol v2: make the hello handshake idempotent A device which doesn't hear the welcome repeats its greeting. Minting a fresh session for every repeat left both ends chasing each other's session ids: the device eventually answered with the id it had been given, the simulator had already moved on and rejected it as INVALID_SESSION, the device restarted the handshake, and so on twice a second for as long as the link was up. The same greeting arriving on a session which has not been used yet is now answered with the session it already has, and only a different device, or one whose session had progressed, gets a new id. Repeated greetings are counted as handshakes and shown in the debug panel, so the condition which causes them stays visible instead of flooding the log. --- application/driveruipanels.cpp | 3 +- hardware/diagnostics/hardware_diagnostics.h | 2 + hardware/protocol/protocol_session.cpp | 49 +++++++++++++++++---- 3 files changed, 44 insertions(+), 10 deletions(-) diff --git a/application/driveruipanels.cpp b/application/driveruipanels.cpp index b84b1086..f678379e 100644 --- a/application/driveruipanels.cpp +++ b/application/driveruipanels.cpp @@ -1393,7 +1393,8 @@ debug_panel::update_section_hardware( std::vector &Output ) { + " symbol " + std::to_string( protocol.unknown_symbols ) + " handle " + std::to_string( protocol.unknown_handles ) + " duplicates " + std::to_string( protocol.duplicate_commands ) - + " rate limited " + std::to_string( protocol.rate_limited ); + + " rate limited " + std::to_string( protocol.rate_limited ) + + " handshakes " + std::to_string( protocol.handshakes ); textline += "\nack " + std::to_string( protocol.acks ) diff --git a/hardware/diagnostics/hardware_diagnostics.h b/hardware/diagnostics/hardware_diagnostics.h index 0028ced7..562ebbbc 100644 --- a/hardware/diagnostics/hardware_diagnostics.h +++ b/hardware/diagnostics/hardware_diagnostics.h @@ -65,6 +65,8 @@ struct protocol_diagnostics std::uint64_t acks = 0; std::uint64_t nacks = 0; std::uint64_t rate_limited = 0; + // powitania powtorzone przez urzadzenie, ktore nie uslyszalo WELCOME + std::uint64_t handshakes = 0; std::uint64_t state_updates = 0; std::uint64_t commands_executed = 0; std::uint64_t controls_applied = 0; diff --git a/hardware/protocol/protocol_session.cpp b/hardware/protocol/protocol_session.cpp index 1c54f95e..ce306fa7 100644 --- a/hardware/protocol/protocol_session.cpp +++ b/hardware/protocol/protocol_session.cpp @@ -486,13 +486,29 @@ void protocol_session::handle_hello( decoded_packet const &Packet ) return; } - // a fresh hello always starts a new session, invalidating whatever the previous one held - m_handles.clear(); - m_handlelookup.clear(); - m_subscriptions.clear(); - m_controlsequence.clear(); - m_transactions.clear(); - m_transactionorder.clear(); + // a hello retry has to be idempotent. a device which didn't hear the welcome repeats its + // greeting, and minting a fresh session for every repeat leaves both ends chasing each + // other's session ids: the device answers with the id it was given, the simulator has + // already moved on and rejects it, the device restarts the handshake, forever. the same + // greeting arriving on a session which hasn't been used yet is answered with that session + bool const rehandshake = ( + ( m_sessionid != 0 ) + && ( m_state == session_state::established ) + && ( true == m_handles.empty() ) + && ( name == m_devicename ) + && ( role == m_devicerole ) + && ( deviceid == m_deviceid ) ); + + if( false == rehandshake ) + { + // a genuinely new session invalidates whatever the previous one held + m_handles.clear(); + m_handlelookup.clear(); + m_subscriptions.clear(); + m_controlsequence.clear(); + m_transactions.clear(); + m_transactionorder.clear(); + } m_peermajor = major; m_peerminor = minor; @@ -506,7 +522,14 @@ void protocol_session::handle_hello( decoded_packet const &Packet ) auto const requested = ( framesize > 0 ? static_cast( framesize ) : protocol_frame_size_default ); m_framesize = std::clamp( std::min( requested, m_config.frame_size ), protocol_frame_size_min, protocol_frame_size_max ); - m_sessionid = generate_session_id(); + if( false == rehandshake ) + { + m_sessionid = generate_session_id(); + } + else + { + ++m_diagnostics.handshakes; + } m_state = session_state::established; m_heartbeattimer = 0.0; m_pingtimer = 0.0; @@ -522,7 +545,15 @@ void protocol_session::handle_hello( decoded_packet const &Packet ) writer.write_string( Global.asVersion ); send( message_type::welcome, packetflag_response, writer ); - WriteLog( "hardware: session " + std::to_string( m_sessionid ) + " established with '" + m_devicename + "' (" + m_devicerole + ")" ); + if( false == rehandshake ) + { + WriteLog( "hardware: session " + std::to_string( m_sessionid ) + " established with '" + m_devicename + "' (" + m_devicerole + ")" ); + } + else if( true == debug_flags.log_messages ) + { + // repeated greetings say the welcome isn't getting through; the panel counts them + WriteLog( "hardware: device '" + m_devicename + "' repeated its greeting, session " + std::to_string( m_sessionid ) + " kept" ); + } } void protocol_session::handle_heartbeat( decoded_packet const &Packet )