Repository navigation
Conversation
poll_write checked that the send buffer was not full, then sent the whole buffer up to the MSS. The last segment could end past the right edge of the peer window; the peer trims it and the tail has to be retransmitted. Cut each write to the usable window: min(max_unacked_bytes, send_window) minus the bytes in flight. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
SajjadPourali
self-requested a review
October 6, 2026 05:44
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
poll_writechecksis_send_buffer_full()before sending, but then sends the whole buffer (up to the MSS) regardless of how much of the peer window is left. The last segment can end past the right edge of the window.Example: a macOS peer, tun2proxy writing 8192-byte chunks, ipstack 1.0.1 (no window scaling).
end - 1. The next two segments produce two duplicate ACKs, one short of the fast-retransmit threshold.Measurements
Path: macOS application → utun → tun2proxy 0.8.3 → SOCKS proxy. A 15 MB HTTPS download, 20 s limit per attempt, TCP headers captured on utun.
Every stall on 1.0.1 matched the sequence above: an ACK at segment end − 1, two duplicate ACKs, then silence. On main the timer-driven retransmission (#92) and window scaling (#91) remove the stall, but the overshoot is still reachable whenever the peer window shrinks below the in-flight cap; it now costs a retransmission instead of a stall.
To make the window shrink on purpose, the reader was rate-limited to 200 KB/s (
curl --limit-rate). Same path, six 4 MB downloads per build:The peer window shrank just as often with the change. Every segment now ends at or before its right edge, and nothing is resent. Throughput is set by the reader in both runs, about 0.2 MB/s.
Change
Tcb::get_usable_send_window():min(max_unacked_bytes, send_window)minus the bytes in flight.poll_writecuts the buffer to the usable window.is_send_buffer_full()is nowusable == 0, same condition as before.Tests
writer_stops_at_the_right_edge_of_the_peer_window: peer window 2000 bytes, two 1460-byte writes. The second is cut to 540 bytes, the third waits for an ACK. Fails on main, passes with this change.cargo fmt --all -- --check,cargo clippy --all-targets --all-features -- -D warningsandcargo testpass.🤖 Generated with Claude Code