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.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,
}
} }
} }

View File

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

View File

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

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

View File

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

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

View File

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

View File

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

View File

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