XMPP: geen ping/keepalive — NAT-idle timeout killt de sessie stil (geen reconnect tot TCP ook drop is) #1418

Closed
opened 2026-08-09 18:25:00 +00:00 by brenno · 0 comments
Owner

Bevinding

lib/xmpp/xmpp_session.dart — de sessie stuurt geen XMPP ping (XEP-0199) of whitespace keepalive. De enige detectie van een dode verbinding is de TCP-close (_FrameReader._onDone), die pas komt als het besturingssysteem de verbinding als dood beschouwt.

Wat er gebeurt

Een NAT-router of firewall die idle verbindingen na 30–120 seconden dropt (een veelvoorkomende standaard), killt de TCP-verbinding stil — de client merkt dit pas als hij iets probeert te verzenden (dan komt een RST) of als de OS-keepalive (typisch 2 uur) de verbinding als dood markeert. In de tussentijd denkt de sessie dat hij live is (_live = true), maar er komt niets binnen en niets gaat weg.

De reconnect-mechanisme (_onStreamDropped) triggert pas als _FrameReader._onDone of _onError vuurt — wat bij een stille NAT-drop pas na de OS-TCP-keepalive-timeout (vaak uren) of helemaal niet gebeurt.

Trust boundary

Netwerk (NAT/firewall) → Applicatie (sessie-levendigheid).

Impact

De samenwerking bevriest stil na een NAT-idle-timeout. De gebruiker ziet geen foutmelding — de UI toont nog steeds "verbonden", maar geen presence/ops/chat komen binnen en niets gaat weg. De reconnect start pas (als al geconfigureerd) nadat de TCP-verbinding ook daadwerkelijk drop is, wat uren kan duren.

Dit is het meest waarschijnlijke unhappy-flow scenario voor een samenwerkingssessie in de praktijk — netwerkonderbrekingen door NAT/firewall zijn alledaags.

Oplossingsrichting

  1. XEP-0199 XMPP Ping: stuur periodiek een <iq type=get><ping xmlns=urn:xmpp:ping/></iq> (bijv. elke 60 seconden). Als de server niet antwoordt binnen de timeout, beschouw de verbinding als dood en trigger _onStreamDropped.
  2. Whitespace keepalive (XEP-0198 §5): stuur een enkel space-teken over de WebSocket — dit houdt de NAT-tabel warm en is goedkoper dan een ping. Maar het detecteert geen dode verbinding (er is geen antwoord).
  3. Combinatie: whitespace keepalive om NAT-timeout te voorkomen, plus XEP-0199 ping om een dode verbinding te detecteren.
  4. Aanvullend: overweeg XEP-0198 Stream Management (SM) — dit biedt niet alleen keepalive, maar ook hervatbaarheid (ack + resume), wat de gap→resync-mechanisme in het transport overbodig zou maken voor korte drops.

Locatie

  • lib/xmpp/xmpp_session.dart — geen ping-logica aanwezig; _startDispatch (regels 498–509) alleen inbound, geen periodieke outbound.
  • lib/xmpp/xmpp_frame_transport_io.dart — geen WebSocket-level ping geconfigureerd.

Severity

HIGH — dit is het meest waarschijnlijke unhappy-flow scenario in de praktijk.

## Bevinding `lib/xmpp/xmpp_session.dart` — de sessie stuurt geen XMPP ping (XEP-0199) of whitespace keepalive. De enige detectie van een dode verbinding is de TCP-close (`_FrameReader._onDone`), die pas komt als het besturingssysteem de verbinding als dood beschouwt. ### Wat er gebeurt Een NAT-router of firewall die idle verbindingen na 30–120 seconden dropt (een veelvoorkomende standaard), killt de TCP-verbinding stil — de client merkt dit pas als hij iets probeert te verzenden (dan komt een RST) of als de OS-keepalive (typisch 2 uur) de verbinding als dood markeert. In de tussentijd denkt de sessie dat hij live is (`_live = true`), maar er komt niets binnen en niets gaat weg. De reconnect-mechanisme (`_onStreamDropped`) triggert pas als `_FrameReader._onDone` of `_onError` vuurt — wat bij een stille NAT-drop pas na de OS-TCP-keepalive-timeout (vaak uren) of helemaal niet gebeurt. ### Trust boundary Netwerk (NAT/firewall) → Applicatie (sessie-levendigheid). ### Impact De samenwerking bevriest stil na een NAT-idle-timeout. De gebruiker ziet geen foutmelding — de UI toont nog steeds "verbonden", maar geen presence/ops/chat komen binnen en niets gaat weg. De reconnect start pas (als al geconfigureerd) nadat de TCP-verbinding ook daadwerkelijk drop is, wat uren kan duren. Dit is het meest waarschijnlijke unhappy-flow scenario voor een samenwerkingssessie in de praktijk — netwerkonderbrekingen door NAT/firewall zijn alledaags. ### Oplossingsrichting 1. **XEP-0199 XMPP Ping:** stuur periodiek een `<iq type=get><ping xmlns=urn:xmpp:ping/></iq>` (bijv. elke 60 seconden). Als de server niet antwoordt binnen de timeout, beschouw de verbinding als dood en trigger `_onStreamDropped`. 2. **Whitespace keepalive (XEP-0198 §5):** stuur een enkel space-teken over de WebSocket — dit houdt de NAT-tabel warm en is goedkoper dan een ping. Maar het detecteert geen dode verbinding (er is geen antwoord). 3. **Combinatie:** whitespace keepalive om NAT-timeout te voorkomen, plus XEP-0199 ping om een dode verbinding te detecteren. 4. **Aanvullend:** overweeg XEP-0198 Stream Management (SM) — dit biedt niet alleen keepalive, maar ook hervatbaarheid (ack + resume), wat de gap→resync-mechanisme in het transport overbodig zou maken voor korte drops. ### Locatie - `lib/xmpp/xmpp_session.dart` — geen ping-logica aanwezig; `_startDispatch` (regels 498–509) alleen inbound, geen periodieke outbound. - `lib/xmpp/xmpp_frame_transport_io.dart` — geen WebSocket-level ping geconfigureerd. ### Severity HIGH — dit is het meest waarschijnlijke unhappy-flow scenario in de praktijk.
brenno 2026-08-09 20:56:28 +00:00
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
LibreKAT/Ocideck#1418
No description provided.