From fb34d7d21cab054451bb5740706d41253f8a54b9 Mon Sep 17 00:00:00 2001 From: feyris-tan <4116042+feyris-tan@users.noreply.github.com> Date: Sat, 10 Jan 2026 16:30:53 +0100 Subject: [PATCH] Reintroduced old IPv4 packet finding method as a fallback. --- skyscraper8/GS/IPv4PacketBruteforce.cs | 47 + skyscraper8/GS/MisHandlerProxy.cs | 4 +- skyscraper8/Skyscraper/IpPacketFinder.cs | 6 +- .../Skyscraper/Scraper/SkyscraperContext.cs | 6630 ++++++++--------- skyscraper8/VersionInfo.cs | 2 +- 5 files changed, 3369 insertions(+), 3320 deletions(-) create mode 100644 skyscraper8/GS/IPv4PacketBruteforce.cs diff --git a/skyscraper8/GS/IPv4PacketBruteforce.cs b/skyscraper8/GS/IPv4PacketBruteforce.cs new file mode 100644 index 0000000..5ccce53 --- /dev/null +++ b/skyscraper8/GS/IPv4PacketBruteforce.cs @@ -0,0 +1,47 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using log4net; +using log4net.Repository.Hierarchy; +using skyscraper5.Skyscraper; +using skyscraper8.GSE; + +namespace skyscraper8.GS +{ + internal class IPv4PacketBruteforce : IMisHandler + { + public IPv4PacketBruteforce(GsContextDto context) + { + Context = context ?? throw new ArgumentNullException(nameof(context)); + logger = LogManager.GetLogger(String.Format("{0} MIS {1}", System.Reflection.MethodBase.GetCurrentMethod().DeclaringType.Name, context.GetMisId())); + } + + + private ILog logger; + private bool notified; + + public GsContextDto Context { get; set; } + public void PushFrame(BBHeader bbHeader, ReadOnlySpan readOnlySpan) + { + List packets = IpPacketFinder.LookForIpPackets(readOnlySpan); + if (packets == null) + return; + + if (packets.Count == 0) + return; + + if (!notified) + { + logger.InfoFormat("Found valid IP traffic on MIS {0}.", Context.GetMisId()); + notified = true; + } + + foreach (byte[] packet in packets) + { + Context.IpOutput.OnIpDatagram(0x0118, packet); + } + } + } +} diff --git a/skyscraper8/GS/MisHandlerProxy.cs b/skyscraper8/GS/MisHandlerProxy.cs index c5842bb..eb6228b 100644 --- a/skyscraper8/GS/MisHandlerProxy.cs +++ b/skyscraper8/GS/MisHandlerProxy.cs @@ -147,7 +147,9 @@ class MisHandlerProxy : IMisHandler } } - return false; + logger.WarnFormat("MIS {0} has an unknown stream type. The IP packet detection algorithm from older skyscraper8 versions will be used. For further analysis, please consider submitting a sample of this stream.", Context.GetMisId()); + misHandler = new IPv4PacketBruteforce(Context); + return false; } private void DrainQueue() diff --git a/skyscraper8/Skyscraper/IpPacketFinder.cs b/skyscraper8/Skyscraper/IpPacketFinder.cs index 65a02cb..d9c9f5a 100644 --- a/skyscraper8/Skyscraper/IpPacketFinder.cs +++ b/skyscraper8/Skyscraper/IpPacketFinder.cs @@ -52,7 +52,7 @@ namespace skyscraper5.Skyscraper return null; } - public static List LookForIpPackets(byte[] gsPacket) + public static List LookForIpPackets(ReadOnlySpan gsPacket) { List result = null; @@ -65,7 +65,7 @@ namespace skyscraper5.Skyscraper if (gsPacket[offset] == 0x45) { - Array.Copy(gsPacket, offset, ipBuffer, 0, ipBuffer.Length); + ipBuffer = gsPacket.Slice(offset, 20).ToArray(); InternetHeader ipv4 = new(ipBuffer); if (!ipv4.ChecksumValid) continue; @@ -76,7 +76,7 @@ namespace skyscraper5.Skyscraper int packetLength = payloadEnd - offset; byte[] finalPacket = new byte[packetLength]; - Array.Copy(gsPacket, offset, finalPacket, 0, packetLength); + finalPacket = gsPacket.Slice(offset, packetLength).ToArray(); if (result == null) result = new List(); result.Add(finalPacket); diff --git a/skyscraper8/Skyscraper/Scraper/SkyscraperContext.cs b/skyscraper8/Skyscraper/Scraper/SkyscraperContext.cs index 641cb37..d592a76 100644 --- a/skyscraper8/Skyscraper/Scraper/SkyscraperContext.cs +++ b/skyscraper8/Skyscraper/Scraper/SkyscraperContext.cs @@ -1,3311 +1,3311 @@ -using log4net; -using moe.yo3explorer.skyscraper8.DVBI.Model; -using skyscraper5.Abertis; -using skyscraper5.Docsis; -using skyscraper5.Docsis.MacManagement; -using skyscraper5.DsmCc.Descriptors; -using skyscraper5.Dvb.DataBroadcasting; -using skyscraper5.Dvb.DataBroadcasting.Biop; -using skyscraper5.Dvb.DataBroadcasting.Dsm.Event; -using skyscraper5.Dvb.DataBroadcasting.Dsm.Stream; -using skyscraper5.Dvb.DataBroadcasting.IntModel; -using skyscraper5.Dvb.DataBroadcasting.SkyscraperVfs; -using skyscraper5.Dvb.Descriptors; -using skyscraper5.Dvb.Psi; -using skyscraper5.Dvb.Psi.Model; -using skyscraper5.Dvb.Subtitling; -using skyscraper5.Dvb.Subtitling.Model; -using skyscraper5.Dvb.SystemSoftwareUpdate; -using skyscraper5.Dvb.SystemSoftwareUpdate.Model; -using skyscraper5.Dvb.TvAnytime; -using skyscraper5.Ietf.Rfc768; -using skyscraper5.Ietf.Rfc971; -using skyscraper5.Mheg5; -using skyscraper5.Mhp.Descriptors; -using skyscraper5.Mhp.Descriptors.InteractionTransportSelectors; -using skyscraper5.Mhp.Si; -using skyscraper5.Mhp.Si.Model; -using skyscraper5.Mpeg2; -using skyscraper5.Mpeg2.Descriptors; -using skyscraper5.Mpeg2.Psi; -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.Plugins; -using skyscraper5.Skyscraper.Scraper.FrameGrabber; -using skyscraper5.Skyscraper.Scraper.Storage.Utilities; -using skyscraper5.Skyscraper.Scraper.StreamAutodetection; -using skyscraper5.Skyscraper.Scraper.Utils; -using skyscraper5.src.Id3; -using skyscraper5.src.InteractionChannel; -using skyscraper5.src.InteractionChannel.Model; -using skyscraper5.src.InteractionChannel.Model.Descriptors; -using skyscraper5.src.Mpeg2; -using skyscraper5.src.Mpeg2.PacketFilter; -using skyscraper5.src.Skyscraper.Scraper.Dns; -using skyscraper5.src.Teletext; -using skyscraper5.T2MI; -using skyscraper5.T2MI.Packets; -using skyscraper5.T2MI.Packets.AdressingFunctions; -using skyscraper5.Teletext; -using skyscraper5.Teletext.Vps; -using skyscraper5.Teletext.Wss; -using skyscraper8.DvbI; -using skyscraper8.DvbNip; -using skyscraper8.Ietf.FLUTE; -using skyscraper8.Ietf.Rfc4236_ULE; -using skyscraper8.Ses; -using skyscraper8.Skyscraper.Scraper.Storage; -using skyscraper8.yo3explorer; -using System.Collections.ObjectModel; -using System.Diagnostics; -using System.Net; -using System.Net.NetworkInformation; -using System.Reflection; -using System.Text; -using MimeKit; -using skyscraper5.src.InteractionChannel.Model2; -using skyscraper8.Abertis; -using skyscraper8.Experimentals.NdsSsu; -using skyscraper8.Experimentals.OtvSsu; -using skyscraper8.GS; -using skyscraper8.GSE; -using skyscraper8.Ieee802_1AB; -using skyscraper8.InteractionChannel.Model; -using skyscraper8.InteractionChannel.Model2; -using skyscraper8.InteractionChannel.Model2.Descriptors; -using skyscraper8.Skyscraper.Net; -using skyscraper8.Skyscraper.Scraper; -using skyscraper8.T2MI; -using Tsubasa.IO; -using Platform = skyscraper5.Dvb.SystemSoftwareUpdate.Model.Platform; -using RntParser = skyscraper5.Dvb.TvAnytime.RntParser; -using skyscraper8.DvbSis; -using skyscraper8.T2MI.Packets; -using skyscraper5.Docsis.AnnexC; -using Ionic.Zlib; - -namespace skyscraper5.Skyscraper.Scraper -{ - public class SkyscraperContext : IPatEventHandler, IPmtEventHandler, INitEventHandler, ITeletextPageHandler, - IBatEventHandler, ISdtEventHandler, ICatEventHandler, ITdtEventHandler, ITotEventHandler, ITsdtEventHandler, - IEitEventHandler, IAitEventHandler, ISubtitleEventHandler, - UpdateNotificationEventHandler, DataCarouselEventHandler, RdsEventHandler, IScte35EventHandler, - IAutodetectionEventHandler, IRstEventHandler, IRntEventHandler, IMultiprotocolEncapsulationEventHandler, ObjectCarouselEventHandler, T2MIEventHandler, - IDisposable, IFrameGrabberEventHandler, IntEventHandler, IRctEventHandler, ISkyscraperContext, IDocsisEventHandler, AbertisDecoderEventHandler, Id3Handler, - InteractionChannelHandler, SgtEventHandler, IDvbNipEventHandler, UleEventHandler, OtvSsuHandler, NdsSsuHandler, ISubTsHandler, ILldpFrameHandler, SisHandler - { - public const bool ALLOW_STREAM_TYPE_AUTODETECTION = true; - public const bool ALLOW_FFMPEG_FRAMEGRABBER = true; - - private static readonly ILog logger = LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType.Name); - - public TsContext DvbContext { get; } - public DataStorage DataStorage { get; } - public ObjectStorage ObjectStorage { get; } - - - public bool SourceIsDisk { get; set; } - - public PsiDecoder PatDecoder { get; private set; } - public PsiDecoder CatDecoder { get; private set; } - public PsiDecoder NitDecoder { get; private set; } - public PsiDecoder Pid0x11Decoder { get; private set; } - public PsiDecoder Pid0x12Decoder { get; private set; } - public IPsiDecoderTransformer PmtDecoderTransformer { get; set; } - public SkyscraperContext(TsContext dvbContext, DataStorage dataStorage = null, ObjectStorage objectStorage = null, int skipAtStart = 0, int? currentNetworkId = null, int? currentTransportStreamId = null) - { - TsDescriptorUnpacker descriptorUnpacker = TsDescriptorUnpacker.GetInstance(); - for (byte i = 0x80; i < 0xfe; i++) - { - descriptorUnpacker.SetUserDefined(i, true); - } - - descriptorUnpacker.SetUserDefined(0xfe, true); - - DvbContext = dvbContext; - - - //PAT - PatDecoder = new PsiDecoder(0, new PatParser(this)); - dvbContext.RegisterPacketProcessor(0, PatDecoder); - //PMT autodetect from PAT - - //CAT - CatDecoder = new PsiDecoder(1, new CatParser(this)); - dvbContext.RegisterPacketProcessor(1, CatDecoder); - - //TSDT (experimental) - dvbContext.RegisterPacketProcessor(2, new PsiDecoder(2, new TsdtParser(this))); - - //IPMP (experimental) - dvbContext.RegisterPacketProcessor(3, new PsiDecoder(3, new IpmpParser(this))); - - //NIT - NitDecoder = new PsiDecoder(0x10, new NitParser(this)); - dvbContext.RegisterPacketProcessor(0x10, NitDecoder); - - //SDT / BAT - Pid0x11Decoder = new PsiDecoder(0x11, new Pid0x11Decoder(this, this)); - dvbContext.RegisterPacketProcessor(0x11, Pid0x11Decoder); - - //EIT - //dvbContext.RegisterPacketProcessor(0x12, new PsiDecoder(0x12, new EitParser(this))); - Pid0x12Decoder = new PsiDecoder(0x12, new Pid0x12Decoder(this)); - dvbContext.RegisterPacketProcessor(0x12, Pid0x12Decoder); - - //RST - DvbContext.RegisterPacketProcessor(0x13, new PsiDecoder(0x13, new RstParser(this))); - - //TDT - //TOT handled by TDT processor - dvbContext.RegisterPacketProcessor(0x14, new PsiDecoder(0x14, new TimetableParser(this, this))); - - //RNT - dvbContext.RegisterPacketProcessor(0x16, new PsiDecoder(0x16, new RntParser(this))); - - //DIT - //PID 0x1E - //won't need these. We operate on broadcasted stuff, so we shouldn't encounter partial TS - - //DIT - //PID 0x1F - //won't need these. We operate on broadcasted stuff, so we shouldn't encounter partial TS - - if (dataStorage == null) - { - throw new ArgumentNullException(nameof(dataStorage)); - } - DataStorage = dataStorage; - - if (objectStorage == null) - { - throw new ArgumentNullException(nameof(objectStorage)); - } - ObjectStorage = objectStorage; - - CurrentNetworkId = currentNetworkId; - CurrentTransportStreamId = currentTransportStreamId; - DsmCcsToLookFor = new Dictionary(); - SsusToLookFor = new List>(); - - this.skipBufferRemain = skipAtStart; - } - - public int? CurrentNetworkId { get; private set; } - public int? CurrentTransportStreamId { get; private set; } - - public TeiFilter TeiFilter { get; private set; } - public ScrambleFilter ScrambleFilter { get; private set; } - public TeiOnOffFilter TeiOnOffFilter { get; private set; } - public void InitalizeFilterChain(params IPacketFilter[] args) - { - if (DvbContext.FilterChain != null) - throw new InvalidOperationException("The filter chain was already initalized."); - if (TeiFilter == null) - TeiFilter = new TeiFilter(); - if (ScrambleFilter == null) - ScrambleFilter = new ScrambleFilter(); - if (TeiOnOffFilter == null) - TeiOnOffFilter = new TeiOnOffFilter(); - - List result = new List(); - result.AddRange(args); - result.Add(TeiFilter); - result.Add(ScrambleFilter); - result.Add(TeiOnOffFilter); - result.Sort(new PluginPrioritySorter()); - DvbContext.FilterChain = result; - - StringBuilder stringBuilder = new StringBuilder(); - stringBuilder.Append("IN"); - for (int i = 0; i < result.Count; i++) - { - stringBuilder.Append(" -> "); - if (result[i] != null) - { - stringBuilder.Append(result[i].GetType().Name); - } - else - { - stringBuilder.Append("(null)"); - } - } - stringBuilder.Append(" -> OUT"); - logger.DebugFormat("Built filter chain: {0}", stringBuilder.ToString()); - } - - public int GetIpCommunicationParties() - { - if (trafficInfos == null) - return 0; - else - return trafficInfos.Count; - } - - public void IngestFromStream(Stream stream) - { - byte[] buffer = new byte[188]; - while (true) - { - if (IsAbortConditionMet()) - break; - - if (stream.Read(buffer, 0, 188) != 188) - break; - - try - { - IngestSinglePacket(buffer); - } - catch (InvalidTsPacketException) - { - break; - } - } - - stream.Close(); - runningEvents = null; - } - - private bool skipBufferStarted; - private int skipBufferRemain; - private bool firstPacketDone = false; - private ulong totalPacketsPushed; - - public void IngestSinglePacket(byte[] buffer) - { - if (buffer.Length != 188) - throw new ArgumentException(String.Format("{0}.{1} != {2}", nameof(buffer), nameof(buffer.Length), - 188)); - - if (skipBufferRemain > 0) - { - if (!skipBufferStarted) - { - LogEvent(SkyscraperContextEvent.StartPacketProcessing, String.Format("Skipping {0} packets before begin.", skipBufferRemain)); - skipBufferStarted = true; - } - skipBufferRemain--; - } - - if (!firstPacketDone) - { - LogEvent(SkyscraperContextEvent.StartPacketProcessing); - if (buffer[0] == 0x47 && buffer[1] == 0x41 && buffer[2] == 0x18 && (buffer[3] & 0x10) != 0 && buffer[4] == 0x00 && buffer[5] == 0x80 && buffer[6] == 0x00) - { - DvbContext.RegisterPacketProcessor(0x0118, new OldStreamReaderDetector()); - SpecialTsType = 2; - } - if (buffer[0] == 0x47 && buffer[1] == 0x41 && buffer[2] == 0x0e && (buffer[3] & 0x10) != 0 && buffer[4] == 0x00 && buffer[5] == 0x80 && buffer[6] == 0x00) - { - if (!DvbContext.IsPidProcessorPresent(0x010e)) - { - DvbContext.RegisterPacketProcessor(0x010e, new Stid135BbFrameReader(CreateGsContext())); - UiJunction?.SetGseMode(); - LogEvent(SkyscraperContextEvent.SpecialTsMode, "STiD135 encapsulated GS detected."); - SpecialTsType = 3; - } - } - firstPacketDone = true; - } - - DvbContext.PushPacket(buffer); - if (totalPacketsPushed++ == 1000) - { - CheckSpecialTs(); - } - } - - private GsContextDto CreateGsContext() - { - //Build the object - GsContextDto child = new GsContextDto(); - child.IpOutput = this; - child.TsOutput = this; - child.Rcs2Output = this; - - //for futureproofing - PropertyInfo[] properties = typeof(GsContextDto).GetProperties(); - foreach (PropertyInfo propertyInfo in properties) - { - object? value = propertyInfo.GetValue(child); - if (value == null) - { - throw new SkyscraperException(String.Format("While creating the {0}, the {1} was not properly set. This is a bug, tell Fey.", nameof(GsContextDto), propertyInfo.Name)); - } - } - - //actually return the object - return child; - } - - private DocsisPacketProcessor docsisPacketProcessor; - public int SpecialTsType { get; private set; } - private void CheckSpecialTs() - { - ulong[] pidStatistics = DvbContext.GetPidStatistics(); - if (pidStatistics == null) - { - totalPacketsPushed = 0; - return; - } - int occupiedPids = pidStatistics.Where(x => x > 0).Count(); - int numTotal = (int)totalPacketsPushed; - int num1fff = (int)pidStatistics[0x1fff]; - double percentage1fff = (double)num1fff * 100.0 / (double)numTotal; - if (true) - { - if (pidStatistics[0x0118] > 0) - { - int num118 = (int)pidStatistics[0x0118]; - double p = (double)num118 * 100.0 / numTotal; - if (p > 58) - { - if (!DvbContext.IsPidProcessorPresent(0x0118)) - { - DvbContext.RegisterPacketProcessor(0x0118, new OldStreamReaderDetector()); - return; - } - } - } - if (pidStatistics[0x010e] > 0) - { - int num10e = (int)pidStatistics[0x010e]; - double p = (double)num10e * 100.0 / numTotal; - if (occupiedPids == 1) - { - if (p > 20) - { - if (!DvbContext.IsPidProcessorPresent(0x010e)) - { - DvbContext.RegisterPacketProcessor(0x010e, new Stid135BbFrameReader(CreateGsContext())); - UiJunction?.SetGseMode(); - LogEvent(SkyscraperContextEvent.SpecialTsMode, "STiD135 encapsulated GS detected."); - SpecialTsType = 3; - return; - } - } - } - } - } - - if (occupiedPids <= 2) - { - if (pidStatistics[0x1ffe] > 10 && num1fff > 10) - { - docsisPacketProcessor = new DocsisPacketProcessor(this); - DvbContext.RegisterPacketProcessor(0x1ffe, docsisPacketProcessor); - UiJunction?.NotifyDocsisCarrier(docsisPacketProcessor.DocsisEnvironment); - LogEvent(SkyscraperContextEvent.SpecialTsMode, "DOCSIS Carrier TS detected."); - SpecialTsType = 4; - return; - } - - int num20 = (int)pidStatistics[0x0020]; - double percentage20 = (double)num20 * 100.0 / (double)numTotal; - if (percentage20 > 99.0 && percentage1fff < 1.0) - { - MultiprotocolEncapsulationDecoder blockstreamDecoder = new MultiprotocolEncapsulationDecoder(this); - DvbContext.RegisterPacketProcessor(0x0020, new PsiDecoder(0x0020,blockstreamDecoder)); - UiJunction?.NotifyBlockstreamCarrier(); - LogEvent(SkyscraperContextEvent.SpecialTsMode, "Blockstream Carrier TS detected."); - SpecialTsType = 5; - return; - } - } - } - - - [DebuggerStepThrough] - private void LogEvent(SkyscraperContextEvent eventType, string name = null) - { - string loggerName = String.Format("{0}{1}", IsChild ? ChildName + ", " : "", eventType.ToString()); - LogManager.GetLogger(loggerName).Info(name); - if (eventType != SkyscraperContextEvent.TdtTime && eventType != SkyscraperContextEvent.TotTime && eventType != SkyscraperContextEvent.Scte35TimeSignal && eventType != SkyscraperContextEvent.Rcs2TdtTime) - { - lastEventTimestamp = DateTime.Now; - } - EventsLogged++; - } - - public ulong EventsLogged { get; private set; } - private DateTime lastEventTimestamp; - - public void NetworkPidFromPat(int networkPid) - { - if (DvbContext.IsPidProcessorPresent(networkPid)) - return; - - DvbContext.RegisterPacketProcessor(networkPid, new PsiDecoder(networkPid, new NitParser(this))); - LogEvent(SkyscraperContextEvent.NetworkPidFromPat); - } - - private PmtTracker pmtTracker; - - public void ProgramMapPidFromPat(int pmtPid, ushort programId) - { - SpecialTsType = 1; - if (CurrentNetworkId.HasValue && CurrentTransportStreamId.HasValue) - { - DataStorage.StorePatEntry(CurrentNetworkId.Value, CurrentTransportStreamId.Value, pmtPid, programId); - } - - if (DvbContext.IsPidProcessorPresent(pmtPid)) - return; - - PsiDecoder pmtParser = new PsiDecoder(pmtPid, new PmtParser(this)); - if (PmtDecoderTransformer != null) - { - PmtDecoderTransformer.Transform(pmtParser); - } - - DvbContext.RegisterPacketProcessor(pmtPid, pmtParser); - LogEvent(SkyscraperContextEvent.ProgramMapPidFromPat, String.Format("PMT for program #{0} is on PID 0x{1:X4}", programId, pmtPid)); - UiJunction?.NotifyPatProgram(pmtPid, programId); - - if (pmtTracker == null) - pmtTracker = new PmtTracker(); - pmtTracker.AddPmtPid(pmtPid); - } - - public void SetTransportStreamId(ushort transportStreamId) - { - if (!CurrentTransportStreamId.HasValue) - { - CurrentTransportStreamId = transportStreamId; - return; - } - } - - private List> SsusToLookFor; - private Dictionary DsmCcsToLookFor; - - public void PmtEvent(ProgramMapping result, int pmtPid) - { - bool logworthy = false; - if (CurrentNetworkId.HasValue && CurrentTransportStreamId.HasValue) - { - - if (!DataStorage.TestForPmtEvent(CurrentNetworkId.Value, CurrentTransportStreamId.Value, result)) - { - if (DataStorage.StorePmtEvent(CurrentNetworkId.Value, CurrentTransportStreamId.Value, result)) - logworthy = true; - } - - if (result.CaSystemId.HasValue && result.CaPid.HasValue) - { - CaDescriptor caDescriptor = new CaDescriptor(result.CaSystemId.Value, result.CaPid.Value, result.CaPrivateData); - NotifyOfCaSystem(caDescriptor, true); - } - } - - bool allPrivateStreams = true; - foreach (ProgramMappingStream mappingStream in result.Streams) - { - if (!mappingStream.IsUserPrivateStream()) - { - allPrivateStreams = false; - break; - } - } - - byte madeUpComponentTags = 1; - foreach (ProgramMappingStream mappingStream in result.Streams) - { - if (mappingStream.CaPid.HasValue) - { - if (!DvbContext.IsPidProcessorPresent(mappingStream.CaPid.Value)) - { - NotifyOfCaSystem(new CaDescriptor(mappingStream.CaSystemId.Value, mappingStream.CaPid.Value, mappingStream.CaPrivateData),true); - } - } - - if (!DvbContext.IsPidProcessorPresent(mappingStream.ElementaryPid)) - { - List> ssuKvs = SsusToLookFor.FindAll(x => x.Key == result.ProgramNumber); - bool foundSsu = false; - foreach (KeyValuePair keyValuePair in ssuKvs) - { - byte ssuComponentTag = keyValuePair.Value; - if (ssuComponentTag == mappingStream.ComponentTag) - { - DvbContext.RegisterPacketProcessor(mappingStream.ElementaryPid, new PsiDecoder(mappingStream.ElementaryPid, new DataCarouselDecoder(mappingStream, result, DataCarouselIntention.SoftwareUpdate, this))); - SsusToLookFor.Remove(keyValuePair); - foundSsu = true; - break; - } - } - - if (foundSsu) - continue; - - - StreamType guessedStreamType = GuessStreamType(mappingStream, result.Streams.Count, result.RegistrationFormatIdentifier, allPrivateStreams); - switch (guessedStreamType) - { - case StreamType.Video: - ITsPacketProcessor videoPacketProcessor = null; - if (ALLOW_FFMPEG_FRAMEGRABBER) - { - if (TcpProxyEnabled) - { - if (!result.CaPid.HasValue) - { - if (!mappingStream.CaPid.HasValue) - { - if (CurrentNetworkId.HasValue && CurrentTransportStreamId.HasValue) - { - if (!ObjectStorage.TestForFramegrab(CurrentNetworkId.Value, CurrentTransportStreamId.Value, result.ProgramNumber, mappingStream.ElementaryPid)) - { - ffmpegFrameGrabber ffmfg = new ffmpegFrameGrabber(CurrentNetworkId.Value, CurrentTransportStreamId.Value, result, mappingStream, this); - ffmfg.TsProxyEndPoint = DvbContext.GetTcpProxyEndPoint(); - videoPacketProcessor = ffmfg; - } - else - { - videoPacketProcessor = new PacketDiscarder(); - } - } - } - } - } - } - - if (videoPacketProcessor != null) - { - DvbContext.RegisterPacketProcessor(mappingStream.ElementaryPid, videoPacketProcessor); - } - +using log4net; +using moe.yo3explorer.skyscraper8.DVBI.Model; +using skyscraper5.Abertis; +using skyscraper5.Docsis; +using skyscraper5.Docsis.MacManagement; +using skyscraper5.DsmCc.Descriptors; +using skyscraper5.Dvb.DataBroadcasting; +using skyscraper5.Dvb.DataBroadcasting.Biop; +using skyscraper5.Dvb.DataBroadcasting.Dsm.Event; +using skyscraper5.Dvb.DataBroadcasting.Dsm.Stream; +using skyscraper5.Dvb.DataBroadcasting.IntModel; +using skyscraper5.Dvb.DataBroadcasting.SkyscraperVfs; +using skyscraper5.Dvb.Descriptors; +using skyscraper5.Dvb.Psi; +using skyscraper5.Dvb.Psi.Model; +using skyscraper5.Dvb.Subtitling; +using skyscraper5.Dvb.Subtitling.Model; +using skyscraper5.Dvb.SystemSoftwareUpdate; +using skyscraper5.Dvb.SystemSoftwareUpdate.Model; +using skyscraper5.Dvb.TvAnytime; +using skyscraper5.Ietf.Rfc768; +using skyscraper5.Ietf.Rfc971; +using skyscraper5.Mheg5; +using skyscraper5.Mhp.Descriptors; +using skyscraper5.Mhp.Descriptors.InteractionTransportSelectors; +using skyscraper5.Mhp.Si; +using skyscraper5.Mhp.Si.Model; +using skyscraper5.Mpeg2; +using skyscraper5.Mpeg2.Descriptors; +using skyscraper5.Mpeg2.Psi; +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.Plugins; +using skyscraper5.Skyscraper.Scraper.FrameGrabber; +using skyscraper5.Skyscraper.Scraper.Storage.Utilities; +using skyscraper5.Skyscraper.Scraper.StreamAutodetection; +using skyscraper5.Skyscraper.Scraper.Utils; +using skyscraper5.src.Id3; +using skyscraper5.src.InteractionChannel; +using skyscraper5.src.InteractionChannel.Model; +using skyscraper5.src.InteractionChannel.Model.Descriptors; +using skyscraper5.src.Mpeg2; +using skyscraper5.src.Mpeg2.PacketFilter; +using skyscraper5.src.Skyscraper.Scraper.Dns; +using skyscraper5.src.Teletext; +using skyscraper5.T2MI; +using skyscraper5.T2MI.Packets; +using skyscraper5.T2MI.Packets.AdressingFunctions; +using skyscraper5.Teletext; +using skyscraper5.Teletext.Vps; +using skyscraper5.Teletext.Wss; +using skyscraper8.DvbI; +using skyscraper8.DvbNip; +using skyscraper8.Ietf.FLUTE; +using skyscraper8.Ietf.Rfc4236_ULE; +using skyscraper8.Ses; +using skyscraper8.Skyscraper.Scraper.Storage; +using skyscraper8.yo3explorer; +using System.Collections.ObjectModel; +using System.Diagnostics; +using System.Net; +using System.Net.NetworkInformation; +using System.Reflection; +using System.Text; +using MimeKit; +using skyscraper5.src.InteractionChannel.Model2; +using skyscraper8.Abertis; +using skyscraper8.Experimentals.NdsSsu; +using skyscraper8.Experimentals.OtvSsu; +using skyscraper8.GS; +using skyscraper8.GSE; +using skyscraper8.Ieee802_1AB; +using skyscraper8.InteractionChannel.Model; +using skyscraper8.InteractionChannel.Model2; +using skyscraper8.InteractionChannel.Model2.Descriptors; +using skyscraper8.Skyscraper.Net; +using skyscraper8.Skyscraper.Scraper; +using skyscraper8.T2MI; +using Tsubasa.IO; +using Platform = skyscraper5.Dvb.SystemSoftwareUpdate.Model.Platform; +using RntParser = skyscraper5.Dvb.TvAnytime.RntParser; +using skyscraper8.DvbSis; +using skyscraper8.T2MI.Packets; +using skyscraper5.Docsis.AnnexC; +using Ionic.Zlib; + +namespace skyscraper5.Skyscraper.Scraper +{ + public class SkyscraperContext : IPatEventHandler, IPmtEventHandler, INitEventHandler, ITeletextPageHandler, + IBatEventHandler, ISdtEventHandler, ICatEventHandler, ITdtEventHandler, ITotEventHandler, ITsdtEventHandler, + IEitEventHandler, IAitEventHandler, ISubtitleEventHandler, + UpdateNotificationEventHandler, DataCarouselEventHandler, RdsEventHandler, IScte35EventHandler, + IAutodetectionEventHandler, IRstEventHandler, IRntEventHandler, IMultiprotocolEncapsulationEventHandler, ObjectCarouselEventHandler, T2MIEventHandler, + IDisposable, IFrameGrabberEventHandler, IntEventHandler, IRctEventHandler, ISkyscraperContext, IDocsisEventHandler, AbertisDecoderEventHandler, Id3Handler, + InteractionChannelHandler, SgtEventHandler, IDvbNipEventHandler, UleEventHandler, OtvSsuHandler, NdsSsuHandler, ISubTsHandler, ILldpFrameHandler, SisHandler + { + public const bool ALLOW_STREAM_TYPE_AUTODETECTION = true; + public const bool ALLOW_FFMPEG_FRAMEGRABBER = true; + + private static readonly ILog logger = LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType.Name); + + public TsContext DvbContext { get; } + public DataStorage DataStorage { get; } + public ObjectStorage ObjectStorage { get; } + + + public bool SourceIsDisk { get; set; } + + public PsiDecoder PatDecoder { get; private set; } + public PsiDecoder CatDecoder { get; private set; } + public PsiDecoder NitDecoder { get; private set; } + public PsiDecoder Pid0x11Decoder { get; private set; } + public PsiDecoder Pid0x12Decoder { get; private set; } + public IPsiDecoderTransformer PmtDecoderTransformer { get; set; } + public SkyscraperContext(TsContext dvbContext, DataStorage dataStorage = null, ObjectStorage objectStorage = null, int skipAtStart = 0, int? currentNetworkId = null, int? currentTransportStreamId = null) + { + TsDescriptorUnpacker descriptorUnpacker = TsDescriptorUnpacker.GetInstance(); + for (byte i = 0x80; i < 0xfe; i++) + { + descriptorUnpacker.SetUserDefined(i, true); + } + + descriptorUnpacker.SetUserDefined(0xfe, true); + + DvbContext = dvbContext; + + + //PAT + PatDecoder = new PsiDecoder(0, new PatParser(this)); + dvbContext.RegisterPacketProcessor(0, PatDecoder); + //PMT autodetect from PAT + + //CAT + CatDecoder = new PsiDecoder(1, new CatParser(this)); + dvbContext.RegisterPacketProcessor(1, CatDecoder); + + //TSDT (experimental) + dvbContext.RegisterPacketProcessor(2, new PsiDecoder(2, new TsdtParser(this))); + + //IPMP (experimental) + dvbContext.RegisterPacketProcessor(3, new PsiDecoder(3, new IpmpParser(this))); + + //NIT + NitDecoder = new PsiDecoder(0x10, new NitParser(this)); + dvbContext.RegisterPacketProcessor(0x10, NitDecoder); + + //SDT / BAT + Pid0x11Decoder = new PsiDecoder(0x11, new Pid0x11Decoder(this, this)); + dvbContext.RegisterPacketProcessor(0x11, Pid0x11Decoder); + + //EIT + //dvbContext.RegisterPacketProcessor(0x12, new PsiDecoder(0x12, new EitParser(this))); + Pid0x12Decoder = new PsiDecoder(0x12, new Pid0x12Decoder(this)); + dvbContext.RegisterPacketProcessor(0x12, Pid0x12Decoder); + + //RST + DvbContext.RegisterPacketProcessor(0x13, new PsiDecoder(0x13, new RstParser(this))); + + //TDT + //TOT handled by TDT processor + dvbContext.RegisterPacketProcessor(0x14, new PsiDecoder(0x14, new TimetableParser(this, this))); + + //RNT + dvbContext.RegisterPacketProcessor(0x16, new PsiDecoder(0x16, new RntParser(this))); + + //DIT + //PID 0x1E + //won't need these. We operate on broadcasted stuff, so we shouldn't encounter partial TS + + //DIT + //PID 0x1F + //won't need these. We operate on broadcasted stuff, so we shouldn't encounter partial TS + + if (dataStorage == null) + { + throw new ArgumentNullException(nameof(dataStorage)); + } + DataStorage = dataStorage; + + if (objectStorage == null) + { + throw new ArgumentNullException(nameof(objectStorage)); + } + ObjectStorage = objectStorage; + + CurrentNetworkId = currentNetworkId; + CurrentTransportStreamId = currentTransportStreamId; + DsmCcsToLookFor = new Dictionary(); + SsusToLookFor = new List>(); + + this.skipBufferRemain = skipAtStart; + } + + public int? CurrentNetworkId { get; private set; } + public int? CurrentTransportStreamId { get; private set; } + + public TeiFilter TeiFilter { get; private set; } + public ScrambleFilter ScrambleFilter { get; private set; } + public TeiOnOffFilter TeiOnOffFilter { get; private set; } + public void InitalizeFilterChain(params IPacketFilter[] args) + { + if (DvbContext.FilterChain != null) + throw new InvalidOperationException("The filter chain was already initalized."); + if (TeiFilter == null) + TeiFilter = new TeiFilter(); + if (ScrambleFilter == null) + ScrambleFilter = new ScrambleFilter(); + if (TeiOnOffFilter == null) + TeiOnOffFilter = new TeiOnOffFilter(); + + List result = new List(); + result.AddRange(args); + result.Add(TeiFilter); + result.Add(ScrambleFilter); + result.Add(TeiOnOffFilter); + result.Sort(new PluginPrioritySorter()); + DvbContext.FilterChain = result; + + StringBuilder stringBuilder = new StringBuilder(); + stringBuilder.Append("IN"); + for (int i = 0; i < result.Count; i++) + { + stringBuilder.Append(" -> "); + if (result[i] != null) + { + stringBuilder.Append(result[i].GetType().Name); + } + else + { + stringBuilder.Append("(null)"); + } + } + stringBuilder.Append(" -> OUT"); + logger.DebugFormat("Built filter chain: {0}", stringBuilder.ToString()); + } + + public int GetIpCommunicationParties() + { + if (trafficInfos == null) + return 0; + else + return trafficInfos.Count; + } + + public void IngestFromStream(Stream stream) + { + byte[] buffer = new byte[188]; + while (true) + { + if (IsAbortConditionMet()) + break; + + if (stream.Read(buffer, 0, 188) != 188) + break; + + try + { + IngestSinglePacket(buffer); + } + catch (InvalidTsPacketException) + { + break; + } + } + + stream.Close(); + runningEvents = null; + } + + private bool skipBufferStarted; + private int skipBufferRemain; + private bool firstPacketDone = false; + private ulong totalPacketsPushed; + + public void IngestSinglePacket(byte[] buffer) + { + if (buffer.Length != 188) + throw new ArgumentException(String.Format("{0}.{1} != {2}", nameof(buffer), nameof(buffer.Length), + 188)); + + if (skipBufferRemain > 0) + { + if (!skipBufferStarted) + { + LogEvent(SkyscraperContextEvent.StartPacketProcessing, String.Format("Skipping {0} packets before begin.", skipBufferRemain)); + skipBufferStarted = true; + } + skipBufferRemain--; + } + + if (!firstPacketDone) + { + LogEvent(SkyscraperContextEvent.StartPacketProcessing); + if (buffer[0] == 0x47 && buffer[1] == 0x41 && buffer[2] == 0x18 && (buffer[3] & 0x10) != 0 && buffer[4] == 0x00 && buffer[5] == 0x80 && buffer[6] == 0x00) + { + DvbContext.RegisterPacketProcessor(0x0118, new OldStreamReaderDetector()); + SpecialTsType = 2; + } + if (buffer[0] == 0x47 && buffer[1] == 0x41 && buffer[2] == 0x0e && (buffer[3] & 0x10) != 0 && buffer[4] == 0x00 && buffer[5] == 0x80 && buffer[6] == 0x00) + { + if (!DvbContext.IsPidProcessorPresent(0x010e)) + { + DvbContext.RegisterPacketProcessor(0x010e, new Stid135BbFrameReader(CreateGsContext())); + UiJunction?.SetGseMode(); + LogEvent(SkyscraperContextEvent.SpecialTsMode, "STiD135 encapsulated GS detected."); + SpecialTsType = 3; + } + } + firstPacketDone = true; + } + + DvbContext.PushPacket(buffer); + if (totalPacketsPushed++ == 1000) + { + CheckSpecialTs(); + } + } + + private GsContextDto CreateGsContext() + { + //Build the object + GsContextDto child = new GsContextDto(); + child.IpOutput = this; + child.TsOutput = this; + child.Rcs2Output = this; + + //for futureproofing + PropertyInfo[] properties = typeof(GsContextDto).GetProperties(); + foreach (PropertyInfo propertyInfo in properties) + { + object? value = propertyInfo.GetValue(child); + if (value == null) + { + throw new SkyscraperException(String.Format("While creating the {0}, the {1} was not properly set. This is a bug, tell Fey.", nameof(GsContextDto), propertyInfo.Name)); + } + } + + //actually return the object + return child; + } + + private DocsisPacketProcessor docsisPacketProcessor; + public int SpecialTsType { get; private set; } + private void CheckSpecialTs() + { + ulong[] pidStatistics = DvbContext.GetPidStatistics(); + if (pidStatistics == null) + { + totalPacketsPushed = 0; + return; + } + int occupiedPids = pidStatistics.Where(x => x > 0).Count(); + int numTotal = (int)totalPacketsPushed; + int num1fff = (int)pidStatistics[0x1fff]; + double percentage1fff = (double)num1fff * 100.0 / (double)numTotal; + if (true) + { + if (pidStatistics[0x0118] > 0) + { + int num118 = (int)pidStatistics[0x0118]; + double p = (double)num118 * 100.0 / numTotal; + if (p > 58) + { + if (!DvbContext.IsPidProcessorPresent(0x0118)) + { + DvbContext.RegisterPacketProcessor(0x0118, new OldStreamReaderDetector()); + return; + } + } + } + if (pidStatistics[0x010e] > 0) + { + int num10e = (int)pidStatistics[0x010e]; + double p = (double)num10e * 100.0 / numTotal; + if (occupiedPids == 1) + { + if (p > 20) + { + if (!DvbContext.IsPidProcessorPresent(0x010e)) + { + DvbContext.RegisterPacketProcessor(0x010e, new Stid135BbFrameReader(CreateGsContext())); + UiJunction?.SetGseMode(); + LogEvent(SkyscraperContextEvent.SpecialTsMode, "STiD135 encapsulated GS detected."); + SpecialTsType = 3; + return; + } + } + } + } + } + + if (occupiedPids <= 2) + { + if (pidStatistics[0x1ffe] > 10 && num1fff > 10) + { + docsisPacketProcessor = new DocsisPacketProcessor(this); + DvbContext.RegisterPacketProcessor(0x1ffe, docsisPacketProcessor); + UiJunction?.NotifyDocsisCarrier(docsisPacketProcessor.DocsisEnvironment); + LogEvent(SkyscraperContextEvent.SpecialTsMode, "DOCSIS Carrier TS detected."); + SpecialTsType = 4; + return; + } + + int num20 = (int)pidStatistics[0x0020]; + double percentage20 = (double)num20 * 100.0 / (double)numTotal; + if (percentage20 > 99.0 && percentage1fff < 1.0) + { + MultiprotocolEncapsulationDecoder blockstreamDecoder = new MultiprotocolEncapsulationDecoder(this); + DvbContext.RegisterPacketProcessor(0x0020, new PsiDecoder(0x0020,blockstreamDecoder)); + UiJunction?.NotifyBlockstreamCarrier(); + LogEvent(SkyscraperContextEvent.SpecialTsMode, "Blockstream Carrier TS detected."); + SpecialTsType = 5; + return; + } + } + } + + + [DebuggerStepThrough] + private void LogEvent(SkyscraperContextEvent eventType, string name = null) + { + string loggerName = String.Format("{0}{1}", IsChild ? ChildName + ", " : "", eventType.ToString()); + LogManager.GetLogger(loggerName).Info(name); + if (eventType != SkyscraperContextEvent.TdtTime && eventType != SkyscraperContextEvent.TotTime && eventType != SkyscraperContextEvent.Scte35TimeSignal && eventType != SkyscraperContextEvent.Rcs2TdtTime) + { + lastEventTimestamp = DateTime.Now; + } + EventsLogged++; + } + + public ulong EventsLogged { get; private set; } + private DateTime lastEventTimestamp; + + public void NetworkPidFromPat(int networkPid) + { + if (DvbContext.IsPidProcessorPresent(networkPid)) + return; + + DvbContext.RegisterPacketProcessor(networkPid, new PsiDecoder(networkPid, new NitParser(this))); + LogEvent(SkyscraperContextEvent.NetworkPidFromPat); + } + + private PmtTracker pmtTracker; + + public void ProgramMapPidFromPat(int pmtPid, ushort programId) + { + SpecialTsType = 1; + if (CurrentNetworkId.HasValue && CurrentTransportStreamId.HasValue) + { + DataStorage.StorePatEntry(CurrentNetworkId.Value, CurrentTransportStreamId.Value, pmtPid, programId); + } + + if (DvbContext.IsPidProcessorPresent(pmtPid)) + return; + + PsiDecoder pmtParser = new PsiDecoder(pmtPid, new PmtParser(this)); + if (PmtDecoderTransformer != null) + { + PmtDecoderTransformer.Transform(pmtParser); + } + + DvbContext.RegisterPacketProcessor(pmtPid, pmtParser); + LogEvent(SkyscraperContextEvent.ProgramMapPidFromPat, String.Format("PMT for program #{0} is on PID 0x{1:X4}", programId, pmtPid)); + UiJunction?.NotifyPatProgram(pmtPid, programId); + + if (pmtTracker == null) + pmtTracker = new PmtTracker(); + pmtTracker.AddPmtPid(pmtPid); + } + + public void SetTransportStreamId(ushort transportStreamId) + { + if (!CurrentTransportStreamId.HasValue) + { + CurrentTransportStreamId = transportStreamId; + return; + } + } + + private List> SsusToLookFor; + private Dictionary DsmCcsToLookFor; + + public void PmtEvent(ProgramMapping result, int pmtPid) + { + bool logworthy = false; + if (CurrentNetworkId.HasValue && CurrentTransportStreamId.HasValue) + { + + if (!DataStorage.TestForPmtEvent(CurrentNetworkId.Value, CurrentTransportStreamId.Value, result)) + { + if (DataStorage.StorePmtEvent(CurrentNetworkId.Value, CurrentTransportStreamId.Value, result)) + logworthy = true; + } + + if (result.CaSystemId.HasValue && result.CaPid.HasValue) + { + CaDescriptor caDescriptor = new CaDescriptor(result.CaSystemId.Value, result.CaPid.Value, result.CaPrivateData); + NotifyOfCaSystem(caDescriptor, true); + } + } + + bool allPrivateStreams = true; + foreach (ProgramMappingStream mappingStream in result.Streams) + { + if (!mappingStream.IsUserPrivateStream()) + { + allPrivateStreams = false; + break; + } + } + + byte madeUpComponentTags = 1; + foreach (ProgramMappingStream mappingStream in result.Streams) + { + if (mappingStream.CaPid.HasValue) + { + if (!DvbContext.IsPidProcessorPresent(mappingStream.CaPid.Value)) + { + NotifyOfCaSystem(new CaDescriptor(mappingStream.CaSystemId.Value, mappingStream.CaPid.Value, mappingStream.CaPrivateData),true); + } + } + + if (!DvbContext.IsPidProcessorPresent(mappingStream.ElementaryPid)) + { + List> ssuKvs = SsusToLookFor.FindAll(x => x.Key == result.ProgramNumber); + bool foundSsu = false; + foreach (KeyValuePair keyValuePair in ssuKvs) + { + byte ssuComponentTag = keyValuePair.Value; + if (ssuComponentTag == mappingStream.ComponentTag) + { + DvbContext.RegisterPacketProcessor(mappingStream.ElementaryPid, new PsiDecoder(mappingStream.ElementaryPid, new DataCarouselDecoder(mappingStream, result, DataCarouselIntention.SoftwareUpdate, this))); + SsusToLookFor.Remove(keyValuePair); + foundSsu = true; + break; + } + } + + if (foundSsu) + continue; + + + StreamType guessedStreamType = GuessStreamType(mappingStream, result.Streams.Count, result.RegistrationFormatIdentifier, allPrivateStreams); + switch (guessedStreamType) + { + case StreamType.Video: + ITsPacketProcessor videoPacketProcessor = null; + if (ALLOW_FFMPEG_FRAMEGRABBER) + { + if (TcpProxyEnabled) + { + if (!result.CaPid.HasValue) + { + if (!mappingStream.CaPid.HasValue) + { + if (CurrentNetworkId.HasValue && CurrentTransportStreamId.HasValue) + { + if (!ObjectStorage.TestForFramegrab(CurrentNetworkId.Value, CurrentTransportStreamId.Value, result.ProgramNumber, mappingStream.ElementaryPid)) + { + ffmpegFrameGrabber ffmfg = new ffmpegFrameGrabber(CurrentNetworkId.Value, CurrentTransportStreamId.Value, result, mappingStream, this); + ffmfg.TsProxyEndPoint = DvbContext.GetTcpProxyEndPoint(); + videoPacketProcessor = ffmfg; + } + else + { + videoPacketProcessor = new PacketDiscarder(); + } + } + } + } + } + } + + if (videoPacketProcessor != null) + { + DvbContext.RegisterPacketProcessor(mappingStream.ElementaryPid, videoPacketProcessor); + } + if (!DvbContext.IsPidProcessorPresent(mappingStream.ElementaryPid)) { DvbContext.RegisterPacketProcessor(mappingStream.ElementaryPid, new PacketDiscarder()); - } - - break; - case StreamType.Teletext: - if (!CurrentNetworkId.HasValue) - break; - if (!CurrentTransportStreamId.HasValue) - break; - TeletextPesProcessor ttp = new TeletextPesProcessor(this, CurrentNetworkId.Value, CurrentTransportStreamId.Value, result.ProgramNumber); - if (result.PrivateDataSpecifier.HasValue) - ttp.PrivateDataSpecifier = result.PrivateDataSpecifier; - if (mappingStream.PrivateDataSpecifier.HasValue) - ttp.PrivateDataSpecifier = mappingStream.PrivateDataSpecifier; - DvbContext.RegisterPacketProcessor(mappingStream.ElementaryPid, new PesDecoder(ttp)); - break; - case StreamType.Audio: - DvbContext.RegisterPacketProcessor(mappingStream.ElementaryPid, new PacketDiscarder()); - break; - case StreamType.Application: - DvbContext.RegisterPacketProcessor(mappingStream.ElementaryPid, - new PsiDecoder(mappingStream.ElementaryPid, new AitParser(this, result.ProgramNumber))); - break; - case StreamType.Ignorable: - break; - case StreamType.HbbTv: - DvbContext.RegisterPacketProcessor(mappingStream.ElementaryPid, - new PsiDecoder(mappingStream.ElementaryPid, - new DataCarouselDecoder(mappingStream, result, DataCarouselIntention.NoIntention, this))); - break; - case StreamType.SystemSoftwareUpdate: - SystemSoftwareUpdateInfo ssuInfo = - new SystemSoftwareUpdateInfo(mappingStream.DataBroadcastSelector); - if (ssuInfo.Valid) - TryRegisterSystemSoftwareUpdateInfo(ssuInfo, mappingStream, result); - break; - case StreamType.Subtitles: - PesDecoder pesDecoder = new PesDecoder(new SubtitleDecoder(this)); - pesDecoder.Tag = "subs"; - DvbContext.RegisterPacketProcessor(mappingStream.ElementaryPid, pesDecoder); - //DvbContext.RegisterPacketProcessor(mappingStream.ElementaryPid, new PacketDumper(new FileInfo("subtitle.ts"))); - break; - case StreamType.DvbMhp: - //Test and make up component tags. - if (!mappingStream.ComponentTag.HasValue) - MakeUpComponentTags(result); - DvbContext.RegisterPacketProcessor(mappingStream.ElementaryPid, - new PsiDecoder(mappingStream.ElementaryPid, - new DataCarouselDecoder(mappingStream, result, DataCarouselIntention.NoIntention, this))); - break; - case StreamType.Scte35: - DvbContext.RegisterPacketProcessor(mappingStream.ElementaryPid, - new PsiDecoder(mappingStream.ElementaryPid, - new Scte35SiDecoder(result.ProgramNumber, this))); - break; - case StreamType.RDS: - RdsPesProcessor rdsPesProcessor = new RdsPesProcessor(mappingStream.ElementaryPid, - result.ProgramNumber, this); - DvbContext.RegisterPacketProcessor(mappingStream.ElementaryPid, - new PesDecoder(rdsPesProcessor)); - break; - case StreamType.MultiprotocolEncapsulation: - MultiprotocolEncapsulationDecoder mpeDec = new MultiprotocolEncapsulationDecoder(this); - DvbContext.RegisterPacketProcessor(mappingStream.ElementaryPid, - new PsiDecoder(mappingStream.ElementaryPid, mpeDec)); - break; - case StreamType.Mheg5: - Mheg5DataBroadcastIdSelector selector = - new Mheg5DataBroadcastIdSelector(mappingStream.DataBroadcastSelector); - //These looked like Object Carousels to me - if (!mappingStream.ComponentTag.HasValue) - MakeUpComponentTags(result); - //ObjectCarouselDecoder ocd = new ObjectCarouselDecoder(mappingStream.ElementaryPid, this, result, mappingStream.ComponentTag.Value); - DataCarouselDecoder dcd = new DataCarouselDecoder(mappingStream, result, DataCarouselIntention.NoIntention, this); - //ocd.Tag = StreamType.Mheg5; - DvbContext.RegisterPacketProcessor(mappingStream.ElementaryPid, new PsiDecoder(mappingStream.ElementaryPid, dcd)); - break; - case StreamType.TryAutodetect: - StreamTypeAutodetection sta = new StreamTypeAutodetection(mappingStream.ElementaryPid, this); - sta.ProgramContext.Program = result; - sta.ProgramContext.Stream = mappingStream; - sta.IntroduceStreamToContestants(); - if (!sta.IsWinnerDetermined) - { - DvbContext.RegisterPacketProcessor(mappingStream.ElementaryPid, sta); - } - break; - case StreamType.IpMacNotification: - IntParser intParser = new IntParser(this); - DvbContext.RegisterPacketProcessor(mappingStream.ElementaryPid, new PsiDecoder(mappingStream.ElementaryPid, intParser)); - break; - case StreamType.RelatedContentTable: - RctParser rctParser = new RctParser(this, result.ProgramNumber); - DvbContext.RegisterPacketProcessor(mappingStream.ElementaryPid, new PsiDecoder(mappingStream.ElementaryPid, rctParser)); - break; - case StreamType.T2Mi: - T2MIDecoder t2miDecoder = new T2MIDecoder(mappingStream.ElementaryPid, this); - DvbContext.RegisterPacketProcessor(mappingStream.ElementaryPid, t2miDecoder); - break; - case StreamType.InteractionChannelForSatellite: - InteractionChannelPsiGatherer interactionChannelDecoder = new InteractionChannelPsiGatherer(); - interactionChannelDecoder.ExpectedTables = mappingStream.UnknownUserDefines[0]; - interactionChannelDecoder.Handler = this; - DvbContext.RegisterPacketProcessor(mappingStream.ElementaryPid, new PsiDecoder(mappingStream.ElementaryPid, interactionChannelDecoder)); - break; - - case StreamType.Id3: - DvbContext.RegisterPacketProcessor(mappingStream.ElementaryPid, new PesDecoder(new Id3PesProcessor(this))); - break; - case StreamType.SisFramingAndTiming: - DvbContext.RegisterPacketProcessor(mappingStream.ElementaryPid, new FtiHandler(mappingStream.ElementaryPid, this, this)); - break; - case StreamType.SisDaughterSiteAdapterConfiguration: - DsAciHandler dsaciHandler = new DsAciHandler(this); - DvbContext.RegisterPacketProcessor(mappingStream.ElementaryPid, new PsiDecoder(mappingStream.ElementaryPid, dsaciHandler)); - break; - case StreamType.SisPsiTables: - SisPsiHandler sisPsiHandler = new SisPsiHandler(this, result.ProgramNumber); - DvbContext.RegisterPacketProcessor(mappingStream.ElementaryPid, new PsiDecoder(mappingStream.ElementaryPid, sisPsiHandler)); - break; - default: - throw new NotImplementedException(String.Format( - "Detection of Stream type for PID 0x{0:X4} in Service {1} - was detected as {2}, but handling for {2} is not implemented yet.", pmtPid, - result.ProgramNumber, guessedStreamType)); - } - } - } - - if (logworthy) - LogEvent(SkyscraperContextEvent.PmtEvent, String.Format("#{0}", result.ProgramNumber)); - - UiJunction?.NotifyPmtProgram(result, pmtPid); - + } + + break; + case StreamType.Teletext: + if (!CurrentNetworkId.HasValue) + break; + if (!CurrentTransportStreamId.HasValue) + break; + TeletextPesProcessor ttp = new TeletextPesProcessor(this, CurrentNetworkId.Value, CurrentTransportStreamId.Value, result.ProgramNumber); + if (result.PrivateDataSpecifier.HasValue) + ttp.PrivateDataSpecifier = result.PrivateDataSpecifier; + if (mappingStream.PrivateDataSpecifier.HasValue) + ttp.PrivateDataSpecifier = mappingStream.PrivateDataSpecifier; + DvbContext.RegisterPacketProcessor(mappingStream.ElementaryPid, new PesDecoder(ttp)); + break; + case StreamType.Audio: + DvbContext.RegisterPacketProcessor(mappingStream.ElementaryPid, new PacketDiscarder()); + break; + case StreamType.Application: + DvbContext.RegisterPacketProcessor(mappingStream.ElementaryPid, + new PsiDecoder(mappingStream.ElementaryPid, new AitParser(this, result.ProgramNumber))); + break; + case StreamType.Ignorable: + break; + case StreamType.HbbTv: + DvbContext.RegisterPacketProcessor(mappingStream.ElementaryPid, + new PsiDecoder(mappingStream.ElementaryPid, + new DataCarouselDecoder(mappingStream, result, DataCarouselIntention.NoIntention, this))); + break; + case StreamType.SystemSoftwareUpdate: + SystemSoftwareUpdateInfo ssuInfo = + new SystemSoftwareUpdateInfo(mappingStream.DataBroadcastSelector); + if (ssuInfo.Valid) + TryRegisterSystemSoftwareUpdateInfo(ssuInfo, mappingStream, result); + break; + case StreamType.Subtitles: + PesDecoder pesDecoder = new PesDecoder(new SubtitleDecoder(this)); + pesDecoder.Tag = "subs"; + DvbContext.RegisterPacketProcessor(mappingStream.ElementaryPid, pesDecoder); + //DvbContext.RegisterPacketProcessor(mappingStream.ElementaryPid, new PacketDumper(new FileInfo("subtitle.ts"))); + break; + case StreamType.DvbMhp: + //Test and make up component tags. + if (!mappingStream.ComponentTag.HasValue) + MakeUpComponentTags(result); + DvbContext.RegisterPacketProcessor(mappingStream.ElementaryPid, + new PsiDecoder(mappingStream.ElementaryPid, + new DataCarouselDecoder(mappingStream, result, DataCarouselIntention.NoIntention, this))); + break; + case StreamType.Scte35: + DvbContext.RegisterPacketProcessor(mappingStream.ElementaryPid, + new PsiDecoder(mappingStream.ElementaryPid, + new Scte35SiDecoder(result.ProgramNumber, this))); + break; + case StreamType.RDS: + RdsPesProcessor rdsPesProcessor = new RdsPesProcessor(mappingStream.ElementaryPid, + result.ProgramNumber, this); + DvbContext.RegisterPacketProcessor(mappingStream.ElementaryPid, + new PesDecoder(rdsPesProcessor)); + break; + case StreamType.MultiprotocolEncapsulation: + MultiprotocolEncapsulationDecoder mpeDec = new MultiprotocolEncapsulationDecoder(this); + DvbContext.RegisterPacketProcessor(mappingStream.ElementaryPid, + new PsiDecoder(mappingStream.ElementaryPid, mpeDec)); + break; + case StreamType.Mheg5: + Mheg5DataBroadcastIdSelector selector = + new Mheg5DataBroadcastIdSelector(mappingStream.DataBroadcastSelector); + //These looked like Object Carousels to me + if (!mappingStream.ComponentTag.HasValue) + MakeUpComponentTags(result); + //ObjectCarouselDecoder ocd = new ObjectCarouselDecoder(mappingStream.ElementaryPid, this, result, mappingStream.ComponentTag.Value); + DataCarouselDecoder dcd = new DataCarouselDecoder(mappingStream, result, DataCarouselIntention.NoIntention, this); + //ocd.Tag = StreamType.Mheg5; + DvbContext.RegisterPacketProcessor(mappingStream.ElementaryPid, new PsiDecoder(mappingStream.ElementaryPid, dcd)); + break; + case StreamType.TryAutodetect: + StreamTypeAutodetection sta = new StreamTypeAutodetection(mappingStream.ElementaryPid, this); + sta.ProgramContext.Program = result; + sta.ProgramContext.Stream = mappingStream; + sta.IntroduceStreamToContestants(); + if (!sta.IsWinnerDetermined) + { + DvbContext.RegisterPacketProcessor(mappingStream.ElementaryPid, sta); + } + break; + case StreamType.IpMacNotification: + IntParser intParser = new IntParser(this); + DvbContext.RegisterPacketProcessor(mappingStream.ElementaryPid, new PsiDecoder(mappingStream.ElementaryPid, intParser)); + break; + case StreamType.RelatedContentTable: + RctParser rctParser = new RctParser(this, result.ProgramNumber); + DvbContext.RegisterPacketProcessor(mappingStream.ElementaryPid, new PsiDecoder(mappingStream.ElementaryPid, rctParser)); + break; + case StreamType.T2Mi: + T2MIDecoder t2miDecoder = new T2MIDecoder(mappingStream.ElementaryPid, this); + DvbContext.RegisterPacketProcessor(mappingStream.ElementaryPid, t2miDecoder); + break; + case StreamType.InteractionChannelForSatellite: + InteractionChannelPsiGatherer interactionChannelDecoder = new InteractionChannelPsiGatherer(); + interactionChannelDecoder.ExpectedTables = mappingStream.UnknownUserDefines[0]; + interactionChannelDecoder.Handler = this; + DvbContext.RegisterPacketProcessor(mappingStream.ElementaryPid, new PsiDecoder(mappingStream.ElementaryPid, interactionChannelDecoder)); + break; + + case StreamType.Id3: + DvbContext.RegisterPacketProcessor(mappingStream.ElementaryPid, new PesDecoder(new Id3PesProcessor(this))); + break; + case StreamType.SisFramingAndTiming: + DvbContext.RegisterPacketProcessor(mappingStream.ElementaryPid, new FtiHandler(mappingStream.ElementaryPid, this, this)); + break; + case StreamType.SisDaughterSiteAdapterConfiguration: + DsAciHandler dsaciHandler = new DsAciHandler(this); + DvbContext.RegisterPacketProcessor(mappingStream.ElementaryPid, new PsiDecoder(mappingStream.ElementaryPid, dsaciHandler)); + break; + case StreamType.SisPsiTables: + SisPsiHandler sisPsiHandler = new SisPsiHandler(this, result.ProgramNumber); + DvbContext.RegisterPacketProcessor(mappingStream.ElementaryPid, new PsiDecoder(mappingStream.ElementaryPid, sisPsiHandler)); + break; + default: + throw new NotImplementedException(String.Format( + "Detection of Stream type for PID 0x{0:X4} in Service {1} - was detected as {2}, but handling for {2} is not implemented yet.", pmtPid, + result.ProgramNumber, guessedStreamType)); + } + } + } + + if (logworthy) + LogEvent(SkyscraperContextEvent.PmtEvent, String.Format("#{0}", result.ProgramNumber)); + + UiJunction?.NotifyPmtProgram(result, pmtPid); + if (pmtTracker != null) { pmtTracker.MarkAsProcessed(pmtPid); if (pmtTracker.ShouldFireAutodetection()) { CheckForHiddenMpes(); - } - } - } - - public void MakeUpComponentTags(ProgramMapping target) - { - bool[] usedTags = new bool[byte.MaxValue]; - foreach (ProgramMappingStream programMappingStream in target.Streams) - { - if (programMappingStream.ComponentTag.HasValue) - { - usedTags[programMappingStream.ComponentTag.Value] = true; - } - } - - usedTags[0] = true; - - foreach (ProgramMappingStream mappingStream in target.Streams) - { - if (!mappingStream.ComponentTag.HasValue) - { - for (byte b = 0; b < Byte.MaxValue; b++) - { - if (!usedTags[b]) - { - usedTags[b] = true; - mappingStream.ComponentTag = b; - break; - } - } - } - } - } - - private void TryRegisterSystemSoftwareUpdateInfo(SystemSoftwareUpdateInfo info, - ProgramMappingStream mappingStream, ProgramMapping mapping) - { - if (DvbContext.IsPidProcessorPresent(mappingStream.ElementaryPid)) - return; - - //TODO: Scrape this once we have an SSU Event handler. - foreach (SystemSoftwareUpdateInfo.Oui infoOui in info.Ouis) - { - switch (infoOui.UpdateType) - { - //Found on ETSI TS 102 006, Page 13 - case 0: //proprietary update solution - if (ALLOW_STREAM_TYPE_AUTODETECTION) - { - StreamTypeAutodetection sta = new StreamTypeAutodetection(mappingStream.ElementaryPid, this); - sta.ProgramContext.Stream = mappingStream; - sta.ProgramContext.Program = mapping; - DvbContext.RegisterPacketProcessor(mappingStream.ElementaryPid, sta); - } - else - DvbContext.RegisterPacketProcessor(mappingStream.ElementaryPid, new PacketDiscarder()); - break; - case 1: //standard update carousel (i.e. without notification table) via broadcast - if (!mappingStream.ComponentTag.HasValue) - { - MakeUpComponentTags(mapping); - } - - DvbContext.RegisterPacketProcessor(mappingStream.ElementaryPid, new PsiDecoder(mappingStream.ElementaryPid, new DataCarouselDecoder(mappingStream, mapping, DataCarouselIntention.SoftwareUpdate, this))); - break; - case 2: //system software update carousel with notification table (UNT) both available via broadcast - case 3: //system software update signalled via broadcast UNT, update available from the return channel - case 4: //system software update signalled via broadcast UNT, update available from the internet - DvbContext.RegisterPacketProcessor(mappingStream.ElementaryPid, new PsiDecoder(mappingStream.ElementaryPid, new UntDecoder(this, mapping))); - break; - case 5: - case 6: - case 7: - case 8: - case 9: - case 10: - case 11: - case 12: - case 13: - case 14: - case 15: - //reserved for future use as of 2015-06 - //ignore it. - break; - default: - throw new NotImplementedException(String.Format("{0} = {1:X2}", nameof(infoOui.UpdateType), - infoOui.UpdateType)); - } - } - } - - private StreamType GuessStreamType(ProgramMappingStream stream, int totalStreams, - uint? parentRegistrationFormatIdentifier, bool allPrivateStreams) - { - if (stream.StreamType == PmtStreamType.H262) - return StreamType.Video; - if (stream.AvcStillPresent.HasValue) - return StreamType.Video; - if (stream.AudioType.HasValue) - return StreamType.Audio; - if (stream.StreamType == PmtStreamType.AvcVideoStream) - return StreamType.Video; - if (stream.StreamType == PmtStreamType.Iso11172Audio) - return StreamType.Audio; - if (stream.StreamType == PmtStreamType.Iso13818_3Audio) - return StreamType.Audio; - if (stream.StreamType == PmtStreamType.Iso13818_7AudioADTS) - return StreamType.Audio; - if (stream.StreamType == PmtStreamType.HevcVideoStream) - return StreamType.Video; - if (stream.StreamType == PmtStreamType.Iso13818_1PesPackets && stream.Ac4ChannelMode.HasValue) - return StreamType.Audio; //AC-4 Audio - if (stream.StreamType == PmtStreamType.Iso13818_1PesPackets && stream.BSID.HasValue) - return StreamType.Audio; - if (stream.StreamType == PmtStreamType.Iso14496_3Audio && stream.AacProfileAndLevel.HasValue) - return StreamType.Audio; - if ((int)stream.StreamType == 0x81 && stream.ComponentType.HasValue) - return StreamType.Audio; //AC-3 Audio, but weird. - if (stream.Teletexts != null) - { - for (int i = 0; i < stream.Teletexts.Length; i++) - { - if (stream.Teletexts[i] != null) - { - return StreamType.Teletext; - } - } - } - - if (stream.Applications != null) - { - return StreamType.Application; - } - - if (stream.DataBroadcastId == 0x0123) - { - return StreamType.HbbTv; - } - - if (stream.DataBroadcastId == 0x000a) - { - return StreamType.SystemSoftwareUpdate; - } - - if (!ALLOW_STREAM_TYPE_AUTODETECTION) - { - if ((int)stream.StreamType == 0xc0 || (int)stream.StreamType == 0xc1) - { - if (stream.PrivateDataSpecifier.HasValue) - throw new NotImplementedException(String.Format("{0}", nameof(stream.PrivateDataSpecifier))); - else - return StreamType.Ignorable; - } - } - - if (stream.StreamType == PmtStreamType.Iso13818_1PesPackets && stream.Subtitlings != null && - stream.Subtitlings.Length > 0) - { - return StreamType.Subtitles; - } - - if (stream.DataBroadcastId == 0xf0) - { - return StreamType.DvbMhp; - } - - if (!ALLOW_STREAM_TYPE_AUTODETECTION) - { - if (!stream.DataBroadcastId.HasValue && stream.StreamType == PmtStreamType.Iso13818_1PrivateSections && - totalStreams == 1) - { - return StreamType.Ignorable; - } - } - - if (stream.FormatIdentifier.HasValue && stream.FormatIdentifier == 0x43554549 && - (int)stream.StreamType == 0x86) - { - return StreamType.Scte35; - } - - if ((int)stream.StreamType == 0x86 && parentRegistrationFormatIdentifier.HasValue && - parentRegistrationFormatIdentifier.Value == 0x43554549) - { - return StreamType.Scte35; - } - - if (stream.DataBroadcastId == 0x0007) //According to dvbservices.com, this is an Object Carousel - { - return StreamType.DvbMhp; - } - - if (stream.StreamType == PmtStreamType.Iso13818_1PesPackets && stream.VbiData != null) - { - return StreamType.Teletext; - } - - if ((byte)stream.StreamType == 0x89 && stream.AncillaryDataDescriptor != null && - stream.AncillaryDataDescriptor.RdsOnly) - return StreamType.RDS; - - if (!ALLOW_STREAM_TYPE_AUTODETECTION) - { - if (stream.StreamType == PmtStreamType.Iso13818_6TypeB && !stream.DataBroadcastId.HasValue) - return StreamType.Ignorable; - - if (stream.StreamType == PmtStreamType.Iso13818_6TypeC && !stream.DataBroadcastId.HasValue) - return StreamType.Ignorable; - - if (stream.DataBroadcastId.HasValue && stream.DataBroadcastId.Value == 0x0140) - { - //Proprietary by CANAL+, does not seem to be documented. - return StreamType.Ignorable; - } - } - - if (stream.DataBroadcastId.HasValue && stream.DataBroadcastId.Value == 0x0005 /*&& stream.StreamType == PmtStreamType.Iso13818_6TypeD*/) - { - return StreamType.MultiprotocolEncapsulation; - } - - if (!ALLOW_STREAM_TYPE_AUTODETECTION) - { - if (allPrivateStreams && !stream.DataBroadcastId.HasValue && !stream.PrivateDataSpecifier.HasValue && - !parentRegistrationFormatIdentifier.HasValue) - return StreamType.Ignorable; - - if (stream.DataBroadcastId == 0x010b) - { - //NDS France Technologies system software download - //sadly undocumented. - return StreamType.Ignorable; - } - - if (stream.StreamType == PmtStreamType.Iso13818_1PesPackets && totalStreams == 1 && - !stream.DataBroadcastId.HasValue && !stream.PrivateDataSpecifier.HasValue) - { - //A single private stream. We have no clue how to deal with it, at all. - return StreamType.Ignorable; - } - } - - if (stream.DataBroadcastId == 0x0106) - { - //Defined in ETSI ES 202 184 V2.4.1 - return StreamType.Mheg5; - } - - if (stream.DataBroadcastId == 0x000b) - { - return StreamType.IpMacNotification; - } - - if (stream.RelatedContentDescriptorPresent.HasValue) - { - if (stream.RelatedContentDescriptorPresent.Value && stream.StreamType == PmtStreamType.Iso13818_1PrivateSections) - { - return StreamType.RelatedContentTable; - } - } - - if (stream.NumT2MiStreams.HasValue && stream.StreamType == PmtStreamType.Iso13818_1PesPackets) - { - return StreamType.T2Mi; - } - - if (stream.UnknownUserDefines != null) - { - if (stream.UnknownUserDefines.Count == 1) - { - if (stream.UnknownUserDefines[0].DescriptorTag == 0xa7) - { - bool interactionChannelPossible = stream.UnknownUserDefines[0].Data.All(x => x == 0x40 || x == 0x41 || x == 0x4d || x == 0x70 || x >= 0xA0); - if (interactionChannelPossible) - { - - return StreamType.InteractionChannelForSatellite; - } - } - } - } - - - if (stream.MetadataApplicationFormat == 0xffff && stream.MetadataApplicationFormatIdentifier == 0x49443320 && stream.MetadataFormat == 0xff && stream.MetadataFormatIdentifier == 0x49443320) - { - return StreamType.Id3; - } - - if (stream.StreamType == PmtStreamType.Iso13818_1PesPackets && stream.DataBroadcastId == 0x000e && stream.DataBroadcastSelector != null) - { - if (stream.DataBroadcastSelector[0] == 0x01) - { - return StreamType.SisFramingAndTiming; - } - if (stream.DataBroadcastSelector[0] == 0x02) - { - return StreamType.SisDaughterSiteAdapterConfiguration; - } - if (stream.DataBroadcastSelector[0] == 0x03) - { - return StreamType.SisPsiTables; - } - } - - if (ALLOW_STREAM_TYPE_AUTODETECTION) - { - //Abandon all hope, ye who enter here... - return StreamType.TryAutodetect; - } - - return StreamType.Unknown; - } - - private int onidHits, onidMisses; - - public void SetNetworkId(ushort networkId) - { - SetNetworkId(networkId, false); - } - - public void SetNetworkId(ushort networkId, bool forceOverwrite = false) - { - if (CurrentNetworkId == null) - { - CurrentNetworkId = networkId; - return; - } - - if (CurrentNetworkId != networkId) - { - onidMisses++; - if (forceOverwrite) - { - CurrentNetworkId = networkId; - } - } - else - onidHits++; - } - - private EitEvent[] runningEvents; - public void OnEitEvent(EitEvent eitEvent) - { - if (DataStorage.StoreEitEvent(eitEvent)) - LogEvent(SkyscraperContextEvent.EitEvent, eitEvent.EventName); - - UiJunction?.NotifyEvent(eitEvent); - - if (eitEvent.RunningStatus == RunningStatus.Running) - { - if (runningEvents == null) - runningEvents = new EitEvent[UInt16.MaxValue]; - runningEvents[eitEvent.ServiceId] = eitEvent; - } - } - - public void OnNitTransportStream(ushort networkId, NitTransportStream transportStream) - { - UiJunction?.NotifyNit(transportStream); - - string name; - switch (transportStream.DeliveryMethod) - { - case NitTransportStream.TransportMedium.DVB_S: - case NitTransportStream.TransportMedium.DVB_S2: - name = String.Format("{3}°{4}/{0}/{1}/{2}", transportStream.Frequency / 100, - transportStream.Polarization.ToString().Substring(0, 1), - (float)transportStream.SymbolRate / 10.0f, transportStream.OrbitalPosition, - transportStream.East.Value ? "E" : "W"); - break; - case NitTransportStream.TransportMedium.DVB_T2: - if (transportStream.Frequency != null) - { - throw new NotImplementedException(); - } - if (transportStream.CellInfos == null) - return; - if (transportStream.CellInfos.Count == 0) - return; - name = String.Format("Center Frequency: {0}", transportStream.GetT2Frequency()); - break; - case NitTransportStream.TransportMedium.Unknown: - return; - case NitTransportStream.TransportMedium.DVB_C: - name = String.Format("{0}/{1}/{2}", transportStream.Frequency / 100000, transportStream.SymbolRate, - transportStream.RenderModulation()); - break; - default: - throw new NotImplementedException(transportStream.DeliveryMethod.ToString()); - } - - if (!DataStorage.TestForNitTransportStream(networkId, transportStream)) - { - DataStorage.StoreNitTransportStream(networkId, transportStream); - LogEvent(SkyscraperContextEvent.OnNitTransportStream, name); - return; - } - - if (DataStorage.UpdateNitTransportStream(networkId, transportStream)) - { - LogEvent(SkyscraperContextEvent.OnNitTransportStreamUpdate, name); - return; - } - } - - public void OnNitNetwork(NitNetwork nitNetwork) - { - if (!string.IsNullOrEmpty(nitNetwork.Name)) - { - - } - if (nitNetwork.XaitPid.HasValue && CurrentNetworkId.HasValue) - { - ushort nitNetworkXaitPid = nitNetwork.XaitPid.Value; - if (nitNetwork.NetworkId == CurrentNetworkId.Value) - { - if (!DvbContext.IsPidProcessorPresent(nitNetworkXaitPid)) - { - AitParser aitParser = new AitParser(this, 0x00); - aitParser.Tag = "XAIT"; - DvbContext.RegisterPacketProcessor(nitNetworkXaitPid, - new PsiDecoder(nitNetworkXaitPid, aitParser)); - LogEvent(SkyscraperContextEvent.XaitDetected, String.Format("PID {0}", nitNetworkXaitPid)); - } - } - } - - if (!DataStorage.TestForNitNetwork(nitNetwork)) - { - DataStorage.StoreNitNetwork(nitNetwork); - LogEvent(SkyscraperContextEvent.OnNitNetwork, nitNetwork.Name); - return; - } - - if (DataStorage.UpdateNitNetwork(nitNetwork)) - { - LogEvent(SkyscraperContextEvent.OnNitNetworkUpdate, nitNetwork.Name); - return; - } - } - - - private HashSet _vpsCoordinates; - - public void OnVpsData(int networkId, int transportStreamId, ushort programNumber, VpsDataBlock vpsDataField) - { - //We don't really need VPS data, but we'll use it as another way of making sure we - //got everything. - if (_vpsCoordinates == null) - { - _vpsCoordinates = new HashSet(); - } - - VpsCoordinate vpsCoordinate = new VpsCoordinate(programNumber, vpsDataField.Month, vpsDataField.Day, - vpsDataField.Hour, vpsDataField.Minute); - if (_vpsCoordinates.Add(vpsCoordinate)) - { - LogEvent(SkyscraperContextEvent.VpsData, - String.Format("{0:D2}.{1:D2} {2:D2}:{3:D2} {4}", vpsCoordinate.Day, vpsCoordinate.Month, - vpsCoordinate.Hour, vpsCoordinate.Minute, vpsCoordinate.ProgramNumber)); - } - } - - - private Dictionary _wssDataBlocks; - - public void OnWssData(int networkId, int transportStreamId, ushort programNumber, WssDataBlock wssDataBlock) - { - if (_wssDataBlocks == null) - { - _wssDataBlocks = new Dictionary(); - } - - if (!_wssDataBlocks.ContainsKey(programNumber)) - { - _wssDataBlocks.Add(programNumber, wssDataBlock); - LogEvent(SkyscraperContextEvent.WssData, programNumber.ToString()); - UiJunction?.NotifyWss(programNumber, wssDataBlock); - } - } - - public void OnTeletextPage(int networkId, int transportStreamId, ushort programNumber, - TeletextMagazine magazine) - { - if (!currentTime.HasValue) - return; - - DataStorage.StoreTeletextPage(networkId, transportStreamId, programNumber, magazine, currentTime.Value); - } - - public void OnBatBouquet(BatBouquet batBouquet) - { - UiJunction?.NotifyBat(batBouquet); - if (DataStorage.TestForBatBouquet(batBouquet)) - { - if (DataStorage.UpdateBatBouquet(batBouquet)) - { - LogEvent(SkyscraperContextEvent.BatBouquetUpdate, batBouquet.BouquetName); - } - } - else - { - DataStorage.StoreBatBouquet(batBouquet); - LogEvent(SkyscraperContextEvent.BatBouquet, batBouquet.BouquetName); - } - } - - public void OnBatTransportStream(BatBouquet batBouquet, BatTransportStream child) - { - UiJunction?.NotifyBatTs(batBouquet.BouquetId, child); - string name = String.Format("{0},{1}", batBouquet.BouquetId, child.OriginalNetworkId); - if (DataStorage.TestForBatTransportStream(batBouquet.BouquetId, child)) - { - if (DataStorage.UpdateBatTransportStream(batBouquet.BouquetId, child)) - { - LogEvent(SkyscraperContextEvent.BatTransportStreamUpdate, name); - } - } - else - { - DataStorage.StoreBatTransportStream(batBouquet.BouquetId, child); - LogEvent(SkyscraperContextEvent.BatTransportStream, name); - } - } - - public void OnSdtService(ushort transportStreamId, ushort originalNetworkId, SdtService sdtService) - { - if (DataStorage.TestForSdtService(transportStreamId, originalNetworkId, sdtService)) - { - if (!IsChild) - { - if (DataStorage.UpdateSdtService(transportStreamId, originalNetworkId, sdtService)) - { - LogEvent(SkyscraperContextEvent.OnSdtServiceUpdate, sdtService.ServiceName); - } - } - } - else - { - DataStorage.StoreSdtService(transportStreamId, originalNetworkId, sdtService); - LogEvent(SkyscraperContextEvent.OnSdtService, sdtService.ServiceName); - } - - UiJunction?.NotifySdtService(sdtService); - } - - private DateTime? currentTime; - private DateTime? currentTimeForTim; - - public void SetCurrentTime(DateTime currentTime) - { - if (!this.currentTime.HasValue) - { - this.currentTime = currentTime; - } - currentTimeForTim = currentTime; - } - - public void SetCurrentProgrammeType(int programNumber, PTY.ProgrammeTypeCodes pty) - { - if (!CurrentNetworkId.HasValue) - return; - - if (!CurrentTransportStreamId.HasValue) - return; - - if (DataStorage.UpdateRdsPty(CurrentNetworkId.Value, CurrentTransportStreamId.Value, programNumber, pty)) - { - LogEvent(SkyscraperContextEvent.RdsPty, String.Format("{0} -> {1}", programNumber, pty.ToString())); - } - } - - public void MarkAsRdsTrafficInformationProgramme(int programNumber) - { - if (!CurrentNetworkId.HasValue) - return; - - if (!CurrentTransportStreamId.HasValue) - return; - - if (DataStorage.MarkAsRdsTrafficInformationProgramme(CurrentNetworkId.Value, CurrentTransportStreamId.Value, programNumber)) - { - LogEvent(SkyscraperContextEvent.RdsTrafficInfoDetected, String.Format("{0}", programNumber)); - } - } - - public void OnTotTime(DateTime utcTime, LocalTimeOffsetDescriptor ltod) - { - UiJunction?.NotifyTot(utcTime, ltod); - SetCurrentTime(utcTime); - - if (!CurrentNetworkId.HasValue) - return; - - if (!CurrentTransportStreamId.HasValue) - return; - - if (DataStorage.UpdateTimeOffsetTable(CurrentNetworkId.Value, CurrentTransportStreamId.Value, utcTime, - ltod)) - LogEvent(SkyscraperContextEvent.TotTime, utcTime.ToString()); - } - - public void OnTdtTime(DateTime utcTime) - { - UiJunction?.NotifyTdt(utcTime); - SetCurrentTime(utcTime); - - if (!CurrentNetworkId.HasValue) - return; - - if (!CurrentTransportStreamId.HasValue) - return; - - if (DataStorage.UpdateTimeAndDate(CurrentNetworkId.Value, CurrentTransportStreamId.Value, utcTime)) - LogEvent(SkyscraperContextEvent.TdtTime, utcTime.ToString()); - } - - public void OnAitApplication(AitApplication aitApplication, ushort programNumber) - { - UiJunction?.NotifyAit(aitApplication); - foreach (TransportProtocolDescriptor transportProtocol in aitApplication.TransportProtocols) - { - switch (transportProtocol.ProtocolId) - { - case 0x01: - ObjectCarouselTransportSelector octs = - (ObjectCarouselTransportSelector)transportProtocol.Selector; - DsmCcsToLookFor[programNumber] = octs.ComponentTag; - break; - case 0x03: - //The interwebs! - break; - default: - if (transportProtocol.Selector == null) - continue; - throw new NotImplementedException(String.Format("{0} {1:x2}", - nameof(transportProtocol.ProtocolId), transportProtocol.ProtocolId)); - } - } - - if (!DataStorage.TestForAitApplication(aitApplication.ApplicationIdentifier)) - { - DataStorage.StoreAitApplication(aitApplication); - LogEvent(SkyscraperContextEvent.AitApplication, aitApplication.TryGetName()); - } - } - - public void NotifyFileArrival(VfsFile vfsFile) - { - UiJunction?.DsmCcVfs(vfsFile); - - if (!CurrentTransportStreamId.HasValue) - return; - if (!CurrentNetworkId.HasValue) - return; - - if (ObjectStorage.ObjectCarouselFileArrival(vfsFile, CurrentTransportStreamId.Value, CurrentNetworkId.Value)) - { - LogEvent(SkyscraperContextEvent.FileArrival, String.Format("PID {0:X4}, Path {1}", vfsFile.SourcePid, vfsFile.ToString())); - } - - } - - public void NotifySubStream(ProgramMapping programMapping, Tap tap, ushort[] eventIds, Dictionary context, EventList_T eventListT, Info_T infoT) - { - foreach (ProgramMappingStream mappingStream in programMapping.Streams) - { - if (mappingStream.ComponentTag.HasValue) - { - ushort l = mappingStream.ComponentTag.Value; - ushort r = tap.AssociationTag; - if (l == r) - { - if (!DvbContext.IsPidProcessorPresent(mappingStream.ElementaryPid)) - { - //DvbContext.RegisterPacketProcessor(mappingStream.ElementaryPid, new PsiDecoder(mappingStream.ElementaryPid, new ObjectCarouselDecoder(mappingStream.ElementaryPid, this, programMapping, mappingStream.ComponentTag.Value))); - DvbContext.RegisterPacketProcessor(mappingStream.ElementaryPid, new PsiDecoder(mappingStream.ElementaryPid, new DataCarouselDecoder(mappingStream, programMapping, DataCarouselIntention.NoIntention, this))); - LogEvent(SkyscraperContextEvent.SubStreamFromObjectCarousel, String.Format("PID {0:X4}", mappingStream.ElementaryPid)); - } - } - } - } - } - - public void NotifyOfCaSystem(CaDescriptor caDescriptor, bool fromPmt = false) - { - if (caDescriptor.CaSystemId == 0x0000) - return; //Invalid CAID - - if (!CurrentNetworkId.HasValue) - return; - if (!CurrentTransportStreamId.HasValue) - return; - - if (!fromPmt) - { - UiJunction?.NotifyCat(caDescriptor); - if (!DataStorage.TestForCaSystem(CurrentNetworkId.Value, CurrentTransportStreamId.Value, caDescriptor.CaPid)) - { - DataStorage.StoreCaSystem(CurrentNetworkId.Value, CurrentTransportStreamId.Value, caDescriptor); - LogEvent(SkyscraperContextEvent.CaSystem, String.Format("{0} on PID {1:X4}", CaSystemNames.GetHumanReadableName(caDescriptor.CaSystemId), caDescriptor.CaPid)); - } - } - - if (!DvbContext.IsPidProcessorPresent(caDescriptor.CaPid)) - { - //These PIDs for CA Systems contain ECM and EMM messages. - //They are specific for *every* CA System. - //It is probably not worth reverse-engineering every single one of them. - //So we just discard these packages. - DvbContext.RegisterPacketProcessor(caDescriptor.CaPid, new PacketDiscarder()); - } - } - - public void NotifyOfSubtitleLine(Page page) - { - - } - - public void UpdateNotification(UpdateNotificationGroup common, UpdateNotificationTarget target, ushort ProgramNumber) - { - /*int hashCode = target.GetHashCode(); - if (!ScraperStorage.TestForUpdateNotification(hashCode, common)) - { - foreach (Compatibility compatibility in target.Compatibilities) - { - foreach (Platform platform in target.Platforms) - { - ScraperStorage.StoreUpdateNotification(hashCode, common, compatibility, platform); - LogEvent(SkyscraperContextEvent.UpdateNotification, - String.Format("{0} -> {1}", compatibility, platform)); - } - } - }*/ - foreach (Compatibility compatibility in target.Compatibilities) - { - foreach (Platform platform in target.Platforms) - { - DataStorage.StoreUpdateNotification(0, common, compatibility, platform); - } - } - - - if (common.AssociationTag.HasValue) - { - Platform platform = new Platform(); - platform.DataBroadcastId = common.DataBroadcastId; - platform.PrivateData = common.PrivateData; - platform.AssociationTag = common.AssociationTag; - platform.UpdateFlag = common.UpdateFlag; - platform.UpdateMethod = common.UpdateMethod; - platform.UpdatePriority = common.UpdatePriority; - target.Platforms.Add(platform); - } - - foreach (Platform targetPlatform in target.Platforms) - { - if (!targetPlatform.AssociationTag.HasValue) - continue; - if (!SsusToLookFor.Any(x => x.Key == ProgramNumber && x.Value == (byte)targetPlatform.AssociationTag)) - { - SsusToLookFor.Add(new KeyValuePair(ProgramNumber, - (byte)targetPlatform.AssociationTag.Value)); - } - } - } - - private Dictionary _dataCarouselProgresses; - - public bool IsModuleWanted(int elementaryPid, ushort moduleId, byte moduleVersion) - { - if (!CurrentNetworkId.HasValue) - return false; - - if (!CurrentTransportStreamId.HasValue) - return false; - - if (DataStorage.IsDsmCcModuleBlacklisted(CurrentNetworkId.Value, CurrentTransportStreamId.Value, elementaryPid, moduleId, moduleVersion)) - return false; - - if (ObjectStorage.IsDsmCcModuleWanted(CurrentNetworkId.Value, CurrentTransportStreamId.Value, elementaryPid, moduleId, moduleVersion)) - return true; - - return false; - } - - public void NotifyOfNewModule(int elementaryPid, ushort moduleInfoModuleId, byte moduleInfoModuleVersion) - { - if (!CurrentNetworkId.HasValue) - return; - - if (!CurrentTransportStreamId.HasValue) - return; - - if (_dataCarouselProgresses == null) - _dataCarouselProgresses = new Dictionary(); - - DatabaseKeyDsmCcModule key = new DatabaseKeyDsmCcModule(CurrentNetworkId.Value, CurrentTransportStreamId.Value, elementaryPid, moduleInfoModuleId, moduleInfoModuleVersion); - - if (dedupModules.Contains(key)) - return; - - if (ObjectStorage.IsDsmCcModuleWanted(CurrentNetworkId.Value, CurrentTransportStreamId.Value, elementaryPid, moduleInfoModuleId, moduleInfoModuleVersion)) - { - if (!_dataCarouselProgresses.ContainsKey(key)) - { - _dataCarouselProgresses.Add(key, 0.0); - } - LogEvent(SkyscraperContextEvent.NotifyOfNewModule, String.Format("PID {2:X4}, Module #{0:X4}, Version {1}", moduleInfoModuleId, moduleInfoModuleVersion, elementaryPid)); - UiJunction?.DsmCcModuleAdd(elementaryPid, moduleInfoModuleId, moduleInfoModuleVersion); - } - } - - public void NotifyModuleDownloadProgress(int elementaryPid, ushort moduleInfoModuleId, byte moduleInfoModuleVersion, double moduleInfoDownloadProgress) - { - if (!CurrentNetworkId.HasValue) - return; - - if (!CurrentTransportStreamId.HasValue) - return; - - if (_dataCarouselProgresses == null) - return; - - DatabaseKeyDsmCcModule key = new DatabaseKeyDsmCcModule(CurrentNetworkId.Value, CurrentTransportStreamId.Value, elementaryPid, moduleInfoModuleId, moduleInfoModuleVersion); - if (_dataCarouselProgresses.ContainsKey(key)) - { - _dataCarouselProgresses[key] = moduleInfoDownloadProgress; - LogEvent(SkyscraperContextEvent.ModuleDownloadProgress, String.Format("PID {3:X4}, Module #{0}, Version {1}, {2}% done", moduleInfoModuleId, moduleInfoModuleVersion, moduleInfoDownloadProgress, elementaryPid)); - UiJunction?.DsmCcModuleProgress(elementaryPid, moduleInfoModuleId, moduleInfoModuleVersion, moduleInfoDownloadProgress); - } - } - - public ObjectCarouselEventHandler GetObjectCarouselEventHandler() - { - return this; - } - - public void NotifyDownloadComplete(int elementaryPid, ushort moduleModuleId, byte moduleModuleVersion, Stream result, bool isObjectCarousel) - { - if (!CurrentNetworkId.HasValue) - return; - - if (!CurrentTransportStreamId.HasValue) - return; - - if (_dataCarouselProgresses == null) - return; - - if (isObjectCarousel) - throw new NotImplementedException(); - - UiJunction?.SetMemorySaverMode(true); - ObjectStorage.DataCarouselModuleArrival(CurrentNetworkId.Value, CurrentTransportStreamId.Value, elementaryPid, moduleModuleId, moduleModuleVersion, result); - UiJunction?.SetMemorySaverMode(false); - - LogEvent(SkyscraperContextEvent.ModuleDownloadComplete, String.Format("Module {0}, Version {1}", moduleModuleId, moduleModuleVersion)); - - DatabaseKeyDsmCcModule key = new DatabaseKeyDsmCcModule(CurrentNetworkId.Value, CurrentTransportStreamId.Value, elementaryPid, moduleModuleId, moduleModuleVersion); - _dataCarouselProgresses.Remove(key); - - UiJunction?.DsmCcModuleComplete(elementaryPid, moduleModuleId, moduleModuleVersion); - } - - public void DsmCcDoItNowEvent(ProgramMapping programMapping, StreamEventDescriptor descriptorListStreamEventDescriptor, int pid) - { - if (!CurrentTransportStreamId.HasValue) - return; - if (!CurrentNetworkId.HasValue) - return; - if (!currentTime.HasValue) - return; - DataStorage.StoreDsmCcDoItNowEvent(currentTime.Value, CurrentNetworkId.Value, CurrentNetworkId.Value, programMapping.ProgramNumber, descriptorListStreamEventDescriptor, pid); - - //These "do-it-now" Events are specific for _EVERY_ application and probably not - //worth extending the scraping time. They are most likely subtitles or commands - //for game-show play-along apps. Therefore we won't create a log entry for these, as it - //would increase scraping duration. - } - - private List dedupModules = new List(); - public void PreventDsmCcModuleRepetition(int elementaryPid, ushort moduleModuleId, byte moduleModuleVersion) - { - dedupModules.Add(new DatabaseKeyDsmCcModule(CurrentNetworkId.Value, CurrentTransportStreamId.Value, elementaryPid, moduleModuleId, moduleModuleVersion)); - } - - public void SetRdsProgrammeServiceName(int programNumber, string programmeService2) - { - if (DataStorage.UpdateRdsProgrammeServiceName(CurrentNetworkId.Value, CurrentTransportStreamId.Value, - programNumber, programmeService2)) - { - LogEvent(SkyscraperContextEvent.RdsProgrammeServiceName, - String.Format("{0:X4}, {1:X4}", programNumber, programmeService2)); - } - } - - public bool TestCanHandleRdsMessages(int programNumber) - { - if (!CurrentNetworkId.HasValue) - return false; - - if (!CurrentTransportStreamId.HasValue) - return false; - - if (!DataStorage.TestForKnownRdsData(CurrentNetworkId.Value, CurrentTransportStreamId.Value, - programNumber)) - { - DataStorage.EnableRdsCollection(CurrentNetworkId.Value, CurrentTransportStreamId.Value, - programNumber); - LogEvent(SkyscraperContextEvent.BeginRdsRecording, - String.Format("{0:X4},{1:X4},{2:X4}", CurrentNetworkId.Value, CurrentTransportStreamId.Value, - programNumber)); - } - - return true; - } - - public void SetRdsRadioText(int programNumber, string text) - { - if (DataStorage.UpdateRdsRadioText(CurrentNetworkId.Value, CurrentTransportStreamId.Value, programNumber, - text)) - { - LogEvent(SkyscraperContextEvent.RdsText, String.Format("{0:X4} [{1}]", programNumber, text)); - } - } - - public void NotifySpliceInsert(ushort ProgramNumber, SpliceInsert spliceInsert) - { - UiJunction?.NotifyScte35(ProgramNumber, spliceInsert); - if (!CurrentNetworkId.HasValue) - return; - - if (!CurrentTransportStreamId.HasValue) - return; - - if (!DataStorage.TestForScte35SpliceInsert(CurrentNetworkId.Value, CurrentTransportStreamId.Value, - ProgramNumber, spliceInsert)) - { - DataStorage.StoreScte35SpliceInsert(CurrentNetworkId.Value, CurrentTransportStreamId.Value, ProgramNumber, spliceInsert); - LogEvent(SkyscraperContextEvent.Scte35Splice, - String.Format("Program {0:X4}, Splice at {1:X16}", ProgramNumber, spliceInsert.SpliceTime)); - } - } - - public void NotifyTimeSignal(ushort programNumber, TimeSignal timeSignal) - { - UiJunction?.NotifyScte35(programNumber, timeSignal); - if (!CurrentNetworkId.HasValue) - return; - - if (!CurrentTransportStreamId.HasValue) - return; - - if (!currentTime.HasValue) - return; - - DataStorage.SetScte35TimeSignal(CurrentNetworkId.Value, CurrentTransportStreamId.Value, currentTime.Value, programNumber, timeSignal); - LogEvent(SkyscraperContextEvent.Scte35TimeSignal, String.Format("Program {0:X4}, Time Signal {1:X16}", programNumber, timeSignal.Value)); - } - - public void NotifyOfCompliance(string compliance) - { - if (!CurrentNetworkId.HasValue) - return; - - if (!CurrentTransportStreamId.HasValue) - return; - - if (!DataStorage.IsCompliant(CurrentNetworkId.Value, CurrentTransportStreamId.Value, compliance)) - { - DataStorage.MarkAsCompliant(CurrentNetworkId.Value, CurrentTransportStreamId.Value, compliance); - LogEvent(SkyscraperContextEvent.Compliance, compliance); - } - } - - public void NotifiyStationIdentification(string stationIdentification) - { - if (!CurrentNetworkId.HasValue) - return; - - if (!CurrentTransportStreamId.HasValue) - return; - - if (DataStorage.SetStationIdentification(CurrentNetworkId.Value, CurrentTransportStreamId.Value, - stationIdentification)) - { - LogEvent(SkyscraperContextEvent.StationIdentification, stationIdentification); - } - } - - public void AutodetectionSucessful(int pid, Contestant contestant, ProgramContext programContext) - { - UiJunction?.NotifyStreamTypeDetection(contestant.Tag, pid); - LogEvent(SkyscraperContextEvent.StreamTypeAutodetection, String.Format("{0} on PID {1:X4}", contestant.Tag, pid)); - contestant.DeclareWinner(this, pid, programContext); - return; - } - - - private IpTrafficHandler ipTrafficHandler; - public void OnIpDatagram(int pid, byte[] payload) - { - if (ipTrafficHandler == null) - { - StorageConnectionManager storageConnectionManager = StorageConnectionManager.GetInstance(); - ipTrafficHandler = storageConnectionManager.GetDefaultIpTrafficHandler(); - } - if (payload.Length == 0) - { - return; - } - - ipTrafficHandler?.HandlePacket(pid, payload); - - int ipVersion = (payload[0] & 0xf0) >> 4; - if (ipVersion == 4) - { - if (Array.TrueForAll(payload, x => x == 0)) - return; - int ihl = (payload[0] & 0x0f); - ihl *= 32; - ihl /= 8; - byte[] ipv4Header = new byte[ihl]; - if (payload.Length < ihl) - return; - Array.Copy(payload, 0, ipv4Header, 0, ihl); - InternetHeader internetHeader = new InternetHeader(ipv4Header); - if (!internetHeader.ChecksumValid) - return; - byte[] ipv4Packet = new byte[payload.Length - ihl]; - Array.Copy(payload, ihl, ipv4Packet, 0, payload.Length - ihl); - OnIpv4PacketArrival(internetHeader, ipv4Packet); - } - else if (ipVersion == 6) - { - if (payload.Length < 40) - { - return; - } - MemoryStream ipv6Stream = new MemoryStream(payload, false); - byte byteA = ipv6Stream.ReadUInt8(); - byte byteB = ipv6Stream.ReadUInt8(); - - int trafficClass = (byteA & 0x0f) << 4; - trafficClass = ((byteB & 0xf0) >> 4); - - int flowLabel = (byteB & 0x0f) << 16; - flowLabel += ipv6Stream.ReadUInt16BE(); - - ushort payloadLength = ipv6Stream.ReadUInt16BE(); - byte nextHeader = ipv6Stream.ReadUInt8(); - byte hopLimit = ipv6Stream.ReadUInt8(); - - IPAddress sourceAddress = new IPAddress(ipv6Stream.ReadBytes(16)); - IPAddress destinationAddress = new IPAddress(ipv6Stream.ReadBytes(16)); - InternetHeader ipv6Header = new InternetHeader(trafficClass, flowLabel, payloadLength, nextHeader, hopLimit, sourceAddress, destinationAddress); - if (ipv6Stream.GetAvailableBytes() >= payloadLength) - { - OnIpv4PacketArrival(ipv6Header, ipv6Stream.ReadBytes(payloadLength)); - } - return; - } - else - { - //throw new Exception("invalid ip packet"); - } - } - - public void GsIpTrafficDetected() - { - LogEvent(SkyscraperContextEvent.SpecialTsMode, "Valid IP Traffic detected"); - } - - private HashSet trafficInfos; - private ReadOnlyCollection mpePlugins; - public SkyscraperDnsCache DnsCache { get; private set; } - - private bool ProcessDns(IpTrafficInfo trafficInfo, byte[] ipv4Packet) - { - if (DnsCache == null) - DnsCache = new SkyscraperDnsCache(DataStorage); - //Handle DNS - bool result = false; - if (trafficInfo.Protocol == 0x11) - { - UserDatagram udpPacket = new UserDatagram(ipv4Packet); - if (udpPacket.Valid) - { - if (udpPacket.SourcePort == 53) - { - result = DnsCache.ProcessDnsPacket(udpPacket.Payload); - } - } - } - trafficInfo.SourceName = DnsCache.GetDnsName(trafficInfo.Source); - trafficInfo.TargetName = DnsCache.GetDnsName(trafficInfo.Target); - return result; - } - - public void OnIpv4PacketArrival(InternetHeader internetHeader, byte[] ipv4Packet) - { - //There are as many use cases as there are internet applications in these. - //Not really required to decode all of them, if you ask me. - /* - * One known use is LX9SES on Astra 23.5, with the following arguments: - * -> Destination Address always 228.64.0.56 - * -> Source Address always 10.225.49.1 - * -> Protocol always 0x11 (UDP) - */ - if (trafficInfos == null) - trafficInfos = new HashSet(); - - IpTrafficInfo iti = IpTrafficInfo.FromInternetHeader(internetHeader); - if (ProcessDns(iti, ipv4Packet)) - { - LogEvent(SkyscraperContextEvent.LearnDns, String.Format("{0} = {1}", DnsCache.LastLearned.Value, DnsCache.LastLearned.Key)); - } - UiJunction?.NotifyMpeTraffic(iti, ipv4Packet.Length); - - if (trafficInfos.Add(iti)) - { - LogEvent(SkyscraperContextEvent.IpTraffic, iti.ToString()); - } - - if (mpePlugins == null) - { - mpePlugins = PluginManager.GetInstance().GetMpePlugins(); - object[] connector = StorageConnectionManager.GetPluginConnectors(DataStorage, ObjectStorage); - foreach (ISkyscraperMpePlugin plugin in mpePlugins) - { - try - { - plugin.ConnectToStorage(connector); - } - catch (Exception e) - { - - } - } - } - - - foreach (ISkyscraperMpePlugin plugin in mpePlugins) - { - if (plugin.CanHandlePacket(internetHeader, ipv4Packet)) - { - plugin.SetContext(currentTime,this); - plugin.HandlePacket(internetHeader, ipv4Packet); - if (plugin.StopProcessingAfterThis()) - return; - } - } - /* - if (internetHeader.Protocol == 0x11) - { - UserDatagram userDatagram = new UserDatagram(ipv4Packet); - if (!userDatagram.Valid) - return; - - if (internetHeader.SourceAddress.Equals(_fpUrmetSrc) && internetHeader.DestinationAddress.Equals(_fpUrmetDst)) - { - //Found on Astra 19.2 12604/H - not the slightest idea what this does. - //Service name is FP URMET. - return; - } - else - { - ipPackets++; - } - } - else if (internetHeader.Protocol == 0x02) - { - IgmpMessage igmpMessage = new IgmpMessage(ipv4Packet); - //Also Found on Astra 19.2 12604/H, I don't think we'll need these. - return; - } - else - { - ipPackets++; - }*/ - } - - public void NotifyRunningStatus(uint transportStreamId, uint originalNetworkId, uint serviceId, uint eventId, - RunningStatus runningStatus) - { - if (!currentTime.HasValue) - return; - - if (DataStorage.StoreRunningStatus(transportStreamId, originalNetworkId, serviceId, eventId, runningStatus, currentTime.Value)) - { - LogEvent(SkyscraperContextEvent.RunningStatusChange, String.Format("({0:X4},{1:X4},{2:X4},{3:X4}) -> {4}", originalNetworkId, transportStreamId, serviceId, eventId, runningStatus)); - } - } - - public bool EnableTimeout { get; set; } - - public int TimeoutSeconds { get; set; } - - public bool CancelOnNextPacket { get; set; } - public ISkyscraperUiJunction UiJunction { get; set; } - - public bool IsAbortConditionMet() - { - if (ffmpegFrameGrabber.BusyFrameGrabbers > 0) - return false; - - if (EnableTimeout && TimeoutSeconds == 0) - TimeoutSeconds = 10; - - if (!firstPacketDone) - return false; - - if (CancelOnNextPacket) - { - LogEvent(SkyscraperContextEvent.AbortConditionMet, "Aborted from another thread."); - CancelOnNextPacket = false; - return true; - } - - if (EnableTimeout) - { - TimeSpan sinceLastEvent = DateTime.Now - lastEventTimestamp; - if (sinceLastEvent.TotalSeconds > TimeoutSeconds) - { - LogEvent(SkyscraperContextEvent.AbortConditionMet, String.Format("Event Timeout after {0} seconds", TimeoutSeconds)); - return true; - } - } - - return false; - } - - public void OnT2MiPacketLoss(int pid, byte expectedPacket, T2MIHeader header) - { - } - - public void OnT2MiPacket(int pid, byte basebandFramePlpId, byte[] basebandPacket) - { - if (subSkyscrapers == null) - subSkyscrapers = new Dictionary(); - - T2MiSubSkyscraperIdentifier subSkyscraperIdentifier = new T2MiSubSkyscraperIdentifier(pid, basebandFramePlpId); - if (!subSkyscrapers.ContainsKey(subSkyscraperIdentifier)) - { - LogEvent(SkyscraperContextEvent.T2MiPlpDetected, String.Format("PID {0:X4}, PLP {1}", pid, basebandFramePlpId)); - } - - OnSubTsPacket(subSkyscraperIdentifier, basebandPacket); - } - - private Dictionary subSkyscrapers; - public void OnSubTsPacket(object identifier, byte[] packet) - { - if (subSkyscrapers == null) - subSkyscrapers = new Dictionary(); - - if (!subSkyscrapers.ContainsKey(identifier)) - { - SkyscraperContext child = new SkyscraperContext(new TsContext(), DataStorage, ObjectStorage); - child.IsChild = true; - child.ChildName = identifier.ToString(); - child.ChildTimestamp = DateTime.Now.Ticks; - - List packetFilters = new List(); - StorageConnectionManager storageConnectionManager = StorageConnectionManager.GetInstance(); - if (storageConnectionManager.IsSubTsDumpingEnabled()) - { - string filename = String.Format("{0}_{1}.ts", child.ChildName.SanitizeFileName(), child.ChildTimestamp); - FileInfo fi = new FileInfo(filename); - TsRecorder packetDumper = new TsRecorder(); - packetDumper.RecordingOutputDirectory = new DirectoryInfo("."); - packetDumper.SetNextFilename(filename); - packetDumper.CreateBufferedStream(); - packetFilters.Add(packetDumper); - } - - child.InitalizeFilterChain(packetFilters.ToArray()); - subSkyscrapers.Add(identifier, child); - } - - SkyscraperContext context = subSkyscrapers[identifier]; - context.IngestSinglePacket(packet); - } - public long ChildTimestamp { get; private set; } - public string ChildName { get; private set; } - public bool IsChild { get; private set; } - - public void OnT2MiTimestamp(int pid, _0x20_DvbT2Timestamp t2Timestamp) - { - if (!CurrentNetworkId.HasValue) - return; - - if (!CurrentTransportStreamId.HasValue) - return; - - if (subSkyscrapers == null) - return; - - List contexts = new List(); - foreach (KeyValuePair subSkyscraper in subSkyscrapers) - { - object subSkyscraperKey = subSkyscraper.Key; - if (!(subSkyscraperKey is T2MiSubSkyscraperIdentifier)) - continue; - - T2MiSubSkyscraperIdentifier identifier = subSkyscraperKey as T2MiSubSkyscraperIdentifier; - if (identifier.Pid != pid) - continue; - - contexts.Add(subSkyscraper.Value); - } - - if (contexts.Count == 0) - return; - - long sum = contexts.Select(x => (long)x.EventsLogged).Sum(); - if (sum < (contexts.Count * 2)) - return; - - DateTime resolveTime = t2Timestamp.ResolveTime(); - DateTime knownTimestamp = DataStorage.T2MiGetTimestamp(CurrentNetworkId.Value, CurrentTransportStreamId.Value, pid); - if (resolveTime > knownTimestamp) - { - DataStorage.T2MiSetTimestamp(CurrentNetworkId.Value, CurrentTransportStreamId.Value, pid, resolveTime); - } - } - - public void OnT2MiIqData(int relatedPid, _0x31_IqData iqData) - { - - } - - public void OnT2MiIqData(int relatedPid, _0x01_IqData iqData2) - { - - } - - public void OnT2MiError(int relatedPid, int skyscraperErrorCode) - { - - } - - public void OnT2MiL1Current(int relatedPid, _0x10_L1Current l1Current) - { - //No clue about this data. It's not really interesting. - } - - public void OnT2MiArbitraryCellInsertion(int relatedPid, _0x02_ArbitraryCellInsertion arbitraryCellInsertion) - { - - } - - public void OnT2MiBalancingCells(int relatedPid, byte frameIndex, uint numActiveBiasCellsPerP2) - { - - } - - public void OnT2MiL1Future(int relatedPid, _0x11_L1Future l1Future) - { - if (l1Future.FutureData.L1DynNext.Length == 0) - return; - - throw new NotImplementedException(); - } - - public void OnT2MiIndividualAddressing(int relatedPid, _0x21_IndividualAddressing individualAddressing) - { - if (!CurrentNetworkId.HasValue) - return; - - if (!CurrentTransportStreamId.HasValue) - return; - - if (subSkyscrapers == null) - return; - - bool any = subSkyscrapers.Where(x => x.Key is T2MiSubSkyscraperIdentifier) - .Select(x => (T2MiSubSkyscraperIdentifier)x.Key) - .Any(); - if (!any) - return; - - foreach (AddressingFunction function in individualAddressing.Commands) - { - if (!DataStorage.T2MiTestForTransmitter(CurrentNetworkId, CurrentTransportStreamId, relatedPid, function.TxIdentifier)) - DataStorage.T2MiRememberTransmitter(CurrentNetworkId, CurrentTransportStreamId, relatedPid, function.TxIdentifier); - - switch (function.Tag) - { - case 0x00: - _0x00_TransmitterTimeOffset tto = (_0x00_TransmitterTimeOffset)function; - DataStorage.T2MiSetTransmitterTimeOffset(CurrentNetworkId, CurrentTransportStreamId, relatedPid, function.TxIdentifier, tto.TimeOffset); - break; - default: - throw new NotImplementedException(String.Format("Individual Addressing function 0x{0:X2}", function.Tag)); - } - } - } - - public bool TcpProxyEnabled - { - get => DvbContext.TcpProxyEnabled; - set => DvbContext.TcpProxyEnabled = value; - } - - public void Dispose() - { - if (TcpProxyEnabled) - TcpProxyEnabled = false; - - - if (ipTrafficHandler != null) - { - ipTrafficHandler.Dispose(); - } - - - if (DvbContext.TcpProxyEnabled) - { - DvbContext.TcpProxyEnabled = false; - } - - if (docsisPacketProcessor != null) - { - docsisPacketProcessor.Dispose(); - } - - if (!SourceIsDisk) - { - if (_dataCarouselProgresses != null) - { - foreach (KeyValuePair item in _dataCarouselProgresses) - { - if (item.Value == 0.0) - continue; - - DataStorage.FailDsmCcDownload(item.Key, item.Value); - } - } - } - - if (_pluginContexts != null) - { - foreach (object plugin in _pluginContexts) - { - IDisposable disposable = plugin as IDisposable; - if (disposable != null) - disposable.Dispose(); - } - _pluginContexts.Clear(); - } - - DataStorage.WaitForCompletion(); - } - - public bool TestForFrame(int currentNetworkId, int transportStreamId, ushort mappingProgramNumber, int mappingStreamElementaryPid) - { - return ObjectStorage.TestForFramegrab(currentNetworkId, transportStreamId, mappingProgramNumber, mappingStreamElementaryPid); - } - - public void NotifyCompletedFrame(int currentNetworkId, int transportStreamId, ushort mappingProgramNumber, - int mappingStreamElementaryPid, byte[] imageData) - { - ObjectStorage.StoreFramegrab(currentNetworkId, transportStreamId, mappingProgramNumber, (ushort)mappingStreamElementaryPid, imageData); - LogEvent(SkyscraperContextEvent.GotFramegrab, String.Format("Program {0:X4}, PID {1:X4}", mappingProgramNumber, mappingStreamElementaryPid)); - UiJunction?.ShowFramegrab(currentNetworkId, transportStreamId, mappingProgramNumber, mappingStreamElementaryPid, imageData); - } - - public void OnIpMacNotification(int sourcePid, Dvb.DataBroadcasting.IntModel.Platform platform, Target target, Operational operational) - { - IEnumerable ipMacNotifications = IpMacNotification.FlatMap(platform, target, operational); - foreach (IpMacNotification notification in ipMacNotifications) - { - if (!DataStorage.TestForIpMacNotification(notification)) - { - DataStorage.StoreIpMacNotification(notification); - LogEvent(SkyscraperContextEvent.IpMacNotification, String.Format("{0} -> {1}", platform.Name, notification.TargetName)); - } - } - } - - public void OnRelatedContent(Rct result, ushort resultProgramNumber) - { - if (result.LinkInfo.Length == 0) - return; - if (runningEvents == null) - return; - if (runningEvents[resultProgramNumber] == null) - return; - - EitEvent lEvent = runningEvents[resultProgramNumber]; - - foreach (RctLinkInfo rctLinkInfo in result.LinkInfo) - { - if (!DataStorage.TestForRelatedContent(lEvent, rctLinkInfo)) - { - DataStorage.SetRelatedContent(lEvent, rctLinkInfo); - LogEvent(SkyscraperContextEvent.RelatedContent, String.Format("Program {0}, Event {1} -> {2}", resultProgramNumber, lEvent.EventId, rctLinkInfo.GetIdentifierString())); - } - } - } - - private bool warnedMissingLocation; - - private void WarnMissingLocation() - { - if (!warnedMissingLocation) - { - LogEvent(SkyscraperContextEvent.LocationMissing); - warnedMissingLocation = true; - } - } - - public void OnParticipantDetected(PhysicalAddress pa) - { - int? currentLocation = DataStorage.GetCurrentLocationId(); - if (currentLocation.HasValue) - { - LogEvent(SkyscraperContextEvent.DocsisParticipant, BitConverter.ToString(pa.GetAddressBytes())); - DataStorage.StoreDocsisParticipant(pa, currentLocation.Value); - } - else - { - WarnMissingLocation(); - } - } - - public void OnCmtsTimestamp(PhysicalAddress source, uint timing) - { - //DOCSIS Timestamps are not interesting to us. - } - - public void OnUpstreamChannel(UpstreamChannelDescriptor mmm) - { - UiJunction?.NotifyDocsisFrequency(mmm.Frequency, true, mmm); - if (!mmm.Frequency.HasValue) - return; - - int? currentLocation = DataStorage.GetCurrentLocationId(); - if (!currentLocation.HasValue) - { - WarnMissingLocation(); - return; - } - - if (!DataStorage.TestForDocsisUpstreamChannel(mmm.Source, mmm.Frequency.Value,currentLocation.Value)) - { - DataStorage.StoreDocsisUpstreamChannel(mmm, currentLocation.Value); - LogEvent(SkyscraperContextEvent.DocsisUpstreamChannel, String.Format("{0} -> {1}", mmm.Source.ToString(), mmm.Frequency.Value)); - } - } - - public void OnDownstreamChannel(PhysicalAddress physicalAddress, MacDomainDescriptor.DownstreamActiveChannel downstreamActiveChannel) - { - UiJunction?.NotifyDocsisFrequency(downstreamActiveChannel.Frequency, false, downstreamActiveChannel); - - if (!downstreamActiveChannel.Frequency.HasValue) - return; - - int? currentLocation = DataStorage.GetCurrentLocationId(); - if (!currentLocation.HasValue) - { - WarnMissingLocation(); - return; - } - - if (!DataStorage.TestForDocsisDownstreamChannel(physicalAddress, downstreamActiveChannel,currentLocation.Value)) - { - DataStorage.StoreDocsisDownstreamChannel(physicalAddress, downstreamActiveChannel,currentLocation.Value); - LogEvent(SkyscraperContextEvent.DocsisDownstreamChannel, String.Format("{0} -> {1}", physicalAddress.ToString(), downstreamActiveChannel.Frequency.Value)); - } - } - - public void OnLearnedIpFromMac(PhysicalAddress arpHeaderSenderHardwareAddress, IPAddress arpHeaderSenderProtocolAddress) - { - int? currentLocation = DataStorage.GetCurrentLocationId(); - if (!currentLocation.HasValue) - { - WarnMissingLocation(); - return; - } - - if (DataStorage.SetCmtsIp(arpHeaderSenderHardwareAddress, arpHeaderSenderProtocolAddress)) - { - LogEvent(SkyscraperContextEvent.LearnedCmtsIp,String.Format("{0} -> {1}",arpHeaderSenderHardwareAddress.ToString(),arpHeaderSenderProtocolAddress.ToString())); - } - } - - public void OnAbertisPacket(int pid, byte[] outBuffer) - { - AbertisSubSkyscraperKey key = new AbertisSubSkyscraperKey(pid); - OnSubTsPacket(key, outBuffer); - } - - public void OnAbertisSyncLoss(int pid, int oldPosition = -1, long newPosition = -1) - { - if (subSkyscrapers == null) - DvbContext.RegisterPacketProcessor(pid, new PacketDiscarder()); - - AbertisSubSkyscraperKey key = new AbertisSubSkyscraperKey(pid); - if (!subSkyscrapers.ContainsKey(key) == null) - DvbContext.RegisterPacketProcessor(pid, new PacketDiscarder()); - - if (!subSkyscrapers[key].firstPacketDone) - DvbContext.RegisterPacketProcessor(pid, new PacketDiscarder()); - else - throw new NotImplementedException( - "I couldn't sync this Abertis-styled stream, and I couldn't figure out why. Could you please share a sample of this stream?"); - } - - public void OnMonochromeData(int networkId, int transportStreamId, ushort programNumber, MonochromeDataField result) - { - throw new NotImplementedException(); - } - - void Id3Handler.OnId3Error(Id3ErrorState state) - { - throw new NotImplementedException(); - } - - void Id3Handler.OnId3Tag(Id3Tag tag) - { - if (tag.IsAllPrivate()) - return; - throw new NotImplementedException(); - } - - void InteractionChannelHandler.OnCorrectionMessage(ushort interactiveNetworkId, Cmt cmt) - { - foreach(Cmt.CmtEntry entry in cmt.Entries) - { - if (!DataStorage.TestForCmtEntry(interactiveNetworkId,entry)) - { - LogEvent(SkyscraperContextEvent.CorrectionMessage, String.Format("Network ID = {0}, Group ID = {1}, Logon ID = {2}, Slot Type = {3}", interactiveNetworkId, entry.GroupId, entry.LoginId,entry.SlotType.ToString())); - DataStorage.InsertCmtEntry(interactiveNetworkId, entry); - } - } - } - - void InteractionChannelHandler.OnFrameComposition(ushort interactiveNetworkId, Fct fct) - { - foreach(Fct.Frame frame in fct.Frames) - { - if (!DataStorage.TestForFrameComposition(interactiveNetworkId,frame)) - { - LogEvent(SkyscraperContextEvent.FrameComposition, String.Format("Network ID = {0}, Frame = {1}", interactiveNetworkId, frame.FrameId)); - DataStorage.InsertFctFrame(interactiveNetworkId, frame); - } - } - } - - private bool[] interactionChannelErrors; - void InteractionChannelHandler.OnInteractionChannelError(InteractionChannelErrorState unexpectedTable) - { - if (interactionChannelErrors == null) - { - interactionChannelErrors = new bool[Enum.GetNames(typeof(InteractionChannelErrorState)).Length]; - } - int offset = (int)unexpectedTable; - if (!interactionChannelErrors[offset]) - { - LogEvent(SkyscraperContextEvent.InteractionChannelError, unexpectedTable.ToString()); - interactionChannelErrors[offset] = true; - } - } - - public void OnRcsMap(Rmt rmt) - { - if (rmt.Linkages != null) - { - foreach(_0x4a_LinkageDescriptor linkage in rmt.Linkages) - { - if (!DataStorage.TestForRmtLinkage(linkage)) - { - LogEvent(SkyscraperContextEvent.RmtLinkage, String.Format("Interactive Network #{0} -> ONID {1}, TSID {2}", linkage.InteractiveNetworkId, linkage.OriginalNetworkId, linkage.TransportStreamId)); - DataStorage.InsertRmtLinkage(linkage); - } - } - } - if (rmt.TransportStreams != null) - { - foreach(Rmt.TransportStream transportStream in rmt.TransportStreams) - { - if (!DataStorage.TestForRmtTransportStream(rmt.NetworkId, transportStream)) - { - LogEvent(SkyscraperContextEvent.RmtTransportStream, String.Format("{0} -> {1},{2}", rmt.NetworkId, transportStream.OriginalNetworkId, transportStream.TransportStreamId)); - DataStorage.InsertRmtTransportStream(rmt.NetworkId, transportStream); - } - } - } - } - - private void CheckForHiddenMpes() - { - uint threshold = 1000; - if (pmtTracker != null) - { - if (!pmtTracker.AllPmtsProcessed) - { - return; - } - - threshold = 1; - } - int[] occupiedPids = DvbContext.GetOccupiedPids(); - ulong[] pidStatistics = DvbContext.GetPidStatistics(); - for (int i = 0; i < (pidStatistics.Length - 1); i++) - { - if (pidStatistics[i] > threshold) - { - if (!occupiedPids.Contains(i)) - { - LogEvent(SkyscraperContextEvent.SpecialTsMode, String.Format("Attaching stream-type autodetector to PID 0x{0:X4}", i)); - DvbContext.RegisterPacketProcessor(i, new StreamTypeAutodetection(i, this)); - } - } - } - } - - public void OnSatellitePosition(ushort interactiveNetworkId, Spt spt) - { - foreach (Spt.Satellite satellite in spt.Satellites) - { - if (!DataStorage.TestForSatellitePosition(interactiveNetworkId,satellite)) - { - LogEvent(SkyscraperContextEvent.SatellitePosition, String.Format("NID = {0}, Satellite ID = {1} (X = {2}, Y = {3}, Z = {4})", interactiveNetworkId, satellite.Id, satellite.X, satellite.Y, satellite.Z)); - DataStorage.StoreSatellitePosition(interactiveNetworkId, satellite); - } - } - } - - void InteractionChannelHandler.OnSuperframeComposition(ushort interactiveNetworkId, Sct sct) - { - foreach(Sct.Superframe superframe in sct.Superframes) - { - if (!DataStorage.TestForSuperframeComposition(interactiveNetworkId,superframe)) - { - LogEvent(SkyscraperContextEvent.SuperframeComposition, String.Format("Network ID = {0}, Superframe ID = {1}, Frequency = {2}/{3}", interactiveNetworkId, superframe.SuperframeId, superframe.SuperframeCentreFrequency,superframe.UplinkPolarization)); - DataStorage.StoreSuperframeComposition(interactiveNetworkId, superframe); - } - } - } - - void InteractionChannelHandler.OnTerminalBurstTimePlan(ushort interactiveNetworkId, Tbtp tbtp) - { - foreach (Tbtp.TbtpFrame frame in tbtp.Frames) - { - foreach (Tbtp.TbtpFrame.BtpEntity btp in frame.BTP) - { - if (DataStorage.TestForTerminalBurstTimePlan(interactiveNetworkId,tbtp.GroupId,btp.LogonId)) - { - LogEvent(SkyscraperContextEvent.TerminalBurstTimePlan, String.Format("Network ID = {0}, Group ID = {1}, Logon ID = {2}", interactiveNetworkId, tbtp.GroupId, btp.LogonId)); - DataStorage.StoreTerminalBurstTimePlan(interactiveNetworkId, tbtp.GroupId, tbtp.SuperframeCount, frame.FrameNumber, btp); - } - } - } - } - - public void OnTimeslotComposition(ushort interactiveNetworkId, Tct tct) - { - throw new NotImplementedException(); - } - - public void OnTerminalBurstTimePlan2(ushort interactiveNetworkId, Tbtp2 tbtp2) - { - foreach (Tbtp2.Frame frame in tbtp2.Frames) - { - for (int assignmentOrdinal = 0; assignmentOrdinal < frame.Assignments.Length; assignmentOrdinal++) - { - Tbtp2.Assignment assignment = frame.Assignments[assignmentOrdinal]; - if (!DataStorage.TestForTerminalBurstTimePlan2(interactiveNetworkId, tbtp2.GroupId, frame.FrameNumber)) - { - LogEvent(SkyscraperContextEvent.TerminalBurstTimePlan2, String.Format("Network ID = {0}, Group ID = {1}, Frame Number = {2}",interactiveNetworkId,tbtp2.GroupId,frame.FrameNumber)); - DataStorage.StoreTerminalBurstTimePlan2(interactiveNetworkId, tbtp2.GroupId, frame); - } - } - } - } - - public void OnFrameComposition2(ushort networkId, Fct2 fct2) - { - foreach (Fct2.Frame frame in fct2.FrameTypes) - { - if (!DataStorage.TestForFrameComposition2(networkId, frame)) - { - LogEvent(SkyscraperContextEvent.FrameComposition2,String.Format("Network ID = {0}, Frame Type = {1}",networkId,frame.FrameType)); - DataStorage.InsertFct2Frame(networkId, frame); - } - } - } - - public void OnBroadcastConfiguration(ushort networkId, Bct bct) - { - foreach (Bct.BroadcastConfiguration txType in bct.TxTypes) - { - if (!DataStorage.TestForBroadcastConfiguration(networkId, txType.TxType)) - { - LogEvent(SkyscraperContextEvent.BroadcastConfiguration, String.Format("Network ID = {0}, Broadcast Configuration #{1}", networkId, txType.TxType)); - DataStorage.InsertBroadcastConfiguration(networkId, txType); - } - } - } - - public void OnRcs2Nit(ushort interactiveNetworkId, RcsNit nit) - { - if (!DataStorage.TestForRcs2Nit(nit)) - { - LogEvent(SkyscraperContextEvent.Rcs2Network, String.Format("Network ID #{0}, ({1}) on {2}", nit.OriginalNetworkId, nit.NetworkName, nit.SatelliteDeliverySystem.ToString())); - DataStorage.InsertRcs2Nit(nit); - } - } - - public void OnRcs2Tdt(ushort interactiveNetworkId, Rcs2Tdt tdt) - { - LogEvent(SkyscraperContextEvent.Rcs2TdtTime, String.Format("Network ID #{0}, {1}", interactiveNetworkId, tdt.Timestamp)); - DataStorage.UpdateRcs2Tdt(interactiveNetworkId, tdt.Timestamp); - } - - public void OnTransmissionModeSupport2(ushort interactiveNetworkId, Tmst2 tmst2) - { - foreach (Tmst2.TransmissionMode mode in tmst2.TransmissionModes) - { - if (!DataStorage.TestForTmst2(interactiveNetworkId, mode)) - { - LogEvent(SkyscraperContextEvent.TransmissionModeSupport2, String.Format("Network ID #{0}, MODCOD {1}", interactiveNetworkId, mode.Modcod)); - DataStorage.InsertTmst2(interactiveNetworkId, mode); - } - } - } - - public void OnFramePayloadFormatAnnouncement(ushort networkId, _0xb7_FramePayloadFormatDescriptor descriptor) - { - foreach (_0xb7_FramePayloadFormatDescriptor.TransmissionContext transmissionContext in descriptor.Contexts) - { - if (!DataStorage.TestForTimFramePayloadFormat(networkId, transmissionContext)) - { - LogEvent(SkyscraperContextEvent.TimFramePayloadFormat,String.Format("Network #{0}, Context ID #{1}",networkId,transmissionContext.TransmissionContextId)); - DataStorage.InsertTimFramePayloadFormat(networkId, transmissionContext); - } - } - } - - public void OnCorrectionMessageExtension(PhysicalAddress macAddress, _0xb1_CorrectionMessageExtensionDescriptor descriptor) - { - if (!DataStorage.TestForTimCorrectionMessageExtension(macAddress)) - { - LogEvent(SkyscraperContextEvent.TimCorrectionExtension, String.Format("For participant {0}", macAddress)); - DataStorage.InsertTimCorrectionMessageExtension(macAddress, descriptor); - } - } - - public void OnControlAssignment(PhysicalAddress macAddress, _0xa4_SyncAssignDescriptor descriptor) - { - if (!DataStorage.TestForTimControlAssignment(macAddress)) - { - LogEvent(SkyscraperContextEvent.TimControlAssignment, String.Format("For participant {0}", macAddress)); - DataStorage.InsertTimControlAssignment(macAddress, descriptor); - } - } - - public void OnSatelliteReturnLink(PhysicalAddress macAddress, _0xa9_SatelliteReturnLinkDescriptor descriptor) - { - if (!DataStorage.TestForTimSatelliteReturnLink(macAddress)) - { - LogEvent(SkyscraperContextEvent.TimSatelliteReturnLink, String.Format("For participant {0}: {1}", macAddress, descriptor)); - DataStorage.InsertTimSatelliteReturnLink(macAddress, descriptor); - } - } - - public void OnLowerLayerService(PhysicalAddress macAddress, _0xbb_LowerLayerServiceDescriptor descriptor) - { - if (!DataStorage.TestForLowerLayerService(macAddress)) - { - LogEvent(SkyscraperContextEvent.TimLowerLayerService, String.Format("For participant {0}", macAddress)); - DataStorage.InsertTimLowerLayerService(macAddress, descriptor); - } - } - - public void OnHigherLayerInitalization(PhysicalAddress macAddress, _0xc4_HigherLayersInitializeDescriptor descriptor) - { - foreach (_0xc4_HigherLayersInitializeDescriptor.Layer2Interface layer2Interface in descriptor.Layer2Interfaces) - { - if (!DataStorage.TestForHigherLayerServiceInitalization(macAddress, layer2Interface)) - { - LogEvent(SkyscraperContextEvent.TimHigherLayerInitalization, String.Format("For participant {0} -> {1}", macAddress, layer2Interface.Ipv4McAddress)); - DataStorage.InsertHigherLayerServiceInitalization(macAddress, layer2Interface); - } - } - } - - public void LogonResponseDescriptor(PhysicalAddress macAddress, _0xb9_LogonResponseDescriptor descriptor) - { - if (!DataStorage.TestForTimLogonResponse(macAddress)) - { - LogEvent(SkyscraperContextEvent.TimLogonResponse, String.Format("For participant {0}: {1}", macAddress, descriptor.ToString())); - DataStorage.InsertTimLogonResponse(macAddress, descriptor); - } - } - - public void OnForwardInteractionPath(PhysicalAddress macAddress, _0xad_ForwardInteractionPathDescriptor descriptor) - { - foreach (_0xad_ForwardInteractionPathDescriptor.ForwardInteractionPath forwardInteractionPath in descriptor.Paths) - { - if (!DataStorage.TestForTimForwardInteractionPath(macAddress, forwardInteractionPath)) - { - LogEvent(SkyscraperContextEvent.TimForwardInteractionPath, String.Format("For participant {0}: {1}", macAddress, forwardInteractionPath.ToString())); - DataStorage.InsertTimForwardInteractionPath(macAddress, forwardInteractionPath); - } - } - } - - public void OnCorrectionMessage(PhysicalAddress mac, _0xa1_CorrectionMessageDescriptor cmd) - { - if (!DataStorage.TestForTim(mac)) - { - LogEvent(SkyscraperContextEvent.Tim, String.Format("for participant {0}", mac.ToString())); - DataStorage.CreateTim(mac); - } - if (DataStorage.CorrectTim(mac, cmd)) - { - LogEvent(SkyscraperContextEvent.TimCorrection, String.Format("for participant {0}", mac.ToString())); - } - } - - public void OnContentionControl(PhysicalAddress mac, _0xab_ContentionControlDescriptor ccdNew) - { - if (!DataStorage.TestForTim(mac)) - { - LogEvent(SkyscraperContextEvent.Tim, String.Format("for participant {0}", mac.ToString())); - DataStorage.CreateTim(mac); - } - if (DataStorage.ContentionTim(mac,ccdNew)) - { - LogEvent(SkyscraperContextEvent.TimContentionControl, String.Format("for participant {0}", mac.ToString())); - } - } - - public void OnCorrectionControl(PhysicalAddress mac, _0xac_CorrectionControlDescriptor descriptor) - { - if (!DataStorage.TestForTim(mac)) - { - LogEvent(SkyscraperContextEvent.Tim, String.Format("for participant {0}", mac.ToString())); - DataStorage.CreateTim(mac); - } - if (DataStorage.CorrectionControlTim(mac,descriptor)) - { - LogEvent(SkyscraperContextEvent.TimCorrectionControl, String.Format("for participant {0}", mac.ToString())); - } - } - - private List networkLayerInfos; - public void OnNetworkLayerInfo(PhysicalAddress mac, _0xa0_NetworkLayerInfoDescriptor nlid) - { - if (currentTimeForTim == null) - return; - if (!DataStorage.TestForTim(mac)) - { - LogEvent(SkyscraperContextEvent.Tim, String.Format("for participant {0}", mac.ToString())); - DataStorage.CreateTim(mac); - } - if (DataStorage.NetworkLayerInfoTim(mac,nlid,currentTimeForTim.Value)) - { - if (networkLayerInfos == null) - networkLayerInfos = new List(); - if (!networkLayerInfos.Contains(mac)) - { - LogEvent(SkyscraperContextEvent.TimNetworkLayerInfo, String.Format("for participant {0}", mac.ToString())); - networkLayerInfos.Add(mac); - } - } - } - - void InteractionChannelHandler.OnTransmissionModeSupport(ushort interactiveNetworkId, Tmst tmst) - { - byte[] knownTmst = DataStorage.GetTmst(interactiveNetworkId); - if (knownTmst == null) - { - LogEvent(SkyscraperContextEvent.TransmissionModeSupport, String.Format("Network ID = {0}, Modes = {1}", interactiveNetworkId, BitConverter.ToString(tmst.Modes))); - DataStorage.InsertTmst(interactiveNetworkId, tmst.Modes); - } - else if (Array.Equals(knownTmst,tmst.Modes)) - { - LogEvent(SkyscraperContextEvent.TransmissionModeUpdate,String.Format("Network ID = {0}, Old Modes = {2}, New Modes = {1}", interactiveNetworkId, BitConverter.ToString(tmst.Modes), BitConverter.ToString(knownTmst))); - DataStorage.UpdateTmst(interactiveNetworkId, tmst.Modes); - } - } - - public int GetRmtTransmissionStandard(ushort networkId) - { - return DataStorage.GetRmtTransmissionStandard(networkId); - } - - public void AutodetectionRuleOut(int pid, Contestant contestant, ProgramContext programContext) - { - //LogEvent(SkyscraperContextEvent.StreamTypeAutodetection, String.Format("PID 0x{0:X4} probably isn't a {1}", pid, contestant.Tag)); - } - - void SgtEventHandler.AnnounceSgtList(SgtList list) - { - if (!DataStorage.TestForSgtList(list)) - { - LogEvent(SkyscraperContextEvent.SgtList, String.Format("List #{0} ({1})", list.ServiceListId, list.GetName())); - DataStorage.InsertSgtList(list); - } - } - - void SgtEventHandler.OnSgtError(SgtError invalidTableId) - { - throw new NotImplementedException(); - } - - void SgtEventHandler.OnSgtService(SgtService child) - { - if (!DataStorage.TestForSgtService(child)) - { - LogEvent(SkyscraperContextEvent.SgtService, String.Format("LCN #{0} in List #{1} ({2})", child.Lcn, child.ServiceListId, child.GetName())); - DataStorage.InsertSgtService(child); - } - } - - public void ProcessVirtualFilesystem(IFilesystem vfs, ProgramMappingStream programMappingStream) - { - yo3explorerToSkyscraperContextBridge context = new yo3explorerToSkyscraperContextBridge(); - context.DataStorage = DataStorage; - if (!currentTime.HasValue) - return; - context.CurrentTime = currentTime.Value; - context.Source = ServiceListEntryPointSource.TransportStream; - context.OriginalNetworkId = CurrentNetworkId; - context.TransportStreamId = CurrentTransportStreamId; - context.PID = programMappingStream.ElementaryPid; - - yo3explorerState state = yo3explorerState.GetInstance(); - - PluginManager pluginManager = PluginManager.GetInstance(); - IReadOnlyList processors = pluginManager.GetFilesystemProcessors(); - - foreach(FilesystemProcessorPlugin processor in processors) - { - processor.ProcessFilesystem(vfs, context, state); - } - } - - public void FluteFileArrival(NipActualCarrierInformation carrier, FluteListener listener) - { - Stream stream = listener.ToStream(); - bool isMime = DvbNipUtilities.IsMime(stream); - if (isMime) - { - MimeMessage message = MimeMessage.Load(stream); - foreach (MimeEntity entity in message.BodyParts) - { - MimePart bodyPart = entity as MimePart; - if (bodyPart.ContentLocation == null) - continue; - - FluteListenerMime fluteListener = new FluteListenerMime(listener.DestinationAddress, listener.DestinationPort, listener.DestinationTsi, listener.DestinationToi); - fluteListener.FileAssociation = new FileType(); - fluteListener.FileAssociation.ContentLocation = bodyPart.ContentLocation.ToString(); - fluteListener.FileAssociation.ContentType = bodyPart.ContentType.MimeType; - fluteListener.FileAssociation.ContentEncoding = null; - fluteListener.WrappedStream = new MemoryStream(); - bodyPart.Content.DecodeTo(fluteListener.WrappedStream); - fluteListener.FileAssociation.ContentLength = (ulong)fluteListener.WrappedStream.Position; - fluteListener.FileAssociation.TransferLength = (ulong)fluteListener.WrappedStream.Position; - fluteListener.FileAssociation.TransferLengthSpecified = true; - fluteListener.WrappedStream.Position = 0; - - FluteFileArrival(carrier, fluteListener); - } - return; - } - - string extension = Path.GetExtension(listener.FileAssociation.ContentLocation).ToLowerInvariant(); - if (!DvbNipUtilities.IsContinuousFileType(extension)) - LogEvent(SkyscraperContextEvent.FluteFileArrival, listener.FileAssociation.ContentLocation); - else - { - IPEndPoint ep = new IPEndPoint(listener.DestinationAddress, listener.DestinationPort); - if (!knownNipSegments.ContainsKey(ep)) - knownNipSegments[ep] = new List(); - knownNipSegments[ep].Add(listener.FileAssociation.ContentLocation); - } - - if (extension.Equals(".m4s")) - { - listener = DvbNipUtilities.PatchMpegDashSegment(listener); - } - - ObjectStorage.DvbNipFileArrival(carrier, listener); - } - - public void OnMulticastGatewayConfiguration(NipActualCarrierInformation carrier, MulticastGatewayConfigurationType multicastGatewayConfiguration) - { - if (multicastGatewayConfiguration.MulticastSession != null) - { - foreach (MulticastSessionType multicastSession in multicastGatewayConfiguration.MulticastSession) - { - if (!DataStorage.DvbNipTestForMulticastSession(multicastSession)) - { - LogEvent(SkyscraperContextEvent.DvbNipMulticastSession, multicastSession.serviceIdentifier); - DataStorage.DvbNipInsertMulticastSession(multicastSession); - } - } - } - - if (multicastGatewayConfiguration.MulticastGatewayConfigurationTransportSession != null) - { - foreach (MulticastGatewayConfigurationTransportSessionType multicastGatewayConfigurationTransportSession in multicastGatewayConfiguration.MulticastGatewayConfigurationTransportSession) - { - if (multicastGatewayConfigurationTransportSession.EndpointAddress == null) - continue; - - MulticastEndpointAddressType endpointAddress = multicastGatewayConfigurationTransportSession.EndpointAddress[0]; - if (!DataStorage.DvbNipTestForMulticastGatewayConfigurationTransportSession(carrier, endpointAddress)) - { - string name = String.Format("{0} -> {1}:{2}, TSI = {3}", endpointAddress.NetworkSourceAddress, - endpointAddress.NetworkDestinationGroupAddress, endpointAddress.TransportDestinationPort, - endpointAddress.MediaTransportSessionIdentifier); - LogEvent(SkyscraperContextEvent.DvbNipMulticastGatewayConfigurationTransportSession, name); - DataStorage.DvbNipInsertMulticastGatewayConfigurationTransportSession(carrier, endpointAddress); - } - } - } - - if (multicastGatewayConfiguration.MulticastGatewaySessionReporting != null) - { - throw new NotImplementedException(nameof(multicastGatewayConfiguration.MulticastGatewaySessionReporting)); - } - } - - public void OnNipCarrierDetected(NipActualCarrierInformation currentCarrierInformation) - { - LogEvent(SkyscraperContextEvent.NipCarrierDetected, String.Format("{0}", currentCarrierInformation.NipStreamProviderName)); - if (!DataStorage.DvbNipTestForCarrier(currentCarrierInformation)) - { - DataStorage.DvbNipInsertCarrier(currentCarrierInformation); - } - } - - public bool IsFileNeeded(string announcedFileContentLocation) - { - if (announcedFileContentLocation.StartsWith("urn:dvb")) - return true; - - return !ObjectStorage.DvbNipTestForFile(announcedFileContentLocation); - } - - public void OnPrivateDataSignallingManifest(NipActualCarrierInformation currentCarrierInformation, PrivateDataSignallingManifestType privateDataSignallingManifest) - { - foreach (PrivateDataProviderType privateDataProvider in privateDataSignallingManifest.PrivateDataProvider) - { - privateDataProvider.privateDataProviderID.FlipEndian(); - uint privateDataSpecifier = BitConverter.ToUInt32(privateDataProvider.privateDataProviderID); - List privateDataSessions = privateDataProvider.PrivateDataSession.SelectMany(x => x.TagRef).ToList(); - bool added = DataStorage.DvbNipPrivateDataSpecifier(currentCarrierInformation, privateDataSignallingManifest.VersionUpdate, privateDataSpecifier, privateDataSessions); - if (added) - { - LogEvent(SkyscraperContextEvent.NipPrivateDataSpecifier, String.Format("{0} -> {1}", currentCarrierInformation.NipStreamProviderName, privateDataSpecifier)); - } - } - } - - public void OnServiceListEntryPoints(NipActualCarrierInformation currentCarrierInformation, ServiceListEntryPoints serviceListEntryPoints, DateTime dvbNipTime, DvbNipServiceListNotifier serviceListNotifier) - { - long sourceHash = DvbIUtils.GetSourceHash(ServiceListEntryPointSource.DvbNip, currentCarrierInformation.NipNetworkId, currentCarrierInformation.NipCarrierId, currentCarrierInformation.NipLinkId); - serviceListNotifier.SetSourceHash(sourceHash); - DvbIDataStorage dataStorage = DataStorage; - - if (dataStorage.TestForDvbiServiceListEntryPoints(sourceHash)) - { - DateTime lastChecked = dataStorage.GetLastDvbiServiceListEntryPointUpdateDate(sourceHash); - TimeSpan sinceLastChecked = dvbNipTime - lastChecked; - if (sinceLastChecked.TotalDays < 1.0) - return; - } - else - { - logger.InfoFormat("New DVB-I Service List Entry Point: {0}", currentCarrierInformation.NipStreamProviderName); - dataStorage.InsertDvbiServiceListEntryPoint(sourceHash); - } - - IEnumerable enumerable = DvbIUtils.FlattenServiceListEntryPoints(serviceListEntryPoints); - foreach (DvbiServiceList serviceList in enumerable) - { - DateTime serviceListLastChecked; - if (dataStorage.TestForDvbiServiceList(serviceList.Id)) - { - serviceListLastChecked = dataStorage.GetDvbiServiceListLastUpdateDate(serviceList.Id); - } - else - { - logger.InfoFormat("New DVB-I Service List: {0}", serviceList.Name); - dataStorage.InsertDvbiServiceList(serviceList); - dataStorage.AddDvbiServiceListToServiceListEntryPoint(serviceList, sourceHash); - serviceListLastChecked = new DateTime(1970, 1, 1); - } - - TimeSpan sinceLastServiceListCheck = dvbNipTime - serviceListLastChecked; - if (sinceLastServiceListCheck.TotalDays < 1.0) - continue; - - serviceListNotifier.AddServiceListUrl(serviceList.URI, serviceList.Id); - /*if (vfs.FileExists(serviceList.URI)) - { - byte[] serviceListBytes = vfs.GetFile(serviceList.URI); - ServiceListType serviceListData = DvbIUtils.UnpackServiceList(serviceListBytes); - HandleServiceList(serviceListData, dataStorage, serviceList.Id); - dataStorage.UpdateDvbiServiceListLastCheckedDate(serviceList.Id, context.CurrentTime); - }*/ - } - - dataStorage.UpdateDvbiServiceListEntryPointUpdateDate(sourceHash, dvbNipTime); - } - - public void OnServiceList(NipActualCarrierInformation currentCarrierInformation, string serviceListId, - ServiceListType serviceList) - { - List services = DvbIUtils.FlattenServiceList(serviceList).ToList(); - DvbIDataStorage dataStorage = DataStorage; - foreach (DvbIService service in services) - { - if (dataStorage.TestForDvbiService(service.Id)) - { - int versionInDb = dataStorage.GetDvbiServiceVersion(service.Id); - if (service.Version > versionInDb) - { - dataStorage.UpdateDvbiService(service); - } - } - else - { - logger.InfoFormat("New DVB-I Service: {0}", service.ServiceName); - dataStorage.InsertDvbiService(service); - dataStorage.AddDvbiServiceToServiceList(service.Id, serviceListId); - } - } - } - - public void OnTimeOffsetFile(NipActualCarrierInformation currentCarrierInformation, TimeOffsetFileType timeOffsetFile) - { - if (timeOffsetFile.time_of_change != DateTime.MinValue) - { - throw new NotImplementedException(); - } - } - - public void OnNetworkInformationFile(NipActualCarrierInformation currentCarrierInformation, NetworkInformationFileType networkInformationFile) - { - List broadcastNetworks = new List(); - if (networkInformationFile.ActualBroadcastNetwork != null) - broadcastNetworks.Add(networkInformationFile.ActualBroadcastNetwork); - if (networkInformationFile.OtherBroadcastNetwork != null) - broadcastNetworks.AddRange(networkInformationFile.OtherBroadcastNetwork); - - foreach (BroadcastNetworkType network in broadcastNetworks) - { - if (!DataStorage.DvbNipTestForNetwork(network)) - { - LogEvent(SkyscraperContextEvent.DvbNipNetwork, network.NetworkName); - DataStorage.DvbNipInsertNetwork(network); - } - } - } - - public void OnServiceInformationFile(NipActualCarrierInformation currentCarrierInformation, ServiceInformationFileType serviceInformationFile) - { - foreach (BroadcastMediaStreamType broadcastMediaStreamType in serviceInformationFile.BroadcastMediaStream) - { - if (!DataStorage.DvbNipTestForService(broadcastMediaStreamType)) - { - string id = String.Format("{0},{1},{2},{3}", broadcastMediaStreamType.NIPNetworkID, - broadcastMediaStreamType.NIPCarrierID, broadcastMediaStreamType.NIPLinkID, - broadcastMediaStreamType.NIPServiceID); - LogEvent(SkyscraperContextEvent.DvbNipService, id); - DataStorage.DvbNipInsertService(broadcastMediaStreamType); - } - } - } - - private Dictionary> knownNipSegments; - private HashSet knownUrls; - public void FluteFileAnnouncement(IPAddress ip, ushort port, FDTInstanceType flute) - { - if (knownUrls == null) - { - knownUrls = new HashSet(); - knownNipSegments = new Dictionary>(); - } - - string url = flute.File[0].ContentLocation; - if (knownUrls.Contains(url)) - return; - - LogEvent(SkyscraperContextEvent.FluteFileAnnouncement, String.Format("{0}:{1} -> {2}", ip.ToString(), port, url)); - knownUrls.Add(url); - - IPEndPoint ep = new IPEndPoint(ip, port); - if (!knownNipSegments.ContainsKey(ep)) - knownNipSegments[ep] = new List(); - knownNipSegments[ep].Add(url); - } - - public void FluteFileDownloadProgress(NipActualCarrierInformation currentCarrierInformation, ulong destinationTsi, ulong destinationToi, double progress, FileType filetype) - { - if (filetype != null) - { - if (!filetype.ContentLocation.Equals("urn:dvb:metadata:cs:NativeIPMulticastTransportObjectTypeCS:2023:bootstrap")) - { - string extension = Path.GetExtension(filetype.ContentLocation).ToLowerInvariant(); - if (!DvbNipUtilities.IsContinuousFileType(extension)) - { - LogEvent(SkyscraperContextEvent.FluteFileProgress, - String.Format("Filename={0}, {1}%", filetype.ContentLocation, progress)); - } - } - } - } - - private List _pluginContexts; - - public List PluginContext - { - get - { - if (_pluginContexts == null) - _pluginContexts = new List(); - - return _pluginContexts; - } - } - - public void OnPluginEvent() - { - lastEventTimestamp = DateTime.Now; - } - - public void OnEthernetFrame(int pid, PhysicalAddress destination, PhysicalAddress source, ushort etherType, byte[] contents) - { - if (Array.TrueForAll(contents, x => x == 0)) - return; - if (etherType <= 1500) - { - OnLlcFrame(etherType, contents); - return; - } - switch (etherType) - { - case 0x0800: - OnIpDatagram(pid, contents); - return; - case 0x22e3: - //This is related to G.9961, a PowerLine standard specified by ITU-T T-REC-G.9961 - //I don't think we need this. - return; - case 0x2f00: - //This is something proprietary. - //Quite possibly related to Extron hardware? - return; - case 0x0806: - //This is an ARP Frame. We don't need it. - return; - case 0x8137: - //This is an IPX Frame. We don't need it. - return; - case 0x86dd: - OnIpDatagram(pid, contents); - return; - case 0x88e1: - //This is related to FRITZ!Powerline. - //Probably very proprietary and undocumented, so I guess we'll discard it. - return; - case 0x890d: - //IEEE Std 802.11 - Fast Roaming Remote Request (802.11r) - //These seem to happen when one moves from one Wi-Fi Access Point to another. We probably don't need that one. - return; - case 0x8912: - //Related to mediaxtream, see https://de.wikipedia.org/wiki/Mediaxtream - //Probably not very interesting. - return; - case 0x9001: - //3Com(Bridge) XNS Sys Mgmt - //Can't say anything about these. I don't have any 3Com equipment. - return; - case 0x94ce: - //Something proprietary. No idea. - return; - case 0xb69d: - //Something proprietary. No idea. - return; - case 0xf67f: - if (contents[20] == 0xaa && contents[21] == 0xaa && contents[22] == 0x03 && contents[23] == 0x00 && contents[24] == 0x00 && contents[25] == 0x00) - { - (contents[26], contents[27]) = (contents[27], contents[26]); - ushort newEtherType = BitConverter.ToUInt16(contents, 26); - byte[] newPacket = new byte[contents.Length - 28]; - Array.Copy(contents, 28, newPacket, 0, newPacket.Length); - OnEthernetFrame(pid, destination, source, newEtherType, newPacket); - } - return; - case 0x94ad: - //Something proprietary. No idea. - return; - case 0x4957: - //Something proprietary. No idea. - return; - case 0x3e30: - //Something proprietary. No idea. - return; - case 0x88cc: - //Link Layer Discovery Protocol - LldpFrame lldpFrame = new LldpFrame(contents); - OnLldpFrame(lldpFrame); - return; - case 0x9417: - case 0xf95c: - //Unknown proprietary. - return; - default: - throw new NotImplementedException(String.Format("EtherType: 0x{0:X4}", etherType)); - } - } - - public void OnUleError(int pid, int errorNo) - { - throw new NotImplementedException(); - } - - public void OnLlcFrame(ushort etherType, byte[] contents) - { - MemoryStream llcStream = new MemoryStream(contents, true); - byte dsap = llcStream.ReadUInt8(); - byte ssap = llcStream.ReadUInt8(); - if (dsap == 0x00 || ssap == 0x00) - { - //This is a NULL frame. It can be discarded either way. - return; - } - if (dsap == 0x42 || ssap == 0x42) - { - //This is a Spanning Tree Frame. We probably don't need it. - return; - } - if (dsap == 0xe0 || ssap == 0xe0) - { - //This is a Novell Netware Frame. We don't need to bother with it. - return; - } - - if (dsap == 0xaa || ssap == 0xaa) - { - byte snapType = llcStream.ReadUInt8(); - if (snapType == 0x03) - { - byte[] oui = llcStream.ReadBytes(3); - ushort snapProtocolId = llcStream.ReadUInt16BE(); - if (snapProtocolId == 0x809b) - { - //This is an AppleTalk Frame. We probably don't need it. - return; - } - else if (snapProtocolId == 0x8137) - { - //This is an IPX Frame. We probably don't need it. - return; - } - else if (snapProtocolId == 0x2000) - { - //This is from Cisco's Discovery Protocol (CDP). Probably not interesting. - return; - } - else - { - throw new NotImplementedException(String.Format("SNAP Frame, OUI = {0:X2}-{1:X2}-{2:X2}, Protocol ID = 0x{3:X4}", oui[0], oui[1], oui[2], snapProtocolId)); - } - } - else - { - throw new NotImplementedException(String.Format("LLC/SNAP Type 0x{0:X2}", snapType)); - } - } - - if (dsap == 0xff || ssap == 0xff) - { - ushort llcLength = llcStream.ReadUInt16BE(); - if (llcLength == etherType) - { - //TEST or XID PDU, likely unneeded. - return; - } - else if (llcLength == 40) - { - //TEST or XID PDU, likely unneeded. - return; - } - else - { - throw new NotImplementedException("LLC/SNAP (2)"); - } - } - - if (dsap == 0x09 && ssap == 0x01) - { - //Likely an LLC management packet (TEST or XID) - return; - } - throw new NotImplementedException("LLC/SNAP"); - } - - public void OnOtvSsuError(int pid, OtvSsuError offsetOutOfRange) - { - DvbContext.RegisterPacketProcessor(pid, new PacketDiscarder()); - } - - public void OnOtvSsuFileAnnouncement(int pid, ushort tableIdExtension, uint fileId, uint unknown1, uint length) - { - LogEvent(SkyscraperContextEvent.OtvSsuFileDetected, String.Format("TID = {0}, FID = {1:X8}, Length = {2}", tableIdExtension, fileId, length)); - } - - public void OnOtvSsuBlock(int pid, ushort tableIdExtension, uint fileId, uint unknown1, uint length) - { - } - - public void OnOtvSsuComplete(int sourcePid, Stream getStream, ushort tableIdExtension, uint fileId, uint unknown1, - uint length) - { - LogEvent(SkyscraperContextEvent.OtvSsuComplete, String.Format("TID = {0}, FID = {1:X8}, Length = {2}", tableIdExtension, fileId, length)); - ObjectStorage.OnOtvSsuComplete(CurrentNetworkId, CurrentTransportStreamId, sourcePid, getStream, tableIdExtension, fileId, unknown1, length); - } - - public bool OnOtvCheckFileAlreadyKnown(int sourcePid, ushort tableIdExtension, uint fileId, uint unknown1, uint length) - { - return ObjectStorage.OtvSsuTestFile(CurrentNetworkId, CurrentTransportStreamId, sourcePid, tableIdExtension, fileId, unknown1, length); - } - - public void OnNdsSsuError(int pid, NdsSsuError error) - { - } - - public void OnNdsSsuFileAnnouncement(int pid, ushort tableIdExtension) - { - LogEvent(SkyscraperContextEvent.NdsSsuFileAnnounced, String.Format("PID = 0x{1:X4}, Table ID Extension = {0}", tableIdExtension, pid)); - } - - public void OnNdsSsuFileComplete(int pid, ushort tableIdExtension, NdsSsuDataMap dataMap) - { - ObjectStorage.OnNdsSsuComplete(CurrentNetworkId, CurrentTransportStreamId, pid, tableIdExtension, dataMap); - } - - public void OnNdsSsuProgress(int pid, ushort tableIdExtension, int blocksDone, int blocksTotal, bool theresMore) - { - LogEvent(SkyscraperContextEvent.NdsSsuProgress, String.Format("PID 0x{0:X4}, File ID {1}, Blocks: {2}/{3}{4}", pid, tableIdExtension, blocksDone, blocksTotal, theresMore ? "+" : "")); - } - - public bool TestNdsSsuFileExists(int pid, ushort tableIdExtension) - { - return ObjectStorage.NdsSsuTestFile(CurrentNetworkId, CurrentTransportStreamId, pid, tableIdExtension); - } - - public void OnReturnTransmissionMOdes(PhysicalAddress macAddress, _0xb2_ReturnTransmissionModesDescriptor descriptor) - { - //TODO: Implement this. - } - - public void OnConnectionControl(PhysicalAddress macAddress, _0xaf_ConnectionControlDescriptor descriptor) - { - //TODO: Implement this. - } - - - private HashSet lldpFrames; - public void OnLldpFrame(LldpFrame frame) - { - if (lldpFrames == null) - lldpFrames = new HashSet(); - - if (lldpFrames.Add(frame)) - { - LogEvent(SkyscraperContextEvent.EthernetLinkLayerDiscovery, frame.ToString()); - } - } - - void T2MIEventHandler.OnFramingAndTimingInformation(int relatedPid, _0xF0_FramingTimingInformation fti) - { - logger.WarnFormat("Found T2MI F&TI Information on PID 0x{0:X4}. This isn't supported yet. It would be great if you could share a sample of this stream, so this can be implemented.", relatedPid); + } + } + } + + public void MakeUpComponentTags(ProgramMapping target) + { + bool[] usedTags = new bool[byte.MaxValue]; + foreach (ProgramMappingStream programMappingStream in target.Streams) + { + if (programMappingStream.ComponentTag.HasValue) + { + usedTags[programMappingStream.ComponentTag.Value] = true; + } + } + + usedTags[0] = true; + + foreach (ProgramMappingStream mappingStream in target.Streams) + { + if (!mappingStream.ComponentTag.HasValue) + { + for (byte b = 0; b < Byte.MaxValue; b++) + { + if (!usedTags[b]) + { + usedTags[b] = true; + mappingStream.ComponentTag = b; + break; + } + } + } + } + } + + private void TryRegisterSystemSoftwareUpdateInfo(SystemSoftwareUpdateInfo info, + ProgramMappingStream mappingStream, ProgramMapping mapping) + { + if (DvbContext.IsPidProcessorPresent(mappingStream.ElementaryPid)) + return; + + //TODO: Scrape this once we have an SSU Event handler. + foreach (SystemSoftwareUpdateInfo.Oui infoOui in info.Ouis) + { + switch (infoOui.UpdateType) + { + //Found on ETSI TS 102 006, Page 13 + case 0: //proprietary update solution + if (ALLOW_STREAM_TYPE_AUTODETECTION) + { + StreamTypeAutodetection sta = new StreamTypeAutodetection(mappingStream.ElementaryPid, this); + sta.ProgramContext.Stream = mappingStream; + sta.ProgramContext.Program = mapping; + DvbContext.RegisterPacketProcessor(mappingStream.ElementaryPid, sta); + } + else + DvbContext.RegisterPacketProcessor(mappingStream.ElementaryPid, new PacketDiscarder()); + break; + case 1: //standard update carousel (i.e. without notification table) via broadcast + if (!mappingStream.ComponentTag.HasValue) + { + MakeUpComponentTags(mapping); + } + + DvbContext.RegisterPacketProcessor(mappingStream.ElementaryPid, new PsiDecoder(mappingStream.ElementaryPid, new DataCarouselDecoder(mappingStream, mapping, DataCarouselIntention.SoftwareUpdate, this))); + break; + case 2: //system software update carousel with notification table (UNT) both available via broadcast + case 3: //system software update signalled via broadcast UNT, update available from the return channel + case 4: //system software update signalled via broadcast UNT, update available from the internet + DvbContext.RegisterPacketProcessor(mappingStream.ElementaryPid, new PsiDecoder(mappingStream.ElementaryPid, new UntDecoder(this, mapping))); + break; + case 5: + case 6: + case 7: + case 8: + case 9: + case 10: + case 11: + case 12: + case 13: + case 14: + case 15: + //reserved for future use as of 2015-06 + //ignore it. + break; + default: + throw new NotImplementedException(String.Format("{0} = {1:X2}", nameof(infoOui.UpdateType), + infoOui.UpdateType)); + } + } + } + + private StreamType GuessStreamType(ProgramMappingStream stream, int totalStreams, + uint? parentRegistrationFormatIdentifier, bool allPrivateStreams) + { + if (stream.StreamType == PmtStreamType.H262) + return StreamType.Video; + if (stream.AvcStillPresent.HasValue) + return StreamType.Video; + if (stream.AudioType.HasValue) + return StreamType.Audio; + if (stream.StreamType == PmtStreamType.AvcVideoStream) + return StreamType.Video; + if (stream.StreamType == PmtStreamType.Iso11172Audio) + return StreamType.Audio; + if (stream.StreamType == PmtStreamType.Iso13818_3Audio) + return StreamType.Audio; + if (stream.StreamType == PmtStreamType.Iso13818_7AudioADTS) + return StreamType.Audio; + if (stream.StreamType == PmtStreamType.HevcVideoStream) + return StreamType.Video; + if (stream.StreamType == PmtStreamType.Iso13818_1PesPackets && stream.Ac4ChannelMode.HasValue) + return StreamType.Audio; //AC-4 Audio + if (stream.StreamType == PmtStreamType.Iso13818_1PesPackets && stream.BSID.HasValue) + return StreamType.Audio; + if (stream.StreamType == PmtStreamType.Iso14496_3Audio && stream.AacProfileAndLevel.HasValue) + return StreamType.Audio; + if ((int)stream.StreamType == 0x81 && stream.ComponentType.HasValue) + return StreamType.Audio; //AC-3 Audio, but weird. + if (stream.Teletexts != null) + { + for (int i = 0; i < stream.Teletexts.Length; i++) + { + if (stream.Teletexts[i] != null) + { + return StreamType.Teletext; + } + } + } + + if (stream.Applications != null) + { + return StreamType.Application; + } + + if (stream.DataBroadcastId == 0x0123) + { + return StreamType.HbbTv; + } + + if (stream.DataBroadcastId == 0x000a) + { + return StreamType.SystemSoftwareUpdate; + } + + if (!ALLOW_STREAM_TYPE_AUTODETECTION) + { + if ((int)stream.StreamType == 0xc0 || (int)stream.StreamType == 0xc1) + { + if (stream.PrivateDataSpecifier.HasValue) + throw new NotImplementedException(String.Format("{0}", nameof(stream.PrivateDataSpecifier))); + else + return StreamType.Ignorable; + } + } + + if (stream.StreamType == PmtStreamType.Iso13818_1PesPackets && stream.Subtitlings != null && + stream.Subtitlings.Length > 0) + { + return StreamType.Subtitles; + } + + if (stream.DataBroadcastId == 0xf0) + { + return StreamType.DvbMhp; + } + + if (!ALLOW_STREAM_TYPE_AUTODETECTION) + { + if (!stream.DataBroadcastId.HasValue && stream.StreamType == PmtStreamType.Iso13818_1PrivateSections && + totalStreams == 1) + { + return StreamType.Ignorable; + } + } + + if (stream.FormatIdentifier.HasValue && stream.FormatIdentifier == 0x43554549 && + (int)stream.StreamType == 0x86) + { + return StreamType.Scte35; + } + + if ((int)stream.StreamType == 0x86 && parentRegistrationFormatIdentifier.HasValue && + parentRegistrationFormatIdentifier.Value == 0x43554549) + { + return StreamType.Scte35; + } + + if (stream.DataBroadcastId == 0x0007) //According to dvbservices.com, this is an Object Carousel + { + return StreamType.DvbMhp; + } + + if (stream.StreamType == PmtStreamType.Iso13818_1PesPackets && stream.VbiData != null) + { + return StreamType.Teletext; + } + + if ((byte)stream.StreamType == 0x89 && stream.AncillaryDataDescriptor != null && + stream.AncillaryDataDescriptor.RdsOnly) + return StreamType.RDS; + + if (!ALLOW_STREAM_TYPE_AUTODETECTION) + { + if (stream.StreamType == PmtStreamType.Iso13818_6TypeB && !stream.DataBroadcastId.HasValue) + return StreamType.Ignorable; + + if (stream.StreamType == PmtStreamType.Iso13818_6TypeC && !stream.DataBroadcastId.HasValue) + return StreamType.Ignorable; + + if (stream.DataBroadcastId.HasValue && stream.DataBroadcastId.Value == 0x0140) + { + //Proprietary by CANAL+, does not seem to be documented. + return StreamType.Ignorable; + } + } + + if (stream.DataBroadcastId.HasValue && stream.DataBroadcastId.Value == 0x0005 /*&& stream.StreamType == PmtStreamType.Iso13818_6TypeD*/) + { + return StreamType.MultiprotocolEncapsulation; + } + + if (!ALLOW_STREAM_TYPE_AUTODETECTION) + { + if (allPrivateStreams && !stream.DataBroadcastId.HasValue && !stream.PrivateDataSpecifier.HasValue && + !parentRegistrationFormatIdentifier.HasValue) + return StreamType.Ignorable; + + if (stream.DataBroadcastId == 0x010b) + { + //NDS France Technologies system software download + //sadly undocumented. + return StreamType.Ignorable; + } + + if (stream.StreamType == PmtStreamType.Iso13818_1PesPackets && totalStreams == 1 && + !stream.DataBroadcastId.HasValue && !stream.PrivateDataSpecifier.HasValue) + { + //A single private stream. We have no clue how to deal with it, at all. + return StreamType.Ignorable; + } + } + + if (stream.DataBroadcastId == 0x0106) + { + //Defined in ETSI ES 202 184 V2.4.1 + return StreamType.Mheg5; + } + + if (stream.DataBroadcastId == 0x000b) + { + return StreamType.IpMacNotification; + } + + if (stream.RelatedContentDescriptorPresent.HasValue) + { + if (stream.RelatedContentDescriptorPresent.Value && stream.StreamType == PmtStreamType.Iso13818_1PrivateSections) + { + return StreamType.RelatedContentTable; + } + } + + if (stream.NumT2MiStreams.HasValue && stream.StreamType == PmtStreamType.Iso13818_1PesPackets) + { + return StreamType.T2Mi; + } + + if (stream.UnknownUserDefines != null) + { + if (stream.UnknownUserDefines.Count == 1) + { + if (stream.UnknownUserDefines[0].DescriptorTag == 0xa7) + { + bool interactionChannelPossible = stream.UnknownUserDefines[0].Data.All(x => x == 0x40 || x == 0x41 || x == 0x4d || x == 0x70 || x >= 0xA0); + if (interactionChannelPossible) + { + + return StreamType.InteractionChannelForSatellite; + } + } + } + } + + + if (stream.MetadataApplicationFormat == 0xffff && stream.MetadataApplicationFormatIdentifier == 0x49443320 && stream.MetadataFormat == 0xff && stream.MetadataFormatIdentifier == 0x49443320) + { + return StreamType.Id3; + } + + if (stream.StreamType == PmtStreamType.Iso13818_1PesPackets && stream.DataBroadcastId == 0x000e && stream.DataBroadcastSelector != null) + { + if (stream.DataBroadcastSelector[0] == 0x01) + { + return StreamType.SisFramingAndTiming; + } + if (stream.DataBroadcastSelector[0] == 0x02) + { + return StreamType.SisDaughterSiteAdapterConfiguration; + } + if (stream.DataBroadcastSelector[0] == 0x03) + { + return StreamType.SisPsiTables; + } + } + + if (ALLOW_STREAM_TYPE_AUTODETECTION) + { + //Abandon all hope, ye who enter here... + return StreamType.TryAutodetect; + } + + return StreamType.Unknown; + } + + private int onidHits, onidMisses; + + public void SetNetworkId(ushort networkId) + { + SetNetworkId(networkId, false); + } + + public void SetNetworkId(ushort networkId, bool forceOverwrite = false) + { + if (CurrentNetworkId == null) + { + CurrentNetworkId = networkId; + return; + } + + if (CurrentNetworkId != networkId) + { + onidMisses++; + if (forceOverwrite) + { + CurrentNetworkId = networkId; + } + } + else + onidHits++; + } + + private EitEvent[] runningEvents; + public void OnEitEvent(EitEvent eitEvent) + { + if (DataStorage.StoreEitEvent(eitEvent)) + LogEvent(SkyscraperContextEvent.EitEvent, eitEvent.EventName); + + UiJunction?.NotifyEvent(eitEvent); + + if (eitEvent.RunningStatus == RunningStatus.Running) + { + if (runningEvents == null) + runningEvents = new EitEvent[UInt16.MaxValue]; + runningEvents[eitEvent.ServiceId] = eitEvent; + } + } + + public void OnNitTransportStream(ushort networkId, NitTransportStream transportStream) + { + UiJunction?.NotifyNit(transportStream); + + string name; + switch (transportStream.DeliveryMethod) + { + case NitTransportStream.TransportMedium.DVB_S: + case NitTransportStream.TransportMedium.DVB_S2: + name = String.Format("{3}°{4}/{0}/{1}/{2}", transportStream.Frequency / 100, + transportStream.Polarization.ToString().Substring(0, 1), + (float)transportStream.SymbolRate / 10.0f, transportStream.OrbitalPosition, + transportStream.East.Value ? "E" : "W"); + break; + case NitTransportStream.TransportMedium.DVB_T2: + if (transportStream.Frequency != null) + { + throw new NotImplementedException(); + } + if (transportStream.CellInfos == null) + return; + if (transportStream.CellInfos.Count == 0) + return; + name = String.Format("Center Frequency: {0}", transportStream.GetT2Frequency()); + break; + case NitTransportStream.TransportMedium.Unknown: + return; + case NitTransportStream.TransportMedium.DVB_C: + name = String.Format("{0}/{1}/{2}", transportStream.Frequency / 100000, transportStream.SymbolRate, + transportStream.RenderModulation()); + break; + default: + throw new NotImplementedException(transportStream.DeliveryMethod.ToString()); + } + + if (!DataStorage.TestForNitTransportStream(networkId, transportStream)) + { + DataStorage.StoreNitTransportStream(networkId, transportStream); + LogEvent(SkyscraperContextEvent.OnNitTransportStream, name); + return; + } + + if (DataStorage.UpdateNitTransportStream(networkId, transportStream)) + { + LogEvent(SkyscraperContextEvent.OnNitTransportStreamUpdate, name); + return; + } + } + + public void OnNitNetwork(NitNetwork nitNetwork) + { + if (!string.IsNullOrEmpty(nitNetwork.Name)) + { + + } + if (nitNetwork.XaitPid.HasValue && CurrentNetworkId.HasValue) + { + ushort nitNetworkXaitPid = nitNetwork.XaitPid.Value; + if (nitNetwork.NetworkId == CurrentNetworkId.Value) + { + if (!DvbContext.IsPidProcessorPresent(nitNetworkXaitPid)) + { + AitParser aitParser = new AitParser(this, 0x00); + aitParser.Tag = "XAIT"; + DvbContext.RegisterPacketProcessor(nitNetworkXaitPid, + new PsiDecoder(nitNetworkXaitPid, aitParser)); + LogEvent(SkyscraperContextEvent.XaitDetected, String.Format("PID {0}", nitNetworkXaitPid)); + } + } + } + + if (!DataStorage.TestForNitNetwork(nitNetwork)) + { + DataStorage.StoreNitNetwork(nitNetwork); + LogEvent(SkyscraperContextEvent.OnNitNetwork, nitNetwork.Name); + return; + } + + if (DataStorage.UpdateNitNetwork(nitNetwork)) + { + LogEvent(SkyscraperContextEvent.OnNitNetworkUpdate, nitNetwork.Name); + return; + } + } + + + private HashSet _vpsCoordinates; + + public void OnVpsData(int networkId, int transportStreamId, ushort programNumber, VpsDataBlock vpsDataField) + { + //We don't really need VPS data, but we'll use it as another way of making sure we + //got everything. + if (_vpsCoordinates == null) + { + _vpsCoordinates = new HashSet(); + } + + VpsCoordinate vpsCoordinate = new VpsCoordinate(programNumber, vpsDataField.Month, vpsDataField.Day, + vpsDataField.Hour, vpsDataField.Minute); + if (_vpsCoordinates.Add(vpsCoordinate)) + { + LogEvent(SkyscraperContextEvent.VpsData, + String.Format("{0:D2}.{1:D2} {2:D2}:{3:D2} {4}", vpsCoordinate.Day, vpsCoordinate.Month, + vpsCoordinate.Hour, vpsCoordinate.Minute, vpsCoordinate.ProgramNumber)); + } + } + + + private Dictionary _wssDataBlocks; + + public void OnWssData(int networkId, int transportStreamId, ushort programNumber, WssDataBlock wssDataBlock) + { + if (_wssDataBlocks == null) + { + _wssDataBlocks = new Dictionary(); + } + + if (!_wssDataBlocks.ContainsKey(programNumber)) + { + _wssDataBlocks.Add(programNumber, wssDataBlock); + LogEvent(SkyscraperContextEvent.WssData, programNumber.ToString()); + UiJunction?.NotifyWss(programNumber, wssDataBlock); + } + } + + public void OnTeletextPage(int networkId, int transportStreamId, ushort programNumber, + TeletextMagazine magazine) + { + if (!currentTime.HasValue) + return; + + DataStorage.StoreTeletextPage(networkId, transportStreamId, programNumber, magazine, currentTime.Value); + } + + public void OnBatBouquet(BatBouquet batBouquet) + { + UiJunction?.NotifyBat(batBouquet); + if (DataStorage.TestForBatBouquet(batBouquet)) + { + if (DataStorage.UpdateBatBouquet(batBouquet)) + { + LogEvent(SkyscraperContextEvent.BatBouquetUpdate, batBouquet.BouquetName); + } + } + else + { + DataStorage.StoreBatBouquet(batBouquet); + LogEvent(SkyscraperContextEvent.BatBouquet, batBouquet.BouquetName); + } + } + + public void OnBatTransportStream(BatBouquet batBouquet, BatTransportStream child) + { + UiJunction?.NotifyBatTs(batBouquet.BouquetId, child); + string name = String.Format("{0},{1}", batBouquet.BouquetId, child.OriginalNetworkId); + if (DataStorage.TestForBatTransportStream(batBouquet.BouquetId, child)) + { + if (DataStorage.UpdateBatTransportStream(batBouquet.BouquetId, child)) + { + LogEvent(SkyscraperContextEvent.BatTransportStreamUpdate, name); + } + } + else + { + DataStorage.StoreBatTransportStream(batBouquet.BouquetId, child); + LogEvent(SkyscraperContextEvent.BatTransportStream, name); + } + } + + public void OnSdtService(ushort transportStreamId, ushort originalNetworkId, SdtService sdtService) + { + if (DataStorage.TestForSdtService(transportStreamId, originalNetworkId, sdtService)) + { + if (!IsChild) + { + if (DataStorage.UpdateSdtService(transportStreamId, originalNetworkId, sdtService)) + { + LogEvent(SkyscraperContextEvent.OnSdtServiceUpdate, sdtService.ServiceName); + } + } + } + else + { + DataStorage.StoreSdtService(transportStreamId, originalNetworkId, sdtService); + LogEvent(SkyscraperContextEvent.OnSdtService, sdtService.ServiceName); + } + + UiJunction?.NotifySdtService(sdtService); + } + + private DateTime? currentTime; + private DateTime? currentTimeForTim; + + public void SetCurrentTime(DateTime currentTime) + { + if (!this.currentTime.HasValue) + { + this.currentTime = currentTime; + } + currentTimeForTim = currentTime; + } + + public void SetCurrentProgrammeType(int programNumber, PTY.ProgrammeTypeCodes pty) + { + if (!CurrentNetworkId.HasValue) + return; + + if (!CurrentTransportStreamId.HasValue) + return; + + if (DataStorage.UpdateRdsPty(CurrentNetworkId.Value, CurrentTransportStreamId.Value, programNumber, pty)) + { + LogEvent(SkyscraperContextEvent.RdsPty, String.Format("{0} -> {1}", programNumber, pty.ToString())); + } + } + + public void MarkAsRdsTrafficInformationProgramme(int programNumber) + { + if (!CurrentNetworkId.HasValue) + return; + + if (!CurrentTransportStreamId.HasValue) + return; + + if (DataStorage.MarkAsRdsTrafficInformationProgramme(CurrentNetworkId.Value, CurrentTransportStreamId.Value, programNumber)) + { + LogEvent(SkyscraperContextEvent.RdsTrafficInfoDetected, String.Format("{0}", programNumber)); + } + } + + public void OnTotTime(DateTime utcTime, LocalTimeOffsetDescriptor ltod) + { + UiJunction?.NotifyTot(utcTime, ltod); + SetCurrentTime(utcTime); + + if (!CurrentNetworkId.HasValue) + return; + + if (!CurrentTransportStreamId.HasValue) + return; + + if (DataStorage.UpdateTimeOffsetTable(CurrentNetworkId.Value, CurrentTransportStreamId.Value, utcTime, + ltod)) + LogEvent(SkyscraperContextEvent.TotTime, utcTime.ToString()); + } + + public void OnTdtTime(DateTime utcTime) + { + UiJunction?.NotifyTdt(utcTime); + SetCurrentTime(utcTime); + + if (!CurrentNetworkId.HasValue) + return; + + if (!CurrentTransportStreamId.HasValue) + return; + + if (DataStorage.UpdateTimeAndDate(CurrentNetworkId.Value, CurrentTransportStreamId.Value, utcTime)) + LogEvent(SkyscraperContextEvent.TdtTime, utcTime.ToString()); + } + + public void OnAitApplication(AitApplication aitApplication, ushort programNumber) + { + UiJunction?.NotifyAit(aitApplication); + foreach (TransportProtocolDescriptor transportProtocol in aitApplication.TransportProtocols) + { + switch (transportProtocol.ProtocolId) + { + case 0x01: + ObjectCarouselTransportSelector octs = + (ObjectCarouselTransportSelector)transportProtocol.Selector; + DsmCcsToLookFor[programNumber] = octs.ComponentTag; + break; + case 0x03: + //The interwebs! + break; + default: + if (transportProtocol.Selector == null) + continue; + throw new NotImplementedException(String.Format("{0} {1:x2}", + nameof(transportProtocol.ProtocolId), transportProtocol.ProtocolId)); + } + } + + if (!DataStorage.TestForAitApplication(aitApplication.ApplicationIdentifier)) + { + DataStorage.StoreAitApplication(aitApplication); + LogEvent(SkyscraperContextEvent.AitApplication, aitApplication.TryGetName()); + } + } + + public void NotifyFileArrival(VfsFile vfsFile) + { + UiJunction?.DsmCcVfs(vfsFile); + + if (!CurrentTransportStreamId.HasValue) + return; + if (!CurrentNetworkId.HasValue) + return; + + if (ObjectStorage.ObjectCarouselFileArrival(vfsFile, CurrentTransportStreamId.Value, CurrentNetworkId.Value)) + { + LogEvent(SkyscraperContextEvent.FileArrival, String.Format("PID {0:X4}, Path {1}", vfsFile.SourcePid, vfsFile.ToString())); + } + + } + + public void NotifySubStream(ProgramMapping programMapping, Tap tap, ushort[] eventIds, Dictionary context, EventList_T eventListT, Info_T infoT) + { + foreach (ProgramMappingStream mappingStream in programMapping.Streams) + { + if (mappingStream.ComponentTag.HasValue) + { + ushort l = mappingStream.ComponentTag.Value; + ushort r = tap.AssociationTag; + if (l == r) + { + if (!DvbContext.IsPidProcessorPresent(mappingStream.ElementaryPid)) + { + //DvbContext.RegisterPacketProcessor(mappingStream.ElementaryPid, new PsiDecoder(mappingStream.ElementaryPid, new ObjectCarouselDecoder(mappingStream.ElementaryPid, this, programMapping, mappingStream.ComponentTag.Value))); + DvbContext.RegisterPacketProcessor(mappingStream.ElementaryPid, new PsiDecoder(mappingStream.ElementaryPid, new DataCarouselDecoder(mappingStream, programMapping, DataCarouselIntention.NoIntention, this))); + LogEvent(SkyscraperContextEvent.SubStreamFromObjectCarousel, String.Format("PID {0:X4}", mappingStream.ElementaryPid)); + } + } + } + } + } + + public void NotifyOfCaSystem(CaDescriptor caDescriptor, bool fromPmt = false) + { + if (caDescriptor.CaSystemId == 0x0000) + return; //Invalid CAID + + if (!CurrentNetworkId.HasValue) + return; + if (!CurrentTransportStreamId.HasValue) + return; + + if (!fromPmt) + { + UiJunction?.NotifyCat(caDescriptor); + if (!DataStorage.TestForCaSystem(CurrentNetworkId.Value, CurrentTransportStreamId.Value, caDescriptor.CaPid)) + { + DataStorage.StoreCaSystem(CurrentNetworkId.Value, CurrentTransportStreamId.Value, caDescriptor); + LogEvent(SkyscraperContextEvent.CaSystem, String.Format("{0} on PID {1:X4}", CaSystemNames.GetHumanReadableName(caDescriptor.CaSystemId), caDescriptor.CaPid)); + } + } + + if (!DvbContext.IsPidProcessorPresent(caDescriptor.CaPid)) + { + //These PIDs for CA Systems contain ECM and EMM messages. + //They are specific for *every* CA System. + //It is probably not worth reverse-engineering every single one of them. + //So we just discard these packages. + DvbContext.RegisterPacketProcessor(caDescriptor.CaPid, new PacketDiscarder()); + } + } + + public void NotifyOfSubtitleLine(Page page) + { + + } + + public void UpdateNotification(UpdateNotificationGroup common, UpdateNotificationTarget target, ushort ProgramNumber) + { + /*int hashCode = target.GetHashCode(); + if (!ScraperStorage.TestForUpdateNotification(hashCode, common)) + { + foreach (Compatibility compatibility in target.Compatibilities) + { + foreach (Platform platform in target.Platforms) + { + ScraperStorage.StoreUpdateNotification(hashCode, common, compatibility, platform); + LogEvent(SkyscraperContextEvent.UpdateNotification, + String.Format("{0} -> {1}", compatibility, platform)); + } + } + }*/ + foreach (Compatibility compatibility in target.Compatibilities) + { + foreach (Platform platform in target.Platforms) + { + DataStorage.StoreUpdateNotification(0, common, compatibility, platform); + } + } + + + if (common.AssociationTag.HasValue) + { + Platform platform = new Platform(); + platform.DataBroadcastId = common.DataBroadcastId; + platform.PrivateData = common.PrivateData; + platform.AssociationTag = common.AssociationTag; + platform.UpdateFlag = common.UpdateFlag; + platform.UpdateMethod = common.UpdateMethod; + platform.UpdatePriority = common.UpdatePriority; + target.Platforms.Add(platform); + } + + foreach (Platform targetPlatform in target.Platforms) + { + if (!targetPlatform.AssociationTag.HasValue) + continue; + if (!SsusToLookFor.Any(x => x.Key == ProgramNumber && x.Value == (byte)targetPlatform.AssociationTag)) + { + SsusToLookFor.Add(new KeyValuePair(ProgramNumber, + (byte)targetPlatform.AssociationTag.Value)); + } + } + } + + private Dictionary _dataCarouselProgresses; + + public bool IsModuleWanted(int elementaryPid, ushort moduleId, byte moduleVersion) + { + if (!CurrentNetworkId.HasValue) + return false; + + if (!CurrentTransportStreamId.HasValue) + return false; + + if (DataStorage.IsDsmCcModuleBlacklisted(CurrentNetworkId.Value, CurrentTransportStreamId.Value, elementaryPid, moduleId, moduleVersion)) + return false; + + if (ObjectStorage.IsDsmCcModuleWanted(CurrentNetworkId.Value, CurrentTransportStreamId.Value, elementaryPid, moduleId, moduleVersion)) + return true; + + return false; + } + + public void NotifyOfNewModule(int elementaryPid, ushort moduleInfoModuleId, byte moduleInfoModuleVersion) + { + if (!CurrentNetworkId.HasValue) + return; + + if (!CurrentTransportStreamId.HasValue) + return; + + if (_dataCarouselProgresses == null) + _dataCarouselProgresses = new Dictionary(); + + DatabaseKeyDsmCcModule key = new DatabaseKeyDsmCcModule(CurrentNetworkId.Value, CurrentTransportStreamId.Value, elementaryPid, moduleInfoModuleId, moduleInfoModuleVersion); + + if (dedupModules.Contains(key)) + return; + + if (ObjectStorage.IsDsmCcModuleWanted(CurrentNetworkId.Value, CurrentTransportStreamId.Value, elementaryPid, moduleInfoModuleId, moduleInfoModuleVersion)) + { + if (!_dataCarouselProgresses.ContainsKey(key)) + { + _dataCarouselProgresses.Add(key, 0.0); + } + LogEvent(SkyscraperContextEvent.NotifyOfNewModule, String.Format("PID {2:X4}, Module #{0:X4}, Version {1}", moduleInfoModuleId, moduleInfoModuleVersion, elementaryPid)); + UiJunction?.DsmCcModuleAdd(elementaryPid, moduleInfoModuleId, moduleInfoModuleVersion); + } + } + + public void NotifyModuleDownloadProgress(int elementaryPid, ushort moduleInfoModuleId, byte moduleInfoModuleVersion, double moduleInfoDownloadProgress) + { + if (!CurrentNetworkId.HasValue) + return; + + if (!CurrentTransportStreamId.HasValue) + return; + + if (_dataCarouselProgresses == null) + return; + + DatabaseKeyDsmCcModule key = new DatabaseKeyDsmCcModule(CurrentNetworkId.Value, CurrentTransportStreamId.Value, elementaryPid, moduleInfoModuleId, moduleInfoModuleVersion); + if (_dataCarouselProgresses.ContainsKey(key)) + { + _dataCarouselProgresses[key] = moduleInfoDownloadProgress; + LogEvent(SkyscraperContextEvent.ModuleDownloadProgress, String.Format("PID {3:X4}, Module #{0}, Version {1}, {2}% done", moduleInfoModuleId, moduleInfoModuleVersion, moduleInfoDownloadProgress, elementaryPid)); + UiJunction?.DsmCcModuleProgress(elementaryPid, moduleInfoModuleId, moduleInfoModuleVersion, moduleInfoDownloadProgress); + } + } + + public ObjectCarouselEventHandler GetObjectCarouselEventHandler() + { + return this; + } + + public void NotifyDownloadComplete(int elementaryPid, ushort moduleModuleId, byte moduleModuleVersion, Stream result, bool isObjectCarousel) + { + if (!CurrentNetworkId.HasValue) + return; + + if (!CurrentTransportStreamId.HasValue) + return; + + if (_dataCarouselProgresses == null) + return; + + if (isObjectCarousel) + throw new NotImplementedException(); + + UiJunction?.SetMemorySaverMode(true); + ObjectStorage.DataCarouselModuleArrival(CurrentNetworkId.Value, CurrentTransportStreamId.Value, elementaryPid, moduleModuleId, moduleModuleVersion, result); + UiJunction?.SetMemorySaverMode(false); + + LogEvent(SkyscraperContextEvent.ModuleDownloadComplete, String.Format("Module {0}, Version {1}", moduleModuleId, moduleModuleVersion)); + + DatabaseKeyDsmCcModule key = new DatabaseKeyDsmCcModule(CurrentNetworkId.Value, CurrentTransportStreamId.Value, elementaryPid, moduleModuleId, moduleModuleVersion); + _dataCarouselProgresses.Remove(key); + + UiJunction?.DsmCcModuleComplete(elementaryPid, moduleModuleId, moduleModuleVersion); + } + + public void DsmCcDoItNowEvent(ProgramMapping programMapping, StreamEventDescriptor descriptorListStreamEventDescriptor, int pid) + { + if (!CurrentTransportStreamId.HasValue) + return; + if (!CurrentNetworkId.HasValue) + return; + if (!currentTime.HasValue) + return; + DataStorage.StoreDsmCcDoItNowEvent(currentTime.Value, CurrentNetworkId.Value, CurrentNetworkId.Value, programMapping.ProgramNumber, descriptorListStreamEventDescriptor, pid); + + //These "do-it-now" Events are specific for _EVERY_ application and probably not + //worth extending the scraping time. They are most likely subtitles or commands + //for game-show play-along apps. Therefore we won't create a log entry for these, as it + //would increase scraping duration. + } + + private List dedupModules = new List(); + public void PreventDsmCcModuleRepetition(int elementaryPid, ushort moduleModuleId, byte moduleModuleVersion) + { + dedupModules.Add(new DatabaseKeyDsmCcModule(CurrentNetworkId.Value, CurrentTransportStreamId.Value, elementaryPid, moduleModuleId, moduleModuleVersion)); + } + + public void SetRdsProgrammeServiceName(int programNumber, string programmeService2) + { + if (DataStorage.UpdateRdsProgrammeServiceName(CurrentNetworkId.Value, CurrentTransportStreamId.Value, + programNumber, programmeService2)) + { + LogEvent(SkyscraperContextEvent.RdsProgrammeServiceName, + String.Format("{0:X4}, {1:X4}", programNumber, programmeService2)); + } + } + + public bool TestCanHandleRdsMessages(int programNumber) + { + if (!CurrentNetworkId.HasValue) + return false; + + if (!CurrentTransportStreamId.HasValue) + return false; + + if (!DataStorage.TestForKnownRdsData(CurrentNetworkId.Value, CurrentTransportStreamId.Value, + programNumber)) + { + DataStorage.EnableRdsCollection(CurrentNetworkId.Value, CurrentTransportStreamId.Value, + programNumber); + LogEvent(SkyscraperContextEvent.BeginRdsRecording, + String.Format("{0:X4},{1:X4},{2:X4}", CurrentNetworkId.Value, CurrentTransportStreamId.Value, + programNumber)); + } + + return true; + } + + public void SetRdsRadioText(int programNumber, string text) + { + if (DataStorage.UpdateRdsRadioText(CurrentNetworkId.Value, CurrentTransportStreamId.Value, programNumber, + text)) + { + LogEvent(SkyscraperContextEvent.RdsText, String.Format("{0:X4} [{1}]", programNumber, text)); + } + } + + public void NotifySpliceInsert(ushort ProgramNumber, SpliceInsert spliceInsert) + { + UiJunction?.NotifyScte35(ProgramNumber, spliceInsert); + if (!CurrentNetworkId.HasValue) + return; + + if (!CurrentTransportStreamId.HasValue) + return; + + if (!DataStorage.TestForScte35SpliceInsert(CurrentNetworkId.Value, CurrentTransportStreamId.Value, + ProgramNumber, spliceInsert)) + { + DataStorage.StoreScte35SpliceInsert(CurrentNetworkId.Value, CurrentTransportStreamId.Value, ProgramNumber, spliceInsert); + LogEvent(SkyscraperContextEvent.Scte35Splice, + String.Format("Program {0:X4}, Splice at {1:X16}", ProgramNumber, spliceInsert.SpliceTime)); + } + } + + public void NotifyTimeSignal(ushort programNumber, TimeSignal timeSignal) + { + UiJunction?.NotifyScte35(programNumber, timeSignal); + if (!CurrentNetworkId.HasValue) + return; + + if (!CurrentTransportStreamId.HasValue) + return; + + if (!currentTime.HasValue) + return; + + DataStorage.SetScte35TimeSignal(CurrentNetworkId.Value, CurrentTransportStreamId.Value, currentTime.Value, programNumber, timeSignal); + LogEvent(SkyscraperContextEvent.Scte35TimeSignal, String.Format("Program {0:X4}, Time Signal {1:X16}", programNumber, timeSignal.Value)); + } + + public void NotifyOfCompliance(string compliance) + { + if (!CurrentNetworkId.HasValue) + return; + + if (!CurrentTransportStreamId.HasValue) + return; + + if (!DataStorage.IsCompliant(CurrentNetworkId.Value, CurrentTransportStreamId.Value, compliance)) + { + DataStorage.MarkAsCompliant(CurrentNetworkId.Value, CurrentTransportStreamId.Value, compliance); + LogEvent(SkyscraperContextEvent.Compliance, compliance); + } + } + + public void NotifiyStationIdentification(string stationIdentification) + { + if (!CurrentNetworkId.HasValue) + return; + + if (!CurrentTransportStreamId.HasValue) + return; + + if (DataStorage.SetStationIdentification(CurrentNetworkId.Value, CurrentTransportStreamId.Value, + stationIdentification)) + { + LogEvent(SkyscraperContextEvent.StationIdentification, stationIdentification); + } + } + + public void AutodetectionSucessful(int pid, Contestant contestant, ProgramContext programContext) + { + UiJunction?.NotifyStreamTypeDetection(contestant.Tag, pid); + LogEvent(SkyscraperContextEvent.StreamTypeAutodetection, String.Format("{0} on PID {1:X4}", contestant.Tag, pid)); + contestant.DeclareWinner(this, pid, programContext); + return; + } + + + private IpTrafficHandler ipTrafficHandler; + public void OnIpDatagram(int pid, byte[] payload) + { + if (ipTrafficHandler == null) + { + StorageConnectionManager storageConnectionManager = StorageConnectionManager.GetInstance(); + ipTrafficHandler = storageConnectionManager.GetDefaultIpTrafficHandler(); + } + if (payload.Length == 0) + { + return; + } + + ipTrafficHandler?.HandlePacket(pid, payload); + + int ipVersion = (payload[0] & 0xf0) >> 4; + if (ipVersion == 4) + { + if (Array.TrueForAll(payload, x => x == 0)) + return; + int ihl = (payload[0] & 0x0f); + ihl *= 32; + ihl /= 8; + byte[] ipv4Header = new byte[ihl]; + if (payload.Length < ihl) + return; + Array.Copy(payload, 0, ipv4Header, 0, ihl); + InternetHeader internetHeader = new InternetHeader(ipv4Header); + if (!internetHeader.ChecksumValid) + return; + byte[] ipv4Packet = new byte[payload.Length - ihl]; + Array.Copy(payload, ihl, ipv4Packet, 0, payload.Length - ihl); + OnIpv4PacketArrival(internetHeader, ipv4Packet); + } + else if (ipVersion == 6) + { + if (payload.Length < 40) + { + return; + } + MemoryStream ipv6Stream = new MemoryStream(payload, false); + byte byteA = ipv6Stream.ReadUInt8(); + byte byteB = ipv6Stream.ReadUInt8(); + + int trafficClass = (byteA & 0x0f) << 4; + trafficClass = ((byteB & 0xf0) >> 4); + + int flowLabel = (byteB & 0x0f) << 16; + flowLabel += ipv6Stream.ReadUInt16BE(); + + ushort payloadLength = ipv6Stream.ReadUInt16BE(); + byte nextHeader = ipv6Stream.ReadUInt8(); + byte hopLimit = ipv6Stream.ReadUInt8(); + + IPAddress sourceAddress = new IPAddress(ipv6Stream.ReadBytes(16)); + IPAddress destinationAddress = new IPAddress(ipv6Stream.ReadBytes(16)); + InternetHeader ipv6Header = new InternetHeader(trafficClass, flowLabel, payloadLength, nextHeader, hopLimit, sourceAddress, destinationAddress); + if (ipv6Stream.GetAvailableBytes() >= payloadLength) + { + OnIpv4PacketArrival(ipv6Header, ipv6Stream.ReadBytes(payloadLength)); + } + return; + } + else + { + //throw new Exception("invalid ip packet"); + } + } + + public void GsIpTrafficDetected() + { + LogEvent(SkyscraperContextEvent.SpecialTsMode, "Valid IP Traffic detected"); + } + + private HashSet trafficInfos; + private ReadOnlyCollection mpePlugins; + public SkyscraperDnsCache DnsCache { get; private set; } + + private bool ProcessDns(IpTrafficInfo trafficInfo, byte[] ipv4Packet) + { + if (DnsCache == null) + DnsCache = new SkyscraperDnsCache(DataStorage); + //Handle DNS + bool result = false; + if (trafficInfo.Protocol == 0x11) + { + UserDatagram udpPacket = new UserDatagram(ipv4Packet); + if (udpPacket.Valid) + { + if (udpPacket.SourcePort == 53) + { + result = DnsCache.ProcessDnsPacket(udpPacket.Payload); + } + } + } + trafficInfo.SourceName = DnsCache.GetDnsName(trafficInfo.Source); + trafficInfo.TargetName = DnsCache.GetDnsName(trafficInfo.Target); + return result; + } + + public void OnIpv4PacketArrival(InternetHeader internetHeader, byte[] ipv4Packet) + { + //There are as many use cases as there are internet applications in these. + //Not really required to decode all of them, if you ask me. + /* + * One known use is LX9SES on Astra 23.5, with the following arguments: + * -> Destination Address always 228.64.0.56 + * -> Source Address always 10.225.49.1 + * -> Protocol always 0x11 (UDP) + */ + if (trafficInfos == null) + trafficInfos = new HashSet(); + + IpTrafficInfo iti = IpTrafficInfo.FromInternetHeader(internetHeader); + if (ProcessDns(iti, ipv4Packet)) + { + LogEvent(SkyscraperContextEvent.LearnDns, String.Format("{0} = {1}", DnsCache.LastLearned.Value, DnsCache.LastLearned.Key)); + } + UiJunction?.NotifyMpeTraffic(iti, ipv4Packet.Length); + + if (trafficInfos.Add(iti)) + { + LogEvent(SkyscraperContextEvent.IpTraffic, iti.ToString()); + } + + if (mpePlugins == null) + { + mpePlugins = PluginManager.GetInstance().GetMpePlugins(); + object[] connector = StorageConnectionManager.GetPluginConnectors(DataStorage, ObjectStorage); + foreach (ISkyscraperMpePlugin plugin in mpePlugins) + { + try + { + plugin.ConnectToStorage(connector); + } + catch (Exception e) + { + + } + } + } + + + foreach (ISkyscraperMpePlugin plugin in mpePlugins) + { + if (plugin.CanHandlePacket(internetHeader, ipv4Packet)) + { + plugin.SetContext(currentTime,this); + plugin.HandlePacket(internetHeader, ipv4Packet); + if (plugin.StopProcessingAfterThis()) + return; + } + } + /* + if (internetHeader.Protocol == 0x11) + { + UserDatagram userDatagram = new UserDatagram(ipv4Packet); + if (!userDatagram.Valid) + return; + + if (internetHeader.SourceAddress.Equals(_fpUrmetSrc) && internetHeader.DestinationAddress.Equals(_fpUrmetDst)) + { + //Found on Astra 19.2 12604/H - not the slightest idea what this does. + //Service name is FP URMET. + return; + } + else + { + ipPackets++; + } + } + else if (internetHeader.Protocol == 0x02) + { + IgmpMessage igmpMessage = new IgmpMessage(ipv4Packet); + //Also Found on Astra 19.2 12604/H, I don't think we'll need these. + return; + } + else + { + ipPackets++; + }*/ + } + + public void NotifyRunningStatus(uint transportStreamId, uint originalNetworkId, uint serviceId, uint eventId, + RunningStatus runningStatus) + { + if (!currentTime.HasValue) + return; + + if (DataStorage.StoreRunningStatus(transportStreamId, originalNetworkId, serviceId, eventId, runningStatus, currentTime.Value)) + { + LogEvent(SkyscraperContextEvent.RunningStatusChange, String.Format("({0:X4},{1:X4},{2:X4},{3:X4}) -> {4}", originalNetworkId, transportStreamId, serviceId, eventId, runningStatus)); + } + } + + public bool EnableTimeout { get; set; } + + public int TimeoutSeconds { get; set; } + + public bool CancelOnNextPacket { get; set; } + public ISkyscraperUiJunction UiJunction { get; set; } + + public bool IsAbortConditionMet() + { + if (ffmpegFrameGrabber.BusyFrameGrabbers > 0) + return false; + + if (EnableTimeout && TimeoutSeconds == 0) + TimeoutSeconds = 10; + + if (!firstPacketDone) + return false; + + if (CancelOnNextPacket) + { + LogEvent(SkyscraperContextEvent.AbortConditionMet, "Aborted from another thread."); + CancelOnNextPacket = false; + return true; + } + + if (EnableTimeout) + { + TimeSpan sinceLastEvent = DateTime.Now - lastEventTimestamp; + if (sinceLastEvent.TotalSeconds > TimeoutSeconds) + { + LogEvent(SkyscraperContextEvent.AbortConditionMet, String.Format("Event Timeout after {0} seconds", TimeoutSeconds)); + return true; + } + } + + return false; + } + + public void OnT2MiPacketLoss(int pid, byte expectedPacket, T2MIHeader header) + { + } + + public void OnT2MiPacket(int pid, byte basebandFramePlpId, byte[] basebandPacket) + { + if (subSkyscrapers == null) + subSkyscrapers = new Dictionary(); + + T2MiSubSkyscraperIdentifier subSkyscraperIdentifier = new T2MiSubSkyscraperIdentifier(pid, basebandFramePlpId); + if (!subSkyscrapers.ContainsKey(subSkyscraperIdentifier)) + { + LogEvent(SkyscraperContextEvent.T2MiPlpDetected, String.Format("PID {0:X4}, PLP {1}", pid, basebandFramePlpId)); + } + + OnSubTsPacket(subSkyscraperIdentifier, basebandPacket); + } + + private Dictionary subSkyscrapers; + public void OnSubTsPacket(object identifier, byte[] packet) + { + if (subSkyscrapers == null) + subSkyscrapers = new Dictionary(); + + if (!subSkyscrapers.ContainsKey(identifier)) + { + SkyscraperContext child = new SkyscraperContext(new TsContext(), DataStorage, ObjectStorage); + child.IsChild = true; + child.ChildName = identifier.ToString(); + child.ChildTimestamp = DateTime.Now.Ticks; + + List packetFilters = new List(); + StorageConnectionManager storageConnectionManager = StorageConnectionManager.GetInstance(); + if (storageConnectionManager.IsSubTsDumpingEnabled()) + { + string filename = String.Format("{0}_{1}.ts", child.ChildName.SanitizeFileName(), child.ChildTimestamp); + FileInfo fi = new FileInfo(filename); + TsRecorder packetDumper = new TsRecorder(); + packetDumper.RecordingOutputDirectory = new DirectoryInfo("."); + packetDumper.SetNextFilename(filename); + packetDumper.CreateBufferedStream(); + packetFilters.Add(packetDumper); + } + + child.InitalizeFilterChain(packetFilters.ToArray()); + subSkyscrapers.Add(identifier, child); + } + + SkyscraperContext context = subSkyscrapers[identifier]; + context.IngestSinglePacket(packet); + } + public long ChildTimestamp { get; private set; } + public string ChildName { get; private set; } + public bool IsChild { get; private set; } + + public void OnT2MiTimestamp(int pid, _0x20_DvbT2Timestamp t2Timestamp) + { + if (!CurrentNetworkId.HasValue) + return; + + if (!CurrentTransportStreamId.HasValue) + return; + + if (subSkyscrapers == null) + return; + + List contexts = new List(); + foreach (KeyValuePair subSkyscraper in subSkyscrapers) + { + object subSkyscraperKey = subSkyscraper.Key; + if (!(subSkyscraperKey is T2MiSubSkyscraperIdentifier)) + continue; + + T2MiSubSkyscraperIdentifier identifier = subSkyscraperKey as T2MiSubSkyscraperIdentifier; + if (identifier.Pid != pid) + continue; + + contexts.Add(subSkyscraper.Value); + } + + if (contexts.Count == 0) + return; + + long sum = contexts.Select(x => (long)x.EventsLogged).Sum(); + if (sum < (contexts.Count * 2)) + return; + + DateTime resolveTime = t2Timestamp.ResolveTime(); + DateTime knownTimestamp = DataStorage.T2MiGetTimestamp(CurrentNetworkId.Value, CurrentTransportStreamId.Value, pid); + if (resolveTime > knownTimestamp) + { + DataStorage.T2MiSetTimestamp(CurrentNetworkId.Value, CurrentTransportStreamId.Value, pid, resolveTime); + } + } + + public void OnT2MiIqData(int relatedPid, _0x31_IqData iqData) + { + + } + + public void OnT2MiIqData(int relatedPid, _0x01_IqData iqData2) + { + + } + + public void OnT2MiError(int relatedPid, int skyscraperErrorCode) + { + + } + + public void OnT2MiL1Current(int relatedPid, _0x10_L1Current l1Current) + { + //No clue about this data. It's not really interesting. + } + + public void OnT2MiArbitraryCellInsertion(int relatedPid, _0x02_ArbitraryCellInsertion arbitraryCellInsertion) + { + + } + + public void OnT2MiBalancingCells(int relatedPid, byte frameIndex, uint numActiveBiasCellsPerP2) + { + + } + + public void OnT2MiL1Future(int relatedPid, _0x11_L1Future l1Future) + { + if (l1Future.FutureData.L1DynNext.Length == 0) + return; + + throw new NotImplementedException(); + } + + public void OnT2MiIndividualAddressing(int relatedPid, _0x21_IndividualAddressing individualAddressing) + { + if (!CurrentNetworkId.HasValue) + return; + + if (!CurrentTransportStreamId.HasValue) + return; + + if (subSkyscrapers == null) + return; + + bool any = subSkyscrapers.Where(x => x.Key is T2MiSubSkyscraperIdentifier) + .Select(x => (T2MiSubSkyscraperIdentifier)x.Key) + .Any(); + if (!any) + return; + + foreach (AddressingFunction function in individualAddressing.Commands) + { + if (!DataStorage.T2MiTestForTransmitter(CurrentNetworkId, CurrentTransportStreamId, relatedPid, function.TxIdentifier)) + DataStorage.T2MiRememberTransmitter(CurrentNetworkId, CurrentTransportStreamId, relatedPid, function.TxIdentifier); + + switch (function.Tag) + { + case 0x00: + _0x00_TransmitterTimeOffset tto = (_0x00_TransmitterTimeOffset)function; + DataStorage.T2MiSetTransmitterTimeOffset(CurrentNetworkId, CurrentTransportStreamId, relatedPid, function.TxIdentifier, tto.TimeOffset); + break; + default: + throw new NotImplementedException(String.Format("Individual Addressing function 0x{0:X2}", function.Tag)); + } + } + } + + public bool TcpProxyEnabled + { + get => DvbContext.TcpProxyEnabled; + set => DvbContext.TcpProxyEnabled = value; + } + + public void Dispose() + { + if (TcpProxyEnabled) + TcpProxyEnabled = false; + + + if (ipTrafficHandler != null) + { + ipTrafficHandler.Dispose(); + } + + + if (DvbContext.TcpProxyEnabled) + { + DvbContext.TcpProxyEnabled = false; + } + + if (docsisPacketProcessor != null) + { + docsisPacketProcessor.Dispose(); + } + + if (!SourceIsDisk) + { + if (_dataCarouselProgresses != null) + { + foreach (KeyValuePair item in _dataCarouselProgresses) + { + if (item.Value == 0.0) + continue; + + DataStorage.FailDsmCcDownload(item.Key, item.Value); + } + } + } + + if (_pluginContexts != null) + { + foreach (object plugin in _pluginContexts) + { + IDisposable disposable = plugin as IDisposable; + if (disposable != null) + disposable.Dispose(); + } + _pluginContexts.Clear(); + } + + DataStorage.WaitForCompletion(); + } + + public bool TestForFrame(int currentNetworkId, int transportStreamId, ushort mappingProgramNumber, int mappingStreamElementaryPid) + { + return ObjectStorage.TestForFramegrab(currentNetworkId, transportStreamId, mappingProgramNumber, mappingStreamElementaryPid); + } + + public void NotifyCompletedFrame(int currentNetworkId, int transportStreamId, ushort mappingProgramNumber, + int mappingStreamElementaryPid, byte[] imageData) + { + ObjectStorage.StoreFramegrab(currentNetworkId, transportStreamId, mappingProgramNumber, (ushort)mappingStreamElementaryPid, imageData); + LogEvent(SkyscraperContextEvent.GotFramegrab, String.Format("Program {0:X4}, PID {1:X4}", mappingProgramNumber, mappingStreamElementaryPid)); + UiJunction?.ShowFramegrab(currentNetworkId, transportStreamId, mappingProgramNumber, mappingStreamElementaryPid, imageData); + } + + public void OnIpMacNotification(int sourcePid, Dvb.DataBroadcasting.IntModel.Platform platform, Target target, Operational operational) + { + IEnumerable ipMacNotifications = IpMacNotification.FlatMap(platform, target, operational); + foreach (IpMacNotification notification in ipMacNotifications) + { + if (!DataStorage.TestForIpMacNotification(notification)) + { + DataStorage.StoreIpMacNotification(notification); + LogEvent(SkyscraperContextEvent.IpMacNotification, String.Format("{0} -> {1}", platform.Name, notification.TargetName)); + } + } + } + + public void OnRelatedContent(Rct result, ushort resultProgramNumber) + { + if (result.LinkInfo.Length == 0) + return; + if (runningEvents == null) + return; + if (runningEvents[resultProgramNumber] == null) + return; + + EitEvent lEvent = runningEvents[resultProgramNumber]; + + foreach (RctLinkInfo rctLinkInfo in result.LinkInfo) + { + if (!DataStorage.TestForRelatedContent(lEvent, rctLinkInfo)) + { + DataStorage.SetRelatedContent(lEvent, rctLinkInfo); + LogEvent(SkyscraperContextEvent.RelatedContent, String.Format("Program {0}, Event {1} -> {2}", resultProgramNumber, lEvent.EventId, rctLinkInfo.GetIdentifierString())); + } + } + } + + private bool warnedMissingLocation; + + private void WarnMissingLocation() + { + if (!warnedMissingLocation) + { + LogEvent(SkyscraperContextEvent.LocationMissing); + warnedMissingLocation = true; + } + } + + public void OnParticipantDetected(PhysicalAddress pa) + { + int? currentLocation = DataStorage.GetCurrentLocationId(); + if (currentLocation.HasValue) + { + LogEvent(SkyscraperContextEvent.DocsisParticipant, BitConverter.ToString(pa.GetAddressBytes())); + DataStorage.StoreDocsisParticipant(pa, currentLocation.Value); + } + else + { + WarnMissingLocation(); + } + } + + public void OnCmtsTimestamp(PhysicalAddress source, uint timing) + { + //DOCSIS Timestamps are not interesting to us. + } + + public void OnUpstreamChannel(UpstreamChannelDescriptor mmm) + { + UiJunction?.NotifyDocsisFrequency(mmm.Frequency, true, mmm); + if (!mmm.Frequency.HasValue) + return; + + int? currentLocation = DataStorage.GetCurrentLocationId(); + if (!currentLocation.HasValue) + { + WarnMissingLocation(); + return; + } + + if (!DataStorage.TestForDocsisUpstreamChannel(mmm.Source, mmm.Frequency.Value,currentLocation.Value)) + { + DataStorage.StoreDocsisUpstreamChannel(mmm, currentLocation.Value); + LogEvent(SkyscraperContextEvent.DocsisUpstreamChannel, String.Format("{0} -> {1}", mmm.Source.ToString(), mmm.Frequency.Value)); + } + } + + public void OnDownstreamChannel(PhysicalAddress physicalAddress, MacDomainDescriptor.DownstreamActiveChannel downstreamActiveChannel) + { + UiJunction?.NotifyDocsisFrequency(downstreamActiveChannel.Frequency, false, downstreamActiveChannel); + + if (!downstreamActiveChannel.Frequency.HasValue) + return; + + int? currentLocation = DataStorage.GetCurrentLocationId(); + if (!currentLocation.HasValue) + { + WarnMissingLocation(); + return; + } + + if (!DataStorage.TestForDocsisDownstreamChannel(physicalAddress, downstreamActiveChannel,currentLocation.Value)) + { + DataStorage.StoreDocsisDownstreamChannel(physicalAddress, downstreamActiveChannel,currentLocation.Value); + LogEvent(SkyscraperContextEvent.DocsisDownstreamChannel, String.Format("{0} -> {1}", physicalAddress.ToString(), downstreamActiveChannel.Frequency.Value)); + } + } + + public void OnLearnedIpFromMac(PhysicalAddress arpHeaderSenderHardwareAddress, IPAddress arpHeaderSenderProtocolAddress) + { + int? currentLocation = DataStorage.GetCurrentLocationId(); + if (!currentLocation.HasValue) + { + WarnMissingLocation(); + return; + } + + if (DataStorage.SetCmtsIp(arpHeaderSenderHardwareAddress, arpHeaderSenderProtocolAddress)) + { + LogEvent(SkyscraperContextEvent.LearnedCmtsIp,String.Format("{0} -> {1}",arpHeaderSenderHardwareAddress.ToString(),arpHeaderSenderProtocolAddress.ToString())); + } + } + + public void OnAbertisPacket(int pid, byte[] outBuffer) + { + AbertisSubSkyscraperKey key = new AbertisSubSkyscraperKey(pid); + OnSubTsPacket(key, outBuffer); + } + + public void OnAbertisSyncLoss(int pid, int oldPosition = -1, long newPosition = -1) + { + if (subSkyscrapers == null) + DvbContext.RegisterPacketProcessor(pid, new PacketDiscarder()); + + AbertisSubSkyscraperKey key = new AbertisSubSkyscraperKey(pid); + if (!subSkyscrapers.ContainsKey(key) == null) + DvbContext.RegisterPacketProcessor(pid, new PacketDiscarder()); + + if (!subSkyscrapers[key].firstPacketDone) + DvbContext.RegisterPacketProcessor(pid, new PacketDiscarder()); + else + throw new NotImplementedException( + "I couldn't sync this Abertis-styled stream, and I couldn't figure out why. Could you please share a sample of this stream?"); + } + + public void OnMonochromeData(int networkId, int transportStreamId, ushort programNumber, MonochromeDataField result) + { + throw new NotImplementedException(); + } + + void Id3Handler.OnId3Error(Id3ErrorState state) + { + throw new NotImplementedException(); + } + + void Id3Handler.OnId3Tag(Id3Tag tag) + { + if (tag.IsAllPrivate()) + return; + throw new NotImplementedException(); + } + + void InteractionChannelHandler.OnCorrectionMessage(ushort interactiveNetworkId, Cmt cmt) + { + foreach(Cmt.CmtEntry entry in cmt.Entries) + { + if (!DataStorage.TestForCmtEntry(interactiveNetworkId,entry)) + { + LogEvent(SkyscraperContextEvent.CorrectionMessage, String.Format("Network ID = {0}, Group ID = {1}, Logon ID = {2}, Slot Type = {3}", interactiveNetworkId, entry.GroupId, entry.LoginId,entry.SlotType.ToString())); + DataStorage.InsertCmtEntry(interactiveNetworkId, entry); + } + } + } + + void InteractionChannelHandler.OnFrameComposition(ushort interactiveNetworkId, Fct fct) + { + foreach(Fct.Frame frame in fct.Frames) + { + if (!DataStorage.TestForFrameComposition(interactiveNetworkId,frame)) + { + LogEvent(SkyscraperContextEvent.FrameComposition, String.Format("Network ID = {0}, Frame = {1}", interactiveNetworkId, frame.FrameId)); + DataStorage.InsertFctFrame(interactiveNetworkId, frame); + } + } + } + + private bool[] interactionChannelErrors; + void InteractionChannelHandler.OnInteractionChannelError(InteractionChannelErrorState unexpectedTable) + { + if (interactionChannelErrors == null) + { + interactionChannelErrors = new bool[Enum.GetNames(typeof(InteractionChannelErrorState)).Length]; + } + int offset = (int)unexpectedTable; + if (!interactionChannelErrors[offset]) + { + LogEvent(SkyscraperContextEvent.InteractionChannelError, unexpectedTable.ToString()); + interactionChannelErrors[offset] = true; + } + } + + public void OnRcsMap(Rmt rmt) + { + if (rmt.Linkages != null) + { + foreach(_0x4a_LinkageDescriptor linkage in rmt.Linkages) + { + if (!DataStorage.TestForRmtLinkage(linkage)) + { + LogEvent(SkyscraperContextEvent.RmtLinkage, String.Format("Interactive Network #{0} -> ONID {1}, TSID {2}", linkage.InteractiveNetworkId, linkage.OriginalNetworkId, linkage.TransportStreamId)); + DataStorage.InsertRmtLinkage(linkage); + } + } + } + if (rmt.TransportStreams != null) + { + foreach(Rmt.TransportStream transportStream in rmt.TransportStreams) + { + if (!DataStorage.TestForRmtTransportStream(rmt.NetworkId, transportStream)) + { + LogEvent(SkyscraperContextEvent.RmtTransportStream, String.Format("{0} -> {1},{2}", rmt.NetworkId, transportStream.OriginalNetworkId, transportStream.TransportStreamId)); + DataStorage.InsertRmtTransportStream(rmt.NetworkId, transportStream); + } + } + } + } + + private void CheckForHiddenMpes() + { + uint threshold = 1000; + if (pmtTracker != null) + { + if (!pmtTracker.AllPmtsProcessed) + { + return; + } + + threshold = 1; + } + int[] occupiedPids = DvbContext.GetOccupiedPids(); + ulong[] pidStatistics = DvbContext.GetPidStatistics(); + for (int i = 0; i < (pidStatistics.Length - 1); i++) + { + if (pidStatistics[i] > threshold) + { + if (!occupiedPids.Contains(i)) + { + LogEvent(SkyscraperContextEvent.SpecialTsMode, String.Format("Attaching stream-type autodetector to PID 0x{0:X4}", i)); + DvbContext.RegisterPacketProcessor(i, new StreamTypeAutodetection(i, this)); + } + } + } + } + + public void OnSatellitePosition(ushort interactiveNetworkId, Spt spt) + { + foreach (Spt.Satellite satellite in spt.Satellites) + { + if (!DataStorage.TestForSatellitePosition(interactiveNetworkId,satellite)) + { + LogEvent(SkyscraperContextEvent.SatellitePosition, String.Format("NID = {0}, Satellite ID = {1} (X = {2}, Y = {3}, Z = {4})", interactiveNetworkId, satellite.Id, satellite.X, satellite.Y, satellite.Z)); + DataStorage.StoreSatellitePosition(interactiveNetworkId, satellite); + } + } + } + + void InteractionChannelHandler.OnSuperframeComposition(ushort interactiveNetworkId, Sct sct) + { + foreach(Sct.Superframe superframe in sct.Superframes) + { + if (!DataStorage.TestForSuperframeComposition(interactiveNetworkId,superframe)) + { + LogEvent(SkyscraperContextEvent.SuperframeComposition, String.Format("Network ID = {0}, Superframe ID = {1}, Frequency = {2}/{3}", interactiveNetworkId, superframe.SuperframeId, superframe.SuperframeCentreFrequency,superframe.UplinkPolarization)); + DataStorage.StoreSuperframeComposition(interactiveNetworkId, superframe); + } + } + } + + void InteractionChannelHandler.OnTerminalBurstTimePlan(ushort interactiveNetworkId, Tbtp tbtp) + { + foreach (Tbtp.TbtpFrame frame in tbtp.Frames) + { + foreach (Tbtp.TbtpFrame.BtpEntity btp in frame.BTP) + { + if (DataStorage.TestForTerminalBurstTimePlan(interactiveNetworkId,tbtp.GroupId,btp.LogonId)) + { + LogEvent(SkyscraperContextEvent.TerminalBurstTimePlan, String.Format("Network ID = {0}, Group ID = {1}, Logon ID = {2}", interactiveNetworkId, tbtp.GroupId, btp.LogonId)); + DataStorage.StoreTerminalBurstTimePlan(interactiveNetworkId, tbtp.GroupId, tbtp.SuperframeCount, frame.FrameNumber, btp); + } + } + } + } + + public void OnTimeslotComposition(ushort interactiveNetworkId, Tct tct) + { + throw new NotImplementedException(); + } + + public void OnTerminalBurstTimePlan2(ushort interactiveNetworkId, Tbtp2 tbtp2) + { + foreach (Tbtp2.Frame frame in tbtp2.Frames) + { + for (int assignmentOrdinal = 0; assignmentOrdinal < frame.Assignments.Length; assignmentOrdinal++) + { + Tbtp2.Assignment assignment = frame.Assignments[assignmentOrdinal]; + if (!DataStorage.TestForTerminalBurstTimePlan2(interactiveNetworkId, tbtp2.GroupId, frame.FrameNumber)) + { + LogEvent(SkyscraperContextEvent.TerminalBurstTimePlan2, String.Format("Network ID = {0}, Group ID = {1}, Frame Number = {2}",interactiveNetworkId,tbtp2.GroupId,frame.FrameNumber)); + DataStorage.StoreTerminalBurstTimePlan2(interactiveNetworkId, tbtp2.GroupId, frame); + } + } + } + } + + public void OnFrameComposition2(ushort networkId, Fct2 fct2) + { + foreach (Fct2.Frame frame in fct2.FrameTypes) + { + if (!DataStorage.TestForFrameComposition2(networkId, frame)) + { + LogEvent(SkyscraperContextEvent.FrameComposition2,String.Format("Network ID = {0}, Frame Type = {1}",networkId,frame.FrameType)); + DataStorage.InsertFct2Frame(networkId, frame); + } + } + } + + public void OnBroadcastConfiguration(ushort networkId, Bct bct) + { + foreach (Bct.BroadcastConfiguration txType in bct.TxTypes) + { + if (!DataStorage.TestForBroadcastConfiguration(networkId, txType.TxType)) + { + LogEvent(SkyscraperContextEvent.BroadcastConfiguration, String.Format("Network ID = {0}, Broadcast Configuration #{1}", networkId, txType.TxType)); + DataStorage.InsertBroadcastConfiguration(networkId, txType); + } + } + } + + public void OnRcs2Nit(ushort interactiveNetworkId, RcsNit nit) + { + if (!DataStorage.TestForRcs2Nit(nit)) + { + LogEvent(SkyscraperContextEvent.Rcs2Network, String.Format("Network ID #{0}, ({1}) on {2}", nit.OriginalNetworkId, nit.NetworkName, nit.SatelliteDeliverySystem.ToString())); + DataStorage.InsertRcs2Nit(nit); + } + } + + public void OnRcs2Tdt(ushort interactiveNetworkId, Rcs2Tdt tdt) + { + LogEvent(SkyscraperContextEvent.Rcs2TdtTime, String.Format("Network ID #{0}, {1}", interactiveNetworkId, tdt.Timestamp)); + DataStorage.UpdateRcs2Tdt(interactiveNetworkId, tdt.Timestamp); + } + + public void OnTransmissionModeSupport2(ushort interactiveNetworkId, Tmst2 tmst2) + { + foreach (Tmst2.TransmissionMode mode in tmst2.TransmissionModes) + { + if (!DataStorage.TestForTmst2(interactiveNetworkId, mode)) + { + LogEvent(SkyscraperContextEvent.TransmissionModeSupport2, String.Format("Network ID #{0}, MODCOD {1}", interactiveNetworkId, mode.Modcod)); + DataStorage.InsertTmst2(interactiveNetworkId, mode); + } + } + } + + public void OnFramePayloadFormatAnnouncement(ushort networkId, _0xb7_FramePayloadFormatDescriptor descriptor) + { + foreach (_0xb7_FramePayloadFormatDescriptor.TransmissionContext transmissionContext in descriptor.Contexts) + { + if (!DataStorage.TestForTimFramePayloadFormat(networkId, transmissionContext)) + { + LogEvent(SkyscraperContextEvent.TimFramePayloadFormat,String.Format("Network #{0}, Context ID #{1}",networkId,transmissionContext.TransmissionContextId)); + DataStorage.InsertTimFramePayloadFormat(networkId, transmissionContext); + } + } + } + + public void OnCorrectionMessageExtension(PhysicalAddress macAddress, _0xb1_CorrectionMessageExtensionDescriptor descriptor) + { + if (!DataStorage.TestForTimCorrectionMessageExtension(macAddress)) + { + LogEvent(SkyscraperContextEvent.TimCorrectionExtension, String.Format("For participant {0}", macAddress)); + DataStorage.InsertTimCorrectionMessageExtension(macAddress, descriptor); + } + } + + public void OnControlAssignment(PhysicalAddress macAddress, _0xa4_SyncAssignDescriptor descriptor) + { + if (!DataStorage.TestForTimControlAssignment(macAddress)) + { + LogEvent(SkyscraperContextEvent.TimControlAssignment, String.Format("For participant {0}", macAddress)); + DataStorage.InsertTimControlAssignment(macAddress, descriptor); + } + } + + public void OnSatelliteReturnLink(PhysicalAddress macAddress, _0xa9_SatelliteReturnLinkDescriptor descriptor) + { + if (!DataStorage.TestForTimSatelliteReturnLink(macAddress)) + { + LogEvent(SkyscraperContextEvent.TimSatelliteReturnLink, String.Format("For participant {0}: {1}", macAddress, descriptor)); + DataStorage.InsertTimSatelliteReturnLink(macAddress, descriptor); + } + } + + public void OnLowerLayerService(PhysicalAddress macAddress, _0xbb_LowerLayerServiceDescriptor descriptor) + { + if (!DataStorage.TestForLowerLayerService(macAddress)) + { + LogEvent(SkyscraperContextEvent.TimLowerLayerService, String.Format("For participant {0}", macAddress)); + DataStorage.InsertTimLowerLayerService(macAddress, descriptor); + } + } + + public void OnHigherLayerInitalization(PhysicalAddress macAddress, _0xc4_HigherLayersInitializeDescriptor descriptor) + { + foreach (_0xc4_HigherLayersInitializeDescriptor.Layer2Interface layer2Interface in descriptor.Layer2Interfaces) + { + if (!DataStorage.TestForHigherLayerServiceInitalization(macAddress, layer2Interface)) + { + LogEvent(SkyscraperContextEvent.TimHigherLayerInitalization, String.Format("For participant {0} -> {1}", macAddress, layer2Interface.Ipv4McAddress)); + DataStorage.InsertHigherLayerServiceInitalization(macAddress, layer2Interface); + } + } + } + + public void LogonResponseDescriptor(PhysicalAddress macAddress, _0xb9_LogonResponseDescriptor descriptor) + { + if (!DataStorage.TestForTimLogonResponse(macAddress)) + { + LogEvent(SkyscraperContextEvent.TimLogonResponse, String.Format("For participant {0}: {1}", macAddress, descriptor.ToString())); + DataStorage.InsertTimLogonResponse(macAddress, descriptor); + } + } + + public void OnForwardInteractionPath(PhysicalAddress macAddress, _0xad_ForwardInteractionPathDescriptor descriptor) + { + foreach (_0xad_ForwardInteractionPathDescriptor.ForwardInteractionPath forwardInteractionPath in descriptor.Paths) + { + if (!DataStorage.TestForTimForwardInteractionPath(macAddress, forwardInteractionPath)) + { + LogEvent(SkyscraperContextEvent.TimForwardInteractionPath, String.Format("For participant {0}: {1}", macAddress, forwardInteractionPath.ToString())); + DataStorage.InsertTimForwardInteractionPath(macAddress, forwardInteractionPath); + } + } + } + + public void OnCorrectionMessage(PhysicalAddress mac, _0xa1_CorrectionMessageDescriptor cmd) + { + if (!DataStorage.TestForTim(mac)) + { + LogEvent(SkyscraperContextEvent.Tim, String.Format("for participant {0}", mac.ToString())); + DataStorage.CreateTim(mac); + } + if (DataStorage.CorrectTim(mac, cmd)) + { + LogEvent(SkyscraperContextEvent.TimCorrection, String.Format("for participant {0}", mac.ToString())); + } + } + + public void OnContentionControl(PhysicalAddress mac, _0xab_ContentionControlDescriptor ccdNew) + { + if (!DataStorage.TestForTim(mac)) + { + LogEvent(SkyscraperContextEvent.Tim, String.Format("for participant {0}", mac.ToString())); + DataStorage.CreateTim(mac); + } + if (DataStorage.ContentionTim(mac,ccdNew)) + { + LogEvent(SkyscraperContextEvent.TimContentionControl, String.Format("for participant {0}", mac.ToString())); + } + } + + public void OnCorrectionControl(PhysicalAddress mac, _0xac_CorrectionControlDescriptor descriptor) + { + if (!DataStorage.TestForTim(mac)) + { + LogEvent(SkyscraperContextEvent.Tim, String.Format("for participant {0}", mac.ToString())); + DataStorage.CreateTim(mac); + } + if (DataStorage.CorrectionControlTim(mac,descriptor)) + { + LogEvent(SkyscraperContextEvent.TimCorrectionControl, String.Format("for participant {0}", mac.ToString())); + } + } + + private List networkLayerInfos; + public void OnNetworkLayerInfo(PhysicalAddress mac, _0xa0_NetworkLayerInfoDescriptor nlid) + { + if (currentTimeForTim == null) + return; + if (!DataStorage.TestForTim(mac)) + { + LogEvent(SkyscraperContextEvent.Tim, String.Format("for participant {0}", mac.ToString())); + DataStorage.CreateTim(mac); + } + if (DataStorage.NetworkLayerInfoTim(mac,nlid,currentTimeForTim.Value)) + { + if (networkLayerInfos == null) + networkLayerInfos = new List(); + if (!networkLayerInfos.Contains(mac)) + { + LogEvent(SkyscraperContextEvent.TimNetworkLayerInfo, String.Format("for participant {0}", mac.ToString())); + networkLayerInfos.Add(mac); + } + } + } + + void InteractionChannelHandler.OnTransmissionModeSupport(ushort interactiveNetworkId, Tmst tmst) + { + byte[] knownTmst = DataStorage.GetTmst(interactiveNetworkId); + if (knownTmst == null) + { + LogEvent(SkyscraperContextEvent.TransmissionModeSupport, String.Format("Network ID = {0}, Modes = {1}", interactiveNetworkId, BitConverter.ToString(tmst.Modes))); + DataStorage.InsertTmst(interactiveNetworkId, tmst.Modes); + } + else if (Array.Equals(knownTmst,tmst.Modes)) + { + LogEvent(SkyscraperContextEvent.TransmissionModeUpdate,String.Format("Network ID = {0}, Old Modes = {2}, New Modes = {1}", interactiveNetworkId, BitConverter.ToString(tmst.Modes), BitConverter.ToString(knownTmst))); + DataStorage.UpdateTmst(interactiveNetworkId, tmst.Modes); + } + } + + public int GetRmtTransmissionStandard(ushort networkId) + { + return DataStorage.GetRmtTransmissionStandard(networkId); + } + + public void AutodetectionRuleOut(int pid, Contestant contestant, ProgramContext programContext) + { + //LogEvent(SkyscraperContextEvent.StreamTypeAutodetection, String.Format("PID 0x{0:X4} probably isn't a {1}", pid, contestant.Tag)); + } + + void SgtEventHandler.AnnounceSgtList(SgtList list) + { + if (!DataStorage.TestForSgtList(list)) + { + LogEvent(SkyscraperContextEvent.SgtList, String.Format("List #{0} ({1})", list.ServiceListId, list.GetName())); + DataStorage.InsertSgtList(list); + } + } + + void SgtEventHandler.OnSgtError(SgtError invalidTableId) + { + throw new NotImplementedException(); + } + + void SgtEventHandler.OnSgtService(SgtService child) + { + if (!DataStorage.TestForSgtService(child)) + { + LogEvent(SkyscraperContextEvent.SgtService, String.Format("LCN #{0} in List #{1} ({2})", child.Lcn, child.ServiceListId, child.GetName())); + DataStorage.InsertSgtService(child); + } + } + + public void ProcessVirtualFilesystem(IFilesystem vfs, ProgramMappingStream programMappingStream) + { + yo3explorerToSkyscraperContextBridge context = new yo3explorerToSkyscraperContextBridge(); + context.DataStorage = DataStorage; + if (!currentTime.HasValue) + return; + context.CurrentTime = currentTime.Value; + context.Source = ServiceListEntryPointSource.TransportStream; + context.OriginalNetworkId = CurrentNetworkId; + context.TransportStreamId = CurrentTransportStreamId; + context.PID = programMappingStream.ElementaryPid; + + yo3explorerState state = yo3explorerState.GetInstance(); + + PluginManager pluginManager = PluginManager.GetInstance(); + IReadOnlyList processors = pluginManager.GetFilesystemProcessors(); + + foreach(FilesystemProcessorPlugin processor in processors) + { + processor.ProcessFilesystem(vfs, context, state); + } + } + + public void FluteFileArrival(NipActualCarrierInformation carrier, FluteListener listener) + { + Stream stream = listener.ToStream(); + bool isMime = DvbNipUtilities.IsMime(stream); + if (isMime) + { + MimeMessage message = MimeMessage.Load(stream); + foreach (MimeEntity entity in message.BodyParts) + { + MimePart bodyPart = entity as MimePart; + if (bodyPart.ContentLocation == null) + continue; + + FluteListenerMime fluteListener = new FluteListenerMime(listener.DestinationAddress, listener.DestinationPort, listener.DestinationTsi, listener.DestinationToi); + fluteListener.FileAssociation = new FileType(); + fluteListener.FileAssociation.ContentLocation = bodyPart.ContentLocation.ToString(); + fluteListener.FileAssociation.ContentType = bodyPart.ContentType.MimeType; + fluteListener.FileAssociation.ContentEncoding = null; + fluteListener.WrappedStream = new MemoryStream(); + bodyPart.Content.DecodeTo(fluteListener.WrappedStream); + fluteListener.FileAssociation.ContentLength = (ulong)fluteListener.WrappedStream.Position; + fluteListener.FileAssociation.TransferLength = (ulong)fluteListener.WrappedStream.Position; + fluteListener.FileAssociation.TransferLengthSpecified = true; + fluteListener.WrappedStream.Position = 0; + + FluteFileArrival(carrier, fluteListener); + } + return; + } + + string extension = Path.GetExtension(listener.FileAssociation.ContentLocation).ToLowerInvariant(); + if (!DvbNipUtilities.IsContinuousFileType(extension)) + LogEvent(SkyscraperContextEvent.FluteFileArrival, listener.FileAssociation.ContentLocation); + else + { + IPEndPoint ep = new IPEndPoint(listener.DestinationAddress, listener.DestinationPort); + if (!knownNipSegments.ContainsKey(ep)) + knownNipSegments[ep] = new List(); + knownNipSegments[ep].Add(listener.FileAssociation.ContentLocation); + } + + if (extension.Equals(".m4s")) + { + listener = DvbNipUtilities.PatchMpegDashSegment(listener); + } + + ObjectStorage.DvbNipFileArrival(carrier, listener); + } + + public void OnMulticastGatewayConfiguration(NipActualCarrierInformation carrier, MulticastGatewayConfigurationType multicastGatewayConfiguration) + { + if (multicastGatewayConfiguration.MulticastSession != null) + { + foreach (MulticastSessionType multicastSession in multicastGatewayConfiguration.MulticastSession) + { + if (!DataStorage.DvbNipTestForMulticastSession(multicastSession)) + { + LogEvent(SkyscraperContextEvent.DvbNipMulticastSession, multicastSession.serviceIdentifier); + DataStorage.DvbNipInsertMulticastSession(multicastSession); + } + } + } + + if (multicastGatewayConfiguration.MulticastGatewayConfigurationTransportSession != null) + { + foreach (MulticastGatewayConfigurationTransportSessionType multicastGatewayConfigurationTransportSession in multicastGatewayConfiguration.MulticastGatewayConfigurationTransportSession) + { + if (multicastGatewayConfigurationTransportSession.EndpointAddress == null) + continue; + + MulticastEndpointAddressType endpointAddress = multicastGatewayConfigurationTransportSession.EndpointAddress[0]; + if (!DataStorage.DvbNipTestForMulticastGatewayConfigurationTransportSession(carrier, endpointAddress)) + { + string name = String.Format("{0} -> {1}:{2}, TSI = {3}", endpointAddress.NetworkSourceAddress, + endpointAddress.NetworkDestinationGroupAddress, endpointAddress.TransportDestinationPort, + endpointAddress.MediaTransportSessionIdentifier); + LogEvent(SkyscraperContextEvent.DvbNipMulticastGatewayConfigurationTransportSession, name); + DataStorage.DvbNipInsertMulticastGatewayConfigurationTransportSession(carrier, endpointAddress); + } + } + } + + if (multicastGatewayConfiguration.MulticastGatewaySessionReporting != null) + { + throw new NotImplementedException(nameof(multicastGatewayConfiguration.MulticastGatewaySessionReporting)); + } + } + + public void OnNipCarrierDetected(NipActualCarrierInformation currentCarrierInformation) + { + LogEvent(SkyscraperContextEvent.NipCarrierDetected, String.Format("{0}", currentCarrierInformation.NipStreamProviderName)); + if (!DataStorage.DvbNipTestForCarrier(currentCarrierInformation)) + { + DataStorage.DvbNipInsertCarrier(currentCarrierInformation); + } + } + + public bool IsFileNeeded(string announcedFileContentLocation) + { + if (announcedFileContentLocation.StartsWith("urn:dvb")) + return true; + + return !ObjectStorage.DvbNipTestForFile(announcedFileContentLocation); + } + + public void OnPrivateDataSignallingManifest(NipActualCarrierInformation currentCarrierInformation, PrivateDataSignallingManifestType privateDataSignallingManifest) + { + foreach (PrivateDataProviderType privateDataProvider in privateDataSignallingManifest.PrivateDataProvider) + { + privateDataProvider.privateDataProviderID.FlipEndian(); + uint privateDataSpecifier = BitConverter.ToUInt32(privateDataProvider.privateDataProviderID); + List privateDataSessions = privateDataProvider.PrivateDataSession.SelectMany(x => x.TagRef).ToList(); + bool added = DataStorage.DvbNipPrivateDataSpecifier(currentCarrierInformation, privateDataSignallingManifest.VersionUpdate, privateDataSpecifier, privateDataSessions); + if (added) + { + LogEvent(SkyscraperContextEvent.NipPrivateDataSpecifier, String.Format("{0} -> {1}", currentCarrierInformation.NipStreamProviderName, privateDataSpecifier)); + } + } + } + + public void OnServiceListEntryPoints(NipActualCarrierInformation currentCarrierInformation, ServiceListEntryPoints serviceListEntryPoints, DateTime dvbNipTime, DvbNipServiceListNotifier serviceListNotifier) + { + long sourceHash = DvbIUtils.GetSourceHash(ServiceListEntryPointSource.DvbNip, currentCarrierInformation.NipNetworkId, currentCarrierInformation.NipCarrierId, currentCarrierInformation.NipLinkId); + serviceListNotifier.SetSourceHash(sourceHash); + DvbIDataStorage dataStorage = DataStorage; + + if (dataStorage.TestForDvbiServiceListEntryPoints(sourceHash)) + { + DateTime lastChecked = dataStorage.GetLastDvbiServiceListEntryPointUpdateDate(sourceHash); + TimeSpan sinceLastChecked = dvbNipTime - lastChecked; + if (sinceLastChecked.TotalDays < 1.0) + return; + } + else + { + logger.InfoFormat("New DVB-I Service List Entry Point: {0}", currentCarrierInformation.NipStreamProviderName); + dataStorage.InsertDvbiServiceListEntryPoint(sourceHash); + } + + IEnumerable enumerable = DvbIUtils.FlattenServiceListEntryPoints(serviceListEntryPoints); + foreach (DvbiServiceList serviceList in enumerable) + { + DateTime serviceListLastChecked; + if (dataStorage.TestForDvbiServiceList(serviceList.Id)) + { + serviceListLastChecked = dataStorage.GetDvbiServiceListLastUpdateDate(serviceList.Id); + } + else + { + logger.InfoFormat("New DVB-I Service List: {0}", serviceList.Name); + dataStorage.InsertDvbiServiceList(serviceList); + dataStorage.AddDvbiServiceListToServiceListEntryPoint(serviceList, sourceHash); + serviceListLastChecked = new DateTime(1970, 1, 1); + } + + TimeSpan sinceLastServiceListCheck = dvbNipTime - serviceListLastChecked; + if (sinceLastServiceListCheck.TotalDays < 1.0) + continue; + + serviceListNotifier.AddServiceListUrl(serviceList.URI, serviceList.Id); + /*if (vfs.FileExists(serviceList.URI)) + { + byte[] serviceListBytes = vfs.GetFile(serviceList.URI); + ServiceListType serviceListData = DvbIUtils.UnpackServiceList(serviceListBytes); + HandleServiceList(serviceListData, dataStorage, serviceList.Id); + dataStorage.UpdateDvbiServiceListLastCheckedDate(serviceList.Id, context.CurrentTime); + }*/ + } + + dataStorage.UpdateDvbiServiceListEntryPointUpdateDate(sourceHash, dvbNipTime); + } + + public void OnServiceList(NipActualCarrierInformation currentCarrierInformation, string serviceListId, + ServiceListType serviceList) + { + List services = DvbIUtils.FlattenServiceList(serviceList).ToList(); + DvbIDataStorage dataStorage = DataStorage; + foreach (DvbIService service in services) + { + if (dataStorage.TestForDvbiService(service.Id)) + { + int versionInDb = dataStorage.GetDvbiServiceVersion(service.Id); + if (service.Version > versionInDb) + { + dataStorage.UpdateDvbiService(service); + } + } + else + { + logger.InfoFormat("New DVB-I Service: {0}", service.ServiceName); + dataStorage.InsertDvbiService(service); + dataStorage.AddDvbiServiceToServiceList(service.Id, serviceListId); + } + } + } + + public void OnTimeOffsetFile(NipActualCarrierInformation currentCarrierInformation, TimeOffsetFileType timeOffsetFile) + { + if (timeOffsetFile.time_of_change != DateTime.MinValue) + { + throw new NotImplementedException(); + } + } + + public void OnNetworkInformationFile(NipActualCarrierInformation currentCarrierInformation, NetworkInformationFileType networkInformationFile) + { + List broadcastNetworks = new List(); + if (networkInformationFile.ActualBroadcastNetwork != null) + broadcastNetworks.Add(networkInformationFile.ActualBroadcastNetwork); + if (networkInformationFile.OtherBroadcastNetwork != null) + broadcastNetworks.AddRange(networkInformationFile.OtherBroadcastNetwork); + + foreach (BroadcastNetworkType network in broadcastNetworks) + { + if (!DataStorage.DvbNipTestForNetwork(network)) + { + LogEvent(SkyscraperContextEvent.DvbNipNetwork, network.NetworkName); + DataStorage.DvbNipInsertNetwork(network); + } + } + } + + public void OnServiceInformationFile(NipActualCarrierInformation currentCarrierInformation, ServiceInformationFileType serviceInformationFile) + { + foreach (BroadcastMediaStreamType broadcastMediaStreamType in serviceInformationFile.BroadcastMediaStream) + { + if (!DataStorage.DvbNipTestForService(broadcastMediaStreamType)) + { + string id = String.Format("{0},{1},{2},{3}", broadcastMediaStreamType.NIPNetworkID, + broadcastMediaStreamType.NIPCarrierID, broadcastMediaStreamType.NIPLinkID, + broadcastMediaStreamType.NIPServiceID); + LogEvent(SkyscraperContextEvent.DvbNipService, id); + DataStorage.DvbNipInsertService(broadcastMediaStreamType); + } + } + } + + private Dictionary> knownNipSegments; + private HashSet knownUrls; + public void FluteFileAnnouncement(IPAddress ip, ushort port, FDTInstanceType flute) + { + if (knownUrls == null) + { + knownUrls = new HashSet(); + knownNipSegments = new Dictionary>(); + } + + string url = flute.File[0].ContentLocation; + if (knownUrls.Contains(url)) + return; + + LogEvent(SkyscraperContextEvent.FluteFileAnnouncement, String.Format("{0}:{1} -> {2}", ip.ToString(), port, url)); + knownUrls.Add(url); + + IPEndPoint ep = new IPEndPoint(ip, port); + if (!knownNipSegments.ContainsKey(ep)) + knownNipSegments[ep] = new List(); + knownNipSegments[ep].Add(url); + } + + public void FluteFileDownloadProgress(NipActualCarrierInformation currentCarrierInformation, ulong destinationTsi, ulong destinationToi, double progress, FileType filetype) + { + if (filetype != null) + { + if (!filetype.ContentLocation.Equals("urn:dvb:metadata:cs:NativeIPMulticastTransportObjectTypeCS:2023:bootstrap")) + { + string extension = Path.GetExtension(filetype.ContentLocation).ToLowerInvariant(); + if (!DvbNipUtilities.IsContinuousFileType(extension)) + { + LogEvent(SkyscraperContextEvent.FluteFileProgress, + String.Format("Filename={0}, {1}%", filetype.ContentLocation, progress)); + } + } + } + } + + private List _pluginContexts; + + public List PluginContext + { + get + { + if (_pluginContexts == null) + _pluginContexts = new List(); + + return _pluginContexts; + } + } + + public void OnPluginEvent() + { + lastEventTimestamp = DateTime.Now; + } + + public void OnEthernetFrame(int pid, PhysicalAddress destination, PhysicalAddress source, ushort etherType, byte[] contents) + { + if (Array.TrueForAll(contents, x => x == 0)) + return; + if (etherType <= 1500) + { + OnLlcFrame(etherType, contents); + return; + } + switch (etherType) + { + case 0x0800: + OnIpDatagram(pid, contents); + return; + case 0x22e3: + //This is related to G.9961, a PowerLine standard specified by ITU-T T-REC-G.9961 + //I don't think we need this. + return; + case 0x2f00: + //This is something proprietary. + //Quite possibly related to Extron hardware? + return; + case 0x0806: + //This is an ARP Frame. We don't need it. + return; + case 0x8137: + //This is an IPX Frame. We don't need it. + return; + case 0x86dd: + OnIpDatagram(pid, contents); + return; + case 0x88e1: + //This is related to FRITZ!Powerline. + //Probably very proprietary and undocumented, so I guess we'll discard it. + return; + case 0x890d: + //IEEE Std 802.11 - Fast Roaming Remote Request (802.11r) + //These seem to happen when one moves from one Wi-Fi Access Point to another. We probably don't need that one. + return; + case 0x8912: + //Related to mediaxtream, see https://de.wikipedia.org/wiki/Mediaxtream + //Probably not very interesting. + return; + case 0x9001: + //3Com(Bridge) XNS Sys Mgmt + //Can't say anything about these. I don't have any 3Com equipment. + return; + case 0x94ce: + //Something proprietary. No idea. + return; + case 0xb69d: + //Something proprietary. No idea. + return; + case 0xf67f: + if (contents[20] == 0xaa && contents[21] == 0xaa && contents[22] == 0x03 && contents[23] == 0x00 && contents[24] == 0x00 && contents[25] == 0x00) + { + (contents[26], contents[27]) = (contents[27], contents[26]); + ushort newEtherType = BitConverter.ToUInt16(contents, 26); + byte[] newPacket = new byte[contents.Length - 28]; + Array.Copy(contents, 28, newPacket, 0, newPacket.Length); + OnEthernetFrame(pid, destination, source, newEtherType, newPacket); + } + return; + case 0x94ad: + //Something proprietary. No idea. + return; + case 0x4957: + //Something proprietary. No idea. + return; + case 0x3e30: + //Something proprietary. No idea. + return; + case 0x88cc: + //Link Layer Discovery Protocol + LldpFrame lldpFrame = new LldpFrame(contents); + OnLldpFrame(lldpFrame); + return; + case 0x9417: + case 0xf95c: + //Unknown proprietary. + return; + default: + throw new NotImplementedException(String.Format("EtherType: 0x{0:X4}", etherType)); + } + } + + public void OnUleError(int pid, int errorNo) + { + throw new NotImplementedException(); + } + + public void OnLlcFrame(ushort etherType, byte[] contents) + { + MemoryStream llcStream = new MemoryStream(contents, true); + byte dsap = llcStream.ReadUInt8(); + byte ssap = llcStream.ReadUInt8(); + if (dsap == 0x00 || ssap == 0x00) + { + //This is a NULL frame. It can be discarded either way. + return; + } + if (dsap == 0x42 || ssap == 0x42) + { + //This is a Spanning Tree Frame. We probably don't need it. + return; + } + if (dsap == 0xe0 || ssap == 0xe0) + { + //This is a Novell Netware Frame. We don't need to bother with it. + return; + } + + if (dsap == 0xaa || ssap == 0xaa) + { + byte snapType = llcStream.ReadUInt8(); + if (snapType == 0x03) + { + byte[] oui = llcStream.ReadBytes(3); + ushort snapProtocolId = llcStream.ReadUInt16BE(); + if (snapProtocolId == 0x809b) + { + //This is an AppleTalk Frame. We probably don't need it. + return; + } + else if (snapProtocolId == 0x8137) + { + //This is an IPX Frame. We probably don't need it. + return; + } + else if (snapProtocolId == 0x2000) + { + //This is from Cisco's Discovery Protocol (CDP). Probably not interesting. + return; + } + else + { + throw new NotImplementedException(String.Format("SNAP Frame, OUI = {0:X2}-{1:X2}-{2:X2}, Protocol ID = 0x{3:X4}", oui[0], oui[1], oui[2], snapProtocolId)); + } + } + else + { + throw new NotImplementedException(String.Format("LLC/SNAP Type 0x{0:X2}", snapType)); + } + } + + if (dsap == 0xff || ssap == 0xff) + { + ushort llcLength = llcStream.ReadUInt16BE(); + if (llcLength == etherType) + { + //TEST or XID PDU, likely unneeded. + return; + } + else if (llcLength == 40) + { + //TEST or XID PDU, likely unneeded. + return; + } + else + { + throw new NotImplementedException("LLC/SNAP (2)"); + } + } + + if (dsap == 0x09 && ssap == 0x01) + { + //Likely an LLC management packet (TEST or XID) + return; + } + throw new NotImplementedException("LLC/SNAP"); + } + + public void OnOtvSsuError(int pid, OtvSsuError offsetOutOfRange) + { + DvbContext.RegisterPacketProcessor(pid, new PacketDiscarder()); + } + + public void OnOtvSsuFileAnnouncement(int pid, ushort tableIdExtension, uint fileId, uint unknown1, uint length) + { + LogEvent(SkyscraperContextEvent.OtvSsuFileDetected, String.Format("TID = {0}, FID = {1:X8}, Length = {2}", tableIdExtension, fileId, length)); + } + + public void OnOtvSsuBlock(int pid, ushort tableIdExtension, uint fileId, uint unknown1, uint length) + { + } + + public void OnOtvSsuComplete(int sourcePid, Stream getStream, ushort tableIdExtension, uint fileId, uint unknown1, + uint length) + { + LogEvent(SkyscraperContextEvent.OtvSsuComplete, String.Format("TID = {0}, FID = {1:X8}, Length = {2}", tableIdExtension, fileId, length)); + ObjectStorage.OnOtvSsuComplete(CurrentNetworkId, CurrentTransportStreamId, sourcePid, getStream, tableIdExtension, fileId, unknown1, length); + } + + public bool OnOtvCheckFileAlreadyKnown(int sourcePid, ushort tableIdExtension, uint fileId, uint unknown1, uint length) + { + return ObjectStorage.OtvSsuTestFile(CurrentNetworkId, CurrentTransportStreamId, sourcePid, tableIdExtension, fileId, unknown1, length); + } + + public void OnNdsSsuError(int pid, NdsSsuError error) + { + } + + public void OnNdsSsuFileAnnouncement(int pid, ushort tableIdExtension) + { + LogEvent(SkyscraperContextEvent.NdsSsuFileAnnounced, String.Format("PID = 0x{1:X4}, Table ID Extension = {0}", tableIdExtension, pid)); + } + + public void OnNdsSsuFileComplete(int pid, ushort tableIdExtension, NdsSsuDataMap dataMap) + { + ObjectStorage.OnNdsSsuComplete(CurrentNetworkId, CurrentTransportStreamId, pid, tableIdExtension, dataMap); + } + + public void OnNdsSsuProgress(int pid, ushort tableIdExtension, int blocksDone, int blocksTotal, bool theresMore) + { + LogEvent(SkyscraperContextEvent.NdsSsuProgress, String.Format("PID 0x{0:X4}, File ID {1}, Blocks: {2}/{3}{4}", pid, tableIdExtension, blocksDone, blocksTotal, theresMore ? "+" : "")); + } + + public bool TestNdsSsuFileExists(int pid, ushort tableIdExtension) + { + return ObjectStorage.NdsSsuTestFile(CurrentNetworkId, CurrentTransportStreamId, pid, tableIdExtension); + } + + public void OnReturnTransmissionMOdes(PhysicalAddress macAddress, _0xb2_ReturnTransmissionModesDescriptor descriptor) + { + //TODO: Implement this. + } + + public void OnConnectionControl(PhysicalAddress macAddress, _0xaf_ConnectionControlDescriptor descriptor) + { + //TODO: Implement this. + } + + + private HashSet lldpFrames; + public void OnLldpFrame(LldpFrame frame) + { + if (lldpFrames == null) + lldpFrames = new HashSet(); + + if (lldpFrames.Add(frame)) + { + LogEvent(SkyscraperContextEvent.EthernetLinkLayerDiscovery, frame.ToString()); + } + } + + void T2MIEventHandler.OnFramingAndTimingInformation(int relatedPid, _0xF0_FramingTimingInformation fti) + { + logger.WarnFormat("Found T2MI F&TI Information on PID 0x{0:X4}. This isn't supported yet. It would be great if you could share a sample of this stream, so this can be implemented.", relatedPid); } public void OnKeyManagementResponse(PrivacyKeyManagementResponse privacyKeyManagementResponse) @@ -3354,10 +3354,10 @@ namespace skyscraper5.Skyscraper.Scraper public void OnSisDsaci(ushort currentDsaGroupId, int versionNumber, byte sectionNumber, byte lastSectionNumber, Stream dsaci) { - if (!CurrentNetworkId.HasValue) - return; - - if (!CurrentTransportStreamId.HasValue) + if (!CurrentNetworkId.HasValue) + return; + + if (!CurrentTransportStreamId.HasValue) return; if (!ObjectStorage.TestForSisDsaci(CurrentNetworkId.Value,CurrentTransportStreamId.Value, currentDsaGroupId, versionNumber)) @@ -3476,15 +3476,15 @@ namespace skyscraper5.Skyscraper.Scraper private bool[] _sisTimestampFlags; public void OnSisTimestamp(int pid, _0x20_DvbT2Timestamp t2Timestamp) { - if (!CurrentNetworkId.HasValue) - return; - - if (!CurrentTransportStreamId.HasValue) - return; - - DateTime resolveTime = t2Timestamp.ResolveTime(); - DateTime knownTimestamp = DataStorage.T2MiGetTimestamp(CurrentNetworkId.Value, CurrentTransportStreamId.Value, pid); - if (resolveTime > knownTimestamp) + if (!CurrentNetworkId.HasValue) + return; + + if (!CurrentTransportStreamId.HasValue) + return; + + DateTime resolveTime = t2Timestamp.ResolveTime(); + DateTime knownTimestamp = DataStorage.T2MiGetTimestamp(CurrentNetworkId.Value, CurrentTransportStreamId.Value, pid); + if (resolveTime > knownTimestamp) { if (_sisTimestampFlags == null) _sisTimestampFlags = new bool[0x1fff]; @@ -3494,7 +3494,7 @@ namespace skyscraper5.Skyscraper.Scraper LogEvent(SkyscraperContextEvent.DvbSisTimestamp, t2Timestamp.ResolveTime().ToString()); _sisTimestampFlags[pid] = true; } - DataStorage.T2MiSetTimestamp(CurrentNetworkId.Value, CurrentTransportStreamId.Value, pid, resolveTime); + DataStorage.T2MiSetTimestamp(CurrentNetworkId.Value, CurrentTransportStreamId.Value, pid, resolveTime); } } @@ -3506,5 +3506,5 @@ namespace skyscraper5.Skyscraper.Scraper context.OnTotTime(totContainer.UtcTime, totContainer.LocalTimeOffset); } } - } -} + } +} diff --git a/skyscraper8/VersionInfo.cs b/skyscraper8/VersionInfo.cs index 35e2afd..e968496 100644 --- a/skyscraper8/VersionInfo.cs +++ b/skyscraper8/VersionInfo.cs @@ -4,7 +4,7 @@ namespace skyscraper8; public class VersionInfo { - private const int PUBLIC_RELEASE = 16; + private const int PUBLIC_RELEASE = 17; public static int GetPublicReleaseNumber() {