Skip to content

Add dialog owner registry for RFC 3891 Replaces dispatch#1526

Open
CraziestPower wants to merge 2 commits intosipsorcery-org:masterfrom
CraziestPower:feature/dialog-registry-replaces-481
Open

Add dialog owner registry for RFC 3891 Replaces dispatch#1526
CraziestPower wants to merge 2 commits intosipsorcery-org:masterfrom
CraziestPower:feature/dialog-registry-replaces-481

Conversation

@CraziestPower
Copy link
Copy Markdown
Contributor

Summary

  • Adds a ISIPDialogOwner interface and Call-ID keyed registry to SIPTransport for direct dialog-based request dispatch
  • Replaces INVITEs are dispatched to the owning agent, with RFC 3891 compliant 481 responses when no matching dialog exists
  • In-dialog requests (BYE, re-INVITE, etc.) are dispatched directly to the owning agent instead of broadcasting to all listeners
  • Multiple Replaces headers in a single INVITE return 400 Bad Request per RFC 3891 Section 3
  • SIPUserAgent and SIPNotifierClient implement ISIPDialogOwner with full lifecycle management (register on dialog establishment, unregister on teardown)
  • Supersedes the silent-ignore workaround from PR Fix attended transfer 400 race when multiple agents share SIPTransport (#1459) #1520 while maintaining full backward compatibility — new INVITEs and out-of-dialog requests still broadcast via SIPTransportRequestReceived

Fixes #1525
Related: #1459, #1520

Test plan

  • dotnet build — all targets compile (0 warnings, 0 errors)
  • 7 new registry CRUD tests (DialogRegistry category) — all pass
  • 5 new dispatch tests (DialogDispatch category) — all pass
  • 3 updated attended transfer tests — verify 481 behavior
  • Full test suite: 576 passed, 8 skipped (pre-existing), 0 failures

🤖 Generated with Claude Code

CraziestPower and others added 2 commits February 16, 2026 19:43
sipsorcery-org#1459)

When multiple SIPUserAgent instances share a SIPTransport, an attended
transfer INVITE with a Replaces header was processed by ALL agents.
Non-matching agents would call AcceptCall (sending 100/180) and then
reject with 400, racing against the correct agent's acceptance.

Move the Replaces Call-ID check before AcceptCall so non-matching agents
silently ignore the request instead of creating a UAS transaction.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…aces handling

Adds a Call-ID keyed dialog owner registry to SIPTransport so that
Replaces INVITEs are dispatched directly to the owning agent, with
proper 481 responses when no matching dialog exists (RFC 3891 §3).

- New ISIPDialogOwner interface for dialog-based dispatch
- ConcurrentDictionary registry with Register/Unregister lifecycle
- Dispatch intercept: Replaces→owner or 481, in-dialog→owner, else broadcast
- Multiple Replaces headers → 400 Bad Request per RFC 3891
- SIPUserAgent and SIPNotifierClient implement ISIPDialogOwner
- Supersedes the silent-ignore workaround from PR sipsorcery-org#1520

Fixes sipsorcery-org#1525

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@sipsorcery
Copy link
Copy Markdown
Member

Thanks for the PR. A code restructure has taken place and the source files for this PR are now in src/SIPSorcery. Can this PR be rebased?

@sipsorcery sipsorcery added the sip label Feb 22, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Attended transfer Replaces INVITE needs RFC 3891 compliant 481 dispatch

2 participants