Fix GnuTLS renegotiation failure on GNUTLS_E_GOT_APPLICATION_DATA#4919
Merged
Fix GnuTLS renegotiation failure on GNUTLS_E_GOT_APPLICATION_DATA#4919
Conversation
During server-initiated TLS renegotiation under load, the client's gnutls_handshake() may encounter application data records (echoed by the server) instead of handshake records and return GNUTLS_E_GOT_APPLICATION_DATA (-38). On some GnuTLS builds (notably macOS Homebrew), gnutls_error_is_fatal() classifies this as fatal, causing ssl_do_handshake() to return PJ_EINVAL and abort the renegotiation. Handle GNUTLS_E_GOT_APPLICATION_DATA as non-fatal (PJ_EPENDING) so the caller retries after draining the buffered application data via gnutls_record_recv() on the next read cycle. Also add write_mutex around gnutls_rehandshake() for session access consistency with ssl_do_handshake() and ssl_read(). Co-Authored-By: Claude Code
Contributor
There was a problem hiding this comment.
Pull request overview
Fixes a GnuTLS renegotiation edge case where gnutls_handshake() can return GNUTLS_E_GOT_APPLICATION_DATA during server-initiated renegotiation, and ensures session access is synchronized consistently during renegotiation initiation.
Changes:
- Treat
GNUTLS_E_GOT_APPLICATION_DATAfromgnutls_handshake()as non-fatal by returningPJ_EPENDINGto allow renegotiation to continue after buffered app data is drained. - Add
write_mutexprotection aroundgnutls_rehandshake()to align session access synchronization with existing handshake/read paths.
sauwming
approved these changes
Apr 15, 2026
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
GNUTLS_E_GOT_APPLICATION_DATA(-38) as non-fatal inssl_do_handshake(), returningPJ_EPENDINGso renegotiation retries after draining buffered application datawrite_mutexaroundgnutls_rehandshake()for session access consistency withssl_do_handshake()andssl_read()Background
During server-initiated TLS renegotiation under load, the client's
gnutls_handshake()may encounter application data records (echoed by the server) instead of the expected handshake records, returningGNUTLS_E_GOT_APPLICATION_DATA(-38). On some GnuTLS builds (notably macOS Homebrew),gnutls_error_is_fatal()classifies this as fatal, causingssl_do_handshake()to returnPJ_EINVALand abort the renegotiation.The fix treats this as non-fatal (
PJ_EPENDING). The buffered application data is consumed by subsequentgnutls_record_recv()calls in the normal read path, and the handshake retries incrementally until completion.CI failures: This has been failing consistently on the
GnuTLS / pjlib,util,pjmedia,pjnathjob across multiple PRs since thessl_sock_stress_testrenegotiation subtest was introduced:Test plan
ssl_sock_stress_test -w 2): fails on "send load + server renegotiation test" with identical errorssl_sock_stress_testpasses 5/5 runsssl_sock_testpasses (no regression)Co-Authored-By: Claude Code