FLUTE works kind of as intended now.
This commit is contained in:
parent
324ba789d5
commit
ef0ee985e4
15
skyscraper8/DvbNip/DvbNipEventHandler.cs
Normal file
15
skyscraper8/DvbNip/DvbNipEventHandler.cs
Normal 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);
|
||||
}
|
||||
}
|
||||
@ -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; }
|
||||
}
|
||||
}
|
||||
|
||||
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -7,7 +7,7 @@ using System.Threading.Tasks;
|
||||
|
||||
namespace skyscraper8.DvbNip
|
||||
{
|
||||
internal class NipActualCarrierInformation
|
||||
public class NipActualCarrierInformation
|
||||
{
|
||||
public NipActualCarrierInformation(byte[] buffer)
|
||||
{
|
||||
|
||||
27
skyscraper8/Ietf/FLUTE/FluteBlockComparer.cs
Normal file
27
skyscraper8/Ietf/FLUTE/FluteBlockComparer.cs
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -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;
|
||||
@ -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);
|
||||
}
|
||||
}
|
||||
@ -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; }
|
||||
}
|
||||
}
|
||||
|
||||
@ -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();
|
||||
|
||||
@ -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)
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -72,6 +72,7 @@
|
||||
TimCorrectionControl,
|
||||
TimNetworkLayerInfo,
|
||||
SgtList,
|
||||
SgtService
|
||||
SgtService,
|
||||
FluteFileArrival
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user