Repository navigation
Conversation
do_dtls() writes every received DTLS record into the read BIO, but once the handshake is done dtls_state_ready() never calls SSL_read(). When our last flight (ChangeCipherSpec + Finished) is lost, the browser retransmits its Finished, nobody processes it, and OpenSSL never retransmits our flight as RFC 6347 section 4.2.4 requires. The browser stays in "connecting" and the call has no audio in either direction. Call SSL_read() in dtls_state_ready() when a record was received, so OpenSSL retransmits the last flight; do_dtls() then sends it. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
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.
Problem
WebRTC calls occasionally have no audio in either direction for the whole call. FreeSWITCH logs
Fingerprint Verified,Activating audio Secure RTP SEND/RECVandDTLS state from SETUP to READY, while the browser's DTLS transport staysconnectinguntil hangup and no RTP flows. In a load test with 1500 concurrent WebRTC calls, 5 of 9,052 calls were affected (FreeSWITCH 1.10.12; the code below is unchanged in 1.11.3 and master).Root cause
do_dtls()writes every received DTLS record into the read BIO and then runs the handler for the current state. Once the handshake is done,dtls_state_ready()never callsSSL_read(), so records received in READY are never processed.As DTLS server in an ordinary handshake, FreeSWITCH sends the last flight (ChangeCipherSpec + Finished). If that flight is lost, the browser retransmits its own last flight, and RFC 6347 section 4.2.4 requires us to answer it: "the node that transmits the last flight (the server in an ordinary handshake or the client in a resumed handshake) MUST respond to a retransmit of the peer's last flight with a retransmit of the last flight. This avoids deadlock conditions if the last flight gets lost."
OpenSSL does this in
dtls1_read_bytes()("If we are server, we may have a repeated FINISHED of the client here, then retransmit our CCS and FINISHED."), but only when the application callsSSL_read().A packet capture on the FreeSWITCH host showed the same sequence for 4 of the affected calls: the browser sends its Finished flight, FreeSWITCH sends its last flight once (it never reaches the browser), then the browser retransmits its Finished 10 times over about 51 seconds (backoff from 50 ms doubling up to about 25.6 s) and FreeSWITCH never answers.
Fix
In
dtls_state_ready(), when a record was received, callSSL_read(). OpenSSL handles the repeated Finished and writes the retransmission into the write BIO, whichdo_dtls()already sends right after the state handler returns. No application data is expected on this association, so whateverSSL_read()returns is discarded; errors other thanSSL_ERROR_WANT_READandSSL_ERROR_ZERO_RETURNare logged.For comparison, Janus (
src/dtls.c) and Asterisk (res/res_rtp_asterisk.c) callSSL_read()right after eachBIO_write()of a received record, whether or not the handshake is done.Testing
FreeSWITCH 1.11.3 (
do_dtls()anddtls_state_ready()are identical on master), Chromium WebRTC clients.We have been running this patch in production since 2026-10-01.
🤖 Generated with Claude Code