mirror of
https://github.com/soypat/lneto.git
synced 2026-09-01 04:19:05 +00:00
refactor stack TCP stuff; begin adding TCP test
This commit is contained in:
+23
-63
@@ -2,7 +2,6 @@ package xnet
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
"io"
|
|
||||||
"net/netip"
|
"net/netip"
|
||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
@@ -30,7 +29,6 @@ type StackAsync struct {
|
|||||||
arp arp.Handler
|
arp arp.Handler
|
||||||
udps internet.StackPorts
|
udps internet.StackPorts
|
||||||
tcps internet.StackPorts
|
tcps internet.StackPorts
|
||||||
tcpconns []tcp.Conn
|
|
||||||
|
|
||||||
dhcpUDP internet.StackUDPPort
|
dhcpUDP internet.StackUDPPort
|
||||||
dhcp dhcpv4.Client
|
dhcp dhcpv4.Client
|
||||||
@@ -59,8 +57,6 @@ type StackConfig struct {
|
|||||||
NTPServer netip.Addr
|
NTPServer netip.Addr
|
||||||
Hostname string
|
Hostname string
|
||||||
MaxTCPConns int
|
MaxTCPConns int
|
||||||
TCPBufferSizeTx int // Size of transmit buffer for TCP connections.
|
|
||||||
TCPBufferSizeRx int // Size of receive buffer for TCP connections.
|
|
||||||
RandSeed int64
|
RandSeed int64
|
||||||
HardwareAddress [6]byte
|
HardwareAddress [6]byte
|
||||||
MTU uint16
|
MTU uint16
|
||||||
@@ -127,44 +123,14 @@ func (s *StackAsync) Reset(cfg StackConfig) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Enable TCP if connections present.
|
// Enable TCP if connections present.
|
||||||
if cfg.MaxTCPConns > 0 {
|
|
||||||
if cfg.TCPBufferSizeRx < minTCPBuffer || cfg.TCPBufferSizeTx < minTCPBuffer {
|
err = s.tcps.ResetTCP(cfg.MaxTCPConns)
|
||||||
return io.ErrShortBuffer
|
if err != nil {
|
||||||
}
|
return err
|
||||||
if cap(s.tcpconns) < cfg.MaxTCPConns {
|
}
|
||||||
s.tcpconns = make([]tcp.Conn, cfg.MaxTCPConns)
|
err = s.ip.Register(&s.tcps)
|
||||||
}
|
if err != nil {
|
||||||
s.tcpconns = s.tcpconns[:cfg.MaxTCPConns]
|
return err
|
||||||
for i := range s.tcpconns {
|
|
||||||
c := &s.tcpconns[i]
|
|
||||||
c.Abort() // Abort forcibly closes connection to allow buffer setting and reduce risk of race conditions.
|
|
||||||
h := c.InternalHandler()
|
|
||||||
sizetx := h.FreeTx()
|
|
||||||
sizerx := h.SizeRx()
|
|
||||||
// If size is sufficient then buffers will remain nil and memory will be reused.
|
|
||||||
var rxbuf, txbuf []byte
|
|
||||||
if sizetx < cfg.TCPBufferSizeTx || sizerx < cfg.TCPBufferSizeRx {
|
|
||||||
buf := make([]byte, cfg.TCPBufferSizeTx+cfg.TCPBufferSizeRx)
|
|
||||||
rxbuf = buf[:cfg.TCPBufferSizeRx]
|
|
||||||
txbuf = buf[cfg.TCPBufferSizeRx : cfg.TCPBufferSizeRx+cfg.TCPBufferSizeTx]
|
|
||||||
}
|
|
||||||
err = c.Configure(tcp.ConnConfig{
|
|
||||||
RxBuf: rxbuf,
|
|
||||||
TxBuf: txbuf,
|
|
||||||
TxPacketQueueSize: 4,
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
err = s.tcps.ResetTCP(cfg.MaxTCPConns)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
err = s.ip.Register(&s.tcps)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Now setup stacks.
|
// Now setup stacks.
|
||||||
@@ -231,6 +197,12 @@ func (s *StackAsync) SetIPAddr(addr netip.Addr) error {
|
|||||||
return s.resetARP()
|
return s.resetARP()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *StackAsync) Addr() netip.Addr {
|
||||||
|
s.mu.Lock()
|
||||||
|
defer s.mu.Unlock()
|
||||||
|
return s.ip.Addr()
|
||||||
|
}
|
||||||
|
|
||||||
func (s *StackAsync) SetHardwareAddress(hw [6]byte) error {
|
func (s *StackAsync) SetHardwareAddress(hw [6]byte) error {
|
||||||
s.mu.Lock()
|
s.mu.Lock()
|
||||||
defer s.mu.Unlock()
|
defer s.mu.Unlock()
|
||||||
@@ -244,38 +216,26 @@ func (s *StackAsync) SetGateway6(gwhw [6]byte) {
|
|||||||
s.link.SetGateway6(gwhw)
|
s.link.SetGateway6(gwhw)
|
||||||
}
|
}
|
||||||
|
|
||||||
var (
|
func (s *StackAsync) start() {
|
||||||
errNoTCP = errors.New("no TCP initialized")
|
|
||||||
errNoTCPConnsAvail = errors.New("all allocated TCP connections busy")
|
|
||||||
)
|
|
||||||
|
|
||||||
func (s *StackAsync) DialTCP(localPort uint16, addrp netip.AddrPort) (conn *tcp.Conn, err error) {
|
}
|
||||||
if len(s.tcpconns) == 0 {
|
|
||||||
return nil, errNoTCP
|
func (s *StackAsync) DialTCP(conn *tcp.Conn, localPort uint16, addrp netip.AddrPort) (err error) {
|
||||||
}
|
if !conn.State().IsClosed() {
|
||||||
for i := range s.tcpconns {
|
return errors.New("conn not closed")
|
||||||
maybeFreeConn := &s.tcpconns[i]
|
|
||||||
state := maybeFreeConn.State()
|
|
||||||
if state.IsClosed() {
|
|
||||||
conn = maybeFreeConn
|
|
||||||
break // Can be used!
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if conn == nil {
|
|
||||||
return nil, errNoTCPConnsAvail
|
|
||||||
}
|
}
|
||||||
conn.Abort() // Conn is closed, safe to abort.
|
conn.Abort() // Conn is closed, safe to abort.
|
||||||
err = conn.OpenActive(localPort, addrp, tcp.Value(s.Prand32()))
|
err = conn.OpenActive(localPort, addrp, tcp.Value(s.Prand32()))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
conn.Abort()
|
conn.Abort()
|
||||||
return nil, err
|
return err
|
||||||
}
|
}
|
||||||
err = s.tcps.Register(conn)
|
err = s.tcps.Register(conn)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
conn.Abort()
|
conn.Abort()
|
||||||
return nil, err
|
return err
|
||||||
}
|
}
|
||||||
return conn, nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
var errNoDNSServer = errors.New("no DNS server- did DHCP complete? You can set a predetermined DNS server in Stack configuration")
|
var errNoDNSServer = errors.New("no DNS server- did DHCP complete? You can set a predetermined DNS server in Stack configuration")
|
||||||
|
|||||||
@@ -113,29 +113,30 @@ func (s StackBlocking) DoLookupIP(host string, timeout time.Duration) (addrs []n
|
|||||||
|
|
||||||
var errTCPFailedToConnect = errors.New("tcp failed to connect")
|
var errTCPFailedToConnect = errors.New("tcp failed to connect")
|
||||||
|
|
||||||
func (s StackBlocking) DoDialTCP(localPort uint16, addrp netip.AddrPort, timeout time.Duration) (conn *tcp.Conn, err error) {
|
func (s StackBlocking) DoDialTCP(conn *tcp.Conn, localPort uint16, addrp netip.AddrPort, timeout time.Duration) (err error) {
|
||||||
conn, err = s.async.DialTCP(localPort, addrp)
|
err = s.async.DialTCP(conn, localPort, addrp)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return err
|
||||||
}
|
}
|
||||||
sleep := timeout/maxIter + 1
|
sleep := timeout/maxIter + 1
|
||||||
deadline := time.Now().Add(timeout)
|
deadline := time.Now().Add(timeout)
|
||||||
for i := 0; i < maxIter; i++ {
|
for i := 0; i < maxIter; i++ {
|
||||||
state := conn.State()
|
state := conn.State()
|
||||||
if state == tcp.StateEstablished {
|
if state == tcp.StateEstablished {
|
||||||
return conn, nil
|
return nil
|
||||||
} else if state == tcp.StateSynSent || state == tcp.StateSynRcvd || conn.InternalHandler().AwaitingSynSend() {
|
} else if state == tcp.StateSynSent || state == tcp.StateSynRcvd || conn.InternalHandler().AwaitingSynSend() {
|
||||||
if err = s.checkDeadline(deadline); err != nil {
|
if err = s.checkDeadline(deadline); err != nil {
|
||||||
return nil, err
|
conn.Abort()
|
||||||
|
return err
|
||||||
}
|
}
|
||||||
time.Sleep(sleep)
|
time.Sleep(sleep)
|
||||||
} else {
|
} else {
|
||||||
// Unexpected state, abort and terminate connection.
|
// Unexpected state, abort and terminate connection.
|
||||||
conn.Abort()
|
conn.Abort()
|
||||||
return nil, errTCPFailedToConnect
|
return errTCPFailedToConnect
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return conn, errDeadlineExceed
|
return errDeadlineExceed
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s StackBlocking) checkDeadline(deadline time.Time) error {
|
func (s StackBlocking) checkDeadline(deadline time.Time) error {
|
||||||
|
|||||||
@@ -83,16 +83,16 @@ func (s StackRetrying) DoResolveHardwareAddress6(addr netip.Addr, timeout time.D
|
|||||||
return hw, errRetriesExceeded
|
return hw, errRetriesExceeded
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s StackRetrying) DoDialTCP(localPort uint16, addrp netip.AddrPort, timeout time.Duration, retries int) (conn *tcp.Conn, err error) {
|
func (s StackRetrying) DoDialTCP(conn *tcp.Conn, localPort uint16, addrp netip.AddrPort, timeout time.Duration, retries int) (err error) {
|
||||||
expectEnd := time.Now().Add(timeout * time.Duration(retries))
|
expectEnd := time.Now().Add(timeout * time.Duration(retries))
|
||||||
for i := 0; i < retries; i++ {
|
for i := 0; i < retries; i++ {
|
||||||
conn, err = s.block.DoDialTCP(localPort, addrp, timeout)
|
err = s.block.DoDialTCP(conn, localPort, addrp, timeout)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
return conn, nil
|
return nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if time.Now().Before(expectEnd) {
|
if time.Now().Before(expectEnd) {
|
||||||
return conn, err
|
return err
|
||||||
}
|
}
|
||||||
return nil, errRetriesExceeded
|
return errRetriesExceeded
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,67 @@
|
|||||||
|
package xnet
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net/netip"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/soypat/lneto/tcp"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestABC(t *testing.T) {
|
||||||
|
const seed = 1234
|
||||||
|
const MTU = 1500
|
||||||
|
var mac = [6]byte{0x02, 0x00, 0x00, 0x00, 0x00, 0x01}
|
||||||
|
var client StackAsync
|
||||||
|
err := client.Reset(StackConfig{
|
||||||
|
StaticAddress: netip.MustParseAddr("10.0.0.1"),
|
||||||
|
MaxTCPConns: 1,
|
||||||
|
MTU: MTU,
|
||||||
|
HardwareAddress: mac,
|
||||||
|
Hostname: "client",
|
||||||
|
RandSeed: seed,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
var macsv = [6]byte{0x02, 0x00, 0x00, 0x00, 0x00, 0x01}
|
||||||
|
var sv StackAsync
|
||||||
|
err = sv.Reset(StackConfig{
|
||||||
|
StaticAddress: netip.MustParseAddr("10.0.0.2"),
|
||||||
|
MaxTCPConns: 1,
|
||||||
|
MTU: MTU,
|
||||||
|
HardwareAddress: macsv,
|
||||||
|
Hostname: "server",
|
||||||
|
RandSeed: seed,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
// IMG_1084.MOV
|
||||||
|
|
||||||
|
const svPort = 80
|
||||||
|
var clconn tcp.Conn
|
||||||
|
err = clconn.Configure(tcp.ConnConfig{
|
||||||
|
RxBuf: make([]byte, MTU),
|
||||||
|
TxBuf: make([]byte, MTU),
|
||||||
|
TxPacketQueueSize: 4,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
err = client.DialTCP(&clconn, 1337, netip.AddrPortFrom(sv.Addr(), svPort))
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
var svconn tcp.Conn
|
||||||
|
err = svconn.Configure(tcp.ConnConfig{
|
||||||
|
RxBuf: make([]byte, MTU),
|
||||||
|
TxBuf: make([]byte, MTU),
|
||||||
|
TxPacketQueueSize: 4,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
// clconn.OpenListen()
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user