skyscraper8/skyscraper8/GS/GSE/GseReader.cs

145 lines
5.3 KiB
C#

using log4net;
using skyscraper5.Dvb.DataBroadcasting;
using skyscraper5.Skyscraper.IO;
namespace skyscraper8.GSE.GSE;
internal class GseReader : IMisHandler
{
private GseLabel lastLabel;
public IMultiprotocolEncapsulationEventHandler mpeEventHandler { get; set; }
private static readonly ILog logger = LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType.Name);
public void PushFrame(BBHeader bbHeader, ReadOnlySpan<byte> readOnlySpan)
{
MemoryStream ms = new MemoryStream(readOnlySpan.ToArray());
while (ms.Position < ms.Length)
{
byte a = ms.ReadUInt8();
bool startIndicator = (a & 0x80) != 0;
bool endIndicator = (a & 0x40) != 0;
int labelTypeIndicator = (a & 0x30) >> 4;
if (!startIndicator && !endIndicator && labelTypeIndicator == 0)
{
//end of BBFrame
return;
}
else
{
int gseLength = (a & 0x0f);
gseLength <<= 8;
gseLength += ms.ReadUInt8();
GsePacket child = new GsePacket(startIndicator, endIndicator, labelTypeIndicator);
if (!startIndicator || !endIndicator)
{
child.FragmentId = ms.ReadUInt8();
gseLength--;
}
if (startIndicator && !endIndicator)
{
child.TotalLength = ms.ReadUInt16BE();
gseLength -= 2;
}
if (startIndicator)
{
child.ProtocolType = ms.ReadUInt16BE();
gseLength -= 2;
if (!endIndicator)
child.TotalLength -= 2;
switch (labelTypeIndicator)
{
case 0:
child.Label = new _6byteLabel(ms.ReadBytes(6));
gseLength -= 6;
if (!endIndicator)
child.TotalLength -= 6;
lastLabel = child.Label;
break;
case 1:
child.Label = new _3byteLabel(ms.ReadBytes(3));
gseLength -= 3;
if (!endIndicator)
child.TotalLength -= 3;
lastLabel = child.Label;
break;
case 2:
child.Label = BroadcastLabel.GetInstance();
break;
case 3:
child.Label = this.lastLabel;
break;
default:
throw new NotImplementedException(String.Format("Unknown label type: {0}", labelTypeIndicator));
}
}
if (!startIndicator && endIndicator)
gseLength -= 4; //for crc32
if (gseLength > ms.GetAvailableBytes())
return;
child.GseDataBytes = ms.ReadBytes(gseLength);
if (!startIndicator && endIndicator)
child.Crc32 = ms.ReadUInt32BE();
ProcessPacket(child);
}
}
}
private bool[] warnedEthertypes;
private GseFragmentation[] fragmentations;
private void ProcessPacket(GsePacket child)
{
if (!child.StartIndicator && child.EndIndicator)
{
if (fragmentations == null)
return;
GseFragmentation currentFragmentation = fragmentations[child.FragmentId.Value];
if (currentFragmentation == null)
return;
currentFragmentation.AddFragement(child);
if (currentFragmentation.Validate())
{
mpeEventHandler.OnIpDatagram(0x010e,currentFragmentation.GetGseDataBytes());
}
fragmentations[child.FragmentId.Value] = null;
return;
}
if (child.StartIndicator && !child.EndIndicator)
{
if (fragmentations == null)
fragmentations = new GseFragmentation[256];
fragmentations[child.FragmentId.Value] = new GseFragmentation(child);
return;
}
if (child.StartIndicator && child.EndIndicator)
{
switch (child.ProtocolType)
{
case 0x0800:
mpeEventHandler.OnIpDatagram(0x010e, child.GseDataBytes);
break;
default:
if (warnedEthertypes == null)
warnedEthertypes = new bool[0xffff];
if (!warnedEthertypes[child.ProtocolType.Value])
{
logger.WarnFormat("This GSE contains other traffic types (type {0:X4}) besides IP (type 0x0800). If it's not too much trouble, please consider submitting a sample.",child.ProtocolType.Value);
warnedEthertypes[child.ProtocolType.Value] = true;
}
break;
}
return;
}
throw new NotImplementedException(child.ToString());
}
}