181 lines
4.7 KiB
C#
181 lines
4.7 KiB
C#
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.AdaptionFieldControl != 1)
|
|
{
|
|
_eventHandler.OnUleError(_pid, 2);
|
|
return;
|
|
}
|
|
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;
|
|
}
|
|
|
|
|
|
}
|
|
}
|