From bf6b08fa68513d4385d9f38b454782488643700e Mon Sep 17 00:00:00 2001 From: simon Date: Fri, 22 May 2026 21:01:47 +0200 Subject: [PATCH] fix(inbound): send 503 response on DispatchNoRuleDrop instead of silently dropping MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When the dispatch layer returns DispatchNoRuleDrop (e.g. no matching dispatch rule, or server-side flood decision), the current code calls cc.Drop() which terminates the SIP transaction without sending any response. However, by the time the dispatch result is evaluated, livekit-sip has already sent 100 Trying and 180 Ringing to the carrier, so the call's existence is already revealed to the caller. The consequence of the silent drop is that the caller hears indefinite ringing: the carrier never receives a final response, keeps the INVITE alive, and only terminates when the caller manually hangs up and a CANCEL arrives. This wastes carrier resources and delivers a confusing user experience ("phone rings forever with no answer"). Since the provisional responses already confirm the endpoint to the caller, sending a 503 Service Unavailable at this point does not leak any additional information, but it immediately terminates the call on the carrier side. Fix: replace cc.Drop() with cc.RespondAndDrop(503) — the same pattern used by DispatchNoRuleReject and DispatchServiceUnavailable. Observed via SIP trace (Homer/HEP): INVITE → 100 → 180 → [13 second gap, no final response] → CANCEL from carrier. livekit-sip logs showed "Closing inbound call / status=486 / reason=flood" with no corresponding "Inbound call closed" entry, confirming the SIP response was never sent. --- pkg/sip/inbound.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/sip/inbound.go b/pkg/sip/inbound.go index c7ab8051..2adf661e 100644 --- a/pkg/sip/inbound.go +++ b/pkg/sip/inbound.go @@ -820,7 +820,7 @@ func (c *inboundCall) handleInvite(ctx context.Context, tid traceid.ID, req *sip return psrpc.NewError(psrpc.Unimplemented, err) case DispatchNoRuleDrop: c.log().Debugw("Rejecting inbound flood") - c.cc.Drop() + c.cc.RespondAndDrop(sip.StatusServiceUnavailable, "Service Unavailable") c.close(ctx, callFlood, stats.ClientError("flood")) return psrpc.NewErrorf(psrpc.PermissionDenied, "call was not authorized by trunk configuration") case DispatchNoRuleReject: