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.Rfc768;
|
||||||
using skyscraper5.Ietf.Rfc971;
|
using skyscraper5.Ietf.Rfc971;
|
||||||
|
using skyscraper5.Skyscraper.IO;
|
||||||
using skyscraper5.Skyscraper.Plugins;
|
using skyscraper5.Skyscraper.Plugins;
|
||||||
using skyscraper8.Ietf.FLUTE;
|
using skyscraper8.Ietf.FLUTE;
|
||||||
using System;
|
using System;
|
||||||
@ -12,21 +13,11 @@ using System.Threading.Tasks;
|
|||||||
namespace skyscraper8.DvbNip
|
namespace skyscraper8.DvbNip
|
||||||
{
|
{
|
||||||
[SkyscraperPlugin]
|
[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)
|
public bool CanHandlePacket(InternetHeader internetHeader, byte[] ipv4Packet)
|
||||||
{
|
{
|
||||||
byte[] destinationBytes = internetHeader.DestinationAddress.GetAddressBytes();
|
if (!internetHeader.IsDestinationMulticast)
|
||||||
int multicastTemp = destinationBytes[0];
|
|
||||||
multicastTemp &= 0b11100000;
|
|
||||||
multicastTemp >>= 4;
|
|
||||||
if (multicastTemp != 0b1110)
|
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (internetHeader.Protocol != 17)
|
if (internetHeader.Protocol != 17)
|
||||||
@ -37,102 +28,115 @@ namespace skyscraper8.DvbNip
|
|||||||
|
|
||||||
public void ConnectToStorage(object[] connector)
|
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)
|
public void HandlePacket(InternetHeader internetHeader, byte[] ipv4Packet)
|
||||||
{
|
{
|
||||||
UserDatagram udpPacket = new UserDatagram(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 (flutes == null)
|
||||||
{
|
flutes = new List<FluteListener>();
|
||||||
if (phase == DvbNipPhase.DownloadMode)
|
|
||||||
|
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 (fluteListener == null)
|
||||||
{
|
{
|
||||||
if (phase == DvbNipPhase.DownloadMode)
|
fluteListener = new FluteListener(internetHeader.DestinationAddress, udpPacket.DestinationPort, lctFrame.LctHeader.TransportSessionIdentifier, lctFrame.LctHeader.TransportObjectIdentifier);
|
||||||
return false;
|
flutes.Add(fluteListener);
|
||||||
|
fluteMisses++;
|
||||||
|
}
|
||||||
else
|
else
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void OnCompletePlay(FluteListener.FlutePlay flutePlay)
|
|
||||||
{
|
|
||||||
if (phase == DvbNipPhase.WaitingForSignalling)
|
|
||||||
{
|
{
|
||||||
phase = DvbNipPhase.DownloadMode;
|
fluteHits++;
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
else if (phase == DvbNipPhase.DownloadMode)
|
fluteListener.PushPacket(lctFrame);
|
||||||
|
if (fluteListener.IsComplete())
|
||||||
{
|
{
|
||||||
if (!flutePlay.Validate())
|
if (fluteListener.DestinationToi == 0)
|
||||||
{
|
{
|
||||||
flutePlay.SetIgnore(true);
|
if (fluteListener.CarrierInformation != null)
|
||||||
flutePlay.SetIgnore(false);
|
{
|
||||||
|
CurrentCarrierInformation = fluteListener.CarrierInformation;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
Stream fluteStream = fluteListener.ToStream();
|
||||||
|
FDTInstanceType fdtAnnouncement = FluteUtilities.UnpackFluteFdt(fluteStream);
|
||||||
|
SetFileAssociations(fluteListener, fdtAnnouncement);
|
||||||
|
fluteStream.Close();
|
||||||
|
fluteStream.Dispose();
|
||||||
|
flutes.Remove(fluteListener);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (flutePlay.TOI == 0)
|
if (fluteListener.FileAssociation == null)
|
||||||
{
|
{
|
||||||
FDTInstanceType fdtInstance = FluteUtilities.UnpackFluteFdt(flutePlay.GetStream());
|
return;
|
||||||
foreach(FileType filetype in fdtInstance.File)
|
}
|
||||||
|
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;
|
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
|
else
|
||||||
{
|
{
|
||||||
if (flutePlay.FileAssociation.ContentLocation.Equals("urn:dvb:metadata:cs:MulticastTransportObjectTypeCS:2021:gateway-configuration"))
|
targetListener = new FluteListener(sourceListener.DestinationAddress, sourceListener.DestinationPort, sourceListener.DestinationTsi, targetToi);
|
||||||
{
|
targetListener.FileAssociation = announcedFile;
|
||||||
MulticastGatewayConfigurationType multicastGatewayConfigurationType = DvbNipUtilities.UnpackMulticastGatewayConfiguration(flutePlay.GetStream());
|
flutes.Add(targetListener);
|
||||||
//TODO: Handle Multicast Gateway configuration
|
|
||||||
flutePlay.SetIgnore(true);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
flutePlay.WriteToFile("test.xml");
|
|
||||||
}
|
}
|
||||||
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;
|
IDvbNipEventHandler? dvbNipEventHandler = skyscraperContext as IDvbNipEventHandler;
|
||||||
flute.RemoveAllPlays();
|
if (dvbNipEventHandler != null)
|
||||||
flute.AddPlay(IPAddress.Parse("224.0.23.14"), 3937, 0, 0);
|
EventHandler = dvbNipEventHandler;
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -141,12 +145,7 @@ namespace skyscraper8.DvbNip
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
private enum DvbNipPhase
|
public NipActualCarrierInformation CurrentCarrierInformation { get; private set; }
|
||||||
{
|
public IDvbNipEventHandler EventHandler { get; private set; }
|
||||||
JustPoweredUp,
|
|
||||||
WaitingForCarrierInformation,
|
|
||||||
WaitingForSignalling,
|
|
||||||
DownloadMode,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -24,5 +24,19 @@ namespace skyscraper8.DvbNip
|
|||||||
MulticastGatewayConfigurationType result = (MulticastGatewayConfigurationType)v;
|
MulticastGatewayConfigurationType result = (MulticastGatewayConfigurationType)v;
|
||||||
return result;
|
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
|
namespace skyscraper8.DvbNip
|
||||||
{
|
{
|
||||||
internal class NipActualCarrierInformation
|
public class NipActualCarrierInformation
|
||||||
{
|
{
|
||||||
public NipActualCarrierInformation(byte[] buffer)
|
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 skyscraper8.DvbNip;
|
||||||
using skyscraper5.Ietf.Rfc971;
|
|
||||||
using skyscraper8.DvbNip;
|
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.IO.Compression;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using System.Linq.Expressions;
|
||||||
using System.Net;
|
using System.Net;
|
||||||
|
using System.Runtime.Serialization;
|
||||||
|
using System.Security.Cryptography.X509Certificates;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
namespace skyscraper8.Ietf.FLUTE
|
namespace skyscraper8.Ietf.FLUTE
|
||||||
{
|
{
|
||||||
internal class FluteListener
|
public class FluteListener
|
||||||
{
|
{
|
||||||
|
public FluteListener(IPAddress destinationAddress, ushort destinationPort, ulong destinationTsi, ulong destinationToi)
|
||||||
internal void AddPlay(IPAddress iPAddress, int port, ulong tsi, ulong toi)
|
|
||||||
{
|
{
|
||||||
if (knownFlutePlays == null)
|
DestinationAddress = destinationAddress;
|
||||||
knownFlutePlays = new List<FlutePlay>();
|
DestinationPort = destinationPort;
|
||||||
|
DestinationTsi = destinationTsi;
|
||||||
FlutePlay? flutePlay = knownFlutePlays.Find(x => x.IPAddress.Equals(iPAddress) &&
|
DestinationToi = destinationToi;
|
||||||
x.Port == port &&
|
|
||||||
x.TSI == tsi &&
|
|
||||||
x.TOI == toi);
|
|
||||||
if (flutePlay != null)
|
|
||||||
return;
|
|
||||||
|
|
||||||
FlutePlay play = new FlutePlay(iPAddress, port, tsi, toi);
|
|
||||||
knownFlutePlays.Add(play);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
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;
|
return;
|
||||||
|
|
||||||
if (eventHandler.IpFilterEnabled())
|
if (lctFrame.LctHeader.FecObjectTransmissionInformation == null)
|
||||||
{
|
{
|
||||||
FlutePlay? ipFound = knownFlutePlays.Find(x => x.IPAddress.Equals(destinationAddress) && x.Port == destinationPort);
|
if (lctFrame.LctHeader.NipActualCarrierInformation != null)
|
||||||
if (ipFound == null)
|
{
|
||||||
|
CarrierInformation = lctFrame.LctHeader.NipActualCarrierInformation;
|
||||||
return;
|
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
|
else
|
||||||
{
|
{
|
||||||
neededEsi = 0;
|
throw new NotImplementedException("non fec");
|
||||||
neededSbn = 0;
|
|
||||||
nextX = 0;
|
|
||||||
buffers = new byte[maxX][];
|
|
||||||
ignore = false;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
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)
|
fluteBlock = new FluteBlock(sbn, esi, lctFrame.Payload);
|
||||||
{
|
blocks.Add(fluteBlock);
|
||||||
if (buffers[0] != null)
|
}
|
||||||
return true;
|
else
|
||||||
else
|
{
|
||||||
return false;
|
blocksDeduplicated++;
|
||||||
}
|
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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
|
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.blocks = blocks;
|
||||||
this.myModuleLength = backing.Select(x => x.Length).Sum();
|
this.myModuleLength = this.blocks.Select(x => x.Payload.LongLength).Sum();
|
||||||
}
|
}
|
||||||
|
|
||||||
private byte[][] backing;
|
private List<FluteListener.FluteBlock> blocks;
|
||||||
private long currentPosition;
|
private long currentPosition;
|
||||||
private long myModuleLength;
|
private long myModuleLength;
|
||||||
|
|
||||||
@ -27,14 +28,14 @@ namespace skyscraper8.Ietf.FLUTE
|
|||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
private int GetRequiredBlockId(long position)
|
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;
|
return i;
|
||||||
}
|
}
|
||||||
|
|
||||||
position -= backing[i].Length;
|
position -= blocks[i].Payload.Length;
|
||||||
}
|
}
|
||||||
throw new ArgumentOutOfRangeException(nameof(position));
|
throw new ArgumentOutOfRangeException(nameof(position));
|
||||||
}
|
}
|
||||||
@ -42,14 +43,14 @@ namespace skyscraper8.Ietf.FLUTE
|
|||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
private int GetOffsetInBlock(long position)
|
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;
|
return (int)position;
|
||||||
}
|
}
|
||||||
|
|
||||||
position -= backing[i].Length;
|
position -= blocks[i].Payload.Length;
|
||||||
}
|
}
|
||||||
throw new ArgumentOutOfRangeException(nameof(position));
|
throw new ArgumentOutOfRangeException(nameof(position));
|
||||||
}
|
}
|
||||||
@ -71,11 +72,11 @@ namespace skyscraper8.Ietf.FLUTE
|
|||||||
|
|
||||||
int requiredBlockId = GetRequiredBlockId(currentPosition);
|
int requiredBlockId = GetRequiredBlockId(currentPosition);
|
||||||
int offsetInBlock = GetOffsetInBlock(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 bytesToCopy = Math.Min(remainingInBlock, count);
|
||||||
int stillNeededToCopy = count - bytesToCopy;
|
int stillNeededToCopy = count - bytesToCopy;
|
||||||
|
|
||||||
Array.Copy(backing[requiredBlockId], offsetInBlock, buffer, offset, bytesToCopy);
|
Array.Copy(blocks[requiredBlockId].Payload, offsetInBlock, buffer, offset, bytesToCopy);
|
||||||
Position += bytesToCopy;
|
Position += bytesToCopy;
|
||||||
int result = bytesToCopy;
|
int result = bytesToCopy;
|
||||||
offset += bytesToCopy;
|
offset += bytesToCopy;
|
||||||
@ -85,11 +86,11 @@ namespace skyscraper8.Ietf.FLUTE
|
|||||||
{
|
{
|
||||||
requiredBlockId++;
|
requiredBlockId++;
|
||||||
offsetInBlock = 0;
|
offsetInBlock = 0;
|
||||||
remainingInBlock = backing[requiredBlockId].Length - offsetInBlock;
|
remainingInBlock = blocks[requiredBlockId].Payload.Length - offsetInBlock;
|
||||||
bytesToCopy = Math.Min(remainingInBlock, count);
|
bytesToCopy = Math.Min(remainingInBlock, count);
|
||||||
stillNeededToCopy = count - bytesToCopy;
|
stillNeededToCopy = count - bytesToCopy;
|
||||||
|
|
||||||
Array.Copy(backing[requiredBlockId], offsetInBlock, buffer, offset, bytesToCopy);
|
Array.Copy(blocks[requiredBlockId].Payload, offsetInBlock, buffer, offset, bytesToCopy);
|
||||||
Position += bytesToCopy;
|
Position += bytesToCopy;
|
||||||
result += bytesToCopy;
|
result += bytesToCopy;
|
||||||
offset += bytesToCopy;
|
offset += bytesToCopy;
|
||||||
@ -119,12 +120,12 @@ namespace skyscraper8.Ietf.FLUTE
|
|||||||
|
|
||||||
public override void SetLength(long value)
|
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)
|
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;
|
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;
|
HeaderLength = IHL * 4;
|
||||||
|
|
||||||
SourceAddress = new IPAddress(ms.ReadBytes(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);
|
Options = ms.ReadBytes(optionsLength);
|
||||||
CalculateChecksum(ipv4Header, IHL);
|
CalculateChecksum(ipv4Header, IHL);
|
||||||
@ -115,5 +122,6 @@ namespace skyscraper5.Ietf.Rfc971
|
|||||||
|
|
||||||
public bool ChecksumValid { get; private set; }
|
public bool ChecksumValid { get; private set; }
|
||||||
public ushort CalculatedChecksum { get; private set; }
|
public ushort CalculatedChecksum { get; private set; }
|
||||||
}
|
public bool IsDestinationMulticast { get; }
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -6,7 +6,7 @@ namespace skyscraper5.Skyscraper.Plugins
|
|||||||
public interface ISkyscraperMpePlugin
|
public interface ISkyscraperMpePlugin
|
||||||
{
|
{
|
||||||
void ConnectToStorage(object[] connector);
|
void ConnectToStorage(object[] connector);
|
||||||
void SetContext(DateTime? currentTime);
|
void SetContext(DateTime? currentTime, object skyscraperContext);
|
||||||
bool CanHandlePacket(InternetHeader internetHeader, byte[] ipv4Packet);
|
bool CanHandlePacket(InternetHeader internetHeader, byte[] ipv4Packet);
|
||||||
void HandlePacket(InternetHeader internetHeader, byte[] ipv4Packet);
|
void HandlePacket(InternetHeader internetHeader, byte[] ipv4Packet);
|
||||||
bool StopProcessingAfterThis();
|
bool StopProcessingAfterThis();
|
||||||
|
|||||||
@ -31,6 +31,7 @@ using skyscraper5.Mpeg2.Psi.Model;
|
|||||||
using skyscraper5.Rds;
|
using skyscraper5.Rds;
|
||||||
using skyscraper5.Rds.Messages;
|
using skyscraper5.Rds.Messages;
|
||||||
using skyscraper5.Scte35;
|
using skyscraper5.Scte35;
|
||||||
|
using skyscraper5.Skyscraper.IO;
|
||||||
using skyscraper5.Skyscraper.Net;
|
using skyscraper5.Skyscraper.Net;
|
||||||
using skyscraper5.Skyscraper.Net.Pcap;
|
using skyscraper5.Skyscraper.Net.Pcap;
|
||||||
using skyscraper5.Skyscraper.Plugins;
|
using skyscraper5.Skyscraper.Plugins;
|
||||||
@ -57,6 +58,8 @@ using skyscraper5.Teletext;
|
|||||||
using skyscraper5.Teletext.Vps;
|
using skyscraper5.Teletext.Vps;
|
||||||
using skyscraper5.Teletext.Wss;
|
using skyscraper5.Teletext.Wss;
|
||||||
using skyscraper8.DvbI;
|
using skyscraper8.DvbI;
|
||||||
|
using skyscraper8.DvbNip;
|
||||||
|
using skyscraper8.Ietf.FLUTE;
|
||||||
using skyscraper8.Ses;
|
using skyscraper8.Ses;
|
||||||
using skyscraper8.yo3explorer;
|
using skyscraper8.yo3explorer;
|
||||||
using System;
|
using System;
|
||||||
@ -80,7 +83,7 @@ namespace skyscraper5.Skyscraper.Scraper
|
|||||||
UpdateNotificationEventHandler, DataCarouselEventHandler, RdsEventHandler, IScte35EventHandler,
|
UpdateNotificationEventHandler, DataCarouselEventHandler, RdsEventHandler, IScte35EventHandler,
|
||||||
IAutodetectionEventHandler, IRstEventHandler, IRntEventHandler, IMultiprotocolEncapsulationEventHandler, ObjectCarouselEventHandler, T2MIEventHandler,
|
IAutodetectionEventHandler, IRstEventHandler, IRntEventHandler, IMultiprotocolEncapsulationEventHandler, ObjectCarouselEventHandler, T2MIEventHandler,
|
||||||
IDisposable, IFrameGrabberEventHandler, IntEventHandler, IRctEventHandler, IGsEventHandler, ISkyscraperContext, IDocsisEventHandler, AbertisDecoderEventHandler, Id3Handler,
|
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_STREAM_TYPE_AUTODETECTION = true;
|
||||||
public const bool ALLOW_FFMPEG_FRAMEGRABBER = true;
|
public const bool ALLOW_FFMPEG_FRAMEGRABBER = true;
|
||||||
@ -1749,7 +1752,7 @@ namespace skyscraper5.Skyscraper.Scraper
|
|||||||
{
|
{
|
||||||
if (plugin.CanHandlePacket(internetHeader, ipv4Packet))
|
if (plugin.CanHandlePacket(internetHeader, ipv4Packet))
|
||||||
{
|
{
|
||||||
plugin.SetContext(currentTime);
|
plugin.SetContext(currentTime,this);
|
||||||
plugin.HandlePacket(internetHeader, ipv4Packet);
|
plugin.HandlePacket(internetHeader, ipv4Packet);
|
||||||
if (plugin.StopProcessingAfterThis())
|
if (plugin.StopProcessingAfterThis())
|
||||||
return;
|
return;
|
||||||
@ -2444,5 +2447,22 @@ namespace skyscraper5.Skyscraper.Scraper
|
|||||||
processor.ProcessFilesystem(vfs, context, state);
|
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,
|
TimCorrectionControl,
|
||||||
TimNetworkLayerInfo,
|
TimNetworkLayerInfo,
|
||||||
SgtList,
|
SgtList,
|
||||||
SgtService
|
SgtService,
|
||||||
|
FluteFileArrival
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user