diff --git a/skyscraper8.Tests/IntegrationTests.cs b/skyscraper8.Tests/IntegrationTests.cs
index a71c8f2..c9d595a 100644
--- a/skyscraper8.Tests/IntegrationTests.cs
+++ b/skyscraper8.Tests/IntegrationTests.cs
@@ -1,5 +1,6 @@
using System;
using System.IO;
+using Microsoft.VisualStudio.TestTools.UnitTesting;
using skyscraper5.Skyscraper;
using skyscraper8.Skyscraper.Scraper.Storage.Tar;
@@ -14,7 +15,9 @@ public class IntegrationTests
string filename = String.Format("{0}.tar", DateTime.Now.ToUnixTime());
FileInfo fi = new FileInfo(filename);
FileStream fileStream = fi.Open(FileMode.OpenOrCreate, FileAccess.ReadWrite, FileShare.Read);
-
+ fi.Refresh();
+ Assert.IsTrue(fi.Exists);
+
Random rng = new Random();
TarArchive tar = new TarArchive(fileStream);
@@ -29,4 +32,4 @@ public class IntegrationTests
tar.WriteEntry(filename, buffer);
}
}
-}
+}
\ No newline at end of file
diff --git a/skyscraper8.Tests/ResourceTests/Ses12GseTest.cs b/skyscraper8.Tests/ResourceTests/Ses12GseTest.cs
new file mode 100644
index 0000000..1b5c307
--- /dev/null
+++ b/skyscraper8.Tests/ResourceTests/Ses12GseTest.cs
@@ -0,0 +1,19 @@
+using Microsoft.VisualStudio.TestTools.UnitTesting;
+using skyscraper8.GS;
+using skyscraper8.GS.GSE_RollingSyncByte;
+using skyscraper8.GSE;
+
+namespace skyscraper8.Tests.ResourceTests;
+
+[TestClass]
+public class Ses12GseTest
+{
+ [TestMethod]
+ public void TestShortPdu()
+ {
+ byte[] datasource = Resources1.Frame00000357_TSGS1_MIS000_SYNC184;
+ GsContextDto dto = new GsContextDto();
+ GseWithRollingSyncByteReader reader = new GseWithRollingSyncByteReader(dto);
+ reader.PushFrame(new BBHeader(new byte[10], 0), datasource);
+ }
+}
diff --git a/skyscraper8.Tests/Resources/Frame00000357_TSGS1_MIS000_SYNC184.bbframe b/skyscraper8.Tests/Resources/Frame00000357_TSGS1_MIS000_SYNC184.bbframe
new file mode 100644
index 0000000..c8c694d
Binary files /dev/null and b/skyscraper8.Tests/Resources/Frame00000357_TSGS1_MIS000_SYNC184.bbframe differ
diff --git a/skyscraper8.Tests/Resources1.Designer.cs b/skyscraper8.Tests/Resources1.Designer.cs
index de7a55d..8910987 100644
--- a/skyscraper8.Tests/Resources1.Designer.cs
+++ b/skyscraper8.Tests/Resources1.Designer.cs
@@ -1,10 +1,9 @@
//------------------------------------------------------------------------------
//
-// Dieser Code wurde von einem Tool generiert.
-// Laufzeitversion:4.0.30319.42000
+// This code was generated by a tool.
//
-// Änderungen an dieser Datei können falsches Verhalten verursachen und gehen verloren, wenn
-// der Code erneut generiert wird.
+// Changes to this file may cause incorrect behavior and will be lost if
+// the code is regenerated.
//
//------------------------------------------------------------------------------
@@ -12,46 +11,32 @@ namespace skyscraper8.Tests {
using System;
- ///
- /// Eine stark typisierte Ressourcenklasse zum Suchen von lokalisierten Zeichenfolgen usw.
- ///
- // Diese Klasse wurde von der StronglyTypedResourceBuilder automatisch generiert
- // -Klasse über ein Tool wie ResGen oder Visual Studio automatisch generiert.
- // Um einen Member hinzuzufügen oder zu entfernen, bearbeiten Sie die .ResX-Datei und führen dann ResGen
- // mit der /str-Option erneut aus, oder Sie erstellen Ihr VS-Projekt neu.
- [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "17.0.0.0")]
- [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
- [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
+ [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "17.0.0.0")]
+ [System.Diagnostics.DebuggerNonUserCodeAttribute()]
+ [System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
internal class Resources1 {
- private static global::System.Resources.ResourceManager resourceMan;
+ private static System.Resources.ResourceManager resourceMan;
- private static global::System.Globalization.CultureInfo resourceCulture;
+ private static System.Globalization.CultureInfo resourceCulture;
- [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
+ [System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
internal Resources1() {
}
- ///
- /// Gibt die zwischengespeicherte ResourceManager-Instanz zurück, die von dieser Klasse verwendet wird.
- ///
- [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
- internal static global::System.Resources.ResourceManager ResourceManager {
+ [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Advanced)]
+ internal static System.Resources.ResourceManager ResourceManager {
get {
- if (object.ReferenceEquals(resourceMan, null)) {
- global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("skyscraper8.Tests.Resources1", typeof(Resources1).Assembly);
+ if (object.Equals(null, resourceMan)) {
+ System.Resources.ResourceManager temp = new System.Resources.ResourceManager("skyscraper8.Tests.Resources1", typeof(Resources1).Assembly);
resourceMan = temp;
}
return resourceMan;
}
}
- ///
- /// Überschreibt die CurrentUICulture-Eigenschaft des aktuellen Threads für alle
- /// Ressourcenzuordnungen, die diese stark typisierte Ressourcenklasse verwenden.
- ///
- [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
- internal static global::System.Globalization.CultureInfo Culture {
+ [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Advanced)]
+ internal static System.Globalization.CultureInfo Culture {
get {
return resourceCulture;
}
@@ -60,39 +45,6 @@ namespace skyscraper8.Tests {
}
}
- ///
- /// Sucht eine lokalisierte Ressource vom Typ System.Byte[].
- ///
- internal static byte[] Frame00000008_TSGS1_MIS000_SYNC001 {
- get {
- object obj = ResourceManager.GetObject("Frame00000008_TSGS1_MIS000_SYNC001", resourceCulture);
- return ((byte[])(obj));
- }
- }
-
- ///
- /// Sucht eine lokalisierte Ressource vom Typ System.Byte[].
- ///
- internal static byte[] Frame00000012_TSGS1_MIS000_SYNC001 {
- get {
- object obj = ResourceManager.GetObject("Frame00000012_TSGS1_MIS000_SYNC001", resourceCulture);
- return ((byte[])(obj));
- }
- }
-
- ///
- /// Sucht eine lokalisierte Ressource vom Typ System.Byte[].
- ///
- internal static byte[] Frame00001343_TSGS1_MIS000_SYNC001 {
- get {
- object obj = ResourceManager.GetObject("Frame00001343_TSGS1_MIS000_SYNC001", resourceCulture);
- return ((byte[])(obj));
- }
- }
-
- ///
- /// Sucht eine lokalisierte Ressource vom Typ System.Byte[].
- ///
internal static byte[] ModemCapabilitiesEncodingTest {
get {
object obj = ResourceManager.GetObject("ModemCapabilitiesEncodingTest", resourceCulture);
@@ -100,9 +52,6 @@ namespace skyscraper8.Tests {
}
}
- ///
- /// Sucht eine lokalisierte Ressource vom Typ System.Byte[].
- ///
internal static byte[] MultipartRegistrationResponseTest {
get {
object obj = ResourceManager.GetObject("MultipartRegistrationResponseTest", resourceCulture);
@@ -110,19 +59,6 @@ namespace skyscraper8.Tests {
}
}
- ///
- /// Sucht eine lokalisierte Ressource vom Typ System.Byte[].
- ///
- internal static byte[] MultipartRegistrationResponseTest2 {
- get {
- object obj = ResourceManager.GetObject("MultipartRegistrationResponseTest2", resourceCulture);
- return ((byte[])(obj));
- }
- }
-
- ///
- /// Sucht eine lokalisierte Ressource vom Typ System.Byte[].
- ///
internal static byte[] PushMacManagementMessage_Version4_Type45 {
get {
object obj = ResourceManager.GetObject("PushMacManagementMessage_Version4_Type45", resourceCulture);
@@ -130,9 +66,6 @@ namespace skyscraper8.Tests {
}
}
- ///
- /// Sucht eine lokalisierte Ressource vom Typ System.Byte[].
- ///
internal static byte[] ranging_response_test {
get {
object obj = ResourceManager.GetObject("ranging_response_test", resourceCulture);
@@ -140,19 +73,13 @@ namespace skyscraper8.Tests {
}
}
- ///
- /// Sucht eine lokalisierte Ressource vom Typ System.Byte[].
- ///
- internal static byte[] sdpTest {
+ internal static byte[] MultipartRegistrationResponseTest2 {
get {
- object obj = ResourceManager.GetObject("sdpTest", resourceCulture);
+ object obj = ResourceManager.GetObject("MultipartRegistrationResponseTest2", resourceCulture);
return ((byte[])(obj));
}
}
- ///
- /// Sucht eine lokalisierte Ressource vom Typ System.Byte[].
- ///
internal static byte[] test_1packet_01 {
get {
object obj = ResourceManager.GetObject("test-1packet-01", resourceCulture);
@@ -160,9 +87,6 @@ namespace skyscraper8.Tests {
}
}
- ///
- /// Sucht eine lokalisierte Ressource vom Typ System.Byte[].
- ///
internal static byte[] test_2packets_02_03 {
get {
object obj = ResourceManager.GetObject("test-2packets-02-03", resourceCulture);
@@ -170,9 +94,6 @@ namespace skyscraper8.Tests {
}
}
- ///
- /// Sucht eine lokalisierte Ressource vom Typ System.Byte[].
- ///
internal static byte[] test_3packets_04_05_06 {
get {
object obj = ResourceManager.GetObject("test-3packets-04-05-06", resourceCulture);
@@ -180,9 +101,6 @@ namespace skyscraper8.Tests {
}
}
- ///
- /// Sucht eine lokalisierte Ressource vom Typ System.Byte[].
- ///
internal static byte[] TransmitChannelConfigurationObject {
get {
object obj = ResourceManager.GetObject("TransmitChannelConfigurationObject", resourceCulture);
@@ -190,14 +108,46 @@ namespace skyscraper8.Tests {
}
}
- ///
- /// Sucht eine lokalisierte Ressource vom Typ System.Byte[].
- ///
internal static byte[] UpstreamChannelDescriptorTest {
get {
object obj = ResourceManager.GetObject("UpstreamChannelDescriptorTest", resourceCulture);
return ((byte[])(obj));
}
}
+
+ internal static byte[] Frame00001343_TSGS1_MIS000_SYNC001 {
+ get {
+ object obj = ResourceManager.GetObject("Frame00001343_TSGS1_MIS000_SYNC001", resourceCulture);
+ return ((byte[])(obj));
+ }
+ }
+
+ internal static byte[] Frame00000008_TSGS1_MIS000_SYNC001 {
+ get {
+ object obj = ResourceManager.GetObject("Frame00000008_TSGS1_MIS000_SYNC001", resourceCulture);
+ return ((byte[])(obj));
+ }
+ }
+
+ internal static byte[] Frame00000012_TSGS1_MIS000_SYNC001 {
+ get {
+ object obj = ResourceManager.GetObject("Frame00000012_TSGS1_MIS000_SYNC001", resourceCulture);
+ return ((byte[])(obj));
+ }
+ }
+
+ internal static byte[] sdpTest {
+ get {
+ object obj = ResourceManager.GetObject("sdpTest", resourceCulture);
+ return ((byte[])(obj));
+ }
+ }
+
+ internal static byte[] Frame00000357_TSGS1_MIS000_SYNC184 {
+ get {
+ object obj = ResourceManager.GetObject("Frame00000357_TSGS1_MIS000_SYNC184", resourceCulture);
+ return ((byte[])(obj));
+ }
+ }
}
}
diff --git a/skyscraper8.Tests/Resources1.resx b/skyscraper8.Tests/Resources1.resx
index 906044f..7aca4aa 100644
--- a/skyscraper8.Tests/Resources1.resx
+++ b/skyscraper8.Tests/Resources1.resx
@@ -160,4 +160,7 @@
Resources\sdpTest.sdp;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
-
\ No newline at end of file
+
+ Resources\Frame00000357_TSGS1_MIS000_SYNC184.bbframe;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
diff --git a/skyscraper8.sln.DotSettings.user b/skyscraper8.sln.DotSettings.user
index 883ca52..b1b6d7e 100644
--- a/skyscraper8.sln.DotSettings.user
+++ b/skyscraper8.sln.DotSettings.user
@@ -1,6 +1,7 @@
ForceIncluded
ForceIncluded
+ ForceIncluded
ForceIncluded
ForceIncluded
ForceIncluded
@@ -39,7 +40,7 @@
<Assembly Path="/home/schiemas/.nuget/packages/allure.net.commons/2.14.1/lib/netstandard2.0/Allure.Net.Commons.dll" />
</AssemblyExplorer>
/home/schiemas/.cache/JetBrains/Rider2025.1/resharper-host/temp/Rider/vAny/CoverageData/_skyscraper8.1808907683/Snapshot/snapshot.utdcvr
- <SessionState ContinuousTestingMode="0" IsActive="True" Name="All tests from <skyscraper8.Tests>" xmlns="urn:schemas-jetbrains-com:jetbrains-ut-session">
+ <SessionState ContinuousTestingMode="0" Name="All tests from <skyscraper8.Tests>" xmlns="urn:schemas-jetbrains-com:jetbrains-ut-session">
<And>
<Namespace>skyscraper8.Tests</Namespace>
<Project Location="\home\schiemas\RiderProjects\skyscraper8\skyscraper8.Tests" Presentation="<skyscraper8.Tests>" />
@@ -59,4 +60,5 @@
<data><HostParameters type="LocalHostParameters" /><Argument type="StandaloneArgument"><Arguments IsNull="False"></Arguments><FileName IsNull="False"></FileName><WorkingDirectory IsNull="False"></WorkingDirectory><Scope><ProcessFilters /></Scope></Argument><Info type="TimelineInfo" /><CoreOptions type="CoreOptions"><CoreTempPath IsNull="False"></CoreTempPath><RemoteEndPoint IsNull="False"></RemoteEndPoint><AdditionalEnvironmentVariables /></CoreOptions><HostOptions type="HostOptions"><HostTempPath IsNull="False"></HostTempPath></HostOptions></data>
True
- True
+ True
+ False
diff --git a/skyscraper8/GS/BBHeader.cs b/skyscraper8/GS/BBHeader.cs
index 13228a3..93bd58c 100644
--- a/skyscraper8/GS/BBHeader.cs
+++ b/skyscraper8/GS/BBHeader.cs
@@ -79,4 +79,9 @@ public class BBHeader : Validatable
/// 3 = Transport
///
public int TsGs { get; private set; }
+
+ public override string ToString()
+ {
+ return String.Format("TsGs: {0}, SyncByte: {1}, UPL: {2}", TsGs, SyncByte,UserPacketLength);
+ }
}
\ No newline at end of file
diff --git a/skyscraper8/GS/BBframeDeencapsulator3.cs b/skyscraper8/GS/BBframeDeencapsulator3.cs
index 094202e..a827251 100644
--- a/skyscraper8/GS/BBframeDeencapsulator3.cs
+++ b/skyscraper8/GS/BBframeDeencapsulator3.cs
@@ -22,7 +22,7 @@ class BbframeDeencapsulator3 : IBbframeDeencapsulator
{
if (numPushed == 0)
{
- logger.InfoFormat("The stream started in the middle of a BBFrame, let's skip to the start of the next one.");
+ logger.InfoFormat("The stream started in the middle of a BBFrame, let's wait for the next one to start.");
}
return;
}
@@ -36,8 +36,7 @@ class BbframeDeencapsulator3 : IBbframeDeencapsulator
mis = new IMisHandler[256];
if (mis[bbHeader.Matype2] == null)
{
- logger.InfoFormat("Found a stream on MIS {0}",bbHeader.Matype2);
- mis[bbHeader.Matype2] = new GsTypeDetector(context.MisClone(bbHeader.Matype2));
+ mis[bbHeader.Matype2] = new MisHandlerProxy(context.MisClone(bbHeader.Matype2));
}
mis[bbHeader.Matype2].PushFrame(bbHeader, new ReadOnlySpan(bbframe, 11, bbframe.Length - 11));
diff --git a/skyscraper8/GS/GSE-RollingSyncByte/GseWithRollingSyncByteReader.cs b/skyscraper8/GS/GSE-RollingSyncByte/GseWithRollingSyncByteReader.cs
new file mode 100644
index 0000000..60e11e5
--- /dev/null
+++ b/skyscraper8/GS/GSE-RollingSyncByte/GseWithRollingSyncByteReader.cs
@@ -0,0 +1,185 @@
+using log4net;
+using skyscraper5.Skyscraper.IO;
+using skyscraper8.GSE;
+using skyscraper8.GSE.GSE;
+
+namespace skyscraper8.GS.GSE_RollingSyncByte;
+
+public class GseWithRollingSyncByteReader : IMisHandler
+{
+ public GsContextDto Context { get; set; }
+
+ private ulong packetSerial;
+ private GseLabel reuse;
+
+ private static readonly ILog logger = LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType.Name);
+ public void PushFrame(BBHeader bbHeader, ReadOnlySpan readOnlySpan)
+ {
+ packetSerial++;
+ byte[] array = readOnlySpan.ToArray();
+ MemoryStream ms = new MemoryStream(array, 0, array.Length - 4);
+ while (ms.GetAvailableBytes() > 0)
+ {
+ byte a = ms.ReadUInt8();
+ bool startIndicator = (a & 0x80) != 0;
+ bool endIndicator = (a & 0x40) != 0;
+ int labelTypeIndicator = (a & 0x30) >> 4;
+ GsePacket gsePacket = new GsePacket(startIndicator, endIndicator, labelTypeIndicator);
+ if (!startIndicator && !endIndicator && labelTypeIndicator == 0)
+ {
+ return;
+ }
+ else
+ {
+ byte b = ms.ReadUInt8();
+ int gseLength = (a & 0x0f) << 8;
+ gseLength += b;
+ int gseRemain = gseLength - 2;
+ if (!startIndicator || !endIndicator)
+ {
+ gsePacket.FragmentId = ms.ReadUInt8();
+ gseRemain--;
+ }
+
+ if (startIndicator && !endIndicator)
+ {
+ gsePacket.TotalLength = ms.ReadUInt16BE();
+ gseRemain -= 2;
+ }
+
+ if (startIndicator)
+ {
+ gsePacket.ProtocolType = ms.ReadUInt16BE();
+ gseRemain -= 2;
+ switch (labelTypeIndicator)
+ {
+ case 0:
+ if (ms.GetAvailableBytes() < 6)
+ return; //The MAC address is sliced in half. I have my doubts that this is even allowed.
+ gsePacket.Label = new _6byteLabel(ms.ReadBytes(6));
+ reuse = gsePacket.Label;
+ gseRemain -= 6;
+ break;
+ case 1:
+ gsePacket.Label = new _3byteLabel(ms.ReadBytes(3));
+ reuse = gsePacket.Label;
+ gseRemain -= 3;
+ break;
+ case 2:
+ gsePacket.Label = BroadcastLabel.GetInstance();
+ break;
+ case 3:
+ gsePacket.Label = reuse;
+ break;
+ }
+ }
+
+ int payloadSize = gseRemain;
+ if (!startIndicator && endIndicator)
+ payloadSize -= 4;
+
+ gsePacket.GseDataBytes = ms.ReadBytes(payloadSize);
+ gseRemain -= payloadSize;
+
+ if (!startIndicator && endIndicator)
+ {
+ gsePacket.Crc32 = ms.ReadUInt32BE();
+ gseRemain -= 4;
+ }
+ }
+
+ ProcessPacket(gsePacket);
+ }
+ }
+
+ private bool[] warnedEthertypes;
+ private GseFragmentation[] fragments;
+
+ public GseWithRollingSyncByteReader(GsContextDto context)
+ {
+ this.Context = context;
+ }
+
+ private void ProcessPacket(GsePacket gsePacket)
+ {
+ if (gsePacket.LabelTypeIndicator == 3 && gsePacket.Label == null)
+ return;
+
+ if (!gsePacket.StartIndicator && gsePacket.EndIndicator)
+ {
+ if (fragments == null)
+ return;
+ if (fragments[gsePacket.FragmentId.Value] == null)
+ return;
+
+ if (fragments[gsePacket.FragmentId.Value].Validate())
+ {
+ byte[] gseDataBytes = fragments[gsePacket.FragmentId.Value].GetGseDataBytes();
+ HandleAssembledFrame(fragments[gsePacket.FragmentId.Value].ProtocolType, gseDataBytes, fragments[gsePacket.FragmentId.Value].Label);
+ }
+ }
+
+ if (gsePacket.StartIndicator && gsePacket.EndIndicator)
+ {
+ Context.InformTrafficType(gsePacket.ProtocolType.Value);
+ HandleAssembledFrame(gsePacket.ProtocolType.Value, gsePacket.GseDataBytes, gsePacket.Label);
+ return;
+ }
+
+ if (gsePacket.StartIndicator && !gsePacket.EndIndicator)
+ {
+ if (fragments == null)
+ fragments = new GseFragmentation[256];
+ fragments[gsePacket.FragmentId.Value] = new GseFragmentation(gsePacket);
+ return;
+ }
+
+ if (!gsePacket.StartIndicator && !gsePacket.EndIndicator)
+ {
+ if (fragments == null)
+ return;
+ if (fragments[gsePacket.FragmentId.Value] == null)
+ return;
+ fragments[gsePacket.FragmentId.Value].AddFragement(gsePacket);
+ return;
+ }
+
+ throw new NotImplementedException();
+ }
+
+ private ulong aolSerial;
+ private void HandleProprietaryAolJunk(byte[] buffer, ushort protocolType)
+ {
+ aolSerial++;
+ string dumpPath = String.Format("{0}{1}{2}.bin", protocolType, Path.DirectorySeparatorChar, aolSerial);
+ FileInfo dumpFile = new FileInfo(dumpPath);
+ dumpFile.Directory.EnsureExists();
+ File.WriteAllBytes(dumpFile.FullName, buffer);
+ }
+
+ private void HandleAssembledFrame(ushort protocolType, byte[] buffer, GseLabel label)
+ {
+ switch (protocolType)
+ {
+ case 0x0002:
+ case 0x0004:
+ HandleProprietaryAolJunk(buffer,protocolType);
+ return;
+ case 0x0091:
+ //according to https://www.iana.org/assignments/ule-next-headers/ule-next-headers.xhtml it's private
+ return;
+ case 0x0800:
+ Context.IpOutput.OnIpDatagram(0x010e, buffer);
+ return;
+ default:
+ if (warnedEthertypes == null)
+ warnedEthertypes = new bool[ushort.MaxValue];
+ if (!warnedEthertypes[protocolType])
+ {
+ logger.WarnFormat("This GSE contains other traffic types (type 0x{0:X4}) besides IP (type 0x0800). If it's not too much trouble, please consider submitting a sample.",protocolType);
+ warnedEthertypes[protocolType] = true;
+ }
+ return;
+ }
+ }
+}
diff --git a/skyscraper8/GS/GSE/GseReader.cs b/skyscraper8/GS/GSE/GseReader.cs
index 8a7f6c8..089bd07 100644
--- a/skyscraper8/GS/GSE/GseReader.cs
+++ b/skyscraper8/GS/GSE/GseReader.cs
@@ -7,6 +7,10 @@ namespace skyscraper8.GSE.GSE;
internal class GseReader : IMisHandler
{
+ public GseReader(GsContextDto dto)
+ {
+ this.Context = dto;
+ }
private GseLabel lastLabel;
private static readonly ILog logger = LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType.Name);
diff --git a/skyscraper8/GS/GsContextDto.cs b/skyscraper8/GS/GsContextDto.cs
index dd8434b..feb6d84 100644
--- a/skyscraper8/GS/GsContextDto.cs
+++ b/skyscraper8/GS/GsContextDto.cs
@@ -10,7 +10,7 @@ using skyscraper8.Skyscraper.Scraper;
namespace skyscraper8.GS
{
- internal class GsContextDto
+ public class GsContextDto
{
public GsContextMisDto MisClone(byte mis)
{
@@ -39,9 +39,21 @@ namespace skyscraper8.GS
public IMultiprotocolEncapsulationEventHandler IpOutput { get; set; }
public InteractionChannelHandler Rcs2Output { get; set; }
+
+ private Dictionary trafficTypes;
+ public void InformTrafficType(ushort trafficType)
+ {
+ if (trafficTypes == null)
+ trafficTypes = new Dictionary();
+
+ if (!trafficTypes.ContainsKey(trafficType))
+ trafficTypes.Add(trafficType, 1);
+ else
+ trafficTypes[trafficType]++;
+ }
}
- internal class GsContextMisDto : GsContextDto
+ public class GsContextMisDto : GsContextDto
{
public byte Mis { get; }
diff --git a/skyscraper8/GS/GsTypeDetector.cs b/skyscraper8/GS/GsTypeDetector.cs
deleted file mode 100644
index a8280a0..0000000
--- a/skyscraper8/GS/GsTypeDetector.cs
+++ /dev/null
@@ -1,109 +0,0 @@
-using log4net;
-using skyscraper5.Dvb.DataBroadcasting;
-using skyscraper8.GS;
-using skyscraper8.GS.GSE_BFBS;
-using skyscraper8.GS.SiminnRadiomidun;
-using skyscraper8.GSE.GSE_HEM;
-using skyscraper8.GSE.GSE;
-using skyscraper8.Skyscraper.Scraper;
-
-namespace skyscraper8.GSE;
-
-class GsTypeDetector : IMisHandler
-{
- public GsContextDto Context { get; set; }
- private readonly ILog logger;
- private HashSet> _postedStreamTypes;
-
- public GsTypeDetector(GsContextMisDto context)
- {
- this.logger = LogManager.GetLogger(String.Format("{0} MIS {1}",System.Reflection.MethodBase.GetCurrentMethod().DeclaringType.Name,context.Mis));
- this.Context = context;
- }
-
- private GseReader gseReader;
- private GseHemReader gseHemReader;
- private SiminnRadiomidunReader siminnRadiomidunReader;
- private BfbsGseReader bfbsGseReader;
- private int simminRadiomidunScore;
- private int bfbsScore;
-
- public void PushFrame(BBHeader bbHeader, ReadOnlySpan readOnlySpan)
- {
- if (readOnlySpan.Length == 0)
- {
- return;
- }
-
- if (bbHeader.TsGs == 1 && bbHeader.SyncByte == 0)
- {
- //Looks like Continuous GSE.
- if (gseReader == null)
- {
- gseReader = new GseReader();
- gseReader.Context = Context;
- }
-
- gseReader.PushFrame(bbHeader, readOnlySpan);
- return;
- }
-
- if (bbHeader.TsGs == 2 && bbHeader.SyncByte == 0)
- {
- //Looks like GSE-HEM
- if (gseHemReader == null)
- {
- gseHemReader = new GseHemReader(Context);
- }
- gseHemReader.PushFrame(bbHeader, readOnlySpan);
- return;
- }
-
- if (bbHeader.TsGs == 0 && bbHeader.SyncByte == 71 && bbHeader.UserPacketLength == 188)
- {
- simminRadiomidunScore++;
- if (simminRadiomidunScore > 10)
- {
- //Looks like a Simmin Radiomidun-like stream.
- if (siminnRadiomidunReader == null)
- {
- //These behave similar to T2-MI. Interesting.
- siminnRadiomidunReader = new SiminnRadiomidunReader(Context);
- }
-
- siminnRadiomidunReader.PushFrame(bbHeader, readOnlySpan);
- return;
- }
-
- return;
- }
- else
- {
- if (simminRadiomidunScore < 10)
- {
- simminRadiomidunScore = 0;
- }
- }
-
- if (bbHeader.TsGs == 1 && bbHeader.SyncByte == 1 && bbHeader.UserPacketLength == 0)
- {
- if (bfbsGseReader == null)
- {
- bfbsGseReader = new BfbsGseReader(Context);
- }
-
- bfbsGseReader.PushFrame(bbHeader, readOnlySpan);
- return;
- }
-
- //We have no idea what this is.
- Tuple streamTypeToPost = new Tuple(bbHeader.TsGs, bbHeader.SyncByte);
- if (_postedStreamTypes == null)
- _postedStreamTypes = new HashSet>();
- if (!_postedStreamTypes.Contains(streamTypeToPost))
- {
- logger.WarnFormat("This GS contains packets of type {0} ({2}) with a sync byte of {1}. This is not supported yet. If it isn't too much trouble, please consider sharing a sample of this stream.",streamTypeToPost.Item1,streamTypeToPost.Item2, (TsGsType)streamTypeToPost.Item1);
- _postedStreamTypes.Add(streamTypeToPost);
- }
- }
-}
\ No newline at end of file
diff --git a/skyscraper8/GS/MisHandlerProxy.cs b/skyscraper8/GS/MisHandlerProxy.cs
new file mode 100644
index 0000000..c5842bb
--- /dev/null
+++ b/skyscraper8/GS/MisHandlerProxy.cs
@@ -0,0 +1,190 @@
+using log4net;
+using skyscraper5.Mpeg2;
+using skyscraper8.GS;
+using skyscraper8.GS.GSE_BFBS;
+using skyscraper8.GS.GSE_RollingSyncByte;
+using skyscraper8.GS.SiminnRadiomidun;
+using skyscraper8.GSE.GSE_HEM;
+using skyscraper8.GSE.GSE;
+
+namespace skyscraper8.GSE;
+
+class MisHandlerProxy : IMisHandler
+{
+ public GsContextDto Context { get; set; }
+ private readonly ILog logger;
+ private HashSet> _postedStreamTypes;
+
+ public MisHandlerProxy(GsContextMisDto context)
+ {
+ this.logger = LogManager.GetLogger(String.Format("{0} MIS {1}",System.Reflection.MethodBase.GetCurrentMethod().DeclaringType.Name,context.Mis));
+ this.Context = context;
+ }
+
+ private int state;
+ private Queue> waitingPackets;
+ private DateTime lastWaitingTimePrinted;
+ private IMisHandler misHandler;
+ private bool unknownStateError;
+
+
+ public void PushFrame(BBHeader bbHeader, ReadOnlySpan readOnlySpan)
+ {
+ if (readOnlySpan.Length == 0)
+ {
+ return;
+ }
+
+ switch (state)
+ {
+ case 0: //No packets collected yet.
+ waitingPackets = new Queue>();
+ logger.InfoFormat("Attempting to detect the stream type of MIS {0}...",bbHeader.Matype2);
+ waitingPackets.Enqueue(new Tuple(bbHeader, readOnlySpan.ToArray()));
+ lastWaitingTimePrinted = DateTime.Now;
+ state = 1;
+ break;
+ case 1:
+ DateTime currentTime = DateTime.Now;
+ if (currentTime - lastWaitingTimePrinted > TimeSpan.FromSeconds(1))
+ {
+ logger.InfoFormat("Waiting for {0} more packets on MIS {1}...",100 - waitingPackets.Count,bbHeader.Matype2);
+ lastWaitingTimePrinted = currentTime;
+ }
+ waitingPackets.Enqueue(new Tuple(bbHeader, readOnlySpan.ToArray()));
+ if (waitingPackets.Count == 100)
+ {
+ state = 2;
+ }
+ break;
+ case 2:
+ RunDetection();
+ DrainQueue();
+ misHandler.PushFrame(bbHeader, readOnlySpan);
+ state = 3;
+ break;
+ case 3:
+ misHandler.PushFrame(bbHeader, readOnlySpan);
+ break;
+ default:
+ if (!unknownStateError)
+ {
+ logger.FatalFormat("The Finite-state machine of the MIS Handler reached an impossible state. This is a bug in skyscraper8. It would be great if you could share a sample of this stream to reproduce this, so I can fix this.");
+ unknownStateError = true;
+ }
+ break;
+ }
+ }
+
+ private enum DetectedGsType
+ {
+ ContinuousGSE,
+ GSE_HEM,
+ SimminRadiomidun,
+ BfbsGSE,
+ GseWithRollingSyncByte
+ }
+
+ private void SucessfulDetection(DetectedGsType detectedGsType)
+ {
+ logger.InfoFormat("MIS {0} looks like {1}, will try to treat it as such.",Context.GetMisId(),detectedGsType);
+ switch (detectedGsType)
+ {
+ case DetectedGsType.ContinuousGSE: misHandler = new GseReader(Context); break;
+ case DetectedGsType.GSE_HEM: misHandler = new GseHemReader(Context); break;
+ case DetectedGsType.SimminRadiomidun: misHandler = new SiminnRadiomidunReader(Context); break;
+ case DetectedGsType.BfbsGSE: misHandler = new BfbsGseReader(Context); break;
+ case DetectedGsType.GseWithRollingSyncByte: misHandler = new GseWithRollingSyncByteReader(Context); break;
+ default:
+ logger.FatalFormat("However, {0} is not implemented yet, sorry...", detectedGsType);
+ misHandler = new NullMisHandler();
+ break;
+ }
+ }
+
+ private bool RunDetection()
+ {
+ //bbHeader.TsGs == 1 && bbHeader.SyncByte == 0
+ int continuousGseScore = waitingPackets.Count(x => x.Item1.TsGs == 1 && x.Item1.SyncByte == 0);
+ if (continuousGseScore == 100)
+ {
+ SucessfulDetection(DetectedGsType.ContinuousGSE);
+ return true;
+ }
+
+ //bbHeader.TsGs == 2 && bbHeader.SyncByte == 0
+ int gseHemScore = waitingPackets.Count(x => x.Item1.TsGs == 2 && x.Item1.SyncByte == 0);
+ if (gseHemScore == 100)
+ {
+ SucessfulDetection(DetectedGsType.GSE_HEM);
+ return true;
+ }
+
+ //bbHeader.TsGs == 0 && bbHeader.SyncByte == 71 && bbHeader.UserPacketLength == 188
+ int simminRadiomidunScore = waitingPackets.Count(x => x.Item1.TsGs == 0 && x.Item1.SyncByte == 71 && x.Item1.UserPacketLength == 188);
+ if (simminRadiomidunScore == 100)
+ {
+ SucessfulDetection(DetectedGsType.SimminRadiomidun);
+ return true;
+ }
+
+ //bbHeader.TsGs == 1 && bbHeader.SyncByte == 1 && bbHeader.UserPacketLength == 0
+ int bfbsGseScore = waitingPackets.Count(x => x.Item1.TsGs == 1 && x.Item1.SyncByte == 1 && x.Item1.UserPacketLength == 0);
+ if (bfbsGseScore == 100)
+ {
+ SucessfulDetection(DetectedGsType.BfbsGSE);
+ return true;
+ }
+
+ bool allPacketsHaveValidCrc32 = AnalyzeCrc32Values();
+
+ if (!allPacketsHaveValidCrc32)
+ {
+ if (StatisticalAnalysis_Ses12_11476v())
+ {
+ SucessfulDetection(DetectedGsType.GseWithRollingSyncByte);
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ private void DrainQueue()
+ {
+ while (waitingPackets.Count > 0)
+ {
+ Tuple dequeue = waitingPackets.Dequeue();
+ misHandler.PushFrame(dequeue.Item1, dequeue.Item2);
+ }
+ waitingPackets = null;
+ }
+
+ private bool AnalyzeCrc32Values()
+ {
+ foreach (Tuple waitingPacket in waitingPackets)
+ {
+ bool validateCrc = DvbCrc32.ValidateCrc(waitingPacket.Item2);
+ if (!validateCrc)
+ return false;
+ }
+
+ return true;
+ }
+
+ private bool StatisticalAnalysis_Ses12_11476v()
+ {
+ byte[] syncBytes = new byte[256];
+ foreach (Tuple dequeue in waitingPackets)
+ {
+ syncBytes[dequeue.Item1.SyncByte]++;
+ if (syncBytes[dequeue.Item1.SyncByte] > 3)
+ return false;
+
+ if (dequeue.Item1.DataFieldLength != dequeue.Item2.Length)
+ return false;
+ }
+
+ return true;
+ }
+}
\ No newline at end of file
diff --git a/skyscraper8/GS/NullMisHandler.cs b/skyscraper8/GS/NullMisHandler.cs
new file mode 100644
index 0000000..42a0bed
--- /dev/null
+++ b/skyscraper8/GS/NullMisHandler.cs
@@ -0,0 +1,12 @@
+using skyscraper8.GSE;
+
+namespace skyscraper8.GS;
+
+class NullMisHandler : IMisHandler
+{
+ public GsContextDto Context { get; set; }
+ public void PushFrame(BBHeader bbHeader, ReadOnlySpan readOnlySpan)
+ {
+
+ }
+}
diff --git a/skyscraper8/Id3/Id3ErrorState.cs b/skyscraper8/Id3/Id3ErrorState.cs
index 9d30317..08f7590 100644
--- a/skyscraper8/Id3/Id3ErrorState.cs
+++ b/skyscraper8/Id3/Id3ErrorState.cs
@@ -9,6 +9,7 @@ namespace skyscraper5.src.Id3
internal enum Id3ErrorState
{
InvalidMagic,
- PacketTooShort
+ PacketTooShort,
+ NullPacket
}
}
diff --git a/skyscraper8/Id3/Id3PesProcessor.cs b/skyscraper8/Id3/Id3PesProcessor.cs
index ef2aeaa..f553a39 100644
--- a/skyscraper8/Id3/Id3PesProcessor.cs
+++ b/skyscraper8/Id3/Id3PesProcessor.cs
@@ -22,6 +22,12 @@ namespace skyscraper5.src.Id3
public void ProcessPesPacket(PesPacket packet)
{
+ if (packet.Payload == null)
+ {
+ handler.OnId3Error(Id3ErrorState.NullPacket);
+ return;
+ }
+
MemoryStream ms = new MemoryStream(packet.Payload, false);
if (ms.ReadUInt8() != 'I')
{
diff --git a/skyscraper8/InteractionChannel/InteractionChannelErrorState.cs b/skyscraper8/InteractionChannel/InteractionChannelErrorState.cs
index 8b05d63..83b2606 100644
--- a/skyscraper8/InteractionChannel/InteractionChannelErrorState.cs
+++ b/skyscraper8/InteractionChannel/InteractionChannelErrorState.cs
@@ -6,7 +6,7 @@ using System.Threading.Tasks;
namespace skyscraper5.src.InteractionChannel
{
- internal enum InteractionChannelErrorState
+ public enum InteractionChannelErrorState
{
UnexpectedTable,
HeaderInvalid,
diff --git a/skyscraper8/InteractionChannel/InteractionChannelHandler.cs b/skyscraper8/InteractionChannel/InteractionChannelHandler.cs
index 7fa0d7d..c5424f1 100644
--- a/skyscraper8/InteractionChannel/InteractionChannelHandler.cs
+++ b/skyscraper8/InteractionChannel/InteractionChannelHandler.cs
@@ -15,7 +15,7 @@ using skyscraper8.InteractionChannel.Model2.Descriptors;
namespace skyscraper5.src.InteractionChannel
{
- internal interface InteractionChannelHandler
+ public interface InteractionChannelHandler
{
void OnCorrectionMessage(ushort interactiveNetworkId, Cmt cmt);
void OnFrameComposition(ushort interactiveNetworkId, Fct fct);
diff --git a/skyscraper8/InteractionChannel/Model/Tmst.cs b/skyscraper8/InteractionChannel/Model/Tmst.cs
index 7894452..3f149ce 100644
--- a/skyscraper8/InteractionChannel/Model/Tmst.cs
+++ b/skyscraper8/InteractionChannel/Model/Tmst.cs
@@ -9,7 +9,7 @@ using System.Threading.Tasks;
namespace skyscraper5.src.InteractionChannel.Model
{
- internal class Tmst : Validatable
+ public class Tmst : Validatable
{
public Tmst(MemoryStream ms)
{
diff --git a/skyscraper8/Mpeg2/Crc32.cs b/skyscraper8/Mpeg2/Crc32.cs
index b2fb901..e109925 100644
--- a/skyscraper8/Mpeg2/Crc32.cs
+++ b/skyscraper8/Mpeg2/Crc32.cs
@@ -125,6 +125,20 @@ namespace skyscraper5.Mpeg2
return crc == 0;
}
+
+ public static uint CreateCrc(ReadOnlySpan data)
+ {
+ uint crc = 0xffffffff;
+
+ for (int i = 0; i < data.Length; i++)
+ {
+ uint b = (crc >> 24) & 0xff;
+ int c = (data[i]) & 0xff;
+ crc = (crc << 8) ^ table[b ^ c];
+ }
+
+ return crc;
+ }
public static uint CreateCrc(MemoryStream ms, int offset, int end)
{
diff --git a/skyscraper8/Program.cs b/skyscraper8/Program.cs
index 810207b..85c94c7 100644
--- a/skyscraper8/Program.cs
+++ b/skyscraper8/Program.cs
@@ -39,8 +39,9 @@ namespace skyscraper5
private static void IntegrationTest()
{
- SoftcamTestProgram softcamTestProgram = new SoftcamTestProgram();
- softcamTestProgram.Run();
+ //SoftcamTestProgram softcamTestProgram = new SoftcamTestProgram();
+ //softcamTestProgram.Run();
+
/*List ssdpDevices = SsdpClient.GetSsdpDevices(1000).ToList();
foreach (SsdpDevice ssdpDevice in ssdpDevices)
{