Commit Graph

12 Commits

Author SHA1 Message Date
Derek den Haas c879d0497c fix(internal): keep the write position when a ring is read empty (#181)
Ring.onReadEnd and Ring.ReadDiscard call Reset() when the last readable
byte is consumed, which rewinds Off and End to 0. That is a valid empty
state, but it also moves the write position, and bytes staged past that
position with PeekWrite are addressed relative to it. After the rewind a
Commit hands back whatever bytes happen to live at the start of the
buffer instead of the staged ones.

tcp stages out-of-order segments exactly this way (see reassembly.store,
"the ring write pointer advances in lockstep with rcv.NXT, so the staged
bytes are always where seq implies"). Reading is driven by the
application, so a receiver that drains its stream while a gap is open
loses the staged tail silently: the stream arrives with the correct
length and the wrong contents.

Observed on a Sophgo SG2002 (100Mbit DWMAC, receive ring dropping frames
under load): a 16 MiB download arrived complete with a different
SHA-256, and TLS over the same path failed with "bad record MAC", while
the transmit path was bit-perfect.

Mark the ring empty without rewinding instead: End=0 is what empty
means, and the write position is then Off, which Ring.Write already
supports explicitly.

Two tests, both failing before the change:

  - internal: staged bytes survive the ring being read empty.
  - tcp: a reassembled stream is byte-identical when segments arrive
    reordered (segment K arrived as the contents of an earlier segment).

Co-authored-by: Derek den Haas <i.pestano@easyflor.nl>
2026-08-24 19:41:05 -03:00
Marvin Drees ab1a0c735a Add out-of-order segment reassembly (#148)
* feat(tcp): add out-of-order segment reassembly

Add an opt-in, bounded out-of-order reassembly buffer so a single lost
segment can be recovered by retransmitting the gap while later segments
are held and delivered once the gap fills.

The receiver also subtracts buffered out-of-order bytes from the
advertised receive window and avoids challenge-ACK aborts for in-window
future data. Reassembly is disabled by default.

Generated with LLM assistance.

Signed-off-by: Marvin Drees <marvin.drees@9elements.com>

* implement review feedback around rx buffer reuse

Signed-off-by: Marvin Drees <marvin.drees@9elements.com>

---------

Signed-off-by: Marvin Drees <marvin.drees@9elements.com>
2026-07-10 10:36:15 -03:00
Marvin Drees f87761f777 chore: bump minimum Go version to 1.24 (#85)
Signed-off-by: Marvin Drees <marvin.drees@9elements.com>
2026-04-16 17:21:23 -03:00
Patricio Whittingslow f5157e7e4a huge fixes to ring buffer implementations and mostly passing tests 2025-11-05 19:21:30 -03:00
Patricio Whittingslow 5e5f21a2b8 rethinking ring buffer semantics and breaking everything in the process 2025-11-05 02:35:53 -03:00
soypat 6a30268f83 done for today :) 2025-01-26 19:02:16 -03:00
soypat 94c59ee84e segment Ring tests more: add TwoWrite,Empty,NonEmpty 2025-01-26 12:19:29 -03:00
soypat c9aca77641 more defined semantics for low level Ring buffer indices 2025-01-26 10:37:04 -03:00
soypat 8b64181167 add TestRingWriteLimited 2025-01-14 07:55:22 -03:00
soypat 0a75ef4670 txqueue work 2025-01-13 19:36:17 -03:00
soypat 73f0b547b3 add tcp ringtx 2025-01-06 07:15:35 -03:00
soypat 17d2987367 add ring buffer implementation 2025-01-05 18:35:56 -03:00