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/services/ArpService.lvt

namespace Livt.Net

/**
 * Owns a checked ARP response graph and keeps it immutable until explicit release.
 * Borrows request storage and an admission strategy. The successful response is
 * independent of RX; all request views close before TryHandle returns.
 */
component ArpService<S: IPacketData, A: IFrameAcceptance> : IResponseService
{
	// Borrowed source, policy and shared parsers; the response graph is owned.
	source: S
	acceptance: A
	ethernet: EthernetFrameParser<S>
	response: ArpResponder<S>

	// Endpoint configuration and publication state, owned by this service.
	localMac: byte[6]
	localIp: byte[4]
	ready: bool

	/**
	 * Borrows source, policy and shared parsers; creates an unpublished response.
	 * Parsers must bind this source in the same clock/reset domain. Serialize
	 * all parser users and close their descendants before handling a request.
	 */
	new(source: S, ethernet: EthernetFrameParser<S>, acceptance: A, localMac: byte[6], localIp: byte[4])
	{
		this.source = source
		this.acceptance = acceptance
		this.localMac = localMac
		this.localIp = localIp
		this.ethernet = ethernet
		this.response = new ArpResponder<S>(ethernet)
	}

	/**
	 * Prepares one supported local request; Busy preserves all previous bytes.
	 * Rejected/failed requests close their views and leave no published response.
	 */
	override fn TryHandle() ServiceResult
	{
		if (this.ready) {
			return ServiceResult.Busy
		}

		if (!this.source.IsReady()) {
			return ServiceResult.NotReady
		}

		this.ethernet.TryParse()

		if (!this.ethernet.IsReady()) {
			this.ethernet.Invalidate()
			return ServiceResult.Invalid
		}

		if (this.ethernet.GetEtherType() != IEthernetPayload.ETHER_TYPE_ARP) {
			this.ethernet.Invalidate()
			return ServiceResult.Ignored
		}

		var peer = this.ethernet.GetSourceMac()

		if (!this.acceptance.Accept(peer, IEthernetPayload.ETHER_TYPE_ARP)) {
			this.ethernet.Invalidate()
			return ServiceResult.Ignored
		}

		var result = this.response.TryPrepareParsed(this.localMac, this.localIp)

		if (result != PacketDataResult.Success) {
			this.response.Invalidate()
			return ServiceResult.Ignored
		}

		this.ready = true
		return ServiceResult.Prepared
	}

	/**
	 * Drops the response only after the caller has ended all response borrows.
	 */
	override fn TryReleaseResponse() PacketDataResult
	{
		if (!this.ready) {
			return PacketDataResult.Invalid
		}

		this.ready = false
		this.response.Invalidate()
		return PacketDataResult.Success
	}

	/**
	 * Reports this service's publication, not mere internal preparation progress.
	 */
	override fn IsReady() bool
	{
		return this.ready
	}

	/**
	 * Returns complete padded frame bytes, or zero before publication.
	 */
	override fn GetAvailableLength() int
	{
		if (!this.ready) {
			return 0
		}

		return this.response.GetAvailableLength()
	}

	/**
	 * Reads a published response byte; output is data only on Success.
	 */
	override fn TryRead(index: int, value: out byte) PacketDataResult
	{
		value = 0x00

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

		return this.response.TryRead(index, value)
	}
}