Recover from an in-dialog INVITE that arrives before our ACK - #1129
Open
23Skidoo wants to merge 2 commits into
Open
Recover from an in-dialog INVITE that arrives before our ACK#112923Skidoo wants to merge 2 commits into
23Skidoo wants to merge 2 commits into
Conversation
Dropping the request leaves the server transaction it opened standing, and that one transaction then blocks the dialog in both directions for the rest of the call: no re-INVITE of ours can be sent, so the session cannot be held or transferred, and every in-dialog INVITE arriving afterwards is answered 500 by the core without ever reaching the application. 491 is the response RFC 3261 s14.2 names for a request that arrives while an offer/answer exchange is outstanding, and it invites the sender to retry once we settle. Any final status would free the transaction; this one also keeps the exchange recoverable.
Session.rollbackOffer is called whenever an offer/answer exchange fails - on a non-2xx response to our own re-INVITE, and when we cannot answer one we received - so that the next exchange starts from a stable peer connection. It resolves without doing anything when the handler implements no rollbackDescription, and the web one did not, so an offer applied by a failed exchange stayed applied and every later attempt failed while creating its description, on a session that was otherwise still up. A stable connection has nothing to discard, so that resolves rather than raising; the pranswer states and a closed connection are refused the way the neighbouring methods refuse them.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
An in-dialog INVITE arriving after the 200 OK but before we send our ACK is dropped by
Session.onInviteRequest, and the server transaction the core opened for it is left standing. That one transaction then blocks the dialog in both directions for the rest of the call:SessionDialog.invitethrows "There is an ongoing re-INVITE server transaction." for every re-INVITE we try to send — soSimpleUser.hold()fails permanently — and the core statelessly answers every later in-dialog INVITE with 500 before the application sees it.We hit this in production with a PBX that sends a connected-identity re-INVITE 28ms after its 200 OK, 36ms before the client's ACK: the user answers a call and can never hold or transfer it.
Two changes.
onInviteRequestnow rejects the early INVITE with491 Request Pendinginstead of dropping it — the response RFC 3261 section 14.2 names for a request arriving while an offer/answer exchange is outstanding. Rejecting completes the server transaction, which is what unblocks the dialog, and surfaces the request todelegate.onInvite.The web SessionDescriptionHandler now implements
rollbackDescription.Session.rollbackOfferalready calls it whenever an offer/answer exchange fails — on a non-2xx answer to our own re-INVITE, and when we cannot answer one we received — but no handler implemented it, so those rollbacks were silent no-ops and an offer applied by a failed exchange stayed applied, leaving the peer connection unable to create its next description.Four specs added for the rollback, verified against a real RTCPeerConnection: without the rollback call, retrying after a failed exchange fails with
Invalid signaling state have-local-offer. The glare recovery is reproduced end to end outside this repo by driving the stack against a peer that deliberately sends its INVITE inside the 200-to-ACK window — red before these changes, green after.This contribution was prepared with LLM assistance (Claude): the investigation, the change, and this description. A human reviewed it and stands behind the submission.