[Bug]: Jingle calls fail after Smacks resume (IQ-result handler for session-accept wiped on reconnect causes ICE deadlock)
### What Monal Release channel are you using?
Alpha
### iOS system version (if applicable)
26.3
### macOS system version (if applicable)
_No response_
### Monal version
Alpha 2348142b
### Used XMPP server (domain)
xmpp.euhd.de
### Which XMPP-Server software are you using?
Prosody
### XMPP Server Software Version
0.13
### How many accounts are you using in Monal?
1
### What happened?
First of all: Thank you for the quick fix in #1588! Commit `1523dc8` elegantly
solves the 18-second wakeup delay by making the unfreeze synchronous.
Since #1588 is now closed, I am opening this new, dedicated issue to address the second, separate problem we discussed in the later comments: Jingle calls still fail if a network switch or TCP reconnect (Smacks resume) occurs right after the call is initiated.
_**Real-world test confirms: Handler-Wipe (not Push infrastructure)**:_
- To isolate the bug, I ran a strict real-world test today.
**Scenario:** Monal is in deep sleep (display off, extended standby) -> Caller (Monocles) switches network -> Monocles initiates a Jingle call.
**Observed behavior:**
- VoIP Push delivered correctly -> Monal wakes up instantly and the CallKit screen rings.
- ICE failure → The caller side (Monocles) receives "connection failed" almost instantly.
**What this proves:** The Push infrastructure works perfectly. The failure occurs strictly within the Jingle state machine during the Smacks Resume that
happens when Monal wakes up.
> **Note:** The fix from #1588 does **not** address this path the failure occurs even when Monal wakes correctly via Push and CallKit responds immediately. This is a second, independent bug.
**Technical Root Cause (The Orphaned State Machine)**
When the connection drops and Smacks resumes, Monal clears its IQ handlers. My raw logs confirm this directly: when the state is serialized during
disconnect, `persistentIqHandlers={}` the Jingle IQ-result handler was **never added to the persistent structure in the first place**, so it cannot
survive any TCP reconnect.
```
10 --> persistState(saved at 2026-03-03 13:59:42 +0000):
isDoingFullReconnect=NO,
...
streamID=fL6YruLBbS_1
persistentIqHandlers={
}
...
RECV Stanza: <resumed h='5824' previd='fL6YruLBbS_1' xmlns='urn:xmpp:sm:3'/>
```
This means every pending IQ callback is flushed including the one registered for the Jingle `session-accept` acknowledgment.
### Why this breaks the call (XEP-0176 violation)
The core issue isn't the *content* of the result IQ it's the handler acting as a **mandatory state transition trigger**. XEP-0176 (Jingle ICE-UDP
Transport) § 4.2 explicitly states:
> "The responder MUST NOT send any candidate-bearing transport-info stanzas until it has received an IQ-result from the initiator in response to the session-accept."
The IQ result is the mandatory synchronization point. The failure chain is:
1. The IQ-result arrives from the caller acknowledging the `session-accept`.
2. Monal discards it and the handler was wiped because it was never registered in `persistentIqHandlers`.
3. Monal's internal state machine is "orphaned": it stalls indefinitely in *"waiting for session-accept acknowledgment"*.
4. Monal never starts the ICE exchange (`transport-info`).
5. The caller times out waiting for candidates → connection fails.
**Comparison with other clients**
Robust Jingle implementations (e.g. `JingleRtpConnection` in Conversations or lib-jitsi-meet) use explicit IQ callbacks to drive this exact state transition. The receipt of the acknowledgment is what moves the session from `pending` to `established`. If that callback is lost during a network hiccup, the next state is never entered.
**A possible fix maybe**
Option 1:
The `persistentIqHandlers` structure **already exists** for exactly this purpose. The fix is targeted: when a Jingle `session-accept` is sent, its IQ-result handler must be registered in `persistentIqHandlers` (not the ephemeral handler dict), so it survives a Smacks resume.
Option 2:
Re-registering all in-progress session handlers on a successful resume would also work, but requires iterating active Jingle sessions on reconnect and is a larger, riskier change.
- On sending `session-accept`: register the IQ-result handler in `persistentIqHandlers` instead of the ephemeral dict.
- On session teardown (accept confirmed or call ended): remove the handler from `persistentIqHandlers` to avoid leaks.
### Anything else?
_No response_
### FAQ
- [x] I have [checked the FAQ](https://github.com/monal-im/Monal/wiki/FAQ---Frequently-Asked-Questions) for my issue
### Considerations for XMPP users
- [x] I have checked if my issue can be solved with [Considerations for XMPP users](https://github.com/monal-im/Monal/wiki/Considerations-for-XMPP-users) and [Considerations for XMPP server admins](https://github.com/monal-im/Monal/wiki/Considerations-for-XMPP-server-admins)
### XEP-Check
- [x] I have checked that at least XEP-198, XEP-0280, XEP-0352, XEP-0357, XEP-0313 and XEP-0163 are activated on my server and shown as 'green' under Settings --> Account--> (i) in advanced settings
### Notifications-Menu
- [x] I have checked that all checkmarks are present under Settings --> Notifications
关闭于 2026-03-09 1 条评论