Don't crash on broken FLUTE messages. Instead, discard them.
This commit is contained in:
parent
f83b920af4
commit
d95d8c0235
@ -72,6 +72,9 @@ namespace skyscraper8.Ietf.FLUTE
|
||||
if (blocks == null)
|
||||
blocks = new Dictionary<Tuple<ushort, ushort>, FluteBlock>();
|
||||
|
||||
if (lctFrame.FecHeader == null)
|
||||
return;
|
||||
|
||||
ushort sbn = lctFrame.FecHeader.SourceBlockNumber;
|
||||
ushort esi = lctFrame.FecHeader.EncodingSymbolId;
|
||||
|
||||
|
||||
@ -1,9 +1,11 @@
|
||||
using skyscraper5.Skyscraper.IO;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using skyscraper5.Skyscraper;
|
||||
|
||||
namespace skyscraper8.Ietf.FLUTE
|
||||
{
|
||||
@ -25,7 +27,10 @@ namespace skyscraper8.Ietf.FLUTE
|
||||
this.CloseObjectFlag = (byteB & 0x01) != 0;
|
||||
|
||||
if (this.Version != 1)
|
||||
throw new NotSupportedException(String.Format("FLUTE Version {0}", Version));
|
||||
{
|
||||
Debug.WriteLine(String.Format("FLUTE Version {0}", Version));
|
||||
return;
|
||||
}
|
||||
|
||||
int HeaderLength = ms.ReadUInt8();
|
||||
HeaderLength *= 4;
|
||||
@ -35,6 +40,8 @@ namespace skyscraper8.Ietf.FLUTE
|
||||
|
||||
byte[] headerBuffer = ms.ReadBytes(HeaderLength);
|
||||
this.LctHeader = new LctHeader(headerBuffer,CongestionControlFlag,TransportSessionIdentifierFlag,TransportObjectIdentifierFlag,HalfWordFlag);
|
||||
if (!this.LctHeader.Valid)
|
||||
return;
|
||||
|
||||
if (ms.GetAvailableBytes() < 4)
|
||||
return;
|
||||
|
||||
@ -2,13 +2,15 @@
|
||||
using skyscraper8.DvbNip;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using skyscraper5.Skyscraper;
|
||||
|
||||
namespace skyscraper8.Ietf.FLUTE
|
||||
{
|
||||
internal class LctHeader
|
||||
internal class LctHeader : Validatable
|
||||
{
|
||||
/// <summary>
|
||||
///
|
||||
@ -32,6 +34,11 @@ namespace skyscraper8.Ietf.FLUTE
|
||||
CongestionControlInformation = ReadField(ms, cciLength);
|
||||
TransportSessionIdentifier = ReadField(ms, tsiLength);
|
||||
TransportObjectIdentifier = ReadField(ms, toiLength);
|
||||
if (CongestionControlInformation == UInt64.MaxValue || TransportSessionIdentifier == UInt64.MaxValue || TransportObjectIdentifier == UInt64.MaxValue)
|
||||
{
|
||||
Valid = false;
|
||||
return;
|
||||
}
|
||||
|
||||
while (ms.GetAvailableBytes() >= 1)
|
||||
{
|
||||
@ -49,7 +56,9 @@ namespace skyscraper8.Ietf.FLUTE
|
||||
this.ContentEncoding = new ContentEncodingOfFdtInstance(fixedHeaderExtension);
|
||||
break;
|
||||
default:
|
||||
throw new NotImplementedException(String.Format("LCT Header Extension {0}", extensionId));
|
||||
Debug.WriteLine(String.Format("LCT Header Extension {0}", extensionId));
|
||||
Valid = false;
|
||||
return;
|
||||
}
|
||||
}
|
||||
else
|
||||
@ -58,6 +67,11 @@ namespace skyscraper8.Ietf.FLUTE
|
||||
headerExtensionLength *= 4;
|
||||
if (headerExtensionLength >= 2)
|
||||
headerExtensionLength -= 2;
|
||||
if (headerExtensionLength > ms.GetAvailableBytes())
|
||||
{
|
||||
Valid = false;
|
||||
return;
|
||||
}
|
||||
byte[] extensionBuffer = ms.ReadBytes(headerExtensionLength);
|
||||
switch(extensionId)
|
||||
{
|
||||
@ -73,11 +87,15 @@ namespace skyscraper8.Ietf.FLUTE
|
||||
this.NipActualCarrierInformation = new NipActualCarrierInformation(extensionBuffer);
|
||||
break;
|
||||
default:
|
||||
throw new NotImplementedException(String.Format("LCT Header Extension {0}", extensionId));
|
||||
Debug.WriteLine(String.Format("LCT Header Extension {0}", extensionId));
|
||||
Valid = false;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Valid = true;
|
||||
}
|
||||
|
||||
private ulong ReadField(Stream stream, int bits)
|
||||
@ -93,7 +111,7 @@ namespace skyscraper8.Ietf.FLUTE
|
||||
case 64:
|
||||
return stream.ReadUInt64BE();
|
||||
default:
|
||||
throw new NotImplementedException(String.Format("{0} bits.", bits));
|
||||
return UInt64.MaxValue;
|
||||
}
|
||||
}
|
||||
public ulong CongestionControlInformation { get; private set; }
|
||||
|
||||
@ -40,7 +40,7 @@ namespace skyscraper5
|
||||
class Program
|
||||
{
|
||||
private static readonly ILog logger = LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType.Name);
|
||||
private const int PUBLIC_RELEASE = 8;
|
||||
private const int PUBLIC_RELEASE = 9;
|
||||
private static void IntegrationTest()
|
||||
{
|
||||
/*List<SsdpDevice> ssdpDevices = SsdpClient.GetSsdpDevices(1000).ToList();
|
||||
|
||||
@ -2,7 +2,7 @@
|
||||
"profiles": {
|
||||
"skyscraper8": {
|
||||
"commandName": "Project",
|
||||
"commandLineArgs": "\"C:\\devel\\skyscraper8\\skyscraper8\\bin\\Debug\\net8.0\\638938290099956387.ts\"",
|
||||
"commandLineArgs": "satip auto 1 H 11141 S2 23500",
|
||||
"remoteDebugEnabled": false
|
||||
},
|
||||
"Container (Dockerfile)": {
|
||||
|
||||
@ -20,7 +20,7 @@ namespace skyscraper8
|
||||
internal class QuickAndDirtySatIpClient
|
||||
{
|
||||
private static readonly ILog logger = LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType.Name);
|
||||
private const bool ENABLE_TS_WRITER = true;
|
||||
private const bool ENABLE_TS_WRITER = false;
|
||||
|
||||
public QuickAndDirtySatIpClient(string[] args)
|
||||
{
|
||||
@ -106,6 +106,11 @@ namespace skyscraper8
|
||||
|
||||
packetQueue = new Queue<byte[]>();
|
||||
RtspSetupResponse setup = rtspClient.GetSetup(url);
|
||||
if (setup.RtspStatusCode == 404)
|
||||
{
|
||||
logger.Fatal("Your SAT>IP server doesn't have a tuner available that can talk to the requested frequency.");
|
||||
return;
|
||||
}
|
||||
setup.OnRtcpPacket += Setup_OnRtcpPacket;
|
||||
setup.OnRtpPacket += Setup_OnRtpPacket;
|
||||
|
||||
|
||||
@ -1,12 +1,14 @@
|
||||
using System;
|
||||
using skyscraper5.Mpeg2;
|
||||
using skyscraper5.Skyscraper;
|
||||
using skyscraper5.Skyscraper.IO;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Net.NetworkInformation;
|
||||
using System.Net.Sockets;
|
||||
using System.Runtime.Serialization;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using skyscraper5.Mpeg2;
|
||||
using skyscraper5.Skyscraper;
|
||||
using skyscraper5.Skyscraper.IO;
|
||||
|
||||
namespace skyscraper8.Skyscraper
|
||||
{
|
||||
@ -15,6 +17,7 @@ namespace skyscraper8.Skyscraper
|
||||
private bool interruptedGseHem;
|
||||
private MemoryStream interruptedGseHemBuffer;
|
||||
private bool interruptedGseHemWantsCrc32;
|
||||
public IGsEventHandler MpeEventHandler { get; set; }
|
||||
|
||||
public void PushPacket(byte[] bbframe)
|
||||
{
|
||||
@ -49,37 +52,202 @@ namespace skyscraper8.Skyscraper
|
||||
}
|
||||
}
|
||||
|
||||
private bool isGseSynced;
|
||||
private int gseNeeded;
|
||||
private MemoryStream gseNeededBuffer;
|
||||
private bool gseNeedMore;
|
||||
private MemoryStream gseAssembler;
|
||||
public int PID;
|
||||
|
||||
private void HandleGse(MemoryStream ms)
|
||||
{
|
||||
if (!isGseSynced)
|
||||
ms.Position = 10;
|
||||
byte syncByte = ms.ReadUInt8();
|
||||
ms.Position = 10;
|
||||
|
||||
long availableBytes = ms.GetAvailableBytes();
|
||||
byte[] readBytes = ms.ReadBytes(availableBytes);
|
||||
|
||||
GseAssemblyState assemblyState = ValidateGse(gseAssembler);
|
||||
if (assemblyState == GseAssemblyState.NOT_YET_BEGUN)
|
||||
{
|
||||
ms.Position = 10;
|
||||
byte syncByte = ms.ReadUInt8();
|
||||
ms.Position = 10;
|
||||
if ((syncByte & 0xc0) == 0xc0)
|
||||
{
|
||||
isGseSynced = true;
|
||||
//Aktuell ist der GSE Assembler nicht beschäftigt, aber wir haben ein Sync-Byte, also kann er loslegen.
|
||||
gseAssembler = new MemoryStream();
|
||||
gseAssembler.Write(readBytes, 0, readBytes.Length);
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
//Aktuell ist der GSE Assembler nicht beschäftigt, und wir haben kein gültiges Sync-Byte, also weg damit.
|
||||
//Console.WriteLine("gse not in sync yet. sync byte = {0}", syncByte);
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (gseNeeded > 0)
|
||||
else if (assemblyState == GseAssemblyState.NEED_MORE_DATA)
|
||||
{
|
||||
int blockSize = (int)System.Math.Min(gseNeeded, ms.GetAvailableBytes());
|
||||
gseNeededBuffer.Write(ms.ReadBytes(blockSize), 0, blockSize);
|
||||
gseNeeded -= blockSize;
|
||||
if (gseNeeded == 0)
|
||||
gseAssembler.Write(readBytes, 0, readBytes.Length);
|
||||
return;
|
||||
}
|
||||
else if (assemblyState == GseAssemblyState.VALID)
|
||||
{
|
||||
gseAssembler.Position = 0;
|
||||
AssembleGse(gseAssembler);
|
||||
//Console.WriteLine("assembled {0} next sync byte is {1}", sucessfulAssembles++,syncByte);
|
||||
if (sucessfulAssembles == 181)
|
||||
{
|
||||
int payloadSize = (int)gseNeededBuffer.Position;
|
||||
gseNeededBuffer.Position = 0;
|
||||
byte[] payloadBuffer = gseNeededBuffer.ReadBytes(payloadSize);
|
||||
|
||||
}
|
||||
gseAssembler = null;
|
||||
HandleGse(ms);
|
||||
return;
|
||||
}
|
||||
else if (assemblyState == GseAssemblyState.BROKEN_SUSPECT_ETHERTYPE)
|
||||
{
|
||||
gseAssembler = null;
|
||||
HandleGse(ms);
|
||||
return;
|
||||
}
|
||||
else if (assemblyState == GseAssemblyState.BROKEN_NEGATIVE_LENGTH)
|
||||
{
|
||||
gseAssembler = null;
|
||||
HandleGse(ms);
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new NotImplementedException(String.Format("Unknown GSE assembler state: {0}, sync byte 0x{1}", assemblyState, syncByte));
|
||||
}
|
||||
}
|
||||
|
||||
private long sucessfulAssembles;
|
||||
enum GseAssemblyState
|
||||
{
|
||||
NOT_YET_BEGUN,
|
||||
VALID,
|
||||
BROKEN_NEGATIVE_LENGTH,
|
||||
NEED_MORE_DATA,
|
||||
BROKEN_SUSPECT_LENGTH,
|
||||
BROKEN_SUSPECT_ETHERTYPE
|
||||
}
|
||||
|
||||
private GseAssemblyState ValidateGse(MemoryStream ms)
|
||||
{
|
||||
if (ms == null)
|
||||
return GseAssemblyState.NOT_YET_BEGUN;
|
||||
|
||||
long backupPosition = ms.Position;
|
||||
ms.Position = 0;
|
||||
while (ms.GetAvailableBytes() > 2)
|
||||
{
|
||||
//GSE-Header
|
||||
byte byteA = ms.ReadUInt8();
|
||||
bool startIndicator = (byteA & 0x80) != 0;
|
||||
bool endIndicator = (byteA & 0x40) != 0;
|
||||
int labelIndicator = (byteA & 0x30) >> 4;
|
||||
if (!startIndicator && !endIndicator && labelIndicator == 0)
|
||||
{
|
||||
//end of base band frame
|
||||
ms.Position = backupPosition;
|
||||
return GseAssemblyState.VALID;
|
||||
}
|
||||
else
|
||||
{
|
||||
byte byteB = ms.ReadUInt8();
|
||||
int gseLength = byteA & 0x0f;
|
||||
gseLength <<= 8;
|
||||
gseLength += byteB;
|
||||
//Console.WriteLine("GSE Length: {0}", gseLength);
|
||||
if (gseLength > 9000)
|
||||
{
|
||||
ms.Position = backupPosition;
|
||||
return GseAssemblyState.BROKEN_SUSPECT_LENGTH;
|
||||
}
|
||||
|
||||
if (!startIndicator || !endIndicator)
|
||||
{
|
||||
byte fragId = ms.ReadUInt8();
|
||||
gseLength--;
|
||||
}
|
||||
|
||||
if (startIndicator && !endIndicator)
|
||||
{
|
||||
ushort totalLength = ms.ReadUInt16BE();
|
||||
gseLength -= 2;
|
||||
}
|
||||
|
||||
if (startIndicator)
|
||||
{
|
||||
if (2 > ms.GetAvailableBytes())
|
||||
{
|
||||
ms.Position = backupPosition;
|
||||
return GseAssemblyState.NEED_MORE_DATA;
|
||||
}
|
||||
ushort protocolType = ms.ReadUInt16BE();
|
||||
if (!ValidateEthertype(protocolType))
|
||||
{
|
||||
ms.Position = backupPosition;
|
||||
return GseAssemblyState.BROKEN_SUSPECT_ETHERTYPE;
|
||||
}
|
||||
gseLength -= 2;
|
||||
if (labelIndicator == 0)
|
||||
{
|
||||
if (6 > ms.GetAvailableBytes())
|
||||
{
|
||||
ms.Position = backupPosition;
|
||||
return GseAssemblyState.NEED_MORE_DATA;
|
||||
}
|
||||
PhysicalAddress sixByteLabel = new PhysicalAddress(ms.ReadBytes(6));
|
||||
gseLength -= 6;
|
||||
}
|
||||
else if (labelIndicator == 1)
|
||||
{
|
||||
byte[] threeByteLabel = ms.ReadBytes(3);
|
||||
gseLength -= 3;
|
||||
}
|
||||
}
|
||||
|
||||
if (!startIndicator && endIndicator)
|
||||
gseLength -= 4;
|
||||
|
||||
int startCrc32 = (int)ms.Position;
|
||||
|
||||
if (gseLength < 0)
|
||||
{
|
||||
ms.Position = backupPosition;
|
||||
return GseAssemblyState.BROKEN_NEGATIVE_LENGTH;
|
||||
}
|
||||
|
||||
if (gseLength > ms.GetAvailableBytes())
|
||||
{
|
||||
ms.Position = backupPosition;
|
||||
return GseAssemblyState.NEED_MORE_DATA;
|
||||
}
|
||||
|
||||
ms.Position += gseLength;
|
||||
if (!startIndicator && endIndicator)
|
||||
{
|
||||
uint crc32 = ms.ReadUInt32BE();
|
||||
int endCrc32 = (int)ms.Position;
|
||||
DvbCrc32.ValidateCrc(ms, startCrc32, endCrc32);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ms.Position = backupPosition;
|
||||
return GseAssemblyState.VALID;
|
||||
}
|
||||
|
||||
private bool ValidateEthertype(ushort ethertype)
|
||||
{
|
||||
if (ethertype == 0x0800)
|
||||
return true; //IPv4
|
||||
if (ethertype == 0x86DD)
|
||||
return true; //IPv6
|
||||
else
|
||||
return false; //There are many more valid values, but since we don't speak anything aside from IPv4/IPv6, we discard it.
|
||||
}
|
||||
private void AssembleGse(MemoryStream ms)
|
||||
{
|
||||
ushort protocolType = 0;
|
||||
while (ms.GetAvailableBytes() > 2)
|
||||
{
|
||||
//GSE-Header
|
||||
@ -98,7 +266,7 @@ namespace skyscraper8.Skyscraper
|
||||
int gseLength = byteA & 0x0f;
|
||||
gseLength <<= 8;
|
||||
gseLength += byteB;
|
||||
|
||||
|
||||
if (!startIndicator || !endIndicator)
|
||||
{
|
||||
byte fragId = ms.ReadUInt8();
|
||||
@ -113,7 +281,7 @@ namespace skyscraper8.Skyscraper
|
||||
|
||||
if (startIndicator)
|
||||
{
|
||||
ushort protocolType = ms.ReadUInt16BE();
|
||||
protocolType = ms.ReadUInt16BE();
|
||||
gseLength -= 2;
|
||||
if (labelIndicator == 0)
|
||||
{
|
||||
@ -131,15 +299,7 @@ namespace skyscraper8.Skyscraper
|
||||
gseLength -= 4;
|
||||
|
||||
int startCrc32 = (int)ms.Position;
|
||||
|
||||
if (gseLength > ms.GetAvailableBytes())
|
||||
{
|
||||
gseNeeded = gseLength;
|
||||
gseNeededBuffer = new MemoryStream();
|
||||
gseNeeded -= (int)ms.GetAvailableBytes();
|
||||
gseNeededBuffer.Write(ms.ReadBytes(ms.GetAvailableBytes()));
|
||||
return;
|
||||
}
|
||||
|
||||
byte[] payload = ms.ReadBytes(gseLength);
|
||||
if (!startIndicator && endIndicator)
|
||||
{
|
||||
@ -148,9 +308,19 @@ namespace skyscraper8.Skyscraper
|
||||
DvbCrc32.ValidateCrc(ms, startCrc32, endCrc32);
|
||||
}
|
||||
|
||||
|
||||
switch (protocolType)
|
||||
{
|
||||
case 0x0800: //IPv4
|
||||
MpeEventHandler.OnIpDatagram(PID, payload);
|
||||
break;
|
||||
default:
|
||||
//throw new NotImplementedException(String.Format("Unknown GSE Protocol ID 0x{0:X4}", protocolType));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@ -40,36 +40,13 @@ namespace skyscraper5.src.Skyscraper
|
||||
{
|
||||
byte[] chi = outbuf.ToArray();
|
||||
if (deencapsulator == null)
|
||||
{
|
||||
deencapsulator = new BbframeDeencapsulator();
|
||||
deencapsulator.MpeEventHandler = mpeEventHandler;
|
||||
deencapsulator.PID = pid;
|
||||
}
|
||||
|
||||
deencapsulator.PushPacket(chi);
|
||||
/*List<byte[]> ipPackets = IpPacketFinder.LookForIpPackets(outbuf.ToArray());
|
||||
if (ipPackets != null)
|
||||
{
|
||||
foreach (byte[] ipPacket in ipPackets)
|
||||
{
|
||||
mpeEventHandler.OnIpDatagram(0x118, ipPacket);
|
||||
packetsRecovered++;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
packetsLost++;
|
||||
}*/
|
||||
/*byte[] ipPacket = IpPacketFinder.LookForIpPacket(outbuf.ToArray(), 32);
|
||||
if (ipPacket != null)
|
||||
{
|
||||
if (!annoncementDone)
|
||||
{
|
||||
mpeEventHandler.GsIpTrafficDetected();
|
||||
annoncementDone = true;
|
||||
}
|
||||
mpeEventHandler.OnIpDatagram(0x0118, ipPacket);
|
||||
packetsRecovered++;
|
||||
}
|
||||
else
|
||||
{
|
||||
packetsLost++;
|
||||
}*/
|
||||
}
|
||||
outbuf = new MemoryStream();
|
||||
outbuf.Write(packets,9, packets[7] - 1);
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user