Repository navigation
Conversation
Since the replication format matches dialogs by their id, the update, value and delete handlers find their dialog by (h_entry, h_id) only, but the id is unique only on the node that created the dialog. Every node raises its next_id past the ids it receives, and a dialog gets its id at the initial INVITE while it is replicated only once answered. So two nodes creating dialogs in the same hash entry while the first call is still ringing can give both calls the same id, and the packets of one call are then applied to the other: contacts and SDPs overwritten (a topology-hidden BYE was sent to the other call's contact), dialog values replaced, and a live dialog deleted when the other call hung up. Check the Call-ID (and the caller tag, where the packet carries it) of the dialog found by id, and log and drop the packet on a mismatch, as the CSeq handler already does through match_dialog(). The create handler also logs such a collision instead of treating the dialog as already created.
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.
Summary
Stop dialog replication from applying one call's update, value and delete packets to a different call that got the same dialog id on another node.
Details
This is a bug fix for any dialog replication cluster where more than one node creates dialogs, such as several active nodes behind an anycast address. Issue #4397 has the full analysis and a reproduction.
Since b3c31fb the replication handlers find their dialog by
(h_entry, h_id)only, which assumes the id is unique in the cluster. It is not: a node allocates the id on the initial INVITE but replicates the dialog only once it is answered, and every node raises itsnext_idpast the ids it receives. So while a call rings on one node, another node can give a new call the same id. From then on:Solution
A new helper,
dlg_repl_id_collision(), compares the Call-ID, and the caller tag when the packet carries one, of the dialog found by id with the packet. On a mismatch it logs(without the From tags for value packets, which do not carry one) and the handler drops the packet. It is called:
dlg_replicated_update()before the "not found, build a new dialog" branch, so no second dialog with the same id is created either;dlg_replicated_value(), on the Call-ID only, as value packets carry no tags;dlg_replicated_delete(), under the entry lock, sincelookup_dlg()returns with the lock released and the legs array can be reallocated; the reference taken bylookup_dlg()is released on a mismatch;dlg_replicated_create(), which keeps skipping the packet but now logs the collision.The check applies only to lookups by id (
DLG_BIN_V4and later; value packets always); older packets are already matched by Call-ID and tags. It does not affect the looping case b3c31fb was written for: looped dialogs share the Call-ID and From tag, so they pass the check and the id still picks the right one.Two nodes can still give the same id to two calls; on the other nodes one of the two calls then has no replica, and an in-dialog request for it that reaches such a node is not matched. This PR does not change id allocation.
How I tested it: two nodes on one host as in #4397, with collisions forced on every run, comparing master 6abfdcc with this branch:
Builds: the whole tree with gcc 14.2.0 and
-Werror(0 warnings), and the dialog module with clang 19.1.7 and-Werror.Compatibility
No configuration, script or replication format change. Packets that belong to the dialog found by id always carry its Call-ID and caller tag, so they are applied as before. The only visible change is the new error line on a collision. There is no platform-specific code.
Closing issues
closes #4397