From ef0ee985e4a7b6f44c1f481103a2d540ae77d39d Mon Sep 17 00:00:00 2001 From: feyris-tan <4116042+feyris-tan@users.noreply.github.com> Date: Sun, 15 Jun 2025 15:37:31 +0200 Subject: [PATCH] FLUTE works kind of as intended now. --- skyscraper8/DvbNip/DvbNipEventHandler.cs | 15 + skyscraper8/DvbNip/DvbNipReceiver.cs | 171 ++++---- skyscraper8/DvbNip/DvbNipUtilities.cs | 14 + .../DvbNip/NipActualCarrierInformation.cs | 2 +- skyscraper8/Ietf/FLUTE/FluteBlockComparer.cs | 27 ++ skyscraper8/Ietf/FLUTE/FluteListener.cs | 386 ++++++++---------- ...MemoryStream.cs => FluteListenerStream.cs} | 35 +- skyscraper8/Ietf/FLUTE/IFluteEventHandler.cs | 18 - .../Ietf/Rfc971_IPv4/InternetHeader.cs | 14 +- .../Plugins/ISkyscraperMpePlugin.cs | 2 +- .../Skyscraper/Scraper/SkyscraperContext.cs | 24 +- .../Scraper/SkyscraperContextEvent.cs | 3 +- 12 files changed, 367 insertions(+), 344 deletions(-) create mode 100644 skyscraper8/DvbNip/DvbNipEventHandler.cs create mode 100644 skyscraper8/Ietf/FLUTE/FluteBlockComparer.cs rename skyscraper8/Ietf/FLUTE/{_2DMemoryStream.cs => FluteListenerStream.cs} (74%) delete mode 100644 skyscraper8/Ietf/FLUTE/IFluteEventHandler.cs diff --git a/skyscraper8/DvbNip/DvbNipEventHandler.cs b/skyscraper8/DvbNip/DvbNipEventHandler.cs new file mode 100644 index 0000000..7b200ac --- /dev/null +++ b/skyscraper8/DvbNip/DvbNipEventHandler.cs @@ -0,0 +1,15 @@ +using skyscraper8.Ietf.FLUTE; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace skyscraper8.DvbNip +{ + internal interface IDvbNipEventHandler + { + void FluteFileArrival(NipActualCarrierInformation currentCarrierInformation, FluteListener fluteListener); + void OnMulticastGatewayConfiguration(NipActualCarrierInformation currentCarrierInformation, MulticastGatewayConfigurationType multicastGatewayConfiguration); + } +} diff --git a/skyscraper8/DvbNip/DvbNipReceiver.cs b/skyscraper8/DvbNip/DvbNipReceiver.cs index 8b5bb96..604b724 100644 --- a/skyscraper8/DvbNip/DvbNipReceiver.cs +++ b/skyscraper8/DvbNip/DvbNipReceiver.cs @@ -1,5 +1,6 @@ using skyscraper5.Ietf.Rfc768; using skyscraper5.Ietf.Rfc971; +using skyscraper5.Skyscraper.IO; using skyscraper5.Skyscraper.Plugins; using skyscraper8.Ietf.FLUTE; using System; @@ -12,21 +13,11 @@ using System.Threading.Tasks; namespace skyscraper8.DvbNip { [SkyscraperPlugin] - internal class DvbNipReceiver : ISkyscraperMpePlugin, IFluteEventHandler + internal class DvbNipReceiver : ISkyscraperMpePlugin { - private DateTime? contextDate; - private object[] contextConnector; - private DvbNipPhase phase; - private FluteListener flute; - - public bool CanHandlePacket(InternetHeader internetHeader, byte[] ipv4Packet) { - byte[] destinationBytes = internetHeader.DestinationAddress.GetAddressBytes(); - int multicastTemp = destinationBytes[0]; - multicastTemp &= 0b11100000; - multicastTemp >>= 4; - if (multicastTemp != 0b1110) + if (!internetHeader.IsDestinationMulticast) return false; if (internetHeader.Protocol != 17) @@ -37,102 +28,115 @@ namespace skyscraper8.DvbNip public void ConnectToStorage(object[] connector) { - contextConnector = connector; } + private uint fluteHits, fluteMisses; + private List flutes = new List(); public void HandlePacket(InternetHeader internetHeader, byte[] ipv4Packet) { UserDatagram udpPacket = new UserDatagram(ipv4Packet); - flute.OnFlutePacket(internetHeader.DestinationAddress, udpPacket.DestinationPort, udpPacket.Payload); - } + LctFrame lctFrame = new LctFrame(udpPacket.Payload); - public void InformToi(IPAddress destinationAddress, ushort destinationPort, ulong transportObjectIdentifier, ulong transportSessionIdentifier) - { - if (phase == DvbNipPhase.DownloadMode) + if (flutes == null) + flutes = new List(); + + FluteListener fluteListener = null; + foreach(FluteListener listenerCandidate in flutes) { - flute.AddPlay(destinationAddress, destinationPort, transportSessionIdentifier, 0); + if (!listenerCandidate.DestinationAddress.Equals(internetHeader.DestinationAddress)) + continue; + if (listenerCandidate.DestinationPort != udpPacket.DestinationPort) + continue; + if (listenerCandidate.DestinationTsi != lctFrame.LctHeader.TransportSessionIdentifier) + continue; + if (listenerCandidate.DestinationToi != lctFrame.LctHeader.TransportObjectIdentifier) + continue; + fluteListener = listenerCandidate; + break; } - } - public bool IpFilterEnabled() - { - if (phase == DvbNipPhase.DownloadMode) - return false; + if (fluteListener == null) + { + fluteListener = new FluteListener(internetHeader.DestinationAddress, udpPacket.DestinationPort, lctFrame.LctHeader.TransportSessionIdentifier, lctFrame.LctHeader.TransportObjectIdentifier); + flutes.Add(fluteListener); + fluteMisses++; + } else - return true; - } - - public void OnCompletePlay(FluteListener.FlutePlay flutePlay) - { - if (phase == DvbNipPhase.WaitingForSignalling) { - phase = DvbNipPhase.DownloadMode; - return; + fluteHits++; } - else if (phase == DvbNipPhase.DownloadMode) + fluteListener.PushPacket(lctFrame); + if (fluteListener.IsComplete()) { - if (!flutePlay.Validate()) + if (fluteListener.DestinationToi == 0) { - flutePlay.SetIgnore(true); - flutePlay.SetIgnore(false); + if (fluteListener.CarrierInformation != null) + { + CurrentCarrierInformation = fluteListener.CarrierInformation; + return; + } + Stream fluteStream = fluteListener.ToStream(); + FDTInstanceType fdtAnnouncement = FluteUtilities.UnpackFluteFdt(fluteStream); + SetFileAssociations(fluteListener, fdtAnnouncement); + fluteStream.Close(); + fluteStream.Dispose(); + flutes.Remove(fluteListener); return; } - if (flutePlay.TOI == 0) + if (fluteListener.FileAssociation == null) { - FDTInstanceType fdtInstance = FluteUtilities.UnpackFluteFdt(flutePlay.GetStream()); - foreach(FileType filetype in fdtInstance.File) + return; + } + if (fluteListener.FileAssociation.ContentLocation.Equals("urn:dvb:metadata:cs:MulticastTransportObjectTypeCS:2021:gateway-configuration")) + { + if(CurrentCarrierInformation != null) { - flute.SetFileAssociation(flutePlay.IPAddress, flutePlay.Port, flutePlay.TSI, filetype.TOI, filetype); + MulticastGatewayConfigurationType multicastGatewayConfiguration = DvbNipUtilities.UnpackMulticastGatewayConfiguration(fluteListener.ToStream()); + EventHandler?.OnMulticastGatewayConfiguration(CurrentCarrierInformation, multicastGatewayConfiguration); + fluteListener.Disabled = true; } return; } + + if (CurrentCarrierInformation != null) + { + EventHandler?.FluteFileArrival(CurrentCarrierInformation, fluteListener); + fluteListener.Disabled = true; + } + return; + } + } + + private void SetFileAssociations(FluteListener sourceListener, FDTInstanceType fdtAnnouncement) + { + foreach(FileType announcedFile in fdtAnnouncement.File) + { + ulong targetToi = ulong.Parse(announcedFile.TOI); + FluteListener? targetListener = flutes.Find(x => + x.DestinationAddress.Equals(sourceListener.DestinationAddress) && + x.DestinationPort == sourceListener.DestinationPort && + x.DestinationTsi == sourceListener.DestinationTsi && + x.DestinationToi == targetToi); + if (targetListener != null) + { + targetListener.FileAssociation = announcedFile; + } else { - if (flutePlay.FileAssociation.ContentLocation.Equals("urn:dvb:metadata:cs:MulticastTransportObjectTypeCS:2021:gateway-configuration")) - { - MulticastGatewayConfigurationType multicastGatewayConfigurationType = DvbNipUtilities.UnpackMulticastGatewayConfiguration(flutePlay.GetStream()); - //TODO: Handle Multicast Gateway configuration - flutePlay.SetIgnore(true); - return; - } - flutePlay.WriteToFile("test.xml"); + targetListener = new FluteListener(sourceListener.DestinationAddress, sourceListener.DestinationPort, sourceListener.DestinationTsi, targetToi); + targetListener.FileAssociation = announcedFile; + flutes.Add(targetListener); } - flutePlay.SetIgnore(true); - } - else - { - throw new NotImplementedException(phase.ToString()); } } - public void OnNipCarrierInformation(NipActualCarrierInformation nipActualCarrierInformation) + public void SetContext(DateTime? currentTime, object skyscraperContext) { - if (phase == DvbNipPhase.WaitingForCarrierInformation) + if (EventHandler == null) { - phase = DvbNipPhase.WaitingForSignalling; - flute.RemoveAllPlays(); - flute.AddPlay(IPAddress.Parse("224.0.23.14"), 3937, 0, 0); - } - } - - public void SetContext(DateTime? currentTime) - { - contextDate = currentTime; - switch(phase) - { - case DvbNipPhase.JustPoweredUp: - flute = new FluteListener(this); - flute.AddPlay(IPAddress.Parse("224.0.23.14"), 3937, 1, 0); - phase = DvbNipPhase.WaitingForCarrierInformation; - break; - case DvbNipPhase.WaitingForCarrierInformation: - break; - case DvbNipPhase.WaitingForSignalling: - break; - case DvbNipPhase.DownloadMode: - break; - default: - throw new NotImplementedException(phase.ToString()); + IDvbNipEventHandler? dvbNipEventHandler = skyscraperContext as IDvbNipEventHandler; + if (dvbNipEventHandler != null) + EventHandler = dvbNipEventHandler; } } @@ -141,12 +145,7 @@ namespace skyscraper8.DvbNip return false; } - private enum DvbNipPhase - { - JustPoweredUp, - WaitingForCarrierInformation, - WaitingForSignalling, - DownloadMode, - } + public NipActualCarrierInformation CurrentCarrierInformation { get; private set; } + public IDvbNipEventHandler EventHandler { get; private set; } } } diff --git a/skyscraper8/DvbNip/DvbNipUtilities.cs b/skyscraper8/DvbNip/DvbNipUtilities.cs index 6509024..f11e52d 100644 --- a/skyscraper8/DvbNip/DvbNipUtilities.cs +++ b/skyscraper8/DvbNip/DvbNipUtilities.cs @@ -24,5 +24,19 @@ namespace skyscraper8.DvbNip MulticastGatewayConfigurationType result = (MulticastGatewayConfigurationType)v; return result; } + + public static string MakeFilename(string originalLocation) + { + string newFilename = originalLocation.Replace("://", "/"); + newFilename = originalLocation.Replace(":", "/"); + + while (newFilename.Contains("//")) + newFilename = newFilename.Replace("//", "/"); + + if (string.IsNullOrEmpty(Path.GetExtension(newFilename))) + newFilename += ".dat"; + + return newFilename; + } } } diff --git a/skyscraper8/DvbNip/NipActualCarrierInformation.cs b/skyscraper8/DvbNip/NipActualCarrierInformation.cs index b8b9f11..0f78d59 100644 --- a/skyscraper8/DvbNip/NipActualCarrierInformation.cs +++ b/skyscraper8/DvbNip/NipActualCarrierInformation.cs @@ -7,7 +7,7 @@ using System.Threading.Tasks; namespace skyscraper8.DvbNip { - internal class NipActualCarrierInformation + public class NipActualCarrierInformation { public NipActualCarrierInformation(byte[] buffer) { diff --git a/skyscraper8/Ietf/FLUTE/FluteBlockComparer.cs b/skyscraper8/Ietf/FLUTE/FluteBlockComparer.cs new file mode 100644 index 0000000..7343ad0 --- /dev/null +++ b/skyscraper8/Ietf/FLUTE/FluteBlockComparer.cs @@ -0,0 +1,27 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace skyscraper8.Ietf.FLUTE +{ + internal class FluteBlockComparer : IComparer + { + public int Compare(FluteListener.FluteBlock? x, FluteListener.FluteBlock? y) + { + uint x1 = MakeUint(x); + uint y1 = MakeUint(y); + int result = x1.CompareTo(y1); + return result; + } + + private uint MakeUint(FluteListener.FluteBlock? x) + { + uint value = x.SourceBlockNumer; + value <<= 16; + value += x.EncodingSymbolId; + return value; + } + } +} diff --git a/skyscraper8/Ietf/FLUTE/FluteListener.cs b/skyscraper8/Ietf/FLUTE/FluteListener.cs index 0599af5..acf90ea 100644 --- a/skyscraper8/Ietf/FLUTE/FluteListener.cs +++ b/skyscraper8/Ietf/FLUTE/FluteListener.cs @@ -1,246 +1,202 @@ -using skyscraper5.Ietf.Rfc768; -using skyscraper5.Ietf.Rfc971; -using skyscraper8.DvbNip; +using skyscraper8.DvbNip; using System; using System.Collections.Generic; +using System.IO.Compression; using System.Linq; +using System.Linq.Expressions; using System.Net; +using System.Runtime.Serialization; +using System.Security.Cryptography.X509Certificates; using System.Text; using System.Threading.Tasks; namespace skyscraper8.Ietf.FLUTE { - internal class FluteListener + public class FluteListener { - - internal void AddPlay(IPAddress iPAddress, int port, ulong tsi, ulong toi) + public FluteListener(IPAddress destinationAddress, ushort destinationPort, ulong destinationTsi, ulong destinationToi) { - if (knownFlutePlays == null) - knownFlutePlays = new List(); - - FlutePlay? flutePlay = knownFlutePlays.Find(x => x.IPAddress.Equals(iPAddress) && - x.Port == port && - x.TSI == tsi && - x.TOI == toi); - if (flutePlay != null) - return; - - FlutePlay play = new FlutePlay(iPAddress, port, tsi, toi); - knownFlutePlays.Add(play); + DestinationAddress = destinationAddress; + DestinationPort = destinationPort; + DestinationTsi = destinationTsi; + DestinationToi = destinationToi; } - internal void OnFlutePacket(IPAddress destinationAddress, ushort destinationPort, byte[] payload) + public IPAddress DestinationAddress { get; } + public ushort DestinationPort { get; } + public ulong DestinationTsi { get; } + public ulong DestinationToi { get; } + + public override string ToString() { - if (knownFlutePlays == null) + if (_disabled) + { + return ""; + } + if (FileAssociation != null) + { + return String.Format("IP={0}, Port={1}, TSI={2}, TOI={3}, Filename={4}", DestinationAddress, DestinationPort, DestinationTsi, DestinationToi, FileAssociation.ContentLocation); + } + return String.Format("IP={0}, Port={1}, TSI={2}, TOI={3}", DestinationAddress, DestinationPort, DestinationTsi, DestinationToi); + } + + internal void PushPacket(LctFrame lctFrame) + { + if (_disabled) return; - if (eventHandler.IpFilterEnabled()) + if (lctFrame.LctHeader.FecObjectTransmissionInformation == null) { - FlutePlay? ipFound = knownFlutePlays.Find(x => x.IPAddress.Equals(destinationAddress) && x.Port == destinationPort); - if (ipFound == null) + if (lctFrame.LctHeader.NipActualCarrierInformation != null) + { + CarrierInformation = lctFrame.LctHeader.NipActualCarrierInformation; return; - } - - - LctFrame lctFrame = new LctFrame(payload); - eventHandler.InformToi(destinationAddress, destinationPort, lctFrame.LctHeader.TransportObjectIdentifier, lctFrame.LctHeader.TransportSessionIdentifier); - if (lctFrame.LctHeader.NipActualCarrierInformation != null) - { - eventHandler.OnNipCarrierInformation(lctFrame.LctHeader.NipActualCarrierInformation); - return; - } - - FlutePlay? flutePlay = knownFlutePlays.Find(x => x.IPAddress.Equals(destinationAddress) && - x.Port == destinationPort && - x.TSI == lctFrame.LctHeader.TransportSessionIdentifier && - x.TOI == lctFrame.LctHeader.TransportObjectIdentifier); - - if (flutePlay == null) - return; - - flutePlay.OnPacket(lctFrame); - - if (flutePlay.IsComplete()) - { - eventHandler.OnCompletePlay(flutePlay); - } - } - - internal void RemoveAllPlays() - { - if (knownFlutePlays == null) - return; - - knownFlutePlays.Clear(); - } - - internal void SetFileAssociation(IPAddress iPAddress, int port, ulong tSI, string tOI, FileType filetype) - { - ulong toiNumeric = ulong.Parse(tOI); - - FlutePlay? flutePlay = knownFlutePlays.Find(x => x.IPAddress.Equals(iPAddress) && - x.Port == port && - x.TSI == tSI && - x.TOI == toiNumeric); - if (flutePlay != null) - { - flutePlay.FileAssociation = filetype; - } - else - { - AddPlay(iPAddress, port, tSI, toiNumeric); - SetFileAssociation(iPAddress, port, tSI, tOI, filetype); - } - } - - private List knownFlutePlays; - private IFluteEventHandler eventHandler; - - public FluteListener(IFluteEventHandler dvbNipReceiver) - { - this.eventHandler = dvbNipReceiver; - } - - public class FlutePlay - { - public FlutePlay(IPAddress iPAddress, int port, ulong tsi, ulong toi) - { - IPAddress = iPAddress; - Port = port; - TSI = tsi; - TOI = toi; - } - - public override string ToString() - { - if (ignore) - { - return ""; - } - return String.Format("IP={0}, Port={1}, TOI={2}, TSI={3}, Name={4}", IPAddress, Port, TOI, TSI, FileAssociation?.ContentLocation); - } - - public IPAddress IPAddress { get; private set; } - public ulong TSI { get; private set; } - public ulong TOI { get; private set; } - public int Port { get; } - public FileType FileAssociation { get; internal set; } - - private int neededEsi, neededSbn; - private ulong nextX, maxX; - private ulong encodingSymbolLength; - private ulong transferLength; - private byte[][] buffers; - private bool ignore; - - internal void OnPacket(LctFrame lctFrame) - { - if (ignore == true) - return; - - if (neededEsi == 0 && neededSbn == 0 && lctFrame.FecHeader.EncodingSymbolId == 0 && lctFrame.FecHeader.SourceBlockNumber == 0) - { - nextX = 0; - encodingSymbolLength = lctFrame.LctHeader.FecObjectTransmissionInformation.EncodingSymbolLength; - transferLength = lctFrame.LctHeader.FecObjectTransmissionInformation.TransferLength; - maxX = (transferLength / encodingSymbolLength) + 1; - buffers = new byte[maxX][]; - buffers[nextX] = lctFrame.Payload; - neededEsi++; - } - else if (neededEsi != 0 || neededSbn != 0) - { - if (IsComplete()) - return; - - nextX++; - buffers[nextX] = lctFrame.Payload; - } - } - - internal bool IsComplete() - { - if (ignore == true) - return false; - - if (buffers == null) - return false; - - ulong currentSize = 0; - for (int i = 0; i < buffers.Length; i++) - { - if (buffers[i] == null) - continue; - currentSize += (ulong)buffers[i].Length; - } - return currentSize >= transferLength; - } - - public _2DMemoryStream GetStream() - { - return new _2DMemoryStream(buffers); - } - - - public void WriteToFile(string filename) - { - FileInfo fi = new FileInfo(filename); - if (fi.Exists) - fi.Delete(); - FileStream fileStream = fi.OpenWrite(); - _2DMemoryStream _2DMemoryStream = GetStream(); - _2DMemoryStream.CopyTo(fileStream); - fileStream.Flush(); - fileStream.Close(); - fileStream.Dispose(); - } - - internal void SetIgnore(bool v) - { - if (v) - { - for (int i = 0; i < buffers.Length; i++) - { - buffers[i] = null; - } - buffers = null; - ignore = true; } else { - neededEsi = 0; - neededSbn = 0; - nextX = 0; - buffers = new byte[maxX][]; - ignore = false; + throw new NotImplementedException("non fec"); } } + - public bool Validate() + if (transferLength == 0) + transferLength = lctFrame.LctHeader.FecObjectTransmissionInformation.TransferLength; + if (blocks == null) + blocks = new List(); + + ushort sbn = lctFrame.FecHeader.SourceBlockNumber; + ushort esi = lctFrame.FecHeader.EncodingSymbolId; + + FluteBlock? fluteBlock = blocks.Find(x => + x.SourceBlockNumer == sbn && + x.EncodingSymbolId == esi); + if (fluteBlock == null) { - if (buffers.Length == 1) - { - if (buffers[0] != null) - return true; - else - return false; - } - int lengthA = buffers[0].Length; - for (int i = 1; i < buffers.Length; i++) - { - if (buffers[i].Length == lengthA) - continue; - else if (buffers[i].Length < lengthA) - lengthA = buffers[i].Length; - else if (buffers[i].Length > lengthA) - return false; - else - throw new NotImplementedException("Failed to validate a FLUTE play"); - } - return true; + fluteBlock = new FluteBlock(sbn, esi, lctFrame.Payload); + blocks.Add(fluteBlock); + } + else + { + blocksDeduplicated++; } } + internal bool IsComplete() + { + if (_disabled) + return false; + if (CarrierInformation != null) + return true; + + if (transferLength == 0) + return false; + + + return DataWritten >= transferLength; + } + + public ulong DataWritten + { + get + { + ulong currentAmount = 0; + foreach (FluteBlock block in blocks) + currentAmount += (uint)block.Payload.Length; + return currentAmount; + } + } + + internal Stream ToStream() + { + if (!IsComplete()) + throw new InvalidOperationException(); + + Stream level1; + if (blocks.Count == 1) + { + level1 = new MemoryStream(blocks[0].Payload); + } + else + { + blocks.Sort(new FluteBlockComparer()); + level1 = new FluteListenerStream(blocks); + } + + if (FileAssociation != null) + { + switch(FileAssociation.ContentEncoding) + { + case null: + break; + case "gzip": + GZipStream level2 = new GZipStream(level1, CompressionMode.Decompress, false); + return level2; + default: + throw new NotImplementedException(FileAssociation.ContentEncoding); + } + } + return level1; + } + + internal void WriteToFile(string filename) + { + FileInfo fi = new FileInfo(filename); + if (fi.Exists) + fi.Delete(); + FileStream fileStream = fi.OpenWrite(); + Stream sourceStream = ToStream(); + sourceStream.CopyTo(fileStream); + sourceStream.Close(); + fileStream.Flush(); + fileStream.Close(); + fileStream.Dispose(); + } + + private ulong transferLength; + private List blocks; + private uint blocksDeduplicated; + + public class FluteBlock + { + public FluteBlock(ushort sourceBlockNumer, ushort encodingSymbolId, byte[] payload) + { + SourceBlockNumer = sourceBlockNumer; + EncodingSymbolId = encodingSymbolId; + Payload = payload; + } + + public ushort SourceBlockNumer { get; } + public ushort EncodingSymbolId { get; } + public byte[] Payload { get; } + + public override string ToString() + { + return String.Format("SBN={0}, ESI={1}", SourceBlockNumer, EncodingSymbolId); + } + } + + public FileType FileAssociation { get; set; } + + public NipActualCarrierInformation CarrierInformation { get; private set; } + + private bool _disabled; + public bool Disabled + { + get + { + return _disabled; + } + set + { + if (value) + { + transferLength = 0; + blocks.Clear(); + blocks = null; + } + _disabled = value; + } + } } } diff --git a/skyscraper8/Ietf/FLUTE/_2DMemoryStream.cs b/skyscraper8/Ietf/FLUTE/FluteListenerStream.cs similarity index 74% rename from skyscraper8/Ietf/FLUTE/_2DMemoryStream.cs rename to skyscraper8/Ietf/FLUTE/FluteListenerStream.cs index 764250e..64c28c4 100644 --- a/skyscraper8/Ietf/FLUTE/_2DMemoryStream.cs +++ b/skyscraper8/Ietf/FLUTE/FluteListenerStream.cs @@ -8,15 +8,16 @@ using System.Threading.Tasks; namespace skyscraper8.Ietf.FLUTE { - internal class _2DMemoryStream : Stream + internal class FluteListenerStream : Stream { - public _2DMemoryStream(byte[][] backing) + + public FluteListenerStream(List blocks) { - this.backing = backing; - this.myModuleLength = backing.Select(x => x.Length).Sum(); + this.blocks = blocks; + this.myModuleLength = this.blocks.Select(x => x.Payload.LongLength).Sum(); } - private byte[][] backing; + private List blocks; private long currentPosition; private long myModuleLength; @@ -27,14 +28,14 @@ namespace skyscraper8.Ietf.FLUTE [MethodImpl(MethodImplOptions.AggressiveInlining)] private int GetRequiredBlockId(long position) { - for (int i = 0; i < backing.Length; i++) + for (int i = 0; i < blocks.Count; i++) { - if (backing[i].Length > position) + if (blocks[i].Payload.Length > position) { return i; } - position -= backing[i].Length; + position -= blocks[i].Payload.Length; } throw new ArgumentOutOfRangeException(nameof(position)); } @@ -42,14 +43,14 @@ namespace skyscraper8.Ietf.FLUTE [MethodImpl(MethodImplOptions.AggressiveInlining)] private int GetOffsetInBlock(long position) { - for (int i = 0; i < backing.Length; i++) + for (int i = 0; i < blocks.Count; i++) { - if (backing[i].Length > position) + if (blocks[i].Payload.Length > position) { return (int)position; } - position -= backing[i].Length; + position -= blocks[i].Payload.Length; } throw new ArgumentOutOfRangeException(nameof(position)); } @@ -71,11 +72,11 @@ namespace skyscraper8.Ietf.FLUTE int requiredBlockId = GetRequiredBlockId(currentPosition); int offsetInBlock = GetOffsetInBlock(currentPosition); - int remainingInBlock = backing[requiredBlockId].Length - offsetInBlock; + int remainingInBlock = blocks[requiredBlockId].Payload.Length - offsetInBlock; int bytesToCopy = Math.Min(remainingInBlock, count); int stillNeededToCopy = count - bytesToCopy; - Array.Copy(backing[requiredBlockId], offsetInBlock, buffer, offset, bytesToCopy); + Array.Copy(blocks[requiredBlockId].Payload, offsetInBlock, buffer, offset, bytesToCopy); Position += bytesToCopy; int result = bytesToCopy; offset += bytesToCopy; @@ -85,11 +86,11 @@ namespace skyscraper8.Ietf.FLUTE { requiredBlockId++; offsetInBlock = 0; - remainingInBlock = backing[requiredBlockId].Length - offsetInBlock; + remainingInBlock = blocks[requiredBlockId].Payload.Length - offsetInBlock; bytesToCopy = Math.Min(remainingInBlock, count); stillNeededToCopy = count - bytesToCopy; - Array.Copy(backing[requiredBlockId], offsetInBlock, buffer, offset, bytesToCopy); + Array.Copy(blocks[requiredBlockId].Payload, offsetInBlock, buffer, offset, bytesToCopy); Position += bytesToCopy; result += bytesToCopy; offset += bytesToCopy; @@ -119,12 +120,12 @@ namespace skyscraper8.Ietf.FLUTE public override void SetLength(long value) { - throw new NotSupportedException("Can't modify the length of a 2DArray"); + throw new NotSupportedException("Can't modify the length of a ModuleInfo"); } public override void Write(byte[] buffer, int offset, int count) { - throw new NotSupportedException("Can't write to a 2DArray"); + throw new NotSupportedException("Can't write to a ModuleInfo"); } public override bool CanRead => true; diff --git a/skyscraper8/Ietf/FLUTE/IFluteEventHandler.cs b/skyscraper8/Ietf/FLUTE/IFluteEventHandler.cs deleted file mode 100644 index 9a65883..0000000 --- a/skyscraper8/Ietf/FLUTE/IFluteEventHandler.cs +++ /dev/null @@ -1,18 +0,0 @@ -using skyscraper8.DvbNip; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Net; -using System.Text; -using System.Threading.Tasks; - -namespace skyscraper8.Ietf.FLUTE -{ - internal interface IFluteEventHandler - { - void InformToi(IPAddress destinationAddress, ushort destinationPort, ulong transportObjectIdentifier, ulong transportSessionIdentifier); - bool IpFilterEnabled(); - void OnCompletePlay(FluteListener.FlutePlay flutePlay); - void OnNipCarrierInformation(NipActualCarrierInformation nipActualCarrierInformation); - } -} diff --git a/skyscraper8/Ietf/Rfc971_IPv4/InternetHeader.cs b/skyscraper8/Ietf/Rfc971_IPv4/InternetHeader.cs index 13111a3..77a64d8 100644 --- a/skyscraper8/Ietf/Rfc971_IPv4/InternetHeader.cs +++ b/skyscraper8/Ietf/Rfc971_IPv4/InternetHeader.cs @@ -35,9 +35,16 @@ namespace skyscraper5.Ietf.Rfc971 HeaderLength = IHL * 4; SourceAddress = new IPAddress(ms.ReadBytes(4)); - DestinationAddress = new IPAddress(ms.ReadBytes(4)); + byte[] destAddresBytes = ms.ReadBytes(4); + int multicastTemp = destAddresBytes[0]; + multicastTemp &= 0b11100000; + multicastTemp >>= 4; + if (multicastTemp == 0b1110) + IsDestinationMulticast = true; - int optionsLength = HeaderLength - (int)ms.Position; + DestinationAddress = new IPAddress(destAddresBytes); + + int optionsLength = HeaderLength - (int)ms.Position; Options = ms.ReadBytes(optionsLength); CalculateChecksum(ipv4Header, IHL); @@ -115,5 +122,6 @@ namespace skyscraper5.Ietf.Rfc971 public bool ChecksumValid { get; private set; } public ushort CalculatedChecksum { get; private set; } - } + public bool IsDestinationMulticast { get; } + } } diff --git a/skyscraper8/Skyscraper/Plugins/ISkyscraperMpePlugin.cs b/skyscraper8/Skyscraper/Plugins/ISkyscraperMpePlugin.cs index 6e1c3e3..84f1b58 100644 --- a/skyscraper8/Skyscraper/Plugins/ISkyscraperMpePlugin.cs +++ b/skyscraper8/Skyscraper/Plugins/ISkyscraperMpePlugin.cs @@ -6,7 +6,7 @@ namespace skyscraper5.Skyscraper.Plugins public interface ISkyscraperMpePlugin { void ConnectToStorage(object[] connector); - void SetContext(DateTime? currentTime); + void SetContext(DateTime? currentTime, object skyscraperContext); bool CanHandlePacket(InternetHeader internetHeader, byte[] ipv4Packet); void HandlePacket(InternetHeader internetHeader, byte[] ipv4Packet); bool StopProcessingAfterThis(); diff --git a/skyscraper8/Skyscraper/Scraper/SkyscraperContext.cs b/skyscraper8/Skyscraper/Scraper/SkyscraperContext.cs index a1cb352..8d359f9 100644 --- a/skyscraper8/Skyscraper/Scraper/SkyscraperContext.cs +++ b/skyscraper8/Skyscraper/Scraper/SkyscraperContext.cs @@ -31,6 +31,7 @@ using skyscraper5.Mpeg2.Psi.Model; using skyscraper5.Rds; using skyscraper5.Rds.Messages; using skyscraper5.Scte35; +using skyscraper5.Skyscraper.IO; using skyscraper5.Skyscraper.Net; using skyscraper5.Skyscraper.Net.Pcap; using skyscraper5.Skyscraper.Plugins; @@ -57,6 +58,8 @@ using skyscraper5.Teletext; using skyscraper5.Teletext.Vps; using skyscraper5.Teletext.Wss; using skyscraper8.DvbI; +using skyscraper8.DvbNip; +using skyscraper8.Ietf.FLUTE; using skyscraper8.Ses; using skyscraper8.yo3explorer; using System; @@ -80,7 +83,7 @@ namespace skyscraper5.Skyscraper.Scraper UpdateNotificationEventHandler, DataCarouselEventHandler, RdsEventHandler, IScte35EventHandler, IAutodetectionEventHandler, IRstEventHandler, IRntEventHandler, IMultiprotocolEncapsulationEventHandler, ObjectCarouselEventHandler, T2MIEventHandler, IDisposable, IFrameGrabberEventHandler, IntEventHandler, IRctEventHandler, IGsEventHandler, ISkyscraperContext, IDocsisEventHandler, AbertisDecoderEventHandler, Id3Handler, - InteractionChannelHandler, SgtEventHandler + InteractionChannelHandler, SgtEventHandler, IDvbNipEventHandler { public const bool ALLOW_STREAM_TYPE_AUTODETECTION = true; public const bool ALLOW_FFMPEG_FRAMEGRABBER = true; @@ -1749,7 +1752,7 @@ namespace skyscraper5.Skyscraper.Scraper { if (plugin.CanHandlePacket(internetHeader, ipv4Packet)) { - plugin.SetContext(currentTime); + plugin.SetContext(currentTime,this); plugin.HandlePacket(internetHeader, ipv4Packet); if (plugin.StopProcessingAfterThis()) return; @@ -2444,5 +2447,22 @@ namespace skyscraper5.Skyscraper.Scraper processor.ProcessFilesystem(vfs, context, state); } } + + public void FluteFileArrival(NipActualCarrierInformation carrier, FluteListener listener) + { + string filename = DvbNipUtilities.MakeFilename(listener.FileAssociation.ContentLocation); + FileInfo fileInfo = new FileInfo(filename); + if (!fileInfo.Exists) + { + LogEvent(SkyscraperContextEvent.FluteFileArrival, listener.FileAssociation.ContentLocation); + fileInfo.Directory.EnsureExists(); + listener.WriteToFile(fileInfo.FullName); + } + } + + public void OnMulticastGatewayConfiguration(NipActualCarrierInformation carrier, MulticastGatewayConfigurationType multicastGatewayConfiguration) + { + + } } } diff --git a/skyscraper8/Skyscraper/Scraper/SkyscraperContextEvent.cs b/skyscraper8/Skyscraper/Scraper/SkyscraperContextEvent.cs index e7e2357..730ece5 100644 --- a/skyscraper8/Skyscraper/Scraper/SkyscraperContextEvent.cs +++ b/skyscraper8/Skyscraper/Scraper/SkyscraperContextEvent.cs @@ -72,6 +72,7 @@ TimCorrectionControl, TimNetworkLayerInfo, SgtList, - SgtService + SgtService, + FluteFileArrival } }