From 30026b2b02d414a0333beaaf12bdd6a1c40e528b Mon Sep 17 00:00:00 2001 From: feyris-tan <4116042+feyris-tan@users.noreply.github.com> Date: Sun, 23 Nov 2025 00:27:00 +0100 Subject: [PATCH] Added functionality necessary to extract the MPEG-DASH segments on the Arsat stream. --- skyscraper8.Tests/Feyllure.cs | 6 +- .../Properties/Resources.Designer.cs | 63 +++++ skyscraper8.Tests/Properties/Resources.resx | 101 +++++++ .../ResourceTests/DocsisTests.cs | 4 +- .../ResourceTests/GsType1SanityTest.cs | 3 + skyscraper8.Tests/ResourceTests/SdpTest.cs | 25 ++ .../ResourceTests/SkyscraperTests.cs | 4 +- skyscraper8.Tests/Resources/sdpTest.sdp | 10 + skyscraper8.Tests/Resources1.Designer.cs | 250 +++++++++++------- skyscraper8.Tests/Resources1.resx | 143 ++++++++-- skyscraper8.Tests/RootTests/DocsisTests.cs | 33 +-- skyscraper8.Tests/RootTests/Mpeg2Tests.cs | 1 + skyscraper8.Tests/skyscraper8.Tests.csproj | 47 ++++ skyscraper8.sln | 10 +- skyscraper8.sln.DotSettings.user | 8 +- skyscraper8/DvbNip/DvbNipReceiver.cs | 131 ++++++--- skyscraper8/DvbNip/DvbNipUtilities.cs | 79 ++++++ .../DvbNip/NipActualCarrierInformation.cs | 9 + skyscraper8/GS/POC/Pts2Bbf2.cs | 2 +- skyscraper8/Ietf/FLUTE/FluteException.cs | 23 ++ skyscraper8/Ietf/FLUTE/FluteListener.cs | 7 +- skyscraper8/Ietf/FLUTE/LctFrame.cs | 19 ++ skyscraper8/Ietf/FluteListenerMime.cs | 24 ++ skyscraper8/Ietf/Rfc4566_SDP/SDP.cs | 159 +++++++++++ .../Ietf/Rfc4566_SDP/SdpAddressType.cs | 14 + skyscraper8/Ietf/Rfc4566_SDP/SdpAttributes.cs | 208 +++++++++++++++ .../Ietf/Rfc4566_SDP/SdpConnectionData.cs | 45 ++++ skyscraper8/Ietf/Rfc4566_SDP/SdpMedia.cs | 51 ++++ .../Ietf/Rfc4566_SDP/SdpNetworkType.cs | 13 + skyscraper8/Ietf/Rfc4566_SDP/SdpOriginator.cs | 58 ++++ skyscraper8/Ietf/Rfc4566_SDP/SdpTimes.cs | 51 ++++ skyscraper8/Program.cs | 2 + skyscraper8/Properties/launchSettings.json | 2 +- skyscraper8/Skyscraper/DateTimeExtensions.cs | 2 + skyscraper8/Skyscraper/IO/StreamExtensions.cs | 9 + skyscraper8/Skyscraper/LongExtensions.cs | 38 +++ .../Skyscraper/Scraper/SkyscraperContext.cs | 32 ++- .../Text/SkyscraperEncodingProvider.cs | 21 +- skyscraper8/VersionInfo.cs | 2 +- skyscraper8/skyscraper8.csproj | 1 + 40 files changed, 1511 insertions(+), 199 deletions(-) create mode 100644 skyscraper8.Tests/Properties/Resources.Designer.cs create mode 100644 skyscraper8.Tests/Properties/Resources.resx create mode 100644 skyscraper8.Tests/ResourceTests/SdpTest.cs create mode 100644 skyscraper8.Tests/Resources/sdpTest.sdp create mode 100644 skyscraper8.Tests/skyscraper8.Tests.csproj create mode 100644 skyscraper8/Ietf/FLUTE/FluteException.cs create mode 100644 skyscraper8/Ietf/FluteListenerMime.cs create mode 100644 skyscraper8/Ietf/Rfc4566_SDP/SDP.cs create mode 100644 skyscraper8/Ietf/Rfc4566_SDP/SdpAddressType.cs create mode 100644 skyscraper8/Ietf/Rfc4566_SDP/SdpAttributes.cs create mode 100644 skyscraper8/Ietf/Rfc4566_SDP/SdpConnectionData.cs create mode 100644 skyscraper8/Ietf/Rfc4566_SDP/SdpMedia.cs create mode 100644 skyscraper8/Ietf/Rfc4566_SDP/SdpNetworkType.cs create mode 100644 skyscraper8/Ietf/Rfc4566_SDP/SdpOriginator.cs create mode 100644 skyscraper8/Ietf/Rfc4566_SDP/SdpTimes.cs create mode 100644 skyscraper8/Skyscraper/LongExtensions.cs diff --git a/skyscraper8.Tests/Feyllure.cs b/skyscraper8.Tests/Feyllure.cs index 8a030e1..70c77a5 100644 --- a/skyscraper8.Tests/Feyllure.cs +++ b/skyscraper8.Tests/Feyllure.cs @@ -1,5 +1,9 @@ +using System; +using System.Collections.Generic; +using System.IO; using System.Runtime.InteropServices; using Allure.Net.Commons; +using Microsoft.VisualStudio.TestTools.UnitTesting; using TestResult = Allure.Net.Commons.TestResult; namespace skyscraper8.Tests; @@ -28,7 +32,7 @@ public class Feyllure writer.WriteLine($".NET={Environment.Version}"); writer.WriteLine($"Machine={Environment.MachineName}"); writer.WriteLine($"User={Environment.UserName}"); - writer.WriteLine($"Framework={context.Properties["TargetFramework"] ?? "net8.0"}"); + writer.WriteLine($"Framework={System.Runtime.InteropServices.RuntimeInformation.FrameworkDescription}"); writer.WriteLine($"BuildDate={DateTime.UtcNow:yyyy-MM-dd HH:mm:ss}"); } diff --git a/skyscraper8.Tests/Properties/Resources.Designer.cs b/skyscraper8.Tests/Properties/Resources.Designer.cs new file mode 100644 index 0000000..8b7e9e7 --- /dev/null +++ b/skyscraper8.Tests/Properties/Resources.Designer.cs @@ -0,0 +1,63 @@ +//------------------------------------------------------------------------------ +// +// Dieser Code wurde von einem Tool generiert. +// Laufzeitversion:4.0.30319.42000 +// +// Änderungen an dieser Datei können falsches Verhalten verursachen und gehen verloren, wenn +// der Code erneut generiert wird. +// +//------------------------------------------------------------------------------ + +namespace skyscraper8.Tests.Properties { + 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()] + internal class Resources { + + private static global::System.Resources.ResourceManager resourceMan; + + private static global::System.Globalization.CultureInfo resourceCulture; + + [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + internal Resources() { + } + + /// + /// 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 { + get { + if (object.ReferenceEquals(resourceMan, null)) { + global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("skyscraper8.Tests.Properties.Resources", typeof(Resources).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 { + get { + return resourceCulture; + } + set { + resourceCulture = value; + } + } + } +} diff --git a/skyscraper8.Tests/Properties/Resources.resx b/skyscraper8.Tests/Properties/Resources.resx new file mode 100644 index 0000000..4fdb1b6 --- /dev/null +++ b/skyscraper8.Tests/Properties/Resources.resx @@ -0,0 +1,101 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 1.3 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.3500.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.3500.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/skyscraper8.Tests/ResourceTests/DocsisTests.cs b/skyscraper8.Tests/ResourceTests/DocsisTests.cs index 220ea87..2b59e6b 100644 --- a/skyscraper8.Tests/ResourceTests/DocsisTests.cs +++ b/skyscraper8.Tests/ResourceTests/DocsisTests.cs @@ -1,7 +1,9 @@ -using skyscraper5.Docsis; +using System; +using skyscraper5.Docsis; using skyscraper5.Docsis.AnnexC; using skyscraper5.Docsis.MacManagement; using System.Net.NetworkInformation; +using Microsoft.VisualStudio.TestTools.UnitTesting; namespace skyscraper8.Tests.ResourceTests { diff --git a/skyscraper8.Tests/ResourceTests/GsType1SanityTest.cs b/skyscraper8.Tests/ResourceTests/GsType1SanityTest.cs index eb7c84d..d9b964a 100644 --- a/skyscraper8.Tests/ResourceTests/GsType1SanityTest.cs +++ b/skyscraper8.Tests/ResourceTests/GsType1SanityTest.cs @@ -1,3 +1,6 @@ +using System; +using System.IO; +using Microsoft.VisualStudio.TestTools.UnitTesting; using skyscraper5.Mpeg2; namespace skyscraper8.Tests.ResourceTests; diff --git a/skyscraper8.Tests/ResourceTests/SdpTest.cs b/skyscraper8.Tests/ResourceTests/SdpTest.cs new file mode 100644 index 0000000..7aa47be --- /dev/null +++ b/skyscraper8.Tests/ResourceTests/SdpTest.cs @@ -0,0 +1,25 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Microsoft.VisualStudio.TestTools.UnitTesting; +using skyscraper8.Ietf.Rfc4566_SDP; + +namespace skyscraper8.Tests.ResourceTests +{ + [TestClass] + public class SdpTest : Feyllure + { + [TestMethod] + public void TestSdpParser() + { + MemoryStream ms = new MemoryStream(Resources1.sdpTest, false); + Assert.IsTrue(SDP.IsSDP(ms)); + + SDP loaded = SDP.Load(ms); + Assert.IsNotNull(loaded); + } + } +} diff --git a/skyscraper8.Tests/ResourceTests/SkyscraperTests.cs b/skyscraper8.Tests/ResourceTests/SkyscraperTests.cs index f4af5c7..5ae68a4 100644 --- a/skyscraper8.Tests/ResourceTests/SkyscraperTests.cs +++ b/skyscraper8.Tests/ResourceTests/SkyscraperTests.cs @@ -1,4 +1,6 @@ -using skyscraper5.Mpeg2; +using System.IO; +using Microsoft.VisualStudio.TestTools.UnitTesting; +using skyscraper5.Mpeg2; using skyscraper5.Skyscraper.Scraper; using skyscraper5.Skyscraper.Scraper.Storage.InMemory; using skyscraper8.Skyscraper.Scraper.Storage; diff --git a/skyscraper8.Tests/Resources/sdpTest.sdp b/skyscraper8.Tests/Resources/sdpTest.sdp new file mode 100644 index 0000000..a44a8d4 --- /dev/null +++ b/skyscraper8.Tests/Resources/sdpTest.sdp @@ -0,0 +1,10 @@ +v=0 +o=enensys Announcement-BM-SC 3962468565 IN IP4 10.10.10.20 +s=Announcement delivery session +t=0 0 +a=mbms-mode:broadcast-mbsfn 61712 +a=source-filter: incl IN IP4 * 10.10.10.20 +a=flute-tsi:9 +m=application 50001 FLUTE/UDP 0 +c=IN IP4 224.0.2.20/10 +b=AS:200 diff --git a/skyscraper8.Tests/Resources1.Designer.cs b/skyscraper8.Tests/Resources1.Designer.cs index 5de37c6..de7a55d 100644 --- a/skyscraper8.Tests/Resources1.Designer.cs +++ b/skyscraper8.Tests/Resources1.Designer.cs @@ -1,9 +1,10 @@ -//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ // -// This code was generated by a tool. +// Dieser Code wurde von einem Tool generiert. +// Laufzeitversion:4.0.30319.42000 // -// Changes to this file may cause incorrect behavior and will be lost if -// the code is regenerated. +// Änderungen an dieser Datei können falsches Verhalten verursachen und gehen verloren, wenn +// der Code erneut generiert wird. // //------------------------------------------------------------------------------ @@ -11,32 +12,46 @@ namespace skyscraper8.Tests { using System; - [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")] - [System.Diagnostics.DebuggerNonUserCodeAttribute()] - [System.Runtime.CompilerServices.CompilerGeneratedAttribute()] + /// + /// 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()] internal class Resources1 { - private static System.Resources.ResourceManager resourceMan; + private static global::System.Resources.ResourceManager resourceMan; - private static System.Globalization.CultureInfo resourceCulture; + private static global::System.Globalization.CultureInfo resourceCulture; - [System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] internal Resources1() { } - [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Advanced)] - internal static System.Resources.ResourceManager ResourceManager { + /// + /// 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 { get { - if (object.Equals(null, resourceMan)) { - System.Resources.ResourceManager temp = new System.Resources.ResourceManager("skyscraper8.Tests.Resources1", typeof(Resources1).Assembly); + if (object.ReferenceEquals(resourceMan, null)) { + global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("skyscraper8.Tests.Resources1", typeof(Resources1).Assembly); resourceMan = temp; } return resourceMan; } } - [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Advanced)] - internal static System.Globalization.CultureInfo Culture { + /// + /// Ü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 { get { return resourceCulture; } @@ -45,83 +60,9 @@ namespace skyscraper8.Tests { } } - internal static byte[] ModemCapabilitiesEncodingTest { - get { - object obj = ResourceManager.GetObject("ModemCapabilitiesEncodingTest", resourceCulture); - return ((byte[])(obj)); - } - } - - internal static byte[] MultipartRegistrationResponseTest { - get { - object obj = ResourceManager.GetObject("MultipartRegistrationResponseTest", resourceCulture); - return ((byte[])(obj)); - } - } - - internal static byte[] PushMacManagementMessage_Version4_Type45 { - get { - object obj = ResourceManager.GetObject("PushMacManagementMessage_Version4_Type45", resourceCulture); - return ((byte[])(obj)); - } - } - - internal static byte[] ranging_response_test { - get { - object obj = ResourceManager.GetObject("ranging_response_test", resourceCulture); - return ((byte[])(obj)); - } - } - - internal static byte[] MultipartRegistrationResponseTest2 { - get { - object obj = ResourceManager.GetObject("MultipartRegistrationResponseTest2", resourceCulture); - return ((byte[])(obj)); - } - } - - internal static byte[] test_1packet_01 { - get { - object obj = ResourceManager.GetObject("test-1packet-01", resourceCulture); - return ((byte[])(obj)); - } - } - - internal static byte[] test_2packets_02_03 { - get { - object obj = ResourceManager.GetObject("test-2packets-02-03", resourceCulture); - return ((byte[])(obj)); - } - } - - internal static byte[] test_3packets_04_05_06 { - get { - object obj = ResourceManager.GetObject("test-3packets-04-05-06", resourceCulture); - return ((byte[])(obj)); - } - } - - internal static byte[] TransmitChannelConfigurationObject { - get { - object obj = ResourceManager.GetObject("TransmitChannelConfigurationObject", resourceCulture); - return ((byte[])(obj)); - } - } - - 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)); - } - } - + /// + /// 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); @@ -129,11 +70,134 @@ namespace skyscraper8.Tests { } } + /// + /// 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); + return ((byte[])(obj)); + } + } + + /// + /// Sucht eine lokalisierte Ressource vom Typ System.Byte[]. + /// + internal static byte[] MultipartRegistrationResponseTest { + get { + object obj = ResourceManager.GetObject("MultipartRegistrationResponseTest", resourceCulture); + return ((byte[])(obj)); + } + } + + /// + /// 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); + return ((byte[])(obj)); + } + } + + /// + /// Sucht eine lokalisierte Ressource vom Typ System.Byte[]. + /// + internal static byte[] ranging_response_test { + get { + object obj = ResourceManager.GetObject("ranging_response_test", resourceCulture); + return ((byte[])(obj)); + } + } + + /// + /// Sucht eine lokalisierte Ressource vom Typ System.Byte[]. + /// + internal static byte[] sdpTest { + get { + object obj = ResourceManager.GetObject("sdpTest", 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); + return ((byte[])(obj)); + } + } + + /// + /// 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); + return ((byte[])(obj)); + } + } + + /// + /// 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); + return ((byte[])(obj)); + } + } + + /// + /// Sucht eine lokalisierte Ressource vom Typ System.Byte[]. + /// + internal static byte[] TransmitChannelConfigurationObject { + get { + object obj = ResourceManager.GetObject("TransmitChannelConfigurationObject", resourceCulture); + return ((byte[])(obj)); + } + } + + /// + /// Sucht eine lokalisierte Ressource vom Typ System.Byte[]. + /// + internal static byte[] UpstreamChannelDescriptorTest { + get { + object obj = ResourceManager.GetObject("UpstreamChannelDescriptorTest", resourceCulture); + return ((byte[])(obj)); + } + } } } diff --git a/skyscraper8.Tests/Resources1.resx b/skyscraper8.Tests/Resources1.resx index 19bd9f7..906044f 100644 --- a/skyscraper8.Tests/Resources1.resx +++ b/skyscraper8.Tests/Resources1.resx @@ -1,24 +1,124 @@ - - - - - - - - text/microsoft-resx - - - 1.3 - - - System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + Resources\ModemCapabilitiesEncodingTest.bin;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 @@ -57,4 +157,7 @@ Resources\Frame00000012_TSGS1_MIS000_SYNC001.bbf;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - + + Resources\sdpTest.sdp;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/skyscraper8.Tests/RootTests/DocsisTests.cs b/skyscraper8.Tests/RootTests/DocsisTests.cs index 27f6c48..3d83f90 100644 --- a/skyscraper8.Tests/RootTests/DocsisTests.cs +++ b/skyscraper8.Tests/RootTests/DocsisTests.cs @@ -1,4 +1,7 @@ +using System; +using System.IO; using System.Net.NetworkInformation; +using Microsoft.VisualStudio.TestTools.UnitTesting; using skyscraper5.Docsis; using skyscraper5.Docsis.AnnexC; @@ -20,7 +23,7 @@ public class DocsisTests : Feyllure RcpIdEncoding rie = new RcpIdEncoding(new byte[] { 7, 1, 0 }); SimplifiedReceiveChannelAssignmentEncoding simplifiedReceiveChannelAssignmentEncoding = rie.SimplifiedReceiveChannelConfiguration; Assert.IsNotNull(simplifiedReceiveChannelAssignmentEncoding); - Assert.ThrowsException(() => new RcpIdEncoding(new byte[] { 255, 1, 0 })); + Assert.Throws(() => new RcpIdEncoding(new byte[] { 255, 1, 0 })); } [TestMethod] @@ -30,7 +33,7 @@ public class DocsisTests : Feyllure ushort epceEProt = epce.EProt; Assert.AreEqual(1, epce.EProt); Assert.AreEqual(1, epce.Type); - Assert.ThrowsException(() => new EthernetLlcPacketClassificationEncoding(new byte[] { 255, 1, 0 })); + Assert.Throws(() => new EthernetLlcPacketClassificationEncoding(new byte[] { 255, 1, 0 })); } [TestMethod] @@ -41,7 +44,7 @@ public class DocsisTests : Feyllure Assert.AreEqual(0,srcae.DownstreamChannelAssignment[0]); Assert.AreEqual(0, srcae.DownstreamProfileAssignment[0]); Assert.AreEqual(0, srcae.PrimaryDownstreamChannelAssignment[0]); - Assert.ThrowsException(() => new SimplifiedReceiveChannelAssignmentEncoding(new byte[] { 254,0,1 })); + Assert.Throws(() => new SimplifiedReceiveChannelAssignmentEncoding(new byte[] { 254,0,1 })); } [TestMethod] @@ -71,7 +74,7 @@ public class DocsisTests : Feyllure Assert.AreEqual(0, tcco.P16Hi); Assert.AreEqual(0, tcco.ListOfIucs[0]); - Assert.ThrowsException(() => + Assert.Throws(() => new CommonTlvEncodingObject.TransmitChannelConfigurationObject(new byte[] { 254, 1, 0 })); } @@ -98,7 +101,7 @@ public class DocsisTests : Feyllure Assert.AreEqual(new TimeSpan(0, 0, 1), commonTlv.InitializingChannelTimeout); ms = new MemoryStream(new byte[] { 254, 1, 0 }); - Assert.ThrowsException(() => new CommonTlvEncodingObject(ms)); + Assert.Throws(() => new CommonTlvEncodingObject(ms)); } [TestMethod] @@ -131,13 +134,13 @@ public class DocsisTests : Feyllure Assert.AreEqual(GeneralPacketClassifierEncoding.DynamicServiceChangeActionEnum.Add, gpce.DynamicServiceChangeAction.Value); Assert.IsNotNull(gpce.EthernetLlcPacketClassificationEncodings); - Assert.ThrowsException(() => new GeneralPacketClassifierEncoding(new byte[] + Assert.Throws(() => new GeneralPacketClassifierEncoding(new byte[] { 12, 4, 255, 1, 0, 0 })); - Assert.ThrowsException(() => new GeneralPacketClassifierEncoding(new byte[] + Assert.Throws(() => new GeneralPacketClassifierEncoding(new byte[] { 254, 1, 0 })); @@ -169,7 +172,7 @@ public class DocsisTests : Feyllure Assert.AreEqual(1, ipce.SourcePortStart.Value); Assert.AreEqual(1, ipce.SourcePortEnd.Value); - Assert.ThrowsException(() => + Assert.Throws(() => new GeneralPacketClassifierEncoding.Ipv4PacketClassificationEncodings(new byte[] { 255, 1, 0 @@ -189,7 +192,7 @@ public class DocsisTests : Feyllure Assert.IsNotNull(sfscao.SidClusterEncoding); Assert.IsNotNull(sfscao.SidClusterSwitchoverCriteria); - Assert.ThrowsException(() => new ServiceFlowSidClusterAssignmentObject(new byte[] + Assert.Throws(() => new ServiceFlowSidClusterAssignmentObject(new byte[] { 255, 1, 0 })); @@ -207,7 +210,7 @@ public class DocsisTests : Feyllure Assert.AreEqual(1, sceo.SidClusterId.Value); Assert.IsNotNull(sceo.SidToChannelMapping); - Assert.ThrowsException(() => new ServiceFlowSidClusterAssignmentObject.SidClusterEncodingObject(new byte[] + Assert.Throws(() => new ServiceFlowSidClusterAssignmentObject.SidClusterEncodingObject(new byte[] { 255, 1, 0 })); @@ -227,7 +230,7 @@ public class DocsisTests : Feyllure Assert.AreEqual(1, stcmo.SID.Value); Assert.AreEqual(ServiceFlowSidClusterAssignmentObject.SidClusterEncodingObject.SidToChannelMappingObject.ActionEnum.Add,stcmo.Action.Value); - Assert.ThrowsException(() => + Assert.Throws(() => new ServiceFlowSidClusterAssignmentObject.SidClusterEncodingObject.SidToChannelMappingObject(new byte[] { 255, 1, 0 @@ -272,7 +275,7 @@ public class DocsisTests : Feyllure Assert.AreEqual((ushort)1, scsco.MaximumTimeInTheSidCluster); buffer = new byte[] { 254, 1, 0 }; - Assert.ThrowsException(() => + Assert.Throws(() => new ServiceFlowSidClusterAssignmentObject.SidClusterSwitchoverCriteriaObject(buffer)); } @@ -478,7 +481,7 @@ public class DocsisTests : Feyllure { 255, 1, 1 }; - Assert.ThrowsException(() => new ModemCapabilitiesEncoding(buffer)); + Assert.Throws(() => new ModemCapabilitiesEncoding(buffer)); } [TestMethod] @@ -555,7 +558,7 @@ public class DocsisTests : Feyllure { 254, 1, 1 }; - Assert.ThrowsException(() => new GeneralServiceFlowEncoding(buffer)); + Assert.Throws(() => new GeneralServiceFlowEncoding(buffer)); } [MacManagementMessageType(0x90,0x01)] @@ -589,7 +592,7 @@ public class DocsisTests : Feyllure Assert.AreEqual(srcAddr, tmmm.Source); Assert.AreEqual(dstAddr, tmmm.Destination); - Assert.ThrowsException(() => new TestableMacManagementMessage(srcAddr, dstAddr, null)); + Assert.Throws(() => new TestableMacManagementMessage(srcAddr, dstAddr, null)); UntestableMacManagementMessage ummm = new UntestableMacManagementMessage(srcAddr, dstAddr, dataBuffer); Assert.IsNull(ummm.MessageType); diff --git a/skyscraper8.Tests/RootTests/Mpeg2Tests.cs b/skyscraper8.Tests/RootTests/Mpeg2Tests.cs index 3cc8322..b667b1f 100644 --- a/skyscraper8.Tests/RootTests/Mpeg2Tests.cs +++ b/skyscraper8.Tests/RootTests/Mpeg2Tests.cs @@ -1,3 +1,4 @@ +using Microsoft.VisualStudio.TestTools.UnitTesting; using skyscraper5.Mpeg2; namespace skyscraper8.Tests.RootTests; diff --git a/skyscraper8.Tests/skyscraper8.Tests.csproj b/skyscraper8.Tests/skyscraper8.Tests.csproj new file mode 100644 index 0000000..b45b07c --- /dev/null +++ b/skyscraper8.Tests/skyscraper8.Tests.csproj @@ -0,0 +1,47 @@ + + + + + net8.0 + + + true + + + + + + + + + + + + + + + + + True + True + Resources.resx + + + True + True + Resources1.resx + + + + + + ResXFileCodeGenerator + Resources.Designer.cs + + + ResXFileCodeGenerator + Resources1.Designer.cs + + + + \ No newline at end of file diff --git a/skyscraper8.sln b/skyscraper8.sln index 474c714..fcb92b9 100644 --- a/skyscraper8.sln +++ b/skyscraper8.sln @@ -65,7 +65,7 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "skyscraper8.UI.MonoGame", " EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "skyscraper8.UI.MonoGame.Bridge", "GUIs\skyscraper8.UI.ImGui.MonoGame.Bridge\skyscraper8.UI.MonoGame.Bridge.csproj", "{1A29F6E6-4B6A-DCCD-1DF1-AA8D020E17D2}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "skyscraper8.Tests", "skyscraper8.Tests\skyscraper8.Tests.csproj", "{011164D8-B6FF-4BAB-B78D-0A174FC691E8}" +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "skyscraper8.Tests", "skyscraper8.Tests\skyscraper8.Tests.csproj", "{84EE9FCD-2C7F-DF84-C1BA-99D018CE9412}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -165,10 +165,10 @@ Global {1A29F6E6-4B6A-DCCD-1DF1-AA8D020E17D2}.Debug|Any CPU.Build.0 = Debug|Any CPU {1A29F6E6-4B6A-DCCD-1DF1-AA8D020E17D2}.Release|Any CPU.ActiveCfg = Release|Any CPU {1A29F6E6-4B6A-DCCD-1DF1-AA8D020E17D2}.Release|Any CPU.Build.0 = Release|Any CPU - {011164D8-B6FF-4BAB-B78D-0A174FC691E8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {011164D8-B6FF-4BAB-B78D-0A174FC691E8}.Debug|Any CPU.Build.0 = Debug|Any CPU - {011164D8-B6FF-4BAB-B78D-0A174FC691E8}.Release|Any CPU.ActiveCfg = Release|Any CPU - {011164D8-B6FF-4BAB-B78D-0A174FC691E8}.Release|Any CPU.Build.0 = Release|Any CPU + {84EE9FCD-2C7F-DF84-C1BA-99D018CE9412}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {84EE9FCD-2C7F-DF84-C1BA-99D018CE9412}.Debug|Any CPU.Build.0 = Debug|Any CPU + {84EE9FCD-2C7F-DF84-C1BA-99D018CE9412}.Release|Any CPU.ActiveCfg = Release|Any CPU + {84EE9FCD-2C7F-DF84-C1BA-99D018CE9412}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/skyscraper8.sln.DotSettings.user b/skyscraper8.sln.DotSettings.user index a51adfd..5796cc7 100644 --- a/skyscraper8.sln.DotSettings.user +++ b/skyscraper8.sln.DotSettings.user @@ -26,11 +26,11 @@ <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" Name="All tests from &lt;skyscraper8.Tests&gt; #2" xmlns="urn:schemas-jetbrains-com:jetbrains-ut-session"> - <Project Location="/home/schiemas/RiderProjects/skyscraper8/skyscraper8.Tests" Presentation="&lt;skyscraper8.Tests&gt;" /> + <SessionState ContinuousTestingMode="0" Name="All tests from &lt;skyscraper8.Tests&gt; #2" xmlns="urn:schemas-jetbrains-com:jetbrains-ut-session"> + <Project Location="\home\schiemas\RiderProjects\skyscraper8\skyscraper8.Tests" Presentation="&lt;skyscraper8.Tests&gt;" /> </SessionState> - <SessionState ContinuousTestingMode="0" IsActive="True" Name="All tests from &lt;skyscraper8.Tests&gt;" xmlns="urn:schemas-jetbrains-com:jetbrains-ut-session"> - <Project Location="/home/schiemas/RiderProjects/skyscraper8/skyscraper8.Tests" Presentation="&lt;skyscraper8.Tests&gt;" /> + <SessionState ContinuousTestingMode="0" IsActive="True" Name="All tests from &lt;skyscraper8.Tests&gt;" xmlns="urn:schemas-jetbrains-com:jetbrains-ut-session"> + <Project Location="\home\schiemas\RiderProjects\skyscraper8\skyscraper8.Tests" Presentation="&lt;skyscraper8.Tests&gt;" /> </SessionState> diff --git a/skyscraper8/DvbNip/DvbNipReceiver.cs b/skyscraper8/DvbNip/DvbNipReceiver.cs index ed89f9d..2a6c6c2 100644 --- a/skyscraper8/DvbNip/DvbNipReceiver.cs +++ b/skyscraper8/DvbNip/DvbNipReceiver.cs @@ -13,6 +13,7 @@ using System.Threading.Tasks; using moe.yo3explorer.skyscraper8.DVBI.Model; using skyscraper8.DvbI; using System.Reflection.Metadata.Ecma335; +using skyscraper8.Ietf.Rfc4566_SDP; namespace skyscraper8.DvbNip { @@ -53,16 +54,28 @@ namespace skyscraper8.DvbNip if (discoveryUdpPacket.DestinationPort == 3937) { LctFrame discoveryLctFrame = new LctFrame(discoveryUdpPacket.Payload); - if (discoveryLctFrame.LctHeader.NipActualCarrierInformation != null) + if (discoveryLctFrame == null) + return; + LctHeader lctHeader = discoveryLctFrame.LctHeader; + if (lctHeader == null) + return; + if (lctHeader.NipActualCarrierInformation != null) { CurrentCarrierInformation = discoveryLctFrame.LctHeader.NipActualCarrierInformation; EventHandler.OnNipCarrierDetected(CurrentCarrierInformation); bootstrapped = true; } + else if (discoveryLctFrame.PayloadContainsNativeIpMulticastTransportObject) + { + CurrentCarrierInformation = new NipActualCarrierInformation(ushort.MaxValue, ushort.MaxValue, ushort.MaxValue, ushort.MaxValue, "(no NIP carrier name provided)"); + EventHandler.OnNipCarrierDetected(CurrentCarrierInformation); + bootstrapped = true; + } } } return; } + UserDatagram udpPacket = new UserDatagram(ipv4Packet); LctFrame lctFrame = new LctFrame(udpPacket.Payload); if (lctFrame.LctHeader == null) @@ -114,6 +127,10 @@ namespace skyscraper8.DvbNip SetFileAssociations(fluteListener, fdtAnnouncement); } } + else + { + Console.WriteLine("aaa"); + } fluteStream.Close(); fluteStream.Dispose(); flutes.Remove(fluteCoordinate); @@ -163,6 +180,7 @@ namespace skyscraper8.DvbNip } } } + private DateTime? currentTime; private bool HandleMetadata(FluteListener fluteListener) @@ -170,56 +188,83 @@ namespace skyscraper8.DvbNip switch (fluteListener.FileAssociation.ContentLocation) { case "urn:dvb:metadata:cs:NativeIPMulticastTransportObjectTypeCS:2023:bootstrap": - MulticastGatewayConfigurationType multicastGatewayConfiguration2023 = DvbNipUtilities.UnpackMulticastGatewayConfiguration(fluteListener.ToStream()); - EventHandler?.OnMulticastGatewayConfiguration(CurrentCarrierInformation, multicastGatewayConfiguration2023); - return true; - case "urn:dvb:metadata:cs:MulticastTransportObjectTypeCS:2021:gateway-configuration": - MulticastGatewayConfigurationType multicastGatewayConfiguration2021 = DvbNipUtilities.UnpackMulticastGatewayConfiguration(fluteListener.ToStream()); - EventHandler?.OnMulticastGatewayConfiguration(CurrentCarrierInformation, multicastGatewayConfiguration2021); - return true; - case "urn:dvb:metadata:nativeip:PrivateDataSignalling": - PrivateDataSignallingManifestType privateDataSignallingManifest = DvbNipUtilities.UnpackPrivateDataSignallingManifest(fluteListener.ToStream()); - EventHandler?.OnPrivateDataSignallingManifest(CurrentCarrierInformation, privateDataSignallingManifest); - return true; - case "urn:dvb:metadata:nativeip:dvb-i-slep": - if (currentTime.HasValue) + Stream stream = fluteListener.ToStream(); + if (DvbNipUtilities.IsXml(stream)) { - Stream rawSlepStream = fluteListener.ToStream(); - byte[] rawSlepBytes = new byte[rawSlepStream.Length]; - rawSlepStream.Read(rawSlepBytes, 0, (int)rawSlepStream.Length); - string rawSlepString = Encoding.UTF8.GetString(rawSlepBytes); - rawSlepString = rawSlepString.Replace(" readOnlySpan = new ReadOnlySpan(bbframe, 11, bbframe.Length - 11); diff --git a/skyscraper8/Ietf/FLUTE/FluteException.cs b/skyscraper8/Ietf/FLUTE/FluteException.cs new file mode 100644 index 0000000..80969e6 --- /dev/null +++ b/skyscraper8/Ietf/FLUTE/FluteException.cs @@ -0,0 +1,23 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace skyscraper8.Ietf.FLUTE +{ + public class FluteException : IetfException + { + public FluteException() + { + } + + public FluteException(string message) : base(message) + { + } + + public FluteException(string message, Exception inner) : base(message, inner) + { + } + } +} diff --git a/skyscraper8/Ietf/FLUTE/FluteListener.cs b/skyscraper8/Ietf/FLUTE/FluteListener.cs index e830616..1c232c4 100644 --- a/skyscraper8/Ietf/FLUTE/FluteListener.cs +++ b/skyscraper8/Ietf/FLUTE/FluteListener.cs @@ -9,6 +9,7 @@ using System.Runtime.Serialization; using System.Security.Cryptography.X509Certificates; using System.Text; using System.Threading.Tasks; +using MimeKit; using skyscraper5.Teletext.Wss; namespace skyscraper8.Ietf.FLUTE @@ -147,8 +148,8 @@ namespace skyscraper8.Ietf.FLUTE return _dataWritten; } } - - public Stream ToStream() + + public virtual Stream ToStream() { if (!IsComplete()) throw new InvalidOperationException(); @@ -164,7 +165,7 @@ namespace skyscraper8.Ietf.FLUTE blockPayloads.Sort(new FluteBlockComparer()); level1 = new FluteListenerStream(blockPayloads); } - + if (FileAssociation != null) { switch(FileAssociation.ContentEncoding) diff --git a/skyscraper8/Ietf/FLUTE/LctFrame.cs b/skyscraper8/Ietf/FLUTE/LctFrame.cs index 0ef7fde..02fc666 100644 --- a/skyscraper8/Ietf/FLUTE/LctFrame.cs +++ b/skyscraper8/Ietf/FLUTE/LctFrame.cs @@ -53,6 +53,11 @@ namespace skyscraper8.Ietf.FLUTE return; Payload = ms.ReadBytes(ms.GetAvailableBytes()); + if (Payload[0] == 0x3c && Payload[1] == 0x3f && Payload[2] == 0x78 && Payload[3] == 0x6d && + Payload[4] == 0x6c && Payload[5] == 0x20) + { + PayloadAsString = Encoding.UTF8.GetString(Payload); + } } public int Version { get; } @@ -67,5 +72,19 @@ namespace skyscraper8.Ietf.FLUTE public bool CloseObjectFlag { get; } public FecHeader FecHeader { get; } public byte[] Payload { get; } + + public string PayloadAsString { get; private set; } + + public bool PayloadContainsNativeIpMulticastTransportObject + { + get + { + if (string.IsNullOrEmpty(PayloadAsString)) + { + return false; + } + return PayloadAsString.Contains("NativeIPMulticastTransportObjectTypeCS"); + } + } } } diff --git a/skyscraper8/Ietf/FluteListenerMime.cs b/skyscraper8/Ietf/FluteListenerMime.cs new file mode 100644 index 0000000..db4b936 --- /dev/null +++ b/skyscraper8/Ietf/FluteListenerMime.cs @@ -0,0 +1,24 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Net; +using System.Text; +using System.Threading.Tasks; +using skyscraper8.Ietf.FLUTE; + +namespace skyscraper8.Ietf +{ + internal class FluteListenerMime : FluteListener + { + public FluteListenerMime(IPAddress destinationAddress, ushort destinationPort, ulong destinationTsi, ulong destinationToi) : base(destinationAddress, destinationPort, destinationTsi, destinationToi) + { + } + + public Stream WrappedStream { get; set; } + + public override Stream ToStream() + { + return WrappedStream; + } + } +} diff --git a/skyscraper8/Ietf/Rfc4566_SDP/SDP.cs b/skyscraper8/Ietf/Rfc4566_SDP/SDP.cs new file mode 100644 index 0000000..9bb8a7e --- /dev/null +++ b/skyscraper8/Ietf/Rfc4566_SDP/SDP.cs @@ -0,0 +1,159 @@ +using log4net; +using skyscraper5.Skyscraper.IO; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using skyscraper8.DvbNip; + +namespace skyscraper8.Ietf.Rfc4566_SDP +{ + public class SDP + { + private static readonly ILog logger = LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType.Name); + + public static bool IsSDP(Stream ms) + { + if (ms.GetAvailableBytes() < 3) + return false; + + byte byteA = ms.ReadUInt8(); + byte byteB = ms.ReadUInt8(); + ms.Position -= 2; + + if (byteA != 'v') + return false; + + if (byteB != '=') + return false; + + return true; + } + + public static SDP Load(Stream stream) + { + StreamReader sr = new StreamReader(stream); + SDP result = null; + while (!sr.EndOfStream) + { + string line = sr.ReadLine(); + if (line[1] != '=') + { + logger.ErrorFormat("Invalid SDP description!"); + return result; + } + + if (result == null) + result = new SDP(); + char opcode = line[0]; + string args = line.Substring(2); + switch (opcode) + { + case 'v': + result.Version = new Version(int.Parse(args), 0); + break; + case 'o': + result.Originator = new SdpOriginator(args.Split(' ')); + break; + case 's': + result.SessionName = args; + break; + case 't': + result.Times = new SdpTimes(args.Split(' ')); + break; + case 'a': + if (result.Attributes == null) + result.Attributes = new SdpAttributeCollection(); + result.Attributes.SetHint(args); + break; + case 'm': + if (result._mediaAnnouncements == null) + result._mediaAnnouncements = new List(); + result._mediaAnnouncements.Add(new SdpMedia(args.Split(' '))); + break; + case 'c': + if (result._connections == null) + result._connections = new List(); + result._connections.Add(new SdpConnectionData(args.Split(' '))); + break; + case 'b': + string bandwidthType = args.Substring(0, 2); + string bandwidthValue = args.Substring(3); + switch (bandwidthType) + { + case "CT": + result.ConferenceTotalBandwidth = long.Parse(bandwidthValue); + break; + case "AS": + result.ApplicationSpecificMaximumBandwidth = long.Parse(bandwidthValue); + break; + default: + logger.WarnFormat("Unknown bandwidth type: {0}", bandwidthType); + break; + } + break; + default: + logger.ErrorFormat("Invalid SDP opcode \"{0}\", please consider sharing a sample of this stream for further analysis.", opcode); + break; + } + } + + return result; + } + + public long? ApplicationSpecificMaximumBandwidth { get; private set; } + + public long? ConferenceTotalBandwidth { get; private set; } + + + private List _mediaAnnouncements; + private List _connections; + + public IReadOnlyList ConnectionData + { + get + { + return _connections.AsReadOnly(); + } + } + public IReadOnlyList MediaAnnouncements + { + get + { + return _mediaAnnouncements.AsReadOnly(); + } + } + public SdpAttributeCollection Attributes { get; private set; } + public SdpTimes Times { get; private set; } + + public string SessionName { get; private set; } + + public SdpOriginator Originator { get; private set; } + + public Version Version { get; private set; } + + public MulticastGatewayConfigurationType ToMulticastGatewayConfiguration() + { + MulticastGatewayConfigurationType result = new MulticastGatewayConfigurationType(); + result.MulticastSession = new MulticastSessionType[_connections.Count]; + + for (int i = 0; i < _connections.Count; i++) + { + result.MulticastSession[i] = new MulticastSessionType(); + result.MulticastSession[i].serviceIdentifier = Originator.ToString(); + result.MulticastSession[i].MulticastTransportSession = new MulticastTransportSessionType[1]; + result.MulticastSession[i].MulticastTransportSession[0] = new MulticastTransportSessionType(); + result.MulticastSession[i].MulticastTransportSession[0].EndpointAddress = new MulticastEndpointAddressType[1]; + result.MulticastSession[i].MulticastTransportSession[0].EndpointAddress[0] = new MulticastEndpointAddressType(); + result.MulticastSession[i].MulticastTransportSession[0].EndpointAddress[0].NetworkDestinationGroupAddress = _connections[i].DestinationAddress; + result.MulticastSession[i].MulticastTransportSession[0].EndpointAddress[0].NetworkSourceAddress = Originator.Address.ToString(); + result.MulticastSession[i].MulticastTransportSession[0].EndpointAddress[0].TransportDestinationPort = _mediaAnnouncements[i].Port.ToString(); + } + + return result; + } + } + + +} diff --git a/skyscraper8/Ietf/Rfc4566_SDP/SdpAddressType.cs b/skyscraper8/Ietf/Rfc4566_SDP/SdpAddressType.cs new file mode 100644 index 0000000..8369486 --- /dev/null +++ b/skyscraper8/Ietf/Rfc4566_SDP/SdpAddressType.cs @@ -0,0 +1,14 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace skyscraper8.Ietf.Rfc4566_SDP +{ + public enum SdpAddressType + { + IP4, + IP6 + } +} diff --git a/skyscraper8/Ietf/Rfc4566_SDP/SdpAttributes.cs b/skyscraper8/Ietf/Rfc4566_SDP/SdpAttributes.cs new file mode 100644 index 0000000..ba359b8 --- /dev/null +++ b/skyscraper8/Ietf/Rfc4566_SDP/SdpAttributes.cs @@ -0,0 +1,208 @@ +using log4net; +using log4net.Repository.Hierarchy; +using skyscraper5.Skyscraper.IO.TunerInterface; +using System; +using System.Collections; +using System.Collections.Generic; +using System.Diagnostics; +using System.Linq; +using System.Net; +using System.Numerics; +using System.Text; +using System.Threading.Tasks; + +namespace skyscraper8.Ietf.Rfc4566_SDP +{ + public class SdpAttributeCollection : IEnumerable + { + private static readonly ILog logger = LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType.Name); + private Dictionary _attributes; + + internal void SetHint(string args) + { + if (_attributes == null) + _attributes = new Dictionary(); + + int indexOf = args.IndexOf(':'); + string key = args.Substring(0, indexOf); + string value = args.Substring(indexOf + 1); + switch (key) + { + case "mbms-mode": + _attributes.Add(key, new MbmsMode(value)); + break; + case "source-filter": + if (!_attributes.ContainsKey(key)) + _attributes.Add(key, new SourceFilter()); + SourceFilter sourceFilter = _attributes[key] as SourceFilter; + sourceFilter.SetHint(value); + break; + case "flute-tsi": + _attributes.Add(key, new FluteTsi(value)); + break; + default: + logger.ErrorFormat("Unknown SDP Attribute: \"{0}\" - please consider sharing a sample of this stream for further analysis.", key); + break; + } + } + + public IEnumerator GetEnumerator() + { + return _attributes.Values.GetEnumerator(); + } + + IEnumerator IEnumerable.GetEnumerator() + { + return _attributes.Values.GetEnumerator(); + } + } + + internal class FluteTsi : SdpAttribute + { + public FluteTsi(string value) : base("flute-tsi") + { + TSI = long.Parse(value); + } + + public long TSI { get; private set; } + + public override string ToString() + { + return TSI.ToString(); + } + } + + internal class SourceFilter : SdpAttribute + { + public SourceFilter() : base("source-filter") + { + } + + public void SetHint(string value) + { + if (_filterChain == null) + _filterChain = new List(); + _filterChain.Add(new SourceFilterChainLink(value.Split(' ',StringSplitOptions.RemoveEmptyEntries))); + } + + private List _filterChain; + + class SourceFilterChainLink + { + private static readonly ILog logger = LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType.Name); + + public SourceFilterChainLink(string[] args) + { + if (args[0].Equals("incl")) + { + Include = true; + } + else if (args[0].Equals("excl")) + { + Include = false; + } + else + { + logger.ErrorFormat("Unknown Filter Mode \"{0}\", assuming exclusion just to be sure.", args[0]); + } + + if (!SdpNetworkType.TryParse(args[1], true, out _networkType)) + { + logger.ErrorFormat("Unknown Network Type \"{0}\", assuming \"IN\" - please consider sharing a sample of this stream so this can be implemented.", args[1]); + _networkType = SdpNetworkType.IN; + } + + if (!SdpAddressType.TryParse(args[2], true, out _addressType)) + { + logger.ErrorFormat("Unknown Address Type \"{0}\", assuming \"IP4\" - please consider sharing a sample of this stream so this can be implemented.", args[2]); + _addressType = SdpAddressType.IP4; + } + + DestinationAddress = args[3]; + + int numSources = args.Length - 4; + Sources = new string[numSources]; + Array.Copy(args, 4, Sources, 0, numSources); + } + + /// + /// If this is true, an incoming packet is accepted, if not it gets discarded. + /// + public bool Include { get; private set; } + + public string[] Sources { get; private set; } + public string DestinationAddress { get; private set; } + private SdpAddressType _addressType; + public SdpAddressType AddressType + { + get => _addressType; + } + + private SdpNetworkType _networkType; + public SdpNetworkType NetworkType + { + get => _networkType; + } + } + } + + internal class MbmsMode : SdpAttribute + { + private static readonly ILog logger = LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType.Name); + + public MbmsMode(string value) + : base("mbms-mode") + { + string[] args = value.Split(' '); + if (args[0].Equals("broadcast-mbsfn")) + { + BigInteger tmgi = BigInteger.Parse(args[1]); + this.Tmgi = tmgi.ToByteArray(); + } + else if (args[0].Equals("broadcast")) + { + BigInteger tmgi = BigInteger.Parse(args[1]); + this.Tmgi = tmgi.ToByteArray(); + this.MbmsCountingIndication = int.Parse(args[2]); + } + else + { + logger.ErrorFormat("Unknown MBMS Mode: {0} - please consider a sharing a sample of this stream if you'd like the developer to look further into this.", args[0]); + } + } + + public int? MbmsCountingIndication { get; private set; } + + public byte[] Tmgi { get; private set; } + + internal enum MbmsBearerMode + { + Unknown, + Broadcast, + BroadcastMbsfn + } + + public MbmsBearerMode BearerMode + { + get + { + if (Tmgi == null) + return MbmsBearerMode.Unknown; + if (MbmsCountingIndication == null) + return MbmsBearerMode.BroadcastMbsfn; + else + return MbmsBearerMode.Broadcast; + } + } + } + + public abstract class SdpAttribute + { + protected SdpAttribute(string key) + { + this.SdpAttributeName = key; + } + + public string SdpAttributeName { get; private set; } + } +} diff --git a/skyscraper8/Ietf/Rfc4566_SDP/SdpConnectionData.cs b/skyscraper8/Ietf/Rfc4566_SDP/SdpConnectionData.cs new file mode 100644 index 0000000..071cf8c --- /dev/null +++ b/skyscraper8/Ietf/Rfc4566_SDP/SdpConnectionData.cs @@ -0,0 +1,45 @@ +using log4net; +using log4net.Repository.Hierarchy; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace skyscraper8.Ietf.Rfc4566_SDP +{ + public class SdpConnectionData + { + private static readonly ILog logger = LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType.Name); + + public SdpConnectionData(string[] args) + { + if (!SdpNetworkType.TryParse(args[0], true, out _networkType)) + { + logger.ErrorFormat("Unknown Network Type \"{0}\", assuming \"IN\" - please consider sharing a sample of this stream so this can be implemented.", args[0]); + _networkType = SdpNetworkType.IN; + } + + if (!SdpAddressType.TryParse(args[1], true, out _addressType)) + { + logger.ErrorFormat("Unknown Address Type \"{0}\", assuming \"IP4\" - please consider sharing a sample of this stream so this can be implemented.", args[1]); + _addressType = SdpAddressType.IP4; + } + + DestinationAddress = args[2]; + } + + public string DestinationAddress { get; private set; } + private SdpAddressType _addressType; + public SdpAddressType AddressType + { + get => _addressType; + } + + private SdpNetworkType _networkType; + public SdpNetworkType NetworkType + { + get => _networkType; + } + } +} diff --git a/skyscraper8/Ietf/Rfc4566_SDP/SdpMedia.cs b/skyscraper8/Ietf/Rfc4566_SDP/SdpMedia.cs new file mode 100644 index 0000000..59ba2f2 --- /dev/null +++ b/skyscraper8/Ietf/Rfc4566_SDP/SdpMedia.cs @@ -0,0 +1,51 @@ +using log4net; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace skyscraper8.Ietf.Rfc4566_SDP +{ + public class SdpMedia + { + private static readonly ILog logger = LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType.Name); + + public SdpMedia(string[] args) + { + if (!MediaType.TryParse(args[0], true, out _mediaType)) + { + logger.ErrorFormat("Unknown Media Type \"{0}\", assuming \"data\"", args[0]); + _mediaType = MediaType.Data; + } + + Port = ushort.Parse(args[1]); + Transport = args[2]; + + int numFormats = args.Length - 3; + FormatList = new string[numFormats]; + Array.Copy(args, 3, FormatList, 0, numFormats); + } + + public string[] FormatList { get; private set; } + + public string Transport { get; private set; } + + public ushort Port { get; private set; } + + private MediaType _mediaType; + public MediaType MediaType + { + get => _mediaType; + } + } + + public enum MediaType + { + Audio, + Video, + Application, + Data, + Control + } +} diff --git a/skyscraper8/Ietf/Rfc4566_SDP/SdpNetworkType.cs b/skyscraper8/Ietf/Rfc4566_SDP/SdpNetworkType.cs new file mode 100644 index 0000000..4939a08 --- /dev/null +++ b/skyscraper8/Ietf/Rfc4566_SDP/SdpNetworkType.cs @@ -0,0 +1,13 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace skyscraper8.Ietf.Rfc4566_SDP +{ + public enum SdpNetworkType + { + IN + } +} diff --git a/skyscraper8/Ietf/Rfc4566_SDP/SdpOriginator.cs b/skyscraper8/Ietf/Rfc4566_SDP/SdpOriginator.cs new file mode 100644 index 0000000..62a95a9 --- /dev/null +++ b/skyscraper8/Ietf/Rfc4566_SDP/SdpOriginator.cs @@ -0,0 +1,58 @@ +using log4net; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Net; +using System.Text; +using System.Threading.Tasks; + +namespace skyscraper8.Ietf.Rfc4566_SDP +{ + public class SdpOriginator + { + private static readonly ILog logger = LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType.Name); + + public SdpOriginator(string[] args) + { + Username = args[0]; + Id = args[1]; + this.Version = long.Parse(args[2]); + if (!SdpNetworkType.TryParse(args[3], true, out _networkType)) + { + logger.ErrorFormat("Unknown Network Type \"{0}\", assuming \"IN\" - please consider sharing a sample of this stream so this can be implemented.", _networkType); + _networkType = SdpNetworkType.IN; + } + + if (!SdpAddressType.TryParse(args[4], true, out _addressType)) + { + logger.ErrorFormat("Unknown Address Type \"{0}\", assuming \"IP4\" - please consider sharing a sample of this stream so this can be implemented.", _addressType); + _addressType = SdpAddressType.IP4; + } + + Address = IPAddress.Parse(args[5]); + } + + public IPAddress Address { get; private set; } + private SdpAddressType _addressType; + public SdpAddressType AddressType + { + get => _addressType; + } + + private SdpNetworkType _networkType; + public SdpNetworkType NetworkType + { + get => _networkType; + } + public long Version { get; set; } + + public string Id { get; set; } + + public string Username { get; set; } + + public override string ToString() + { + return String.Format("{0} {1} {2} {3} {4}", Username, Id, NetworkType, AddressType, Address); + } + } +} diff --git a/skyscraper8/Ietf/Rfc4566_SDP/SdpTimes.cs b/skyscraper8/Ietf/Rfc4566_SDP/SdpTimes.cs new file mode 100644 index 0000000..8ebacb8 --- /dev/null +++ b/skyscraper8/Ietf/Rfc4566_SDP/SdpTimes.cs @@ -0,0 +1,51 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using skyscraper8.Skyscraper; + +namespace skyscraper8.Ietf.Rfc4566_SDP +{ + public struct SdpTimes + { + private const long NTP_OFFSET = 2208988800L; + private readonly long _startTime; + private readonly long _stopTime; + + public SdpTimes(string[] args) + { + _startTime = long.Parse(args[0]); + _stopTime = long.Parse(args[1]); + } + + public bool IsNull + { + get => _startTime == 0; + } + + public DateTime? StartTime + { + get + { + if (_startTime == 0) + return null; + + long tmp = _startTime - NTP_OFFSET; + return tmp.AsUnixtime(); + } + } + + public DateTime? EndTime + { + get + { + if (_stopTime == 0) + return null; + + long tmp = _stopTime - NTP_OFFSET; + return tmp.AsUnixtime(); + } + } + } +} diff --git a/skyscraper8/Program.cs b/skyscraper8/Program.cs index fac28f2..7a622d8 100644 --- a/skyscraper8/Program.cs +++ b/skyscraper8/Program.cs @@ -355,7 +355,9 @@ namespace skyscraper5 if (args[0].ToLowerInvariant().Equals("make-catalogue")) { DirectoryInfo di = new DirectoryInfo(args[1]); + logger.InfoFormat("Input directory: {0}", di.FullName); FileInfo fi = new FileInfo(args[2]); + logger.InfoFormat("Output File: {0}", fi.FullName); CatalogueGenerator catalogueGenerator = new CatalogueGenerator(di, fi); catalogueGenerator.Run(); catalogueGenerator.Dispose(); diff --git a/skyscraper8/Properties/launchSettings.json b/skyscraper8/Properties/launchSettings.json index 8660a46..3ce0d08 100644 --- a/skyscraper8/Properties/launchSettings.json +++ b/skyscraper8/Properties/launchSettings.json @@ -2,7 +2,7 @@ "profiles": { "skyscraper8": { "commandName": "Project", - "commandLineArgs": "make-catalogue \"D:\\\\Stash\\\\\" \"D:\\\\index.csv\"", + "commandLineArgs": "\"Z:\\Persönliches\\Satellitescommunity\\65W11304V.TS\"", "remoteDebugEnabled": false }, "Container (Dockerfile)": { diff --git a/skyscraper8/Skyscraper/DateTimeExtensions.cs b/skyscraper8/Skyscraper/DateTimeExtensions.cs index 18e7891..cf1d109 100644 --- a/skyscraper8/Skyscraper/DateTimeExtensions.cs +++ b/skyscraper8/Skyscraper/DateTimeExtensions.cs @@ -19,5 +19,7 @@ namespace skyscraper5.Skyscraper { return ToUnixTime(dt) * 1000; } + + } } diff --git a/skyscraper8/Skyscraper/IO/StreamExtensions.cs b/skyscraper8/Skyscraper/IO/StreamExtensions.cs index 97a04fa..c2d5fe2 100644 --- a/skyscraper8/Skyscraper/IO/StreamExtensions.cs +++ b/skyscraper8/Skyscraper/IO/StreamExtensions.cs @@ -333,5 +333,14 @@ namespace skyscraper5.Skyscraper.IO stream.Position--; return readUInt8; } + + public static void DumpToFile(this Stream stream, string filename) + { + FileStream fileStream = File.OpenWrite(filename); + stream.CopyTo(fileStream); + fileStream.Flush(true); + fileStream.Close(); + fileStream.Dispose(); + } } } diff --git a/skyscraper8/Skyscraper/LongExtensions.cs b/skyscraper8/Skyscraper/LongExtensions.cs new file mode 100644 index 0000000..00f5d4f --- /dev/null +++ b/skyscraper8/Skyscraper/LongExtensions.cs @@ -0,0 +1,38 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace skyscraper8.Skyscraper +{ + internal static class LongExtensions + { + /// + /// + /// + /// + /// stolen from https://stackoverflow.com/a/250400 + /// + public static DateTime AsUnixtime(this long l) + { + DateTime dateTime = new DateTime(1970, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc); + dateTime = dateTime.AddSeconds(l); + return dateTime; + } + + /// + /// + /// + /// + /// stolen from https://stackoverflow.com/a/250400 + /// + public static DateTime AsJavaMillis(this long javaTimeStamp) + { + // Java timestamp is milliseconds past epoch + DateTime dateTime = new DateTime(1970, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc); + dateTime = dateTime.AddMilliseconds(javaTimeStamp); + return dateTime; + } + } +} diff --git a/skyscraper8/Skyscraper/Scraper/SkyscraperContext.cs b/skyscraper8/Skyscraper/Scraper/SkyscraperContext.cs index 52f4e55..bd98081 100644 --- a/skyscraper8/Skyscraper/Scraper/SkyscraperContext.cs +++ b/skyscraper8/Skyscraper/Scraper/SkyscraperContext.cs @@ -77,6 +77,7 @@ using System.Net.NetworkInformation; using System.Reflection; using System.Security.Policy; using System.Text; +using MimeKit; using skyscraper5.src.InteractionChannel.Model2; using skyscraper8.Abertis; using skyscraper8.Experimentals.NdsSsu; @@ -85,6 +86,7 @@ using skyscraper8.GS; using skyscraper8.GSE; using skyscraper8.GSE.GSE; using skyscraper8.Ieee802_1AB; +using skyscraper8.Ietf; using skyscraper8.InteractionChannel.Model; using skyscraper8.InteractionChannel.Model2; using skyscraper8.InteractionChannel.Model2.Descriptors; @@ -2738,7 +2740,35 @@ namespace skyscraper5.Skyscraper.Scraper public void FluteFileArrival(NipActualCarrierInformation carrier, FluteListener listener) { - string extension = Path.GetExtension(listener.FileAssociation.ContentLocation).ToLowerInvariant(); + Stream stream = listener.ToStream(); + bool isMime = DvbNipUtilities.IsMime(stream); + if (isMime) + { + MimeMessage message = MimeMessage.Load(stream); + foreach (MimeEntity entity in message.BodyParts) + { + MimePart bodyPart = entity as MimePart; + if (bodyPart.ContentLocation == null) + continue; + + FluteListenerMime fluteListener = new FluteListenerMime(listener.DestinationAddress, listener.DestinationPort, listener.DestinationTsi, listener.DestinationToi); + fluteListener.FileAssociation = new FileType(); + fluteListener.FileAssociation.ContentLocation = bodyPart.ContentLocation.ToString(); + fluteListener.FileAssociation.ContentType = bodyPart.ContentType.MimeType; + fluteListener.FileAssociation.ContentEncoding = null; + fluteListener.WrappedStream = new MemoryStream(); + bodyPart.Content.DecodeTo(fluteListener.WrappedStream); + fluteListener.FileAssociation.ContentLength = (ulong)fluteListener.WrappedStream.Position; + fluteListener.FileAssociation.TransferLength = (ulong)fluteListener.WrappedStream.Position; + fluteListener.FileAssociation.TransferLengthSpecified = true; + fluteListener.WrappedStream.Position = 0; + + FluteFileArrival(carrier, fluteListener); + } + return; + } + + string extension = Path.GetExtension(listener.FileAssociation.ContentLocation).ToLowerInvariant(); if (!DvbNipUtilities.IsContinuousFileType(extension)) LogEvent(SkyscraperContextEvent.FluteFileArrival, listener.FileAssociation.ContentLocation); else diff --git a/skyscraper8/Skyscraper/Text/SkyscraperEncodingProvider.cs b/skyscraper8/Skyscraper/Text/SkyscraperEncodingProvider.cs index 1589a6d..18dccb7 100644 --- a/skyscraper8/Skyscraper/Text/SkyscraperEncodingProvider.cs +++ b/skyscraper8/Skyscraper/Text/SkyscraperEncodingProvider.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; +using log4net; using skyscraper5.Skyscraper.Text.Encodings; namespace skyscraper5.Skyscraper.Text @@ -36,18 +37,20 @@ namespace skyscraper5.Skyscraper.Text } } - public override Encoding? GetEncoding(int codepage) + private static readonly ILog logger = LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType.Name); + private List encodings; + public override Encoding? GetEncoding(int codepage) { - if (codepage == 1200) - return null; + if (encodings == null) + encodings = new List(); - if (codepage == 65001) - return null; + if (!encodings.Contains(codepage)) + { + logger.InfoFormat("Detected text encoding: {0}", codepage); + encodings.Add(codepage); + } - if (codepage == 0) - return null; - - throw new NotImplementedException(); + return null; } public override Encoding? GetEncoding(string name) diff --git a/skyscraper8/VersionInfo.cs b/skyscraper8/VersionInfo.cs index dc9f50e..39a5854 100644 --- a/skyscraper8/VersionInfo.cs +++ b/skyscraper8/VersionInfo.cs @@ -4,7 +4,7 @@ namespace skyscraper8; public class VersionInfo { - private const int PUBLIC_RELEASE = 13; + private const int PUBLIC_RELEASE = 14; public static int GetPublicReleaseNumber() { diff --git a/skyscraper8/skyscraper8.csproj b/skyscraper8/skyscraper8.csproj index 98d9846..45804f8 100644 --- a/skyscraper8/skyscraper8.csproj +++ b/skyscraper8/skyscraper8.csproj @@ -25,6 +25,7 @@ +