Livt packages

Livt.Net

Version 1.4.1

Ethernet, IPv4, TCP, UDP, ARP, TFTP, and Telnet networking components for Livt hardware.

Published files (163)

tests/TcpStreamServerStorageChecks.lvt

namespace Livt.Net.Tests

using Livt.Net
using Livt.IO

/**
 * Exercises a shared TCP server with independent connection and retransmission scenarios.
 */
@Context(ClockFrequency = 50MHz)
component TcpStreamServerStorageChecks<R: IRam<byte> & new(), T: IRam<byte> & new()>
{
	// Owned source, parsers and server reused with explicit scenario initialization.
	data: ArrayPacketData<64>
	ethernet: EthernetFrameParser<ArrayPacketData<64>>
	ipv4: Ipv4PacketParser<EthernetFrameParser<ArrayPacketData<64>>>
	server: TcpStreamServer<ArrayPacketData<64>, 23, 8, 8, 1, R, T>

	// Fixture ACK adjustment for the current connection generation.
	acknowledgmentOffset: uint

	/**
	 * Constructs an isolated packet source, shared parsers and small RAM-backed TCP server.
	 */
	new()
	{
		this.data = new ArrayPacketData<64>()
		this.ethernet = new EthernetFrameParser<ArrayPacketData<64>>(this.data)
		this.ipv4 = new Ipv4PacketParser<EthernetFrameParser<ArrayPacketData<64>>>(this.ethernet)
		this.server = new TcpStreamServer<ArrayPacketData<64>, 23, 8, 8, 1, R, T>(this.ethernet, this.ipv4, [2, 0, 0, 0, 0, 2], [10, 0, 0, 1])
	}

	/**
	 * Returns an independently checksummed wire fixture byte; unspecified padding is zero. Offsets
	 * 0..13 are Ethernet, 14..33 IPv4, and 34 onward TCP header/options/payload.
	 */
	fn Fixture(packet: int, index: int) byte
	{
		match (packet)
		{
			0 =>
			{
				// SYN advertises MSS 5, smaller than the eight-byte TX buffer.
				match (index)
				{
					0 =>
					{
						return 0x02
					}
					5 =>
					{
						return 0x02
					}
					6 =>
					{
						return 0x02
					}
					11 =>
					{
						return 0x01
					}
					12 =>
					{
						return 0x08
					}
					14 =>
					{
						return 0x45
					}
					17 =>
					{
						return 0x2C
					}
					20 =>
					{
						return 0x40
					}
					22 =>
					{
						return 0x40
					}
					23 =>
					{
						return 0x06
					}
					24 =>
					{
						return 0x26
					}
					25 =>
					{
						return 0xCA
					}
					26 =>
					{
						return 0x0A
					}
					29 =>
					{
						return 0x02
					}
					30 =>
					{
						return 0x0A
					}
					33 =>
					{
						return 0x01
					}
					34 =>
					{
						return 0x9C
					}
					35 =>
					{
						return 0x40
					}
					37 =>
					{
						return 0x17
					}
					38 =>
					{
						return 0xFF
					}
					39 =>
					{
						return 0xFF
					}
					40 =>
					{
						return 0xFF
					}
					41 =>
					{
						return 0xFE
					}
					46 =>
					{
						return 0x60
					}
					47 =>
					{
						return 0x02
					}
					49 =>
					{
						return 0x08
					}
					50 =>
					{
						return 0xED
					}
					51 =>
					{
						return 0x74
					}
					54 =>
					{
						return 0x02
					}
					55 =>
					{
						return 0x04
					}
					57 =>
					{
						return 0x05
					}
					_ =>
					{
						return 0
					}
				}
			}
			1 =>
			{
				match (index)
				{
					0 =>
					{
						return 0x02
					}
					5 =>
					{
						return 0x02
					}
					6 =>
					{
						return 0x02
					}
					11 =>
					{
						return 0x01
					}
					12 =>
					{
						return 0x08
					}
					14 =>
					{
						return 0x45
					}
					17 =>
					{
						return 0x28
					}
					20 =>
					{
						return 0x40
					}
					22 =>
					{
						return 0x40
					}
					23 =>
					{
						return 0x06
					}
					24 =>
					{
						return 0x26
					}
					25 =>
					{
						return 0xCE
					}
					26 =>
					{
						return 0x0A
					}
					29 =>
					{
						return 0x02
					}
					30 =>
					{
						return 0x0A
					}
					33 =>
					{
						return 0x01
					}
					34 =>
					{
						return 0x9C
					}
					35 =>
					{
						return 0x40
					}
					37 =>
					{
						return 0x17
					}
					38 =>
					{
						return 0xFF
					}
					39 =>
					{
						return 0xFF
					}
					40 =>
					{
						return 0xFF
					}
					41 =>
					{
						return 0xFF
					}
					44 =>
					{
						return 0x04
					}
					45 =>
					{
						return 0x01
					}
					46 =>
					{
						return 0x50
					}
					47 =>
					{
						return 0x10
					}
					49 =>
					{
						return 0x08
					}
					50 =>
					{
						return 0xFB
					}
					51 =>
					{
						return 0x71
					}
					_ =>
					{
						return 0
					}
				}
			}
			2 =>
			{
				match (index)
				{
					0 =>
					{
						return 0x02
					}
					5 =>
					{
						return 0x02
					}
					6 =>
					{
						return 0x02
					}
					11 =>
					{
						return 0x01
					}
					12 =>
					{
						return 0x08
					}
					14 =>
					{
						return 0x45
					}
					17 =>
					{
						return 0x2B
					}
					20 =>
					{
						return 0x40
					}
					22 =>
					{
						return 0x40
					}
					23 =>
					{
						return 0x06
					}
					24 =>
					{
						return 0x26
					}
					25 =>
					{
						return 0xCB
					}
					26 =>
					{
						return 0x0A
					}
					29 =>
					{
						return 0x02
					}
					30 =>
					{
						return 0x0A
					}
					33 =>
					{
						return 0x01
					}
					34 =>
					{
						return 0x9C
					}
					35 =>
					{
						return 0x40
					}
					37 =>
					{
						return 0x17
					}
					38 =>
					{
						return 0xFF
					}
					39 =>
					{
						return 0xFF
					}
					40 =>
					{
						return 0xFF
					}
					41 =>
					{
						return 0xFF
					}
					44 =>
					{
						return 0x04
					}
					45 =>
					{
						return 0x01
					}
					46 =>
					{
						return 0x50
					}
					47 =>
					{
						return 0x18
					}
					49 =>
					{
						return 0x08
					}
					50 =>
					{
						return 0x37
					}
					51 =>
					{
						return 0x04
					}
					54 =>
					{
						return 0x61
					}
					55 =>
					{
						return 0x62
					}
					56 =>
					{
						return 0x63
					}
					_ =>
					{
						return 0
					}
				}
			}
			3 =>
			{
				match (index)
				{
					0 =>
					{
						return 0x02
					}
					5 =>
					{
						return 0x02
					}
					6 =>
					{
						return 0x02
					}
					11 =>
					{
						return 0x01
					}
					12 =>
					{
						return 0x08
					}
					14 =>
					{
						return 0x45
					}
					17 =>
					{
						return 0x29
					}
					20 =>
					{
						return 0x40
					}
					22 =>
					{
						return 0x40
					}
					23 =>
					{
						return 0x06
					}
					24 =>
					{
						return 0x26
					}
					25 =>
					{
						return 0xCD
					}
					26 =>
					{
						return 0x0A
					}
					29 =>
					{
						return 0x02
					}
					30 =>
					{
						return 0x0A
					}
					33 =>
					{
						return 0x01
					}
					34 =>
					{
						return 0x9C
					}
					35 =>
					{
						return 0x40
					}
					37 =>
					{
						return 0x17
					}
					41 =>
					{
						return 0x08
					}
					44 =>
					{
						return 0x04
					}
					45 =>
					{
						return 0x01
					}
					46 =>
					{
						return 0x50
					}
					47 =>
					{
						return 0x18
					}
					49 =>
					{
						return 0x08
					}
					50 =>
					{
						return 0x8A
					}
					51 =>
					{
						return 0x60
					}
					54 =>
					{
						return 0x71
					}
					_ =>
					{
						return 0
					}
				}
			}
			4 =>
			{
				match (index)
				{
					0 =>
					{
						return 0x02
					}
					5 =>
					{
						return 0x02
					}
					6 =>
					{
						return 0x02
					}
					11 =>
					{
						return 0x01
					}
					12 =>
					{
						return 0x08
					}
					14 =>
					{
						return 0x45
					}
					17 =>
					{
						return 0x29
					}
					20 =>
					{
						return 0x40
					}
					22 =>
					{
						return 0x40
					}
					23 =>
					{
						return 0x06
					}
					24 =>
					{
						return 0x26
					}
					25 =>
					{
						return 0xCD
					}
					26 =>
					{
						return 0x0A
					}
					29 =>
					{
						return 0x02
					}
					30 =>
					{
						return 0x0A
					}
					33 =>
					{
						return 0x01
					}
					34 =>
					{
						return 0x9C
					}
					35 =>
					{
						return 0x40
					}
					37 =>
					{
						return 0x17
					}
					41 =>
					{
						return 0x02
					}
					44 =>
					{
						return 0x04
					}
					45 =>
					{
						return 0x01
					}
					46 =>
					{
						return 0x50
					}
					47 =>
					{
						return 0x18
					}
					49 =>
					{
						return 0x08
					}
					50 =>
					{
						return 0x83
					}
					51 =>
					{
						return 0x67
					}
					54 =>
					{
						return 0x78
					}
					_ =>
					{
						return 0
					}
				}
			}
			5 =>
			{
				match (index)
				{
					0 =>
					{
						return 0x02
					}
					5 =>
					{
						return 0x02
					}
					6 =>
					{
						return 0x02
					}
					11 =>
					{
						return 0x01
					}
					12 =>
					{
						return 0x08
					}
					14 =>
					{
						return 0x45
					}
					17 =>
					{
						return 0x28
					}
					20 =>
					{
						return 0x40
					}
					22 =>
					{
						return 0x40
					}
					23 =>
					{
						return 0x06
					}
					24 =>
					{
						return 0x26
					}
					25 =>
					{
						return 0xCE
					}
					26 =>
					{
						return 0x0A
					}
					29 =>
					{
						return 0x02
					}
					30 =>
					{
						return 0x0A
					}
					33 =>
					{
						return 0x01
					}
					34 =>
					{
						return 0x9C
					}
					35 =>
					{
						return 0x40
					}
					37 =>
					{
						return 0x17
					}
					41 =>
					{
						return 0x02
					}
					44 =>
					{
						return 0x04
					}
					45 =>
					{
						return 0x03
					}
					46 =>
					{
						return 0x50
					}
					47 =>
					{
						return 0x10
					}
					49 =>
					{
						return 0x02
					}
					50 =>
					{
						return 0xFB
					}
					51 =>
					{
						return 0x73
					}
					_ =>
					{
						return 0
					}
				}
			}
			6 =>
			{
				match (index)
				{
					0 =>
					{
						return 0x02
					}
					5 =>
					{
						return 0x02
					}
					6 =>
					{
						return 0x02
					}
					11 =>
					{
						return 0x01
					}
					12 =>
					{
						return 0x08
					}
					14 =>
					{
						return 0x45
					}
					17 =>
					{
						return 0x28
					}
					20 =>
					{
						return 0x40
					}
					22 =>
					{
						return 0x40
					}
					23 =>
					{
						return 0x06
					}
					24 =>
					{
						return 0x26
					}
					25 =>
					{
						return 0xCE
					}
					26 =>
					{
						return 0x0A
					}
					29 =>
					{
						return 0x02
					}
					30 =>
					{
						return 0x0A
					}
					33 =>
					{
						return 0x01
					}
					34 =>
					{
						return 0x9C
					}
					35 =>
					{
						return 0x40
					}
					37 =>
					{
						return 0x17
					}
					41 =>
					{
						return 0x02
					}
					44 =>
					{
						return 0x04
					}
					45 =>
					{
						return 0x06
					}
					46 =>
					{
						return 0x50
					}
					47 =>
					{
						return 0x10
					}
					49 =>
					{
						return 0x08
					}
					50 =>
					{
						return 0xFB
					}
					51 =>
					{
						return 0x6A
					}
					_ =>
					{
						return 0
					}
				}
			}
			7 =>
			{
				match (index)
				{
					0 =>
					{
						return 0x02
					}
					5 =>
					{
						return 0x02
					}
					6 =>
					{
						return 0x02
					}
					11 =>
					{
						return 0x01
					}
					12 =>
					{
						return 0x08
					}
					14 =>
					{
						return 0x45
					}
					17 =>
					{
						return 0x28
					}
					20 =>
					{
						return 0x40
					}
					22 =>
					{
						return 0x40
					}
					23 =>
					{
						return 0x06
					}
					24 =>
					{
						return 0x26
					}
					25 =>
					{
						return 0xCE
					}
					26 =>
					{
						return 0x0A
					}
					29 =>
					{
						return 0x02
					}
					30 =>
					{
						return 0x0A
					}
					33 =>
					{
						return 0x01
					}
					34 =>
					{
						return 0x9C
					}
					35 =>
					{
						return 0x40
					}
					37 =>
					{
						return 0x17
					}
					41 =>
					{
						return 0x02
					}
					44 =>
					{
						return 0x04
					}
					45 =>
					{
						return 0x06
					}
					46 =>
					{
						return 0x50
					}
					47 =>
					{
						return 0x10
					}
					50 =>
					{
						return 0xFB
					}
					51 =>
					{
						return 0x72
					}
					_ =>
					{
						return 0
					}
				}
			}
			8 =>
			{
				match (index)
				{
					0 =>
					{
						return 0x02
					}
					5 =>
					{
						return 0x02
					}
					6 =>
					{
						return 0x02
					}
					11 =>
					{
						return 0x01
					}
					12 =>
					{
						return 0x08
					}
					14 =>
					{
						return 0x45
					}
					17 =>
					{
						return 0x28
					}
					20 =>
					{
						return 0x40
					}
					22 =>
					{
						return 0x40
					}
					23 =>
					{
						return 0x06
					}
					24 =>
					{
						return 0x26
					}
					25 =>
					{
						return 0xCE
					}
					26 =>
					{
						return 0x0A
					}
					29 =>
					{
						return 0x02
					}
					30 =>
					{
						return 0x0A
					}
					33 =>
					{
						return 0x01
					}
					34 =>
					{
						return 0x9C
					}
					35 =>
					{
						return 0x40
					}
					37 =>
					{
						return 0x17
					}
					41 =>
					{
						return 0x02
					}
					44 =>
					{
						return 0x04
					}
					45 =>
					{
						return 0x06
					}
					46 =>
					{
						return 0x50
					}
					47 =>
					{
						return 0x10
					}
					49 =>
					{
						return 0x01
					}
					50 =>
					{
						return 0xFB
					}
					51 =>
					{
						return 0x71
					}
					_ =>
					{
						return 0
					}
				}
			}
			9 =>
			{
				match (index)
				{
					0 =>
					{
						return 0x02
					}
					5 =>
					{
						return 0x02
					}
					6 =>
					{
						return 0x02
					}
					11 =>
					{
						return 0x01
					}
					12 =>
					{
						return 0x08
					}
					14 =>
					{
						return 0x45
					}
					17 =>
					{
						return 0x28
					}
					20 =>
					{
						return 0x40
					}
					22 =>
					{
						return 0x40
					}
					23 =>
					{
						return 0x06
					}
					24 =>
					{
						return 0x26
					}
					25 =>
					{
						return 0xCE
					}
					26 =>
					{
						return 0x0A
					}
					29 =>
					{
						return 0x02
					}
					30 =>
					{
						return 0x0A
					}
					33 =>
					{
						return 0x01
					}
					34 =>
					{
						return 0x9C
					}
					35 =>
					{
						return 0x40
					}
					37 =>
					{
						return 0x17
					}
					41 =>
					{
						return 0x02
					}
					44 =>
					{
						return 0x04
					}
					45 =>
					{
						return 0x07
					}
					46 =>
					{
						return 0x50
					}
					47 =>
					{
						return 0x10
					}
					49 =>
					{
						return 0x08
					}
					50 =>
					{
						return 0xFB
					}
					51 =>
					{
						return 0x69
					}
					_ =>
					{
						return 0
					}
				}
			}
			10 =>
			{
				match (index)
				{
					0 =>
					{
						return 0x02
					}
					5 =>
					{
						return 0x02
					}
					6 =>
					{
						return 0x02
					}
					11 =>
					{
						return 0x01
					}
					12 =>
					{
						return 0x08
					}
					14 =>
					{
						return 0x45
					}
					17 =>
					{
						return 0x28
					}
					20 =>
					{
						return 0x40
					}
					22 =>
					{
						return 0x40
					}
					23 =>
					{
						return 0x06
					}
					24 =>
					{
						return 0x26
					}
					25 =>
					{
						return 0xCE
					}
					26 =>
					{
						return 0x0A
					}
					29 =>
					{
						return 0x02
					}
					30 =>
					{
						return 0x0A
					}
					33 =>
					{
						return 0x01
					}
					34 =>
					{
						return 0x9C
					}
					35 =>
					{
						return 0x40
					}
					37 =>
					{
						return 0x17
					}
					41 =>
					{
						return 0x02
					}
					44 =>
					{
						return 0x04
					}
					45 =>
					{
						return 0x07
					}
					46 =>
					{
						return 0x50
					}
					47 =>
					{
						return 0x11
					}
					49 =>
					{
						return 0x08
					}
					50 =>
					{
						return 0xFB
					}
					51 =>
					{
						return 0x68
					}
					_ =>
					{
						return 0
					}
				}
			}
			11 =>
			{
				match (index)
				{
					0 =>
					{
						return 0x02
					}
					5 =>
					{
						return 0x02
					}
					6 =>
					{
						return 0x02
					}
					11 =>
					{
						return 0x01
					}
					12 =>
					{
						return 0x08
					}
					14 =>
					{
						return 0x45
					}
					17 =>
					{
						return 0x28
					}
					20 =>
					{
						return 0x40
					}
					22 =>
					{
						return 0x40
					}
					23 =>
					{
						return 0x06
					}
					24 =>
					{
						return 0x26
					}
					25 =>
					{
						return 0xCE
					}
					26 =>
					{
						return 0x0A
					}
					29 =>
					{
						return 0x02
					}
					30 =>
					{
						return 0x0A
					}
					33 =>
					{
						return 0x01
					}
					34 =>
					{
						return 0x9C
					}
					35 =>
					{
						return 0x40
					}
					37 =>
					{
						return 0x17
					}
					41 =>
					{
						return 0x03
					}
					44 =>
					{
						return 0x04
					}
					45 =>
					{
						return 0x08
					}
					46 =>
					{
						return 0x50
					}
					47 =>
					{
						return 0x10
					}
					49 =>
					{
						return 0x08
					}
					50 =>
					{
						return 0xFB
					}
					51 =>
					{
						return 0x67
					}
					_ =>
					{
						return 0
					}
				}
			}
			_ =>
			{
				return 0
			}
		}
	}

	/**
	 * Publishes one complete fixture into the borrowed source and passes it to the server at
	 * millisecond time now.
	 */
	fn Receive(packet: int, now: uint)
	{
		if (this.data.IsReady()) {
			this.data.TryRelease()
		} else {
			this.data.TryClear()
		}

		// Each SYN at time zero advances the server ISN by 1024.
		if (packet == 0) {
			this.acknowledgmentOffset = this.server.GetGeneration() << 10
		}

		var oldAck = ((this.Fixture(packet, 42) as uint) << 24) | ((this.Fixture(packet, 43) as uint) << 16)
		oldAck = oldAck | ((this.Fixture(packet, 44) as uint) << 8) | (this.Fixture(packet, 45) as uint)
		var newAck = oldAck + this.acknowledgmentOffset
		var checksum = NetworkOrder.Word(this.Fixture(packet, 50), this.Fixture(packet, 51))
		// Incremental replacement preserves deliberately invalid fixture checksums.
		var sum = 65535 - checksum + 65535 - ((oldAck >> 16) as int) + 65535 - ((oldAck & 65535) as int)
		sum = sum + ((newAck >> 16) as int) + ((newAck & 65535) as int)
		checksum = ChecksumArithmetic.Finish(sum)

		for (var i = 0; i < 60; i++) {
			var value = this.Fixture(packet, i)
			value = this.Fixture(packet, i)

			if ((this.Fixture(packet, 47) & 0x10) != 0) {
				if (i >= 42 && i < 46) {
					value = (newAck >> ((45 - i) * 8)) as byte
				} elif (i == 50) {
					value = NetworkOrder.HighByte(checksum)
				} elif (i == 51) {
					value = NetworkOrder.LowByte(checksum)
				}
			}

			assert this.data.TryWrite(i, value) == PacketDataResult.Success
		}

		assert this.data.TryPublish() == PacketDataResult.Success
		assert this.server.TryHandle(now)
	}

	/**
	 * Reads one byte of the currently published response, asserting that the borrow is valid.
	 */
	fn ByteAt(index: int) byte
	{
		var value: byte = 0
		assert this.server.TryRead(index, value) == PacketDataResult.Success
		return value
	}

	/**
	 * Checks ordering, checksum rejection, MSS limits, partial acknowledgments, retries, zero-window
	 * recovery and passive close from a listening server.
	 */
	public fn StreamRetransmissionAndClose()
	{
		this.ExerciseStreamRetransmissionAndClose()
		this.ExerciseStreamRetransmissionAndClose()
	}

	/**
	 * Exercises the complete stream lifecycle from a fresh connection, preserving the generation.
	 */
	fn ExerciseStreamRetransmissionAndClose()
	{
		this.server.Abort()
		this.Receive(0, 0)
		assert this.server.Poll(0)
		assert this.ByteAt(47) == 0x12
		assert this.ByteAt(41) == 0
		assert this.ByteAt(45) == 255
		this.server.ReleaseFrame()
		this.Receive(1, 10)
		assert this.server.IsConnected()
		this.Receive(2, 20)
		var value: byte = 0
		assert this.server.TryReceive(value) && value == 97
		assert this.server.TryReceive(value) && value == 98
		assert this.server.TryReceive(value) && value == 99
		assert !this.server.TryReceive(value) && value == 0
		this.Receive(2, 30)
		assert !this.server.TryReceive(value)
		this.Receive(3, 40)
		assert !this.server.TryReceive(value)
		this.Receive(4, 50)
		assert !this.server.TryReceive(value)
		assert this.server.Poll(60)
		assert this.ByteAt(45) == 2
		this.server.ReleaseFrame()
		assert this.server.TryTransmit(72, 100)
		assert this.server.TryTransmit(69, 100)
		assert this.server.TryTransmit(76, 100)
		assert this.server.TryTransmit(76, 100)
		assert this.server.TryTransmit(79, 100)
		assert !this.server.TryTransmit(88, 100)
		assert this.server.Poll(110)
		assert this.ByteAt(47) == 0x18
		assert this.ByteAt(54) == 72 && this.ByteAt(58) == 79
		assert !this.server.TryTransmit(88, 110)
		this.server.ReleaseFrame()
		this.Receive(5, 120)
		assert this.server.Poll(1110)
		assert this.ByteAt(41) == 3
		assert this.ByteAt(54) == 76 && this.ByteAt(56) == 79
		this.server.ReleaseFrame()
		this.Receive(6, 1200)
		assert !this.server.HasPendingOutput()
		this.Receive(7, 1210)
		assert this.server.TryTransmit(90, 1220)
		assert this.server.Poll(1500)
		assert this.ByteAt(47) == 0x10
		assert this.ByteAt(41) == 5
		this.server.ReleaseFrame()
		this.Receive(8, 1600)
		assert this.server.Poll(1600)
		assert this.ByteAt(54) == 90
		this.server.ReleaseFrame()
		this.Receive(9, 1610)
		this.Receive(10, 1620)
		assert this.server.HasPeerClosed()
		this.server.Close()
		assert this.server.Poll(1620)
		assert this.ByteAt(47) == 0x11
		this.server.ReleaseFrame()
		this.Receive(11, 1630)
		assert this.server.GetState() == TcpStreamState.Listening
	}

	/**
	 * Returns a handshake ACK fixture with its 32-bit acknowledgment replaced at Ethernet offsets
	 * 42..45 and its checksum fields 50..51 cleared.
	 */
	fn AckByte(index: int, acknowledgment: uint) byte
	{
		if (index == 42) {
			return (acknowledgment >> 24) as byte
		}

		if (index == 43) {
			return (acknowledgment >> 16) as byte
		}

		if (index == 44) {
			return (acknowledgment >> 8) as byte
		}

		if (index == 45) {
			return acknowledgment as byte
		}

		if (index == 50 || index == 51) {
			return 0
		}

		return this.Fixture(1, index)
	}

	/**
	 * Publishes a handshake ACK with a freshly calculated pseudo-header checksum, independent of the
	 * server generation.
	 */
	fn ReceiveAck(acknowledgment: uint, now: uint)
	{
		var sum: int = 0x141D
		sum = 0x141D

		for (var i = 34; i < 54; i = i + 2) {
			var high = this.AckByte(i, acknowledgment)
			var low = this.AckByte(i + 1, acknowledgment)
			sum = sum + NetworkOrder.Word(high, low)
		}

		var checksum = ChecksumArithmetic.Finish(sum)

		if (this.data.IsReady()) {
			this.data.TryRelease()
		} else {
			this.data.TryClear()
		}

		for (var i = 0; i < 60; i++) {
			var value = this.AckByte(i, acknowledgment)

			if (i == 50) {
				value = NetworkOrder.HighByte(checksum)
			}

			if (i == 51) {
				value = NetworkOrder.LowByte(checksum)
			}

			assert this.data.TryWrite(i, value) == PacketDataResult.Success
		}

		assert this.data.TryPublish() == PacketDataResult.Success
		assert this.server.TryHandle(now)
	}

	/**
	 * Keeps an acknowledged stream open across long idle periods and resumes both byte directions.
	 */
	public fn ResumesAfterLongIdle()
	{
		this.server.Abort()
		this.Receive(0, 0)
		assert this.server.Poll(0)
		this.server.ReleaseFrame()
		this.Receive(1, 10)
		assert this.server.IsConnected()
		assert !this.server.Poll(300011)
		assert this.server.IsConnected()
		assert !this.server.Poll(3600010)
		assert this.server.IsConnected()
		this.Receive(2, 3600020)
		var value: byte = 0
		assert this.server.TryReceive(value) && value == 97
		assert this.server.TryReceive(value) && value == 98
		assert this.server.TryReceive(value) && value == 99
		assert !this.server.TryReceive(value)
		assert this.server.TryTransmit(65, 3600030)
		assert this.server.Poll(3600040)
		assert this.ByteAt(47) == 0x18
		assert this.ByteAt(54) == 65
		this.server.ReleaseFrame()
		this.server.Abort()
	}

	/**
	 * Bounds unanswered handshake retries even though acknowledged idle streams stay connected.
	 */
	public fn AbandonsUnansweredHandshakeAfterRetryLimit()
	{
		this.server.Abort()
		this.Receive(0, 0)
		assert this.server.Poll(0)
		this.server.ReleaseFrame()

		for (var retry = 1; retry <= 8; retry++) {
			assert this.server.Poll((retry * 60000) as uint)
			assert this.ByteAt(47) == 0x12
			this.server.ReleaseFrame()
		}

		assert !this.server.Poll(540000)
		assert this.server.GetState() == TcpStreamState.Listening
	}

	/**
	 * Checks SYN-ACK retry and the conservative initial data timeout after handshake loss.
	 */
	public fn LostHandshakeAndDataTimeout()
	{
		this.server.Abort()
		this.Receive(0, 0)
		assert this.server.Poll(0)
		var acknowledgment = (this.ByteAt(38) as uint) << 24
		acknowledgment = acknowledgment | ((this.ByteAt(39) as uint) << 16)
		acknowledgment = acknowledgment | ((this.ByteAt(40) as uint) << 8)
		acknowledgment = acknowledgment | (this.ByteAt(41) as uint)
		acknowledgment++
		this.server.ReleaseFrame()
		assert !this.server.Poll(999)
		assert this.server.Poll(1000)
		assert this.ByteAt(47) == 0x12
		this.server.ReleaseFrame()
		this.ReceiveAck(acknowledgment, 1010)
		assert this.server.IsConnected()
		assert this.server.TryTransmit(65, 2000)
		assert this.server.Poll(2010)
		this.server.ReleaseFrame()
		assert !this.server.Poll(5009)
		assert this.server.Poll(5010)
		assert this.ByteAt(54) == 65
		this.server.ReleaseFrame()
	}
}