mirror of
https://github.com/soypat/lneto.git
synced 2026-08-10 18:03:43 +00:00
64b2647a5e
* 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
99 lines
2.1 KiB
Go
99 lines
2.1 KiB
Go
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")
|
|
}
|
|
})
|
|
}
|