Skip to content

internal: propagate WANT_WRITE from the DTLS 1.3 receive timeout - #11396

Open
yosuke-wolfssl wants to merge 1 commit into
wolfSSL:masterfrom
yosuke-wolfssl:fix/f_13343
Open

internal: propagate WANT_WRITE from the DTLS 1.3 receive timeout#11396
yosuke-wolfssl wants to merge 1 commit into
wolfSSL:masterfrom
yosuke-wolfssl:fix/f_13343

Conversation

@yosuke-wolfssl

Copy link
Copy Markdown
Contributor

Problem

wolfSSLReceive() answers a WOLFSSL_CBIO_ERR_TIMEOUT by calling
Dtls13RtxTimeout(), which sends a DTLS 1.3 ACK or retransmits the last flight.
On a non-blocking transport that send can return WANT_WRITE, but the branch
tested only < 0 and returned WOLFSSL_FATAL_ERROR — the application saw a dead
connection where it should have seen "wait for writability and call again". The
source carried /* TODO: support WANT_WRITE here */ from the commit that added
the branch.

wolfSSL_dtls_got_timeout() already handled the identical return correctly, so
the two ways of driving a DTLS 1.3 timeout disagreed.

Reachable through both supported IO paths: a custom recv callback returning
WOLFSSL_CBIO_ERR_TIMEOUT paired with a send callback returning
WOLFSSL_CBIO_ERR_WANT_WRITE, and the built-in EmbedReceiveFrom() timeout
paths (dtls_timeout accounting, SO_RCVTIMEO).

Closes f-13343.

Fix (src/internal.c)

  • wolfSSLReceive() captures the result. WANT_WRITE sets
    dtls13SendingAckOrRtx, marking the record as still owing a write, and
    returns WANT_WRITE; a genuine failure still returns WOLFSSL_FATAL_ERROR.
  • GetInputData_ex() passes WANT_WRITE through rather than folding it into
    SOCKET_ERROR_E, under #ifdef WOLFSSL_DTLS13.

Both are required: WANT_WRITE is -327, so without the second hunk the first
is rewritten to SOCKET_ERROR_E in the next frame.

Nothing above needed changing. DoProcessReplyEx() already permits WANT_WRITE
as a retry state, ReceiveData() already exempts it from its error-state guard,
and the connect/accept flush and wolfSSL_dtls13_do_scheduled_work() already
settle the owed record off dtls13SendingAckOrRtx.

Tests

Test Coverage
test_dtls13_rtx_timeout_want_write handshake: wolfSSL_connect() reports WANT_WRITE; the retry sends the retransmission
test_dtls13_rtx_timeout_want_write_read post-handshake: wolfSSL_read() reports it, wolfSSL_dtls13_pending_work() reports the debt, the pump sends it

Verification

  • Both tests fail with either hunk reverted, pass with both.
  • dtls13 22/22, dtls 82/82, full API 676 passed / 0 failed, make check 0 failed.
  • Clean builds with --disable-dtls and --enable-dtls --disable-dtls13; the new
    tests skip rather than fail there.

Not in this PR

Two sites mishandle the widened return only on record-spanning transports (SCTP
or WOLFSSL_DTLS_RECORDS_CAN_SPAN_DATAGRAMS), unreachable on plain UDP:
GetDtlsRecordHeader() folds WANT_WRITE into LENGTH_ERROR, and
DtlsShouldDrop() drops it post-handshake. That filter already folds WANT_READ
the same way, so all three belong together in a follow-up.

@yosuke-wolfssl yosuke-wolfssl self-assigned this Sep 8, 2026
Copilot AI lite review requested due to automatic review settings September 8, 2026 01:56

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

wolfSSLReceive() returns raw WANT_WRITE instead of WC_NO_ERR_TRACE(WANT_WRITE), which can break propagation under error-trace builds and undermine the fix.

Once you've addressed the issues Copilot identified, you can request another Copilot review.

Pull request overview

This PR fixes DTLS 1.3 non-blocking behavior by correctly propagating WANT_WRITE when a receive timeout triggers an ACK/retransmit that cannot be sent immediately, aligning wolfSSLReceive()’s timeout path with existing DTLS timeout handling and adding regression tests.

Changes:

  • Update wolfSSLReceive() to return WANT_WRITE (and set dtls13SendingAckOrRtx) when Dtls13RtxTimeout() cannot write on a non-blocking transport.
  • Update GetInputData_ex() to pass WANT_WRITE through instead of folding it into SOCKET_ERROR_E (DTLS 1.3 builds).
  • Add two DTLS 1.3 API tests covering WANT_WRITE propagation on timeout during handshake and post-handshake read.
File summaries
File Description
tests/api/test_dtls13.h Registers the two new DTLS 1.3 timeout/WANT_WRITE tests in the DTLS 1.3 test group.
tests/api/test_dtls13.c Adds two manual-memio tests validating WANT_WRITE propagation and scheduled-work flushing after timeout-triggered retransmit/ACK.
src/internal.c Implements WANT_WRITE propagation for DTLS 1.3 timeout-driven ACK/retransmit and ensures the read path preserves WANT_WRITE.
Review details
  • Files reviewed: 3/3 changed files
  • Comments generated: 1
  • Review effort level: Lite

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread src/internal.c Outdated
- wolfSSLReceive() captures Dtls13RtxTimeout()'s result. On WANT_WRITE
  it sets dtls13SendingAckOrRtx and returns WANT_WRITE; a negative
  result still returns WOLFSSL_FATAL_ERROR.
- GetInputData_ex() returns WANT_WRITE to its caller instead of
  rewriting it to SOCKET_ERROR_E, under WOLFSSL_DTLS13.
- wolfSSLReceive()'s comment names WANT_READ and WANT_WRITE among the
  values it returns.
- tests: test_dtls13_rtx_timeout_want_write and
  test_dtls13_rtx_timeout_want_write_read cover the handshake and read
  paths, with a receive callback that reports a set number of timeouts.

Issue: F-13343

@wolfSSL-Fenrir-bot wolfSSL-Fenrir-bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fenrir Automated Review — PR #11396

Scan targets checked: wolfcrypt-rs-bugs, wolfssl-bugs, wolfssl-src

Fenrir result: Approved ✅

No new issues found in the changed files.

Advisory only — this automated result does not count as a GitHub approval.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants