145 lines
5.3 KiB
C#
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());
|
|
}
|
|
} |