diff --git a/examples/berkeley-listener/berkeley_server.go b/examples/berkeley-listener/berkeley_server.go index 5d072a7..50ad2e4 100644 --- a/examples/berkeley-listener/berkeley_server.go +++ b/examples/berkeley-listener/berkeley_server.go @@ -104,11 +104,11 @@ func run() error { var stack xnet.StackAsync if err := stack.Reset(xnet.StackConfig{ - Hostname: "berkeley-http", - RandSeed: softRand, - HardwareAddress: nicHW, - MTU: uint16(mtu), - MaxTCPConns: 1024, + Hostname: "berkeley-http", + RandSeed: softRand, + HardwareAddress: nicHW, + MTU: uint16(mtu), + MaxActiveTCPPorts: 1024, }); err != nil { return err } @@ -202,7 +202,7 @@ func run() error { blocking := stack.StackBlocking(5 * time.Millisecond) berkeley := blocking.StackGo(xnet.StackGoConfig{ ListenerPoolConfig: xnet.TCPPoolConfig{ - PoolSize: flagPoolSize, + PoolSize: uint16(flagPoolSize), QueueSize: 3, TxBufSize: mtu, RxBufSize: mtu, @@ -328,12 +328,12 @@ func tryPoll(iface ltesto.Interface, poll time.Duration) (dataMayBeReady bool, _ func mockClient(stack *xnet.StackAsync, port uint16, subnet netip.Prefix) { target := netip.AddrPortFrom(stack.Addr(), port) err := mockStack.Reset(xnet.StackConfig{ - StaticAddress: subnet.Addr().Next(), - MaxTCPConns: 1, - HardwareAddress: stack.Gateway6(), - Hostname: "the-other", - MTU: uint16(stack.MTU()), - RandSeed: int64(stack.Prand32()), + StaticAddress: subnet.Addr().Next(), + MaxActiveTCPPorts: 1, + HardwareAddress: stack.Gateway6(), + Hostname: "the-other", + MTU: uint16(stack.MTU()), + RandSeed: int64(stack.Prand32()), }) if err != nil { panic(err.Error()) diff --git a/examples/httpserver/main.go b/examples/httpserver/main.go index 449a7d3..2aa29a1 100644 --- a/examples/httpserver/main.go +++ b/examples/httpserver/main.go @@ -101,11 +101,11 @@ func run() (err error) { var stack xnet.StackAsync err = stack.Reset(xnet.StackConfig{ - Hostname: "httpserver", - RandSeed: softRand, - HardwareAddress: nicHW, - MTU: uint16(mtu), - MaxTCPConns: 1000, + Hostname: "httpserver", + RandSeed: softRand, + HardwareAddress: nicHW, + MTU: uint16(mtu), + MaxActiveTCPPorts: 1000, }) if err != nil { return err diff --git a/examples/min-working-example/main-mwe.go b/examples/min-working-example/main-mwe.go index 39858b8..bd72ab4 100644 --- a/examples/min-working-example/main-mwe.go +++ b/examples/min-working-example/main-mwe.go @@ -64,7 +64,7 @@ func run(ctx context.Context, stack *xnet.StackAsync) error { Hostname: "lneto-mwe", RandSeed: time.Now().UnixNano(), // A passive TCP listener to many remote ports takes up one spot, active TCP clients to one remote port take up a spot. - MaxTCPConns: 1, + MaxActiveTCPPorts: 1, // MaxUDPConns: 1 , // For MDNS support. // AcceptMulticast: true, // For MDNS. MTU: uint16(framelen - ethernet.MaxOverheadSize), diff --git a/examples/xcurl/main.go b/examples/xcurl/main.go index c37bc77..f69bff8 100644 --- a/examples/xcurl/main.go +++ b/examples/xcurl/main.go @@ -121,11 +121,11 @@ func run() (err error) { var stack xnet.StackAsync err = stack.Reset(xnet.StackConfig{ - Hostname: "xnet-test", - RandSeed: softRand, - HardwareAddress: brHW, - MTU: uint16(mtu), - MaxTCPConns: 1, + Hostname: "xnet-test", + RandSeed: softRand, + HardwareAddress: brHW, + MTU: uint16(mtu), + MaxActiveTCPPorts: 1, }) if err != nil { return err diff --git a/internet/stack-ports.go b/internet/stack-ports.go index 7c54cc6..c80df2f 100644 --- a/internet/stack-ports.go +++ b/internet/stack-ports.go @@ -22,21 +22,21 @@ type StackPorts struct { rstQueue tcp.RSTQueue } -func (ps *StackPorts) ResetUDP(maxNodes int) error { +func (ps *StackPorts) ResetUDP(maxNodes uint16) error { return ps.Reset(uint64(lneto.IPProtoUDP), 2, maxNodes) } -func (ps *StackPorts) ResetTCP(maxNodes int) error { +func (ps *StackPorts) ResetTCP(maxNodes uint16) error { return ps.Reset(uint64(lneto.IPProtoTCP), 2, maxNodes) } -func (ps *StackPorts) Reset(protocol uint64, dstPortOffset uint16, maxNodes int) error { +func (ps *StackPorts) Reset(protocol uint64, dstPortOffset, maxNodes uint16) error { if protocol > math.MaxUint16 { return lneto.ErrInvalidConfig } else if maxNodes <= 0 { return lneto.ErrInvalidConfig } - ps.handlers.reset("StackPorts(proto="+strconv.Itoa(int(protocol))+")", maxNodes) + ps.handlers.reset("StackPorts(proto="+strconv.Itoa(int(protocol))+")", int(maxNodes)) *ps = StackPorts{ connID: ps.connID + 1, handlers: ps.handlers, @@ -118,15 +118,15 @@ func (mfsp *StackPortsMACFiltered) Register(h lneto.StackNode, addr []byte) erro return mfsp.sp.handlers.registerByPortProto(nodeFromStackNode(h, port, proto, addr)) } -func (ps *StackPortsMACFiltered) ResetUDP(maxNodes int) error { +func (ps *StackPortsMACFiltered) ResetUDP(maxNodes uint16) error { return ps.sp.ResetUDP(maxNodes) } -func (ps *StackPortsMACFiltered) ResetTCP(maxNodes int) error { +func (ps *StackPortsMACFiltered) ResetTCP(maxNodes uint16) error { return ps.sp.ResetTCP(maxNodes) } -func (ps *StackPortsMACFiltered) Reset(protocol uint64, dstPortOffset uint16, maxNodes int) error { +func (ps *StackPortsMACFiltered) Reset(protocol uint64, dstPortOffset, maxNodes uint16) error { return ps.sp.Reset(protocol, dstPortOffset, maxNodes) } diff --git a/x/xnet/stack-async.go b/x/xnet/stack-async.go index 6294d4e..9255637 100644 --- a/x/xnet/stack-async.go +++ b/x/xnet/stack-async.go @@ -62,13 +62,17 @@ type StackAsync struct { } type StackConfig struct { - StaticAddress netip.Addr - DNSServer netip.Addr - NTPServer netip.Addr - RandSeed int64 - Hostname string - MaxTCPConns int - MaxUDPConns int + StaticAddress netip.Addr + DNSServer netip.Addr + NTPServer netip.Addr + RandSeed int64 + Hostname string + + // MaxActiveTCPPorts and MaxActiveUDPPorts are a memory guardrail to limit + // number of simultaneous open TCP/UDP ports. The memory impact at the stack level + // of a port corresponds to ~64 bytes excluding the registered StackNode i.e: [tcp.Conn] or [udp.Conn]. + MaxActiveTCPPorts, MaxActiveUDPPorts uint16 + EthernetTxCRC32Update func(crc uint32, b []byte) uint32 HardwareAddress [6]byte @@ -170,16 +174,16 @@ func (s *StackAsync) Reset(cfg StackConfig) error { if err != nil { return err } - udpConns := 3 + cfg.MaxUDPConns // DHCP, DNS, NTP + user-registered. + udpConns := 3 + cfg.MaxActiveUDPPorts // DHCP, DNS, NTP + user-registered. err = s.udps.ResetUDP(udpConns) if err != nil { return err } - internal.SliceReuse(&s.userUDPs, cfg.MaxUDPConns) + internal.SliceReuse(&s.userUDPs, int(cfg.MaxActiveUDPPorts)) // Enable TCP if connections present. - if cfg.MaxTCPConns > 0 { - err = s.tcps.ResetTCP(cfg.MaxTCPConns) + if cfg.MaxActiveTCPPorts > 0 { + err = s.tcps.ResetTCP(cfg.MaxActiveTCPPorts) if err != nil { return err } diff --git a/x/xnet/tcppool.go b/x/xnet/tcppool.go index f6f039a..9d220f1 100644 --- a/x/xnet/tcppool.go +++ b/x/xnet/tcppool.go @@ -32,7 +32,8 @@ func _() { } type TCPPoolConfig struct { - PoolSize int + // PoolSize determines the maximum number of active incoming TCP connections to the pool. + PoolSize uint16 QueueSize int TxBufSize int RxBufSize int @@ -58,7 +59,7 @@ func NewTCPPool(cfg TCPPoolConfig) (*TCPPool, error) { if cfg.EstablishedTimeout <= 0 || cfg.ClosingTimeout <= 0 { return nil, lneto.ErrInvalidConfig } - n := cfg.PoolSize + n := int(cfg.PoolSize) pool := &TCPPool{ acquiredAt: make([]int64, n), closingAt: make([]int64, n), diff --git a/x/xnet/xnet_bench_test.go b/x/xnet/xnet_bench_test.go index d18c8b3..34f76e1 100644 --- a/x/xnet/xnet_bench_test.go +++ b/x/xnet/xnet_bench_test.go @@ -83,23 +83,23 @@ func BenchmarkTCPHandshake(b *testing.B) { clconn, svconn := new(tcp.Conn), new(tcp.Conn) err := sv.Reset(StackConfig{ - Hostname: "Server", - RandSeed: 1, - StaticAddress: netip.AddrFrom4([4]byte{10, 0, 0, 1}), - MaxTCPConns: 1, - HardwareAddress: [6]byte{0xbe, 0xef, 0, 0, 0, 1}, - MTU: MTU, + Hostname: "Server", + RandSeed: 1, + StaticAddress: netip.AddrFrom4([4]byte{10, 0, 0, 1}), + MaxActiveTCPPorts: 1, + HardwareAddress: [6]byte{0xbe, 0xef, 0, 0, 0, 1}, + MTU: MTU, }) if err != nil { b.Fatal(err) } err = client.Reset(StackConfig{ - Hostname: "Client", - RandSeed: 2, - StaticAddress: netip.AddrFrom4([4]byte{10, 0, 0, 2}), - MaxTCPConns: 1, - HardwareAddress: [6]byte{0xbe, 0xef, 0, 0, 0, 2}, - MTU: MTU, + Hostname: "Client", + RandSeed: 2, + StaticAddress: netip.AddrFrom4([4]byte{10, 0, 0, 2}), + MaxActiveTCPPorts: 1, + HardwareAddress: [6]byte{0xbe, 0xef, 0, 0, 0, 2}, + MTU: MTU, }) if err != nil { b.Fatal(err) diff --git a/x/xnet/xnet_concurrent_test.go b/x/xnet/xnet_concurrent_test.go index e12978c..8cf4a1e 100644 --- a/x/xnet/xnet_concurrent_test.go +++ b/x/xnet/xnet_concurrent_test.go @@ -30,12 +30,12 @@ func TestTCPListener_ConcurrentEcho(t *testing.T) { serverMAC := [6]byte{0xaa, 0xbb, 0xcc, 0x00, 0x00, 0x01} serverIP := netip.AddrFrom4([4]byte{10, 0, 0, 1}) err := serverStack.Reset(StackConfig{ - Hostname: "Server", - RandSeed: seed, - StaticAddress: serverIP, - MaxTCPConns: numClients, - HardwareAddress: serverMAC, - MTU: MTU, + Hostname: "Server", + RandSeed: seed, + StaticAddress: serverIP, + MaxActiveTCPPorts: numClients, + HardwareAddress: serverMAC, + MTU: MTU, }) if err != nil { t.Fatal(err) @@ -72,12 +72,12 @@ func TestTCPListener_ConcurrentEcho(t *testing.T) { clientMAC := [6]byte{0xaa, 0xbb, 0xcc, 0x00, 0x01, byte(i + 1)} clientIP := netip.AddrFrom4([4]byte{10, 0, 0, byte(i + 10)}) err := clientStacks[i].Reset(StackConfig{ - Hostname: fmt.Sprintf("Client%d", i), - RandSeed: int64(seed + i + 1), - StaticAddress: clientIP, - MaxTCPConns: 1, - HardwareAddress: clientMAC, - MTU: MTU, + Hostname: fmt.Sprintf("Client%d", i), + RandSeed: int64(seed + i + 1), + StaticAddress: clientIP, + MaxActiveTCPPorts: 1, + HardwareAddress: clientMAC, + MTU: MTU, }) if err != nil { t.Fatalf("client %d reset: %v", i, err) diff --git a/x/xnet/xnet_listener_test.go b/x/xnet/xnet_listener_test.go index 317606a..7202027 100644 --- a/x/xnet/xnet_listener_test.go +++ b/x/xnet/xnet_listener_test.go @@ -19,23 +19,23 @@ func TestStackAsyncListener_SingleConnection(t *testing.T) { // Create two stacks. client, sv := new(StackAsync), new(StackAsync) err := client.Reset(StackConfig{ - Hostname: "Client", - RandSeed: seed, - StaticAddress: netip.AddrFrom4([4]byte{10, 0, 0, 1}), - MaxTCPConns: 1, - HardwareAddress: [6]byte{0xbe, 0xef, 0, 0, 0, 1}, - MTU: MTU, + Hostname: "Client", + RandSeed: seed, + StaticAddress: netip.AddrFrom4([4]byte{10, 0, 0, 1}), + MaxActiveTCPPorts: 1, + HardwareAddress: [6]byte{0xbe, 0xef, 0, 0, 0, 1}, + MTU: MTU, }) if err != nil { t.Fatal(err) } err = sv.Reset(StackConfig{ - Hostname: "Server", - RandSeed: ^seed, - StaticAddress: netip.AddrFrom4([4]byte{10, 0, 0, 2}), - MaxTCPConns: 1, // Note: We use listener, not direct TCP conn registration. - HardwareAddress: [6]byte{0xbe, 0xef, 0, 0, 0, 2}, - MTU: MTU, + Hostname: "Server", + RandSeed: ^seed, + StaticAddress: netip.AddrFrom4([4]byte{10, 0, 0, 2}), + MaxActiveTCPPorts: 1, // Note: We use listener, not direct TCP conn registration. + HardwareAddress: [6]byte{0xbe, 0xef, 0, 0, 0, 2}, + MTU: MTU, }) if err != nil { t.Fatal(err) @@ -131,12 +131,12 @@ func TestStackAsyncListener_MultiSequentialConn(t *testing.T) { // Create two stacks. sv := new(StackAsync) err := sv.Reset(StackConfig{ - Hostname: "Server", - RandSeed: ^seed, - StaticAddress: netip.AddrFrom4([4]byte{10, 0, 0, 2}), - MaxTCPConns: 1, // Note: We use listener, not direct TCP conn registration. - HardwareAddress: [6]byte{0xbe, 0xef, 0, 0, 0, 2}, - MTU: MTU, + Hostname: "Server", + RandSeed: ^seed, + StaticAddress: netip.AddrFrom4([4]byte{10, 0, 0, 2}), + MaxActiveTCPPorts: 1, // Note: We use listener, not direct TCP conn registration. + HardwareAddress: [6]byte{0xbe, 0xef, 0, 0, 0, 2}, + MTU: MTU, }) if err != nil { t.Fatal(err) @@ -171,12 +171,12 @@ func TestStackAsyncListener_MultiSequentialConn(t *testing.T) { doRequest := func(caddrp netip.AddrPort, sleep time.Duration, data []byte) { var client StackAsync err := client.Reset(StackConfig{ - Hostname: "Client", - RandSeed: seed, - StaticAddress: caddrp.Addr(), - MaxTCPConns: 1, - HardwareAddress: chw, - MTU: MTU, + Hostname: "Client", + RandSeed: seed, + StaticAddress: caddrp.Addr(), + MaxActiveTCPPorts: 1, + HardwareAddress: chw, + MTU: MTU, }) if err != nil { panic(err) diff --git a/x/xnet/xnet_mdns_test.go b/x/xnet/xnet_mdns_test.go index b44e035..4975241 100644 --- a/x/xnet/xnet_mdns_test.go +++ b/x/xnet/xnet_mdns_test.go @@ -43,13 +43,13 @@ func TestMDNS_QueryResponse(t *testing.T) { // Setup responder stack with mDNS service. responderStack := new(StackAsync) err = responderStack.Reset(StackConfig{ - Hostname: "responder", - RandSeed: 1234, - StaticAddress: responderAddr, - HardwareAddress: responderMAC, - MTU: MTU, - MaxUDPConns: 1, - AcceptMulticast: true, + Hostname: "responder", + RandSeed: 1234, + StaticAddress: responderAddr, + HardwareAddress: responderMAC, + MTU: MTU, + MaxActiveUDPPorts: 1, + AcceptMulticast: true, }) if err != nil { t.Fatal("responder reset:", err) @@ -73,13 +73,13 @@ func TestMDNS_QueryResponse(t *testing.T) { // Setup querier stack. querierStack := new(StackAsync) err = querierStack.Reset(StackConfig{ - Hostname: "querier", - RandSeed: 5678, - StaticAddress: querierAddr, - HardwareAddress: querierMAC, - MTU: MTU, - MaxUDPConns: 1, - AcceptMulticast: true, + Hostname: "querier", + RandSeed: 5678, + StaticAddress: querierAddr, + HardwareAddress: querierMAC, + MTU: MTU, + MaxActiveUDPPorts: 1, + AcceptMulticast: true, }) if err != nil { t.Fatal("querier reset:", err) @@ -278,13 +278,13 @@ func newMDNSStack(t *testing.T, hostname string, seed int64, const MTU = 1500 stack := new(StackAsync) err := stack.Reset(StackConfig{ - Hostname: hostname, - RandSeed: seed, - StaticAddress: addr, - HardwareAddress: mac, - MTU: MTU, - MaxUDPConns: 1, - AcceptMulticast: true, + Hostname: hostname, + RandSeed: seed, + StaticAddress: addr, + HardwareAddress: mac, + MTU: MTU, + MaxActiveUDPPorts: 1, + AcceptMulticast: true, }) if err != nil { t.Fatal(hostname, "reset:", err) diff --git a/x/xnet/xnet_test.go b/x/xnet/xnet_test.go index c876694..6697cc0 100644 --- a/x/xnet/xnet_test.go +++ b/x/xnet/xnet_test.go @@ -175,12 +175,12 @@ func newTCPStacks(t testing.TB, randSeed int64, mtu int) (s1, s2 *StackAsync, c1 c1, c2 = new(tcp.Conn), new(tcp.Conn) byte1 := byte(randSeed)/4 - 1 err := s1.Reset(StackConfig{ - Hostname: "Stack1", - RandSeed: randSeed, - StaticAddress: netip.AddrFrom4([4]byte{10, 0, 0, byte1}), - MaxTCPConns: 1, - HardwareAddress: [6]byte{0xbe, 0xef, 0, 0, 0, byte1}, - MTU: uint16(mtu), + Hostname: "Stack1", + RandSeed: randSeed, + StaticAddress: netip.AddrFrom4([4]byte{10, 0, 0, byte1}), + MaxActiveTCPPorts: 1, + HardwareAddress: [6]byte{0xbe, 0xef, 0, 0, 0, byte1}, + MTU: uint16(mtu), }) if err != nil { t.Fatal(err) @@ -188,12 +188,12 @@ func newTCPStacks(t testing.TB, randSeed int64, mtu int) (s1, s2 *StackAsync, c1 byte2 := byte1 + 1 err = s2.Reset(StackConfig{ - Hostname: "Stack2", - RandSeed: ^randSeed, - StaticAddress: netip.AddrFrom4([4]byte{10, 0, 0, byte2}), - MaxTCPConns: 1, - HardwareAddress: [6]byte{0xbe, 0xef, 0, 0, 0, byte2}, - MTU: uint16(mtu), + Hostname: "Stack2", + RandSeed: ^randSeed, + StaticAddress: netip.AddrFrom4([4]byte{10, 0, 0, byte2}), + MaxActiveTCPPorts: 1, + HardwareAddress: [6]byte{0xbe, 0xef, 0, 0, 0, byte2}, + MTU: uint16(mtu), }) if err != nil { t.Fatal(err)