Livt packages

Livt.Net

Version 1.4.1

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

Published files (163)

src/tcp/TcpConnectionRecognizer.lvt

namespace Livt.Net

/**
 * Recognizes endpoint policy over one parsed Ethernet/IPv4/TCP graph.
 */
component TcpConnectionRecognizer<S: IPacketData> : IPacketData
{
	// Borrowed shared parser pair and owned TCP descendant.
	ethernet: EthernetFrameParser<S>
	ipv4: Ipv4PacketParser<EthernetFrameParser<S>>
	tcp: TcpHeaderParser<Ipv4PacketParser<EthernetFrameParser<S>>>

	// Validation state for the current recognition lifetime.
	status: PacketParseResult

	/**
	 * Borrows the shared Ethernet/IPv4 pair; creates only the TCP descendant.
	 * One serialized owner must invalidate this descendant before reusing either parser.
	 */
	new(ethernet: EthernetFrameParser<S>, ipv4: Ipv4PacketParser<EthernetFrameParser<S>>)
	{
		this.ethernet = ethernet
		this.ipv4 = ipv4
		tcp = new TcpHeaderParser<Ipv4PacketParser<EthernetFrameParser<S>>>(ipv4)
	}

	/**
	 * Closes descendants before ancestors; call before source release or reuse.
	 */
	public fn Invalidate()
	{
		tcp.Invalidate()
		ipv4.Invalidate()
		ethernet.Invalidate()
		status = PacketParseResult.NotReady
	}

	/**
	 * Parses once; HeaderOnly preserves incomplete IP capture explicitly. No checksum enforcement.
	 */
	public fn TryParse() PacketParseResult
	{
		this.Invalidate()
		status = ethernet.TryParse()

		if (!ethernet.IsReady()) {
			return status
		}

		if (ethernet.GetEtherType() != IEthernetPayload.ETHER_TYPE_IPV4) {
			status = PacketParseResult.Unsupported
			return status
		}

		status = ipv4.TryParse()

		if (!ipv4.IsReady()) {
			return status
		}

		if (ipv4.GetProtocol() != IIpv4Payload.PROTOCOL_TCP) {
			status = PacketParseResult.Unsupported
			return status
		}

		var tcpStatus = tcp.TryParse()

		if (tcpStatus != PacketParseResult.Success) {
			status = tcpStatus
		}

		return status
	}

	/**
	 * Returns structural status without implying checksum or wire-length validation.
	 */
	public fn GetStatus() PacketParseResult
	{
		if ((status == PacketParseResult.Success || status == PacketParseResult.HeaderOnly) && !tcp.IsReady()) {
			return PacketParseResult.NotReady
		}

		return status
	}

	/**
	 * Applies endpoint policy separately from structural parsing.
	 */
	public fn IsForEndpoint(localIp: byte[4], localPort: int) bool
	{
		if (!this.IsReady()) {
			return false
		}

		var destination = ipv4.GetDestinationIpv4()

		if (destination[0] != localIp[0] || destination[1] != localIp[1] || destination[2] != localIp[2] || destination[3] != localIp[3]) {
			return false
		}

		return tcp.GetDestinationPort() == localPort
	}

	/**
	 * Recognizes the supported flags and endpoint; SYN options are accepted but not interpreted.
	 */
	public fn IsSynRequest(localIp: byte[4], localPort: int) bool
	{
		return this.IsForEndpoint(localIp, localPort) && tcp.GetFlags() == 2
	}

	/**
	 * Recognizes the supported flags and endpoint; SYN options are accepted but not interpreted.
	 */
	public fn IsAckOnlyPacket(localIp: byte[4], localPort: int) bool
	{
		return this.IsForEndpoint(localIp, localPort) && tcp.GetFlags() == 16 && tcp.GetHeaderLength() == 20
	}

	/**
	 * Recognizes the supported flags and endpoint; SYN options are accepted but not interpreted.
	 */
	public fn IsPshAckPacket(localIp: byte[4], localPort: int) bool
	{
		return this.IsForEndpoint(localIp, localPort) && tcp.GetFlags() == 24 && tcp.GetHeaderLength() == 20
	}

	/** Returns the peer MAC only while the complete protocol graph is usable. */
	public fn GetSourceMac() byte[6]
	{
		var empty: byte[6] = [0x00, 0x00, 0x00, 0x00, 0x00, 0x00]

		if (!this.IsReady()) {
			return empty
		}

		return this.ethernet.GetSourceMac()
	}

	/**
	 * Returns cached metadata only while the composed parse is usable.
	 */
	public fn GetSourceIpv4() byte[4]
	{
		var empty: byte[4] = [0x00, 0x00, 0x00, 0x00]

		if (!this.IsReady()) {
			return empty
		}

		return ipv4.GetSourceIpv4()
	}

	/**
	 * Returns cached metadata only while the composed parse is usable.
	 */
	public fn GetSourcePort() int
	{
		if (!this.IsReady()) {
			return 0
		}

		return tcp.GetSourcePort()
	}

	/**
	 * Returns cached metadata only while the composed parse is usable.
	 */
	public fn GetSequenceNumber() uint
	{
		if (!this.IsReady()) {
			return 0
		}

		return tcp.GetSequenceNumber()
	}

	/**
	 * Returns cached metadata only while the composed parse is usable.
	 */
	public fn GetDeclaredPayloadLength() int
	{
		if (!this.IsReady()) {
			return 0
		}

		return ipv4.GetDeclaredPayloadLength() - tcp.GetHeaderLength()
	}

	/**
	 * Reports supported headers, allowing a captured prefix of the payload.
	 */
	override fn IsReady() bool
	{
		return (status == PacketParseResult.Success || status == PacketParseResult.HeaderOnly) && tcp.IsReady()
	}

	/**
	 * Returns captured TCP payload size, excluding enclosing padding.
	 */
	override fn GetAvailableLength() int
	{
		if (!this.IsReady()) {
			return 0
		}

		return tcp.GetAvailableLength()
	}

	/**
	 * Reads the bounded TCP payload. The source remains borrowed until invalidation.
	 */
	override fn TryRead(index: int, value: out byte) PacketDataResult
	{
		value = 0x00

		if (!this.IsReady()) {
			return PacketDataResult.NotReady
		}

		var readValue: byte = 0x00
		var result = tcp.TryRead(index, readValue)
		value = readValue
		return result
	}
}