FLUTE works kind of as intended now.

This commit is contained in:
feyris-tan 2025-06-15 15:37:31 +02:00
parent 324ba789d5
commit ef0ee985e4
12 changed files with 367 additions and 344 deletions

View File

@ -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);
}
}

View File

@ -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<FluteListener> flutes = new List<FluteListener>();
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 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; }
}
}

View File

@ -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;
}
}
}

View File

@ -7,7 +7,7 @@ using System.Threading.Tasks;
namespace skyscraper8.DvbNip
{
internal class NipActualCarrierInformation
public class NipActualCarrierInformation
{
public NipActualCarrierInformation(byte[] buffer)
{

View File

@ -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<FluteListener.FluteBlock>
{
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;
}
}
}

View File

@ -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? 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 "<disabled>";
}
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<FlutePlay> 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 "<disabled>";
}
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<FluteBlock>();
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<FluteBlock> 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;
}
}
}
}

View File

@ -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<FluteListener.FluteBlock> 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<FluteListener.FluteBlock> 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;

View File

@ -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);
}
}

View File

@ -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; }
}
}

View File

@ -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();

View File

@ -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)
{
}
}
}

View File

@ -72,6 +72,7 @@
TimCorrectionControl,
TimNetworkLayerInfo,
SgtList,
SgtService
SgtService,
FluteFileArrival
}
}