diff --git a/skyscraper8.sln.DotSettings.user b/skyscraper8.sln.DotSettings.user
index 24e0a36..33fbc3f 100644
--- a/skyscraper8.sln.DotSettings.user
+++ b/skyscraper8.sln.DotSettings.user
@@ -1,3 +1,4 @@
ForceIncluded
+ ForceIncluded
<data><HostParameters type="LocalHostParameters" /><Argument type="StandaloneArgument"><Arguments IsNull="False"></Arguments><FileName IsNull="False"></FileName><WorkingDirectory IsNull="False"></WorkingDirectory><Scope><ProcessFilters /></Scope></Argument><Info type="TimelineInfo" /><CoreOptions type="CoreOptions"><CoreTempPath IsNull="False"></CoreTempPath><RemoteEndPoint IsNull="False"></RemoteEndPoint><AdditionalEnvironmentVariables /></CoreOptions><HostOptions type="HostOptions"><HostTempPath IsNull="False"></HostTempPath></HostOptions></data>
\ No newline at end of file
diff --git a/skyscraper8/GSE/BbfUdpDecap.cs b/skyscraper8/GSE/BbfUdpDecap.cs
new file mode 100644
index 0000000..dd04066
--- /dev/null
+++ b/skyscraper8/GSE/BbfUdpDecap.cs
@@ -0,0 +1,261 @@
+using System.Net;
+using System.Runtime.InteropServices;
+using skyscraper5.Skyscraper.IO;
+
+namespace skyscraper8.GSE;
+
+public class BbfUdpDecap : IBbframeDeencapsulator
+{
+ public IUdpDecapOutput Sink { get; set; }
+ public long NumPushed { get; private set; }
+
+ public void SetTargetIp(IPAddress ip)
+ {
+ HasTargetIp = ip.GetAddressBytes();
+ }
+
+ public void SetTargetPort(int tmp)
+ {
+ HasTargetPort = new byte[4];
+ HasTargetPort[0] = (byte)(tmp >> 8);
+ HasTargetPort[1] = (byte)(tmp & 0xff);
+ }
+
+ private byte? HasMis;
+ private byte[] HasSourceIp;
+ private byte[] HasTargetIp;
+ private byte[] HasSourcePort;
+ private byte[] HasTargetPort;
+
+ private byte[] inData;
+
+ [StructLayout(LayoutKind.Sequential, Pack = 1)]
+ struct bbheader
+ {
+ public byte MaType1;
+ public byte MaType2;
+ public byte Upl1;
+ public byte Upl2;
+ public byte Dfl1;
+ public byte Dfl2;
+ public byte Sync;
+ public byte SyncD1;
+ public byte SyncD2;
+ public byte Crc8;
+ }
+
+ [StructLayout(LayoutKind.Sequential, Pack = 1)]
+ unsafe struct Layer3
+ {
+ public byte l3sync;
+ public bbheader header;
+ public fixed byte Data[7254-10];
+ }
+ public unsafe void PushPacket(byte[] bbframe)
+ {
+ NumPushed++;
+
+ if (inData == null)
+ {
+ inData = new byte[8100];
+ }
+
+ if (fragmentor == null)
+ {
+ fragmentor = new byte[256][];
+ fragmentorLength = new int[256];
+ fragmentorPos = new int[256];
+ }
+ MemoryStream inbuf = new MemoryStream(bbframe);
+ Layer3 myLayer;
+ while (true)
+ {
+ if (inbuf.Peek() == 0xb8)
+ break;
+ inbuf.ReadByte();
+ }
+
+ while (true)
+ {
+ int fail = inbuf.Read(inData, 0, 11);
+ if (fail != 11)
+ break;
+ myLayer = MemoryMarshal.Read(inData);
+ if (myLayer.l3sync != 0xb8)
+ {
+ while (true)
+ {
+ if (inbuf.Peek() == 0xb8)
+ break;
+ fail = inbuf.Read(inData, 0, 1);
+ if (fail != 1)
+ break;
+ }
+ }
+
+ int bblength = myLayer.header.Dfl1 << 8 | myLayer.header.Dfl2;
+ bblength >>= 3;
+ fail = inbuf.Read(inData, 11, bblength);
+ if (fail != bblength)
+ break;
+ myLayer = MemoryMarshal.Read(inData);
+ if (HasMis.HasValue && (myLayer.header.MaType2 != HasMis.Value))
+ continue;
+
+ int pos = 0;
+ while (pos < bblength - 4)
+ {
+ int gseLength = ((myLayer.Data[pos] & 0x0f) << 8) | (myLayer.Data[pos + 1]);
+ if ((myLayer.Data[pos] & 0xf0) == 0) break;
+ if (gseLength + 2 > bblength - pos) break;
+ if (!ProcessBbFrame(&myLayer.Data[pos], gseLength))
+ break;
+ pos += gseLength += 2;
+ }
+ }
+ }
+
+ private byte[][] fragmentor;
+ private int[] fragmentorLength;
+ private int[] fragmentorPos;
+
+ private unsafe void Copy(byte* src, byte[] dst, int srcOffset, int dstOffset, int len)
+ {
+ for (int i = 0; i < len; i++)
+ {
+ dst[dstOffset + i] = src[srcOffset + i];
+ }
+ }
+ private unsafe bool ProcessBbFrame(byte* payload, int gseLength)
+ {
+ uint offset = 0;
+ uint fragId = 0;
+
+ if ((payload[0] & 0xc0) == 0x80)
+ {
+ fragId = payload[2];
+ int length=(payload[3]<<8) | payload[4];
+ if(fragmentor[fragId]!=null)
+ fragmentor[fragId] = null;
+ fragmentor[fragId] = new byte[length + 2];
+ fragmentorLength[fragId] = length + 2;
+ fragmentor[fragId][0] = payload[0];
+ fragmentor[fragId][1] = payload[1];
+ fragmentor[fragId][0] |= 0xc0;
+ Copy(payload, fragmentor[fragId], 5, 2, gseLength - 3);
+ fragmentorPos[fragId] = gseLength - 1;
+ }
+ else if ((payload[0] & 0xc0) == 0x00)
+ {
+ throw new NotImplementedException("inbetween packet");
+ }
+ else if ((payload[0] & 0xc0) == 0x40)
+ {
+ fragId = payload[2];
+ if (fragmentor[fragId] == null)
+ return true;
+
+ Copy(payload, fragmentor[fragId], 3, fragmentorPos[fragId], gseLength - 5);
+ fragmentorPos[fragId] += gseLength - 1;
+ fixed (byte* p = fragmentor[fragId])
+ {
+ ProcessBbFrame(p, fragmentorLength[fragId]);
+ }
+ fragmentor[fragId] = null;
+
+ }
+ else if ((payload[0] & 0xc0) == 0xc0)
+ {
+ if (payload[offset + 2] == 0x00 && payload[offset + 3] == 0x04)
+ {
+ throw new NotImplementedException("ethertype 0x0400");
+ }
+ else if (payload[offset + 2] == 0x00 && payload[offset + 3] == 0x00)
+ {
+ throw new NotImplementedException("ethertype 0x0000");
+ }
+ else if (payload[offset + 2] == 0x08 && payload[offset + 3] == 0x00)
+ {
+ if((payload[0]&0x30)==0x01) {
+ offset += 3; //3-byte label
+ }
+ else if((payload[0] & 0x30) == 0x00) {
+ offset += 6; //MAC address
+ }
+
+ offset += 0x10; //IPv4 header
+ if (IsSelected(&payload[offset]))
+ {
+ offset += 0x10;
+ }
+ else
+ {
+ return true;
+ }
+
+ long sinkSize = gseLength + 2 -offset;
+ byte[] sinkMe = new byte[sinkSize];
+ Copy(payload,sinkMe,(int)offset,0, sinkMe.Length);
+ Sink.Write(sinkMe);
+ return true;
+ }
+
+ //throw new NotImplementedException("complete packet");
+ }
+ else if ((payload[0] & 0x0f0) == 0x00)
+ {
+ throw new NotImplementedException("padding packet");
+ }
+ return true;
+ }
+
+ private unsafe bool IsSelected(byte* buf)
+ {
+ byte zero = buf[0];
+ byte one = buf[1];
+ byte two = buf[2];
+ byte three = buf[3];
+ byte four = buf[4];
+ byte five = buf[5];
+ byte six = buf[6];
+ byte seven = buf[7];
+
+ if(HasSourceIp != null && (!(zero==HasSourceIp[0] && one==HasSourceIp[1] && two==HasSourceIp[2] && three==HasSourceIp[3])))
+ return false;
+ if(HasTargetIp != null && (!(four==HasTargetIp[0] && five==HasTargetIp[1] && six==HasTargetIp[2] && seven==HasTargetIp[3])))
+ return false;
+ if(HasSourcePort != null &&(!(buf[0x8]==HasSourcePort[0] && buf[0x9]==HasSourcePort[1])))
+ return false;
+ if(HasTargetPort != null &&(!(buf[0xa]==HasTargetPort[0] && buf[0xb]==HasTargetPort[1])))
+ return false;
+ return true;
+ }
+
+ public interface IUdpDecapOutput
+ {
+ public void Write(byte[] buffer);
+ }
+
+ internal class UdpDecapFileOutput : IUdpDecapOutput
+ {
+ public UdpDecapFileOutput(FileInfo file)
+ {
+ file.Directory.EnsureExists();
+ ourStream = file.OpenWrite();
+ }
+
+ private FileStream ourStream;
+
+ public void Write(byte[] udpPacket)
+ {
+ ourStream.Write(udpPacket, 0, udpPacket.Length);
+ }
+
+ public void Dispose()
+ {
+ ourStream.Flush();
+ ourStream.Close();
+ ourStream.Dispose();
+ }
+ }
+}
\ No newline at end of file
diff --git a/skyscraper8/GSE/Pts2Bbf.cs b/skyscraper8/GSE/Pts2Bbf.cs
index 60dd0a3..3996159 100644
--- a/skyscraper8/GSE/Pts2Bbf.cs
+++ b/skyscraper8/GSE/Pts2Bbf.cs
@@ -1,3 +1,4 @@
+using System.Net;
using log4net;
using skyscraper5.Mpeg2;
using skyscraper5.Skyscraper.Scraper;
@@ -10,7 +11,7 @@ public class Pts2Bbf
{
private static readonly ILog logger = LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType.Name);
- public static void Run(FileInfo file)
+ public static void Run(FileInfo file, bool useUdpDecap = false)
{
if (!file.Exists)
{
@@ -18,8 +19,23 @@ public class Pts2Bbf
return;
}
- string changeExtension = Path.ChangeExtension(file.FullName, ".sbbf");
- BbframeDumper dumper = new BbframeDumper(new FileInfo(changeExtension));
+ IBbframeDeencapsulator dumper;
+ if (useUdpDecap)
+ {
+ string changeExtension = Path.ChangeExtension(file.FullName, ".sdecap");
+ BbfUdpDecap.UdpDecapFileOutput udpDecapSink = new BbfUdpDecap.UdpDecapFileOutput(new FileInfo(changeExtension));
+
+ BbfUdpDecap bbfUdpDecap = new BbfUdpDecap();
+ bbfUdpDecap.SetTargetPort(1234);
+ bbfUdpDecap.SetTargetIp(IPAddress.Parse("239.199.2.1"));
+ bbfUdpDecap.Sink = udpDecapSink;
+ dumper = bbfUdpDecap;
+ }
+ else
+ {
+ string changeExtension = Path.ChangeExtension(file.FullName, ".sbbf");
+ dumper = new BbframeDumper(new FileInfo(changeExtension));
+ }
FileStream fileStream = file.OpenRead();
diff --git a/skyscraper8/Program.cs b/skyscraper8/Program.cs
index 0b42bd6..c4dfb54 100644
--- a/skyscraper8/Program.cs
+++ b/skyscraper8/Program.cs
@@ -310,9 +310,18 @@ namespace skyscraper5
if (args[0].ToLowerInvariant().Equals("pts2bbf"))
{
- FileInfo fi = new FileInfo(args[1]);
- Pts2Bbf.Run(fi);
- return;
+ if (args[1].ToLowerInvariant().Equals("bbfudpdecap"))
+ {
+ FileInfo fi = new FileInfo(args[2]);
+ Pts2Bbf.Run(fi, true);
+ return;
+ }
+ else
+ {
+ FileInfo fi = new FileInfo(args[1]);
+ Pts2Bbf.Run(fi, false);
+ return;
+ }
}
}
diff --git a/skyscraper8/Skyscraper/IO/StreamExtensions.cs b/skyscraper8/Skyscraper/IO/StreamExtensions.cs
index 9b7b93c..97a04fa 100644
--- a/skyscraper8/Skyscraper/IO/StreamExtensions.cs
+++ b/skyscraper8/Skyscraper/IO/StreamExtensions.cs
@@ -322,5 +322,16 @@ namespace skyscraper5.Skyscraper.IO
stream.Write(buffer, 0, 8);
}
+ public static byte Peek(this Stream stream)
+ {
+ if (!stream.CanSeek)
+ throw new NotSupportedException("Stream is not peekable");
+ if (stream.Position == stream.Length)
+ throw new EndOfStreamException();
+
+ byte readUInt8 = stream.ReadUInt8();
+ stream.Position--;
+ return readUInt8;
+ }
}
}
diff --git a/skyscraper8/skyscraper8.csproj b/skyscraper8/skyscraper8.csproj
index dc8b3e8..5ee6e44 100644
--- a/skyscraper8/skyscraper8.csproj
+++ b/skyscraper8/skyscraper8.csproj
@@ -13,11 +13,13 @@
False
False
+ true
False
False
+ true