Tcp buffer bug fix (#79)

* start working on tracking down tcp buffer bug

* mtu refactor

* modularize test

* more precise testing

* tests fail, but is it the failure we are looking for?

* fix typo in espradio link (#76)

* implement a new backoff abstraction (#75)

* rewrite backoff api

* rewrite tcp.Conn.Write

* keep fixing small things

* much better Conn.Read implementation

* fix critical overflow bug in internal.ConnRWBackoff

---------

Co-authored-by: Joel Wetzell <jwetzell@yahoo.com>
This commit is contained in:
Pat Whittingslow
2026-04-14 19:11:29 -03:00
committed by GitHub
parent 5bde7a9979
commit 75a812a8d7
22 changed files with 354 additions and 109 deletions
+35 -7
View File
@@ -9,6 +9,7 @@ import (
"testing"
"time"
"github.com/soypat/lneto"
"github.com/soypat/lneto/arp"
"github.com/soypat/lneto/ethernet"
"github.com/soypat/lneto/internal"
@@ -29,7 +30,7 @@ const (
func TestTCPConn_ReadBlocksUntilDataAvailable(t *testing.T) {
const seed = 5678
const MTU = 1500
const MTU = ethernet.MaxMTU
const svPort = 8080
client, sv, clconn, svconn := newTCPStacks(t, seed, MTU)
tst := testerFrom(t, MTU)
@@ -151,7 +152,7 @@ func TestStackAsyncTCP_multipacket(t *testing.T) {
func TestStackAsyncTCP_singlepacket(t *testing.T) {
const seed = 1234
const MTU = 1500
const MTU = ethernet.MaxMTU
const svPort = 80
client, sv, clconn, svconn := newTCPStacks(t, seed, MTU)
tst := testerFrom(t, MTU)
@@ -283,8 +284,19 @@ func (tst *tester) TestTCPHandshake(stack1, stack2 *StackAsync) {
noExchange(0),
noExchange(1),
}
for _, wants := range exch {
tst.TCPExchange(wants, stack1, stack2)
var got [len(exch)]struct {
seg tcp.Segment
}
for i, wants := range exch {
haveFailed := tst.t.Failed()
got[i].seg = tst.TCPExchange(wants, stack1, stack2)
if haveFailed != tst.t.Failed() {
tst.t.Logf("print out sent segments (%d):\n", i+1)
for k := range i + 1 {
str := tcp.StringExchange(got[k].seg, 255, 255, exch[k].SourceIdx == 0) // states unknown.
tst.t.Log(str)
}
}
}
}
@@ -734,7 +746,7 @@ func (tst *tester) getARPOperation() arp.Operation {
// The bug was that reset() cleared bufRx when state became CLOSED.
func TestTCPConn_BufferNotClearedOnPassiveClose(t *testing.T) {
const seed = 9999
const MTU = 1500
const MTU = ethernet.MaxMTU
const svPort = 8080
client, sv, clconn, svconn := newTCPStacks(t, seed, MTU)
tst := testerFrom(t, MTU)
@@ -915,8 +927,8 @@ func TestTCPConn_BufferNotClearedOnPassiveClose(t *testing.T) {
}
func TestStackAsync_ICMPEchoChecksum(t *testing.T) {
const MTU = 1500
const MaxFrameLength = MTU + 14 + 4 // Ethernet header+FCS.
const MTU = ethernet.MaxMTU
const MaxFrameLength = MTU + ethernet.MaxOverheadSize // Ethernet header+FCS+VLAN.
stackAddr := netip.AddrFrom4([4]byte{192, 168, 1, 99})
stackMAC := [6]byte{0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff}
routerAddr := [4]byte{192, 168, 1, 1}
@@ -1017,3 +1029,19 @@ const (
protoIPv4 = "IPv4"
protoTCP = "TCP"
)
func getTCPFrame(etherFrame []byte) (tcp.Frame, bool) {
efrm, err := ethernet.NewFrame(etherFrame)
if err != nil || efrm.EtherTypeOrSize() != ethernet.TypeIPv4 {
return tcp.Frame{}, false
}
ifrm, err := ipv4.NewFrame(efrm.Payload())
if err != nil || ifrm.Protocol() != lneto.IPProtoTCP {
return tcp.Frame{}, false
}
tfrm, err := tcp.NewFrame(ifrm.Payload())
if err != nil {
return tcp.Frame{}, false
}
return tfrm, true
}