Conversation
send_dialog_request moved the dialog to Early on every non-100 provisional, including responses to our own re-INVITE or UPDATE on an established dialog. A 183 to a session-refresh re-INVITE therefore regressed a Confirmed dialog to Early for good (the final 200 does not restore it): bye() is then refused outside Confirmed and hangup() falls through to a CANCEL of the long-completed INVITE, which times out, so the call can no longer be torn down. RFC 3261 §12 has a dialog move from early to confirmed and never back, and a provisional to a mid-dialog request does not create early state. Only take the Early transition while the dialog is still in a pre-confirmation state (Calling / Trying / Early). On a confirmed dialog the provisional is still notified as before, so callers keep seeing it, but the stored state stays Confirmed. The initial INVITE path (process_invite) is unchanged, and reliable provisionals to a re-INVITE are still PRACKed. Adds tests driving a raw UDP peer: the initial INVITE's 183 still reports Early, while a 100/183/200 to an in-dialog re-INVITE or UPDATE keeps the dialog Confirmed, the 183 is still notified, and BYE succeeds.
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.
Bug
DialogInner::send_dialog_request(src/dialog/dialog.rs, theProvisionalarm) moves the dialog toEarlyon every non-100 provisional response. That includes responses to our own in-dialog requests on an established dialog. A peer that answers a re-INVITE (for example a session-timer refresh) or an UPDATE with183 Session Progressflips aConfirmeddialog back toEarly. The dialog stays there: the final200 OKto the re-INVITE does not restoreConfirmed.Since 0.6.1 (23dfb20),
bye_with_headersreturnsErroutsideConfirmed, andhangup()picks CANCEL whenevercan_cancel()is true, which coversEarly. On such a dialog:bye()fails withcannot send BYE in state Early(...).hangup()sends a CANCEL for the initial INVITE, which completed long ago. The CANCEL times out (408) and nothing ends the session. The call can no longer be hung up (see also ServerInviteDialog::bye is a silent no-op outside Confirmed/WaitAck #136).return_to_confirmed(4feaf95) fixes the same kind of state leak for requests we receive (UAS side). It does not cover a provisional response to a request we send.Reproduction (on
main@ 5958064)This PR adds
src/dialog/tests/test_in_dialog_provisional.rs. It drives a UAC dialog against a raw UDP peer:100,183,200. The dialog reachesConfirmed.100,183,200.Confirmed, reports noEarlystate, and thatbye()succeeds.On
main, both new tests fail:With the state assertions skipped, the dialog is still
Earlyafter the re-INVITE's200, and:RFC
Fix
The
Earlytransition insend_dialog_requestnow runs only while the dialog has not been confirmed yet (can_cancel(), meaningCalling/Trying/Early). 8 lines total, most of them a comment.can_cancel()was chosen over!is_confirmed()on purpose.!is_confirmed()would still let a 1xx resetWaitAck, and the states held after an inbound request (Refer,Message,Publish, ...), toEarly.Unchanged:
process_invite(invite_dialog.rs, and the legacyclient_dialog.rswrapper). ItsTrying→Earlytransitions and early route-set handling behave as before. The new test asserts that a183to the initial INVITE is still reported asEarly.handle_provisional_responsestill runs for provisionals to a re-INVITE, so reliable 1xx still get their PRACK.Compatibility / risk
Earlywhen a 1xx arrives for an in-dialog request on a confirmed dialog. TheDialogState::Earlynotification for that 1xx is still sent exactly as before (it is the only way a caller sees a provisional to its re-INVITE, e.g. a reliable 183 with SDP), so no subscriber loses information.cargo fmt --all -- --checkpasses, andcargo testpasses: 332 lib tests (330 existing plus 2 new) and 65 doctests.cargo clippy --all-targetsshows no warnings in the changed code; the existing warning counts are unchanged.