mirror of
https://github.com/soypat/lneto.git
synced 2026-09-10 08:39:30 +00:00
tcp: retransmit logic rollback (#61)
* tcp: remove retransmit logic entirely; add duplicate ack counting to ControlBlock * retransmit implemented in nice simple straightforward way * narrow down retransmission cases * remove old timing tests * add ControlBlock retransmit test * add failing handler test * reworking payload length semantic meaning in code * fix establish conn logic * clean up tests and add TCB dupack generation and test it * catch pending retransmit satisfy in test * add fuzz test for control block * bugfix: be more strict in what is considered dupack * add IncomingIsDupACK docs * limit queue of retransmits * protect retransmit overflow from incorrectly updating nxt
This commit is contained in:
@@ -0,0 +1,98 @@
|
||||
package tcp
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/soypat/lneto/internal"
|
||||
)
|
||||
|
||||
func FuzzTCPControlBlock(f *testing.F) {
|
||||
const (
|
||||
mutopFlags = 1 << iota
|
||||
mutopSeq
|
||||
mutopAck
|
||||
mutopMaxBit
|
||||
)
|
||||
const mutopBits = mutopMaxBit - 1
|
||||
const (
|
||||
mutPacketBits = 4
|
||||
|
||||
mutFlags = 1 << iota
|
||||
)
|
||||
const wnd = 1500
|
||||
var seed uint64
|
||||
editPkt := func(rngSeed, ops uint64, seg *Segment) {
|
||||
ops &= mutopBits
|
||||
if ops&mutopFlags != 0 {
|
||||
seg.Flags ^= Flags(seed & uint64(FlagACK|FlagFIN|FlagRST|FlagSYN))
|
||||
}
|
||||
if ops&mutopSeq != 0 {
|
||||
seg.SEQ = Value(int32(seg.SEQ) + int32(int8(uint8(rngSeed>>32))))
|
||||
}
|
||||
if ops&mutopAck != 0 {
|
||||
seg.ACK = Value(int32(seg.ACK) + int32(int8(uint8(rngSeed>>48))))
|
||||
}
|
||||
}
|
||||
f.Add(seed, uint64(mutopFlags))
|
||||
f.Fuzz(func(t *testing.T, seed, op uint64) {
|
||||
var tcb0, tcb1 ControlBlock
|
||||
iss0 := Value(seed)
|
||||
iss1 := Value(seed >> 32)
|
||||
err := tcb0.Open(iss0, wnd)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
synseg := ClientSynSegment(iss1, wnd)
|
||||
err = tcb1.Send(synseg)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
err = tcb0.Recv(synseg)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
sent := 0
|
||||
const maxpkts = 30
|
||||
pktEdits := internal.Prand64(seed)
|
||||
nextOp := internal.Prand64(op)
|
||||
for range maxpkts {
|
||||
nextOp = internal.Prand64(nextOp)
|
||||
seg0, ok := tcb0.PendingSegment(10)
|
||||
if ok {
|
||||
edit := pktEdits&1 != 0
|
||||
pktEdits >>= 1
|
||||
if edit {
|
||||
editPkt(seed, nextOp, &seg0)
|
||||
}
|
||||
err = tcb0.Send(seg0)
|
||||
if err == nil {
|
||||
sent++
|
||||
err = tcb1.Recv(seg0)
|
||||
if err != nil {
|
||||
t.Fatal("packet sent from TCB0 to TCB1 failed:\n", StringExchange(seg0, tcb0.State(), tcb1.State(), false))
|
||||
}
|
||||
}
|
||||
}
|
||||
nextOp = internal.Prand64(nextOp)
|
||||
seg1, ok := tcb1.PendingSegment(10)
|
||||
if ok {
|
||||
edit := pktEdits&1 != 0
|
||||
pktEdits >>= 1
|
||||
if edit {
|
||||
editPkt(seed, nextOp, &seg1)
|
||||
}
|
||||
err = tcb1.Send(seg1)
|
||||
if err == nil {
|
||||
sent++
|
||||
err = tcb0.Recv(seg1)
|
||||
if err != nil {
|
||||
t.Fatal("packet sent from TCB1 to TCB0 failed:\n", StringExchange(seg1, tcb0.State(), tcb1.State(), true))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if sent == 0 {
|
||||
t.Fatal("no packets sent")
|
||||
}
|
||||
})
|
||||
}
|
||||
Reference in New Issue
Block a user