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/packet/PacketHeader.lvt
namespace Livt.Net
/**
* Internal fixed-header cache and bounded payload view.
* The owner invalidates descendants before reloading or releasing the source.
* Only the header is copied; payload reads remain scheduled source operations.
*/
component PacketHeader<S: IPacketData, SIZE: int> : IPacketData
{
// Borrowed provider; reads and payload views share its publication lifetime.
source: S
// Owned header snapshot and validation state.
const HEADER_BITS: int = SIZE * 8
const LOAD_BITS: int = Bits.RequiredFor(SIZE)
header: logic[HEADER_BITS]
loaded: bool
opened: bool
// Opened payload bounds relative to the borrowed provider.
payloadOffset: int
payloadLength: int
/**
* Binds stable packet storage.
*/
new(source: S)
{
this.source = source
}
/**
* Invalidates both the cache and its payload view before source reuse.
*/
public fn Invalidate()
{
loaded = false
opened = false
payloadLength = 0
}
/**
* Reads the fixed header once; any failure discards the prior cache.
*/
public fn TryLoad() PacketParseResult
{
this.Invalidate()
if (!source.IsReady()) {
return PacketParseResult.NotReady
}
var captured = source.GetAvailableLength()
if (captured < SIZE) {
return PacketParseResult.Truncated
}
for (var i: logic[LOAD_BITS] = 0; ((i as uint) as int) < SIZE; i++) {
var value: byte = 0x00
var result = source.TryRead((i as uint) as int, value)
if (result != PacketDataResult.Success) {
return PacketParseResult.NotReady
}
// A constant shift appends one byte without an indexed array write.
header = (header << 8) | ((value as uint) as logic[HEADER_BITS])
}
loaded = true
return PacketParseResult.Success
}
/**
* Returns source capture size, never a wire-length claim.
*/
public fn GetCapturedLength() int
{
return source.GetAvailableLength()
}
/**
* Reads a cached octet for internal protocol decoding.
*/
public fn GetByte(index: int) byte
{
if (!loaded || !source.IsReady() || index < 0 || index >= SIZE) {
return 0x00
}
return this.ByteAt(header, index)
}
/**
* Decodes an unsigned network-order word from the cache.
*/
public fn GetWord(index: int) int
{
var high = this.GetByte(index)
var low = this.GetByte(index + 1)
return NetworkOrder.Word(high, low)
}
/**
* Decodes a network-order sequence number without signed overflow.
*/
public fn GetSequence(index: int) uint
{
var high = this.GetWord(index)
var low = this.GetWord(index + 2)
return ((high as uint) << 16) | (low as uint)
}
/**
* Opens only a range contained in the captured prefix.
*/
public fn TryOpenPayload(offset: int, length: int) PacketParseResult
{
opened = false
var available = source.GetAvailableLength()
if (!loaded || !source.IsReady()) {
return PacketParseResult.NotReady
}
if (offset < SIZE || offset > available || length < 0 || length > available - offset) {
return PacketParseResult.Invalid
}
payloadOffset = offset
payloadLength = length
opened = true
return PacketParseResult.Success
}
/**
* Reports whether validated payload bounds are available.
*/
override fn IsReady() bool
{
return opened && source.IsReady()
}
/**
* Returns the captured payload length, excluding enclosing padding.
*/
override fn GetAvailableLength() int
{
if (!this.IsReady()) {
return 0
}
return payloadLength
}
/**
* Reads a payload-relative byte without copying payload storage.
*/
override fn TryRead(index: int, value: out byte) PacketDataResult
{
value = 0x00
if (!this.IsReady()) {
return PacketDataResult.NotReady
}
if (index < 0 || index >= payloadLength) {
return PacketDataResult.Invalid
}
var readValue: byte = 0x00
var result = source.TryRead(payloadOffset + index, readValue)
value = readValue
return result
}
/** Pure selection from a fully loaded network-order shift register. */
inline fn ByteAt[](snapshot: logic[HEADER_BITS], index: int) byte
{
if (index < 0 || index >= SIZE) { return 0x00 }
return (snapshot >> ((SIZE - 1 - index) << 3)) as byte
}
}