mirror of
https://github.com/soypat/lneto.git
synced 2026-09-07 23:39:04 +00:00
tcp: simplified Policy implementation based on @MDr164 (#190)
* begin prepping policy refactor manually * implement tcp.Policy and refactor rto to use it * fix CI * chatting with claude gave me idea to reformulate Policy * tcp.Policy: add newTransmitLimit output * merge with main and fix failing tests * remove fix.patch * answer my own comments
This commit is contained in:
+58
-11
@@ -227,18 +227,36 @@ func (rtx *ringTx) RetransmitFromUNA() {
|
||||
if oldest == nil {
|
||||
return // Nothing in the retransmission queue.
|
||||
}
|
||||
unaSeq := oldest.seq
|
||||
if rtx.sentend != 0 {
|
||||
// Merge sent region [sentoff, sentend) back into unsent.
|
||||
rtx.unsentoff = rtx.sentoff
|
||||
if rtx.unsentend == 0 {
|
||||
rtx.unsentend = rtx.sentend
|
||||
}
|
||||
rtx.sentoff = 0
|
||||
rtx.sentend = 0
|
||||
rtx.RetransmitFrom(oldest.seq)
|
||||
}
|
||||
|
||||
// RetransmitFrom rewinds the transmit queue so sent-but-unacked data from seq onward
|
||||
// becomes unsent again causing next [ringTx.MakePacket] to resend them.
|
||||
//
|
||||
// Must be called when [ControlBlock.RetransmitFrom] returns true so the
|
||||
// ring and control block state are coherent.
|
||||
func (rtx *ringTx) RetransmitFrom(seq Value) {
|
||||
pkt := rtx.slist.packetContaining(seq)
|
||||
if pkt == nil {
|
||||
return // seq not in the retransmission queue.
|
||||
}
|
||||
// Clear packet metadata; sequence tracking restarts from UNA.
|
||||
rtx.slist.Reset(cap(rtx.slist.pkts), unaSeq)
|
||||
rewindOff, rewindSeq := pkt.off, pkt.seq
|
||||
// The write position is unsentend, except when the unsent region is empty
|
||||
// (unsentend==0) in which case data ends where the sent region ends. Capture
|
||||
// it before reopening the unsent region over the rewound packets.
|
||||
writeEnd := rtx.unsentend
|
||||
if writeEnd == 0 {
|
||||
writeEnd = rtx.sentend
|
||||
}
|
||||
if rewindOff == rtx.sentoff {
|
||||
rtx.sentoff = 0 // Whole queue rewound: sent region becomes empty.
|
||||
rtx.sentend = 0
|
||||
} else {
|
||||
rtx.sentend = rewindOff
|
||||
}
|
||||
rtx.unsentoff = rewindOff
|
||||
rtx.unsentend = writeEnd
|
||||
rtx.slist.truncateFrom(rewindSeq)
|
||||
}
|
||||
|
||||
func (rtx *ringTx) consolidateBufs() {
|
||||
@@ -331,6 +349,35 @@ func (sl *sentlist) Free() int {
|
||||
return cap(sl.pkts) - len(sl.pkts)
|
||||
}
|
||||
|
||||
// packetContaining returns the queued packet whose sequence range covers seq, or
|
||||
// nil when no packet does.
|
||||
func (sl *sentlist) packetContaining(seq Value) *ringidx {
|
||||
for i := range sl.pkts {
|
||||
pkt := &sl.pkts[i]
|
||||
if pkt.seq.LessThanEq(seq) && seq.LessThan(pkt.endSeq()) {
|
||||
return pkt
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// truncateFrom drops the packet starting at seq and every packet sent after it,
|
||||
// so their data can be re-queued as unsent. seq must be a packet start sequence
|
||||
// (see [sentlist.packetContaining]). When no packet survives, the auxiliary
|
||||
// sequence counter is rewound to seq so [sentlist.EndSeq] keeps reporting where
|
||||
// the next packet begins.
|
||||
func (sl *sentlist) truncateFrom(seq Value) {
|
||||
for i := range sl.pkts {
|
||||
if sl.pkts[i].seq == seq {
|
||||
sl.pkts = sl.pkts[:i]
|
||||
if i == 0 {
|
||||
sl.ssn = seq
|
||||
}
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (sl *sentlist) AddPacket(datalen, off, bufsize int, seq Value) *ringidx {
|
||||
free := sl.Free()
|
||||
if free == 0 {
|
||||
|
||||
Reference in New Issue
Block a user