Added a rudimentary ULE deframer.

This commit is contained in:
feyris-tan 2025-07-19 22:44:49 +02:00
parent 0453a7115a
commit 8c76f9a421
5 changed files with 293 additions and 0 deletions

View File

@ -0,0 +1,24 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using skyscraper5;
namespace skyscraper8.Ietf
{
public class IetfException : SkyscraperException
{
public IetfException()
{
}
public IetfException(string message) : base(message)
{
}
public IetfException(string message, Exception inner) : base(message, inner)
{
}
}
}

View File

@ -0,0 +1,46 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.NetworkInformation;
using System.Text;
using System.Threading.Tasks;
using skyscraper5.Skyscraper.Plugins;
using skyscraper5.Skyscraper.Scraper;
using skyscraper5.Skyscraper.Scraper.StreamAutodetection;
namespace skyscraper8.Ietf.Rfc4236_ULE
{
[SkyscraperPlugin]
internal class UleContestant : Contestant, UleEventHandler
{
public UleContestant(int pid) : base("ULE", pid)
{
PacketProcessor = new UlePacketProcessor(pid, this);
}
public override void Dispose()
{
throw new NotImplementedException();
}
public override void DeclareWinner(SkyscraperContext skyscraperContext, int pid, ProgramContext programContext)
{
throw new NotImplementedException();
}
public override void Introduce(ProgramContext programContext)
{
throw new NotImplementedException();
}
public void OnEthernetFrame(int pid, PhysicalAddress destination, PhysicalAddress source, ushort etherType, byte[] contents)
{
Score++;
}
public void OnUleError(int pid, int errorNo)
{
Score--;
}
}
}

View File

@ -0,0 +1,24 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.NetworkInformation;
using System.Text;
using System.Threading.Tasks;
namespace skyscraper8.Ietf.Rfc4236_ULE
{
internal interface UleEventHandler
{
void OnEthernetFrame(int pid, PhysicalAddress destination, PhysicalAddress source, ushort etherType, byte[] contents);
/// <summary>
/// The UlePacketProcessor is supposed to call this whenever an Error occurs during deframing.
/// </summary>
/// <param name="pid">The source PID of the ULE ES</param>
/// <param name="errorNo">
/// Set this to:
/// 1* for a CRC error.
/// </param>
void OnUleError(int pid, int errorNo);
}
}

View File

@ -0,0 +1,23 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace skyscraper8.Ietf.Rfc4236_ULE
{
public class UleException : IetfException
{
public UleException()
{
}
public UleException(string message) : base(message)
{
}
public UleException(string message, Exception inner) : base(message, inner)
{
}
}
}

View File

@ -0,0 +1,176 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.NetworkInformation;
using System.Text;
using System.Threading.Tasks;
using skyscraper5.Mpeg2;
using skyscraper5.Skyscraper.IO;
namespace skyscraper8.Ietf.Rfc4236_ULE
{
internal class UlePacketProcessor : ITsPacketProcessor, IPayloadUnitDecoder
{
private readonly int _pid;
private readonly UleEventHandler _eventHandler;
private bool reassemblyMode;
private int reassemblyRemainingBytes;
private MemoryStream reassemblyStream;
private long offset;
public UlePacketProcessor(int pid, UleEventHandler eventHandler)
{
_pid = pid;
_eventHandler = eventHandler;
}
public void PushPacket(TsPacket packet)
{
if (packet.PayloadUnitStart)
{
PushPusiPacket(packet);
}
else
{
if (reassemblyMode)
{
int availableBytes = Math.Min(184, reassemblyRemainingBytes);
reassemblyStream.Write(packet.RawPacket, 4, availableBytes);
reassemblyRemainingBytes -= availableBytes;
if (reassemblyRemainingBytes == 0)
{
reassemblyMode = false;
reassemblyStream.Position = 0;
OnReassembledPacket(reassemblyStream);
reassemblyStream = null;
}
}
else
{
//Es gibt keine neue Payload Unit, und wir bauen uns auch keine zusammen, also diese wegwerfen.
return;
}
}
offset += 188;
}
private void PushPusiPacket(TsPacket packet)
{
bool multipleSndusInPacket = false;
MemoryStream payload = new MemoryStream(packet.RawPacket, false);
payload.Position += 4;
byte nextPacketOffset = payload.ReadUInt8();
if (!reassemblyMode)
payload.Position += nextPacketOffset;
while (payload.GetAvailableBytes() > 0)
{
if (reassemblyMode)
{
int availableBytes = Math.Min((int)payload.GetAvailableBytes(), reassemblyRemainingBytes);
byte[] stepBuffer = new byte[availableBytes];
int sucessfullyCopiedBytes = payload.Read(stepBuffer, 0, availableBytes);
if (sucessfullyCopiedBytes != availableBytes)
throw new UleException("Byte copy operation failed during reassembly.");
reassemblyStream.Write(stepBuffer, 0, sucessfullyCopiedBytes);
reassemblyRemainingBytes -= sucessfullyCopiedBytes;
if (reassemblyRemainingBytes == 0)
{
reassemblyMode = false;
reassemblyStream.Position = 0;
OnReassembledPacket(reassemblyStream);
reassemblyStream = null;
multipleSndusInPacket = true;
}
}
else
{
if (payload.GetAvailableBytes() == 1)
{
/*"If only one byte remains unprocessed in the TS Packet payload
after completion of the Current SNDU, the Receiver MUST discard this
final byte of TS Packet payload."*/
break;
}
byte lengthByteA = payload.ReadUInt8();
bool destinationAddressAbsent = (lengthByteA & 0x80) != 0;
byte lengthByteB = payload.ReadUInt8();
int length = lengthByteA & 0x7f;
length <<= 8;
length += lengthByteB;
length += 2;
if (length == 0x8001)
{
break;
}
reassemblyMode = true;
reassemblyRemainingBytes = length;
reassemblyStream = new MemoryStream();
reassemblyStream.WriteUInt8(lengthByteA);
reassemblyStream.WriteUInt8(lengthByteB);
}
}
}
private void OnReassembledPacket(MemoryStream ms)
{
bool crc = DvbCrc32.ValidateCrc(ms, 0, (int)ms.Length);
if (!crc)
{
_eventHandler.OnUleError(_pid, 1);
return;
}
byte lengthByteA = ms.ReadUInt8();
bool destinationAddressAbsent = (lengthByteA & 0x80) != 0;
byte lengthBytesB = ms.ReadUInt8();
ushort typeField = ms.ReadUInt16BE();
PhysicalAddress destAddress = null;
if (!destinationAddressAbsent)
destAddress = new PhysicalAddress(ms.ReadBytes(6));
long packetSize = ms.GetAvailableBytes() - 4;
byte[] pdu = ms.ReadBytes(packetSize);
uint crc32 = ms.ReadUInt32BE();
switch (typeField)
{
case 1:
OnBridgedFrame(pdu);
break;
default:
throw new NotImplementedException(String.Format("ULE Type 0x{0:X4}", typeField));
}
}
private void OnBridgedFrame(byte[] pdu)
{
MemoryStream ms = new MemoryStream(pdu, false);
PhysicalAddress destination = new PhysicalAddress(ms.ReadBytes(6));
PhysicalAddress source = new PhysicalAddress(ms.ReadBytes(6));
ushort etherType = ms.ReadUInt16BE();
byte[] contents = ms.ReadBytes(ms.GetAvailableBytes());
//_eventHandler.OnEthernetFrame(_pid, destination, source, etherType, contents);
}
public void PacketLoss()
{
reassemblyMode = false;
reassemblyRemainingBytes = 0;
reassemblyStream = null;
}
}
}