func (c *Context) CreateConnected(iss seqnum.Value, rcvWnd seqnum.Size, epRcvBuf *tcpip.ReceiveBufferSizeOption) {
	c.CreateConnectedWithRawOptions(iss, rcvWnd, epRcvBuf, nil)
}
CreateConnected creates a connected TCP endpoint.
package context
import (
	"bytes"
	"testing"
	"time"
	tcpip "github.com/brewlin/net-protocol/protocol"
	"github.com/brewlin/net-protocol/pkg/buffer"
	"github.com/brewlin/net-protocol/checker"
	"github.com/brewlin/net-protocol/protocol/header"
	"github.com/brewlin/net-protocol/link/channel"
	"github.com/brewlin/net-protocol/protocol/network/ipv4"
	"github.com/brewlin/net-protocol/protocol/network/ipv6"
	"github.com/brewlin/net-protocol/pkg/seqnum"
	"github.com/brewlin/net-protocol/stack"
	"github.com/brewlin/net-protocol/protocol/transport/tcp"
	"github.com/brewlin/net-protocol/pkg/waiter"
)
const (
	StackAddr = "\x0a\x00\x00\x01"
	StackPort = 1234
	TestAddr = "\x0a\x00\x00\x02"
	TestPort = 4096
	StackV6Addr = "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01"
	TestV6Addr = "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02"
	StackV4MappedAddr = "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xff\xff" + StackAddr
	TestV4MappedAddr = "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xff\xff" + TestAddr
	V4MappedWildcardAddr = "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xff\xff\x00\x00\x00\x00"
	testInitialSequenceNumber = 789
)
var defaultWindowScale = tcp.FindWndScale(tcp.DefaultBufferSize)
type Headers struct {
	SrcPort uint16
	DstPort uint16
	SeqNum seqnum.Value
	AckNum seqnum.Value
	Flags int
	RcvWnd seqnum.Size
	TCPOpts []byte
}
type Context struct {
	t      *testing.T
	linkEP *channel.Endpoint
	s      *stack.Stack
	IRS seqnum.Value
	Port uint16
	EP tcpip.Endpoint
	WQ waiter.Queue
	TimeStampEnabled bool
}
func New(t *testing.T, mtu uint32) *Context {
	s := stack.New([]string{ipv4.ProtocolName, ipv6.ProtocolName}, []string{tcp.ProtocolName}, stack.Options{})
	if err := s.SetTransportProtocolOption(tcp.ProtocolNumber, tcp.SendBufferSizeOption{1, tcp.DefaultBufferSize, tcp.DefaultBufferSize * 10}); err != nil {
		t.Fatalf("SetTransportProtocolOption failed: %v", err)
	}
	if err := s.SetTransportProtocolOption(tcp.ProtocolNumber, tcp.ReceiveBufferSizeOption{1, tcp.DefaultBufferSize, tcp.DefaultBufferSize * 10}); err != nil {
		t.Fatalf("SetTransportProtocolOption failed: %v", err)
	}
	id, linkEP := channel.New(1000, mtu, "")
	if err := s.CreateNIC(1, id); err != nil {
		t.Fatalf("CreateNIC failed: %v", err)
	}
	if err := s.AddAddress(1, ipv4.ProtocolNumber, StackAddr); err != nil {
		t.Fatalf("AddAddress failed: %v", err)
	}
	if err := s.AddAddress(1, ipv6.ProtocolNumber, StackV6Addr); err != nil {
		t.Fatalf("AddAddress failed: %v", err)
	}
	s.SetRouteTable([]tcpip.Route{
		{
			Destination: "\x00\x00\x00\x00",
			Mask:        "\x00\x00\x00\x00",
			Gateway:     "",
			NIC:         1,
		},
		{
			Destination: "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00",
			Mask:        "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00",
			Gateway:     "",
			NIC:         1,
		},
	})
	return &Context{
		t:      t,
		s:      s,
		linkEP: linkEP,
	}
}
func (c *Context) Cleanup() {
	if c.EP != nil {
		c.EP.Close()
	}
}
func (c *Context) Stack() *stack.Stack {
	return c.s
}
func (c *Context) CheckNoPacketTimeout(errMsg string, wait time.Duration) {
	c.t.Helper()
	select {
	case <-c.linkEP.C:
		c.t.Fatal(errMsg)
	case <-time.After(wait):
	}
}
func (c *Context) CheckNoPacket(errMsg string) {
	c.CheckNoPacketTimeout(errMsg, 1*time.Second)
}
func (c *Context) GetPacket() []byte {
	select {
	case p := <-c.linkEP.C:
		if p.Proto != ipv4.ProtocolNumber {
			c.t.Fatalf("Bad network protocol: got %v, wanted %v", p.Proto, ipv4.ProtocolNumber)
		}
		b := make([]byte, len(p.Header)+len(p.Payload))
		copy(b, p.Header)
		copy(b[len(p.Header):], p.Payload)
		checker.IPv4(c.t, b, checker.SrcAddr(StackAddr), checker.DstAddr(TestAddr))
		return b
	case <-time.After(2 * time.Second):
		c.t.Fatalf("Packet wasn't written out")
	}
	return nil
}
func (c *Context) GetPacketNonBlocking() []byte {
	select {
	case p := <-c.linkEP.C:
		if p.Proto != ipv4.ProtocolNumber {
			c.t.Fatalf("Bad network protocol: got %v, wanted %v", p.Proto, ipv4.ProtocolNumber)
		}
		b := make([]byte, len(p.Header)+len(p.Payload))
		copy(b, p.Header)
		copy(b[len(p.Header):], p.Payload)
		checker.IPv4(c.t, b, checker.SrcAddr(StackAddr), checker.DstAddr(TestAddr))
		return b
	default:
		return nil
	}
}
func (c *Context) SendICMPPacket(typ header.ICMPv4Type, code uint8, p1, p2 []byte, maxTotalSize int) {
	buf := buffer.NewView(header.IPv4MinimumSize + header.ICMPv4MinimumSize + len(p1) + len(p2))
	if len(buf) > maxTotalSize {
		buf = buf[:maxTotalSize]
	}
	ip := header.IPv4(buf)
	ip.Encode(&header.IPv4Fields{
		IHL:         header.IPv4MinimumSize,
		TotalLength: uint16(len(buf)),
		TTL:         65,
		Protocol:    uint8(header.ICMPv4ProtocolNumber),
		SrcAddr:     TestAddr,
		DstAddr:     StackAddr,
	})
	ip.SetChecksum(^ip.CalculateChecksum())
	icmp := header.ICMPv4(buf[header.IPv4MinimumSize:])
	icmp.SetType(typ)
	icmp.SetCode(code)
	copy(icmp[header.ICMPv4MinimumSize:], p1)
	copy(icmp[header.ICMPv4MinimumSize+len(p1):], p2)
	c.linkEP.Inject(ipv4.ProtocolNumber, buf.ToVectorisedView())
}
func (c *Context) BuildSegment(payload []byte, h *Headers) buffer.VectorisedView {
	buf := buffer.NewView(header.TCPMinimumSize + header.IPv4MinimumSize + len(h.TCPOpts) + len(payload))
	copy(buf[len(buf)-len(payload):], payload)
	copy(buf[len(buf)-len(payload)-len(h.TCPOpts):], h.TCPOpts)
	ip := header.IPv4(buf)
	ip.Encode(&header.IPv4Fields{
		IHL:         header.IPv4MinimumSize,
		TotalLength: uint16(len(buf)),
		TTL:         65,
		Protocol:    uint8(tcp.ProtocolNumber),
		SrcAddr:     TestAddr,
		DstAddr:     StackAddr,
	})
	ip.SetChecksum(^ip.CalculateChecksum())
	t := header.TCP(buf[header.IPv4MinimumSize:])
	t.Encode(&header.TCPFields{
		SrcPort:    h.SrcPort,
		DstPort:    h.DstPort,
		SeqNum:     uint32(h.SeqNum),
		AckNum:     uint32(h.AckNum),
		DataOffset: uint8(header.TCPMinimumSize + len(h.TCPOpts)),
		Flags:      uint8(h.Flags),
		WindowSize: uint16(h.RcvWnd),
	})
	xsum := header.Checksum([]byte(TestAddr), 0)
	xsum = header.Checksum([]byte(StackAddr), xsum)
	xsum = header.Checksum([]byte{0, uint8(tcp.ProtocolNumber)}, xsum)
	length := uint16(header.TCPMinimumSize + len(h.TCPOpts) + len(payload))
	xsum = header.Checksum(payload, xsum)
	t.SetChecksum(^t.CalculateChecksum(xsum, length))
	return buf.ToVectorisedView()
}
func (c *Context) SendSegment(s buffer.VectorisedView) {
	c.linkEP.Inject(ipv4.ProtocolNumber, s)
}
func (c *Context) SendPacket(payload []byte, h *Headers) {
	c.linkEP.Inject(ipv4.ProtocolNumber, c.BuildSegment(payload, h))
}
func (c *Context) SendAck(seq seqnum.Value, bytesReceived int) {
	c.SendPacket(nil, &Headers{
		SrcPort: TestPort,
		DstPort: c.Port,
		Flags:   header.TCPFlagAck,
		SeqNum:  seqnum.Value(testInitialSequenceNumber).Add(1),
		AckNum:  c.IRS.Add(1 + seqnum.Size(bytesReceived)),
		RcvWnd:  30000,
	})
}
func (c *Context) ReceiveAndCheckPacket(data []byte, offset, size int) {
	b := c.GetPacket()
	checker.IPv4(c.t, b,
		checker.PayloadLen(size+header.TCPMinimumSize),
		checker.TCP(
			checker.DstPort(TestPort),
			checker.SeqNum(uint32(c.IRS.Add(seqnum.Size(1+offset)))),
			checker.AckNum(uint32(seqnum.Value(testInitialSequenceNumber).Add(1))),
			checker.TCPFlagsMatch(header.TCPFlagAck, ^uint8(header.TCPFlagPsh)),
		),
	)
	pdata := data[offset:][:size]
	if p := b[header.IPv4MinimumSize+header.TCPMinimumSize:]; bytes.Compare(pdata, p) != 0 {
		c.t.Fatalf("Data is different: expected %v, got %v", pdata, p)
	}
}
func (c *Context) ReceiveNonBlockingAndCheckPacket(data []byte, offset, size int) bool {
	b := c.GetPacketNonBlocking()
	if b == nil {
		return false
	}
	checker.IPv4(c.t, b,
		checker.PayloadLen(size+header.TCPMinimumSize),
		checker.TCP(
			checker.DstPort(TestPort),
			checker.SeqNum(uint32(c.IRS.Add(seqnum.Size(1+offset)))),
			checker.AckNum(uint32(seqnum.Value(testInitialSequenceNumber).Add(1))),
			checker.TCPFlagsMatch(header.TCPFlagAck, ^uint8(header.TCPFlagPsh)),
		),
	)
	pdata := data[offset:][:size]
	if p := b[header.IPv4MinimumSize+header.TCPMinimumSize:]; bytes.Compare(pdata, p) != 0 {
		c.t.Fatalf("Data is different: expected %v, got %v", pdata, p)
	}
	return true
}
func (c *Context) CreateV6Endpoint(v6only bool) {
	var err *tcpip.Error
	c.EP, err = c.s.NewEndpoint(tcp.ProtocolNumber, ipv6.ProtocolNumber, &c.WQ)
	if err != nil {
		c.t.Fatalf("NewEndpoint failed: %v", err)
	}
	var v tcpip.V6OnlyOption
	if v6only {
		v = 1
	}
	if err := c.EP.SetSockOpt(v); err != nil {
		c.t.Fatalf("SetSockOpt failed failed: %v", err)
	}
}
func (c *Context) GetV6Packet() []byte {
	select {
	case p := <-c.linkEP.C:
		if p.Proto != ipv6.ProtocolNumber {
			c.t.Fatalf("Bad network protocol: got %v, wanted %v", p.Proto, ipv6.ProtocolNumber)
		}
		b := make([]byte, len(p.Header)+len(p.Payload))
		copy(b, p.Header)
		copy(b[len(p.Header):], p.Payload)
		checker.IPv6(c.t, b, checker.SrcAddr(StackV6Addr), checker.DstAddr(TestV6Addr))
		return b
	case <-time.After(2 * time.Second):
		c.t.Fatalf("Packet wasn't written out")
	}
	return nil
}
func (c *Context) SendV6Packet(payload []byte, h *Headers) {
	buf := buffer.NewView(header.TCPMinimumSize + header.IPv6MinimumSize + len(payload))
	copy(buf[len(buf)-len(payload):], payload)
	ip := header.IPv6(buf)
	ip.Encode(&header.IPv6Fields{
		PayloadLength: uint16(header.TCPMinimumSize + len(payload)),
		NextHeader:    uint8(tcp.ProtocolNumber),
		HopLimit:      65,
		SrcAddr:       TestV6Addr,
		DstAddr:       StackV6Addr,
	})
	t := header.TCP(buf[header.IPv6MinimumSize:])
	t.Encode(&header.TCPFields{
		SrcPort:    h.SrcPort,
		DstPort:    h.DstPort,
		SeqNum:     uint32(h.SeqNum),
		AckNum:     uint32(h.AckNum),
		DataOffset: header.TCPMinimumSize,
		Flags:      uint8(h.Flags),
		WindowSize: uint16(h.RcvWnd),
	})
	xsum := header.Checksum([]byte(TestV6Addr), 0)
	xsum = header.Checksum([]byte(StackV6Addr), xsum)
	xsum = header.Checksum([]byte{0, uint8(tcp.ProtocolNumber)}, xsum)
	length := uint16(header.TCPMinimumSize + len(payload))
	xsum = header.Checksum(payload, xsum)
	t.SetChecksum(^t.CalculateChecksum(xsum, length))
	c.linkEP.Inject(ipv6.ProtocolNumber, buf.ToVectorisedView())
}