Skip to content

fix: retry close_notify in poll_shutdown when the send buffer is full - #78

Open
ArniDagur wants to merge 2 commits into
rustls:mainfrom
ArniDagur:fix-shutdown-close-notify-retry
Open

fix: retry close_notify in poll_shutdown when the send buffer is full#78
ArniDagur wants to merge 2 commits into
rustls:mainfrom
ArniDagur:fix-shutdown-close-notify-retry

Conversation

@ArniDagur

@ArniDagur ArniDagur commented Aug 7, 2026

Copy link
Copy Markdown
Contributor

poll_shutdown marked the write side closed before enforcing a successful close_notify. With a full send buffer this resulted in two bugs:

  1. Shutdown failed with WouldBlock, which is an error type that should not escape a poll-based API.
  2. Subsequent retries of the shutdown skipped the close_notify entirely, since write_closed was already set.

We fix this by only marking the write side closed once the alert is sent (or has failed fatally), and retrying on WouldBlock.

The retry uses a new AsyncWriteReady trait, which mirrors the preexisting AsyncReadReady. It exposes tokio's poll_write_ready and try_io. The latter clears write-readiness when send_close_notify returns WouldBlock, so the task parks until the socket becomes writable instead of busy-polling.

This PR introduces a minor breaking change, since the AsyncWrite impl for KtlsStream<IO> now requires IO: AsyncWriteReady. This change also lays the foundation for additional work, including in relation to properly implementing KeyUpdate (which I plan on doing).

@ArniDagur
ArniDagur force-pushed the fix-shutdown-close-notify-retry branch from ee2dae6 to e862e48 Compare August 8, 2026 15:04
@ArniDagur

Copy link
Copy Markdown
Contributor Author

@ctz @djz @cpu

I know you guys are busy with the main rustls project, and this is a smaller crate so it's not a priority in terms of reviews. That said there are definitely some improvements to ktls that I want to make and I can only do them with your help!

I would volunteer to help with the maintenance of ktls, but that doesn't help much if the main burden is reviewing my own PRs. Can you think of anything else?

@djc

djc commented Sep 1, 2026

Copy link
Copy Markdown
Member

I would volunteer to help with the maintenance of ktls, but that doesn't help much if the main burden is reviewing my own PRs. Can you think of anything else?

I think we should wait it out a bit to see if the situation with review bandwidth improves as we get on top of rustls 0.24.

Comment thread ktls/src/async_write_ready.rs Outdated
Comment thread ktls/src/async_write_ready.rs Outdated
Comment thread ktls/src/ktls_stream.rs Outdated
@ArniDagur
ArniDagur force-pushed the fix-shutdown-close-notify-retry branch 3 times, most recently from 8b3e536 to f89f17f Compare September 1, 2026 17:01
@ArniDagur

Copy link
Copy Markdown
Contributor Author

Code review comments have been addressed. I squashed the changes into one commit.

@djc djc left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Thanks.

It would be nicer to have a separate commit that renames async_read_ready.rs to async_ready.rs, to help engage Git's rename tracking.

The module is about to gain an `AsyncWriteReady` trait next to
`AsyncReadReady`, so give it a name that covers both. Renaming it on its
own keeps the change visible to Git's rename detection.
`poll_shutdown` marked the write side closed _before_ enforcing a
successful `close_notify`. With a full send buffer this resulted
in two bugs:

1. Shutdown failed with `WouldBlock`, which is an error type that
should not escape a poll-based API.
2. Subsequent retries of the shutdown skipped the `close_notify`
entirely, since `write_closed` was already set.

We fix this by only marking the write side closed once the alert is
sent (or has failed fatally), and retrying on `WouldBlock`.

The retry uses a new `AsyncWriteReady` trait, which mirrors the
preexisting `AsyncReadReady`. It exposes tokio's `poll_write_ready` and
`try_io`. The latter `try_write_io` clears write-readiness when
`send_close_notify` returns `WouldBlock`, so the task parks until the
socket becomes writable instead of [busy-polling][1].

[1]: https://github.com/rustls/ktls/blob/5e3c7d6ceadbb1ae98d06908d559490723899aed/ktls/src/ktls_stream.rs#L268-L277

This PR introduces a minor breaking change, since the `AsyncWrite` impl
for `KtlsStream<IO>` now requires `IO: AsyncWriteReady`. This change also
lays the foundation for additional work, including in relation to properly
implementing `KeyUpdate`.
@ArniDagur
ArniDagur force-pushed the fix-shutdown-close-notify-retry branch from f89f17f to 198807b Compare September 2, 2026 16:50
@ArniDagur

Copy link
Copy Markdown
Contributor Author

It would be nicer to have a separate commit that renames async_read_ready.rs to async_ready.rs, to help engage Git's rename tracking.

This is done

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.

2 participants