General
The 15-Minute SIP Drop: Why RFC 4028 Session Timers Quietly Kill Enterprise Voice Calls
calricon / field note
Every telecom engineer has faced the dreaded support ticket: enterprise customer calls abruptly hanging up at exactly 15 minutes or 30 minutes on the dot. The culprit is almost never audio degradation or packet loss—it is RFC 4028 SIP Session Timers misfiring across NAT firewalls, carrier Session Border Controllers (SBCs), and asymmetric refresher negotiations. Here is how elite voice engineers diagnose mid-dialog signaling failures and eliminate the 15-minute ghost drop forever.
The Core Premise: Why Voice Calls Abruptly Die at Exactly 900 Seconds
When enterprise phone calls drop dead at exactly the 15-minute or 30-minute mark, the underlying network is not dropping packets; your SIP signaling core is committing suicide by protocol compliance. Under IETF RFC 4028, SIP Session Timers exist to prevent "zombie calls" from lingering in carrier billing systems when endpoints crash without sending a teardown message. The standard establishes a default session expiration of 1,800 seconds (30 minutes) and mandates that the negotiated "refresher" must transmit a mid-dialog re-INVITE or UPDATE request at exactly half the session interval—900 seconds (15 minutes). However, because voice audio (RTP) flows over dynamic high-port UDP channels while SIP signaling on port 5060 sits completely silent after initial call setup, intermediate stateful NAT firewalls expire their UDP translation tables within 30 to 120 seconds. When the 15-minute refresh request arrives at the firewall perimeter, the packet is silently dropped. After standard retransmission timers expire (Timer B / Timer F = 32 seconds), the initiating PBX assumes the remote endpoint has vanished and transmits an immediate BYE, severing a crystal-clear executive call mid-sentence.
"There is no support ticket more frustrating than the 15-minute drop. Wireshark shows MOS scores of 4.4, zero jitter, and zero packet loss on the RTP stream. Then, out of nowhere, an unannounced BYE packet appears on the signaling plane. You aren't experiencing an audio failure; you are suffering from NAT amnesia."
The Protocol Mechanics: How RFC 4028 Arms the Invisibility Clock
To eliminate phantom sessions that waste carrier trunk capacity, RFC 4028 defines a periodic session refresh mechanism. When an outbound INVITE initiates a call, it negotiates two critical parameters:
Session-Expires: 1800;refresher=uac: Specifies the maximum allowable session duration before a refresh is mandatory, alongside the designated refresh initiator (the User Agent Client,uac, or User Agent Server,uas).Min-SE: 90: Establishes a lower floor (typically 90 seconds) to prevent malicious endpoints or proxies from overwhelming servers with high-frequency refresh spam.
Per RFC 4028 Section 7.1, "The refresher MUST send a session refresh request before the session expiration is reached. It is RECOMMENDED that this be sent halfway through the session interval." For a standard 1,800-second session, the refresher arms a countdown timer set to 900 seconds.
If the refresher transmits the re-INVITE or UPDATE and receives a 200 OK response, both ends reset their expiration clocks for another 1,800 seconds. If no valid response arrives before the session expires—or if transaction timers time out during the refresh attempt—either party is legally required to tear down the dialog by sending a BYE request.
The 4 Root Causes of Mid-Dialog Session Timer Teardowns
1. NAT Firewall Pinhole Expiration (The Port 5060 Amnesia Trap)
Enterprise and residential edge routers (Cisco ASA, Fortinet FortiGate, pfSense, Palo Alto Networks, or home Wi-Fi routers) maintain stateful NAT translation tables. When a SIP client behind a firewall establishes an outbound call, the firewall opens a temporary UDP mapping on public port 5060:
- RTP Keeps Itself Alive: Audio packets flow every 20 milliseconds (50 packets per second in both directions). This constant barrage keeps the dynamic RTP pinholes (e.g., UDP ports 16384–32768) permanently open.
- SIP Signaling Goes Comatose: Once the call answers with
200 OKandACK, no SIP signaling packets cross the network for hundreds of seconds. Most firewalls enforce a strict UDP idle timeout of 30 to 120 seconds. - The 900-Second Ambush: When the cloud PBX acts as the refresher and sends a
re-INVITEto the client at second 900, the packet strikes a closed NAT firewall. The firewall drops the packet. The PBX retransmits at exponential intervals (Timer A / Timer B) for 32 seconds, gives up, and transmits aBYE.
2. The Refresher Deadlock ("You First" Protocol Glare)
Carrier interconnection trunks often involve multiple Session Border Controllers (SBCs), media gateways, and third-party AI voice platforms (such as Twilio, Bandwidth, Vapi, or Plivo). Severe incompatibilities emerge during session timer header negotiation:
- Header Stripping: Some intermediaries strip the
Supported: timerorSession-Expiresheaders on outbound legs to simplify upstream processing, but neglect to remove them on ingress legs. - The Mutual Inaction Trap: If the cloud PBX sends
Session-Expires: 1800;refresher=uas, but the carrier SBC replies with a200 OKomitting therefresherparameter, RFC 4028 dictates that the UAC remains the default refresher. If the PBX's SIP stack misinterprets the response and assumes the carrier is refreshing, neither entity sends there-INVITE. Exactly at 1,800.00 seconds, both systems generate simultaneousBYErequests with reason codeSIP;cause=200;text="Session Timer Expired".
3. The Strict vs. Loose Routing ACK Black Hole
Even when a re-INVITE successfully traverses the NAT barrier, the refresh transaction requires a complete three-way handshake: re-INVITE -> 200 OK -> ACK.
- Stateful Proxy Route Rewriting: If intermediate Kamailio or OpenSIPS proxies rewrite the
Record-Routeheader or fail to preserve loose routing (RFC 3261 compliantlrparameter) on mid-dialog messages, the downstream client transmits theACKto an unroutable internal IP address. - Timer H Destruction: The server receives the
200 OK, but its transaction engine never sees theACK. Under SIP Timer H (typically 32 seconds), the server assumes the transaction has catastrophically failed, drops the call, and cleans up the dialog state.
4. SDP Offer/Answer Glare During Mid-Call Features
Many legacy SIP implementations implement session timers by sending full re-INVITE messages with an active Session Description Protocol (SDP) body instead of lightweight UPDATE requests:
- Collision with User Action: If a human call center agent presses "Mute", "Hold", or initiates an attended transfer near minute 15, the client generates a
re-INVITEwitha=sendonlyat the exact second the PBX dispatches its session refreshre-INVITE. - The 491 Request Pending Nightmare: In SIP, concurrent offers on the same dialog trigger a
491 Request Pendingerror. While RFC 3261 mandates random backoff timers (Timer X/Y) to resolve glare, poorly written SIP stacks fail to retry, panic, and tear down the call.
The Production Comparison: Fragile Default vs. Calricon Resilient Core
| Dimension | Standard Default PBX Setup | Failure Mode | Calricon Resilient VoIP Core |
|---|---|---|---|
| Signaling Transport | Plain UDP on port 5060 | NAT firewall closes port after 30s of silence | SIP over TLS/TCP with CRLF keep-alives (RFC 5626) |
| Refresh Method | Full re-INVITE with SDP offer |
SDP glare (491 Pending) on hold/transfer |
Lightweight UPDATE without SDP mutation |
| Refresher Assignment | Negotiated dynamically (often uac) |
Client behind NAT fails to receive inbound refresh | Edge SBC anchors session and forces refresher=uas |
| Ghost Call Detection | Relies exclusively on RFC 4028 signaling | Signaling failures drop perfectly active audio | Bilateral RTCP media inactivity timeouts (15s) |
| Carrier Trunk Leg | Passes through customer session headers | Incompatible timer mismatches with upstream PSTN | B2BUA topology hiding; strips timer headers on carrier leg |
The Engineering Blueprint: Eliminating the 15-Minute Drop Forever
1. Enforce Outbound Keep-Alives via CRLF Pings (RFC 5626)
Never rely on signaling packets to keep NAT translation tables alive. Configure your SIP edge proxies and softphones to transmit bidirectional double-CRLF (\r\n\r\n) keep-alive pings over the existing signaling socket every 20 to 25 seconds:
- Zero Protocol Overhead: CRLF pings consume 4 bytes and do not trigger SIP parser execution or transaction state machines.
- Permanent NAT Binding: The edge firewall never closes port 5060, ensuring mid-dialog
re-INVITErequests reach the client instantly.
2. Enforce UPDATE over re-INVITE for Session Refresh
Configure your PBX core (Asterisk, FreeSWITCH, or OpenSIPS) to utilize SIP UPDATE (RFC 3311) instead of re-INVITE for session timer refresh:
# Asterisk pjsip.conf configuration for clean session timers [endpoint-template](!) type = endpoint timers = yes timers_sess_expires = 1800 timers_min_se = 90 timers_refresh_method = update # Prevent SDP renegotiation glare! direct_media = no rtp_timeout = 30 rtp_timeout_hold = 300
3. Anchor Session Timers at the SBC Edge and Normalize Carrier Trunks
If you route traffic across external SIP trunking providers (Twilio, Bandwidth, Telnyx), isolate the customer signaling leg from the carrier leg using a Back-to-Back User Agent (B2BUA) like RTPEngine and Kamailio:
# Kamailio: Strip Session Timers from Carrier Leg if Upstream Fails Refresh
route[HANDLE_SESSION_TIMERS] {
if (is_method("INVITE")) {
# Strip timer negotiation from carrier leg to prevent 900s mismatch
if ($rd == "carrier-trunk.pstn.com") {
remove_hf("Session-Expires");
remove_hf("Min-SE");
remove_hf("Supported");
append_hf("Supported: replaces, 100rel\r\n");
}
}
}
4. Shift Zombie Call Detection to Media Layer RTCP Timeouts
Signaling keep-alives are a fragile proxy for call health. The true indicator of an active call is whether RTP audio is flowing. Configure your media relay (RTPEngine, Asterisk, or FreeSWITCH) to terminate calls based on RTP/RTCP media inactivity:
- Set
rtp_timeout = 15(teardown call if zero audio packets arrive for 15 seconds while unheld). - Set
rtp_timeout_hold = 600(allow up to 10 minutes of silence if explicit hold signaling has been negotiated). - By relying on the media plane to catch real disconnects, you can safely lengthen SIP session timers to 3,600 or 7,200 seconds, reducing signaling traffic by 75% and virtually eliminating mid-call timer dropouts.
The Strategic Takeaway: Decouple Signaling Keep-Alives from Call Survival
RFC 4028 was authored in 2005 for an idealized telecom world of static IP PBXs and open enterprise firewalls. In the modern cloud ecosystem—dominated by aggressive NAT middleboxes, roaming mobile softphones, and hybrid carrier SBC interconnects—default session timer settings are an operational landmine.
By enforcing persistent CRLF keep-alives, switching to lightweight UPDATE refreshes, and delegating zombie call detection to real-time RTCP media monitoring, voice platform architects can permanently eliminate the dreaded 15-minute disconnect and ensure enterprise calls last as long as the conversation demands.