stream ciphers do not work with udp FOOL
goon
This commit is contained in:
parent
ccc7ea5b25
commit
b49acd08d4
17 changed files with 295 additions and 113 deletions
29
protocol.md
29
protocol.md
|
@ -322,13 +322,32 @@ Communication between the master server and clients will be done over a WebSocke
|
|||
</thead>
|
||||
<tr>
|
||||
<td class="center">1</td>
|
||||
<td>Succeeded</td>
|
||||
<td>Boolean</td>
|
||||
<td>Server Count (<i>n</i>)</td>
|
||||
<td>Packed Unsigned Short</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="center">2</td>
|
||||
<td>Message</td>
|
||||
<td>String</td>
|
||||
<td><i>r</i> > 1</td>
|
||||
<td colspan="2">Iterated over <i>n</i> (0 ≤ <i>i</i> ≤ <i>n - 1</i>)</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="center">2 + 4<i>i</i></td>
|
||||
<td>Server Id</td>
|
||||
<td>Packed Unsigned Short</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="center">3 + 4<i>i</i></td>
|
||||
<td>User Count</td>
|
||||
<td>Packed Unsigned Short</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="center">4 + 4<i>i</i></td>
|
||||
<td>IP Address</td>
|
||||
<td>IPv4 String</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="center">5 + 4<i>i</i></td>
|
||||
<td>Port</td>
|
||||
<td>Packed Unsigned Short</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
|
|
|
@ -21,6 +21,7 @@ namespace SockScape {
|
|||
"Master Port",
|
||||
"Master Addr",
|
||||
"Master Secret",
|
||||
"Master IV",
|
||||
"Max Users"
|
||||
}
|
||||
},
|
||||
|
|
70
server/Encryption/BlockCipher.cs
Normal file
70
server/Encryption/BlockCipher.cs
Normal file
|
@ -0,0 +1,70 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Numerics;
|
||||
using System.Security.Cryptography;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using Glove;
|
||||
|
||||
namespace SockScape.Encryption {
|
||||
class BlockCipher {
|
||||
public const int KeySize = 192;
|
||||
public const int KeySizeBytes = KeySize / 8;
|
||||
|
||||
private readonly byte[] Key = new byte[KeySizeBytes];
|
||||
private readonly byte[] IV;
|
||||
|
||||
public BlockCipher(BigInteger key) {
|
||||
Key = Key.Select(x => (byte)0).ToArray();
|
||||
Array.Copy(key.ToByteArray(), Key, Key.Length);
|
||||
|
||||
IV = Configuration.General["Master IV"].Str.HexStringToBytes()
|
||||
?? new byte[] { 0x0b, 0xfc, 0xd7, 0x2d, 0x23, 0xb7, 0x83, 0xb2 };
|
||||
}
|
||||
|
||||
public byte[] Encrypt(byte[] data) {
|
||||
try {
|
||||
var ms = new MemoryStream();
|
||||
var cs = new CryptoStream(ms,
|
||||
new TripleDESCryptoServiceProvider().CreateEncryptor(Key, IV),
|
||||
CryptoStreamMode.Write);
|
||||
|
||||
cs.Write(data, 0, data.Length);
|
||||
cs.FlushFinalBlock();
|
||||
|
||||
byte[] ret = ms.ToArray();
|
||||
|
||||
cs.Close();
|
||||
ms.Close();
|
||||
|
||||
return ret;
|
||||
} catch(Exception e) {
|
||||
Console.WriteLine($"TDES ENCRYPT ERROR: {e.Message}");
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public byte[] Decrypt(byte[] data) {
|
||||
try {
|
||||
var ms = new MemoryStream(data);
|
||||
var cs = new CryptoStream(ms,
|
||||
new TripleDESCryptoServiceProvider().CreateEncryptor(Key, IV),
|
||||
CryptoStreamMode.Read);
|
||||
|
||||
byte[] ret = new byte[data.Length];
|
||||
cs.Read(ret, 0, data.Length);
|
||||
|
||||
cs.Close();
|
||||
ms.Close();
|
||||
|
||||
return ret;
|
||||
} catch(Exception e) {
|
||||
Console.WriteLine($"TDES DECRYPT ERROR: {e.Message}");
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -6,10 +6,14 @@ using System.Threading.Tasks;
|
|||
using System.Numerics;
|
||||
using Glove;
|
||||
using System.Globalization;
|
||||
using System.Security.Cryptography;
|
||||
|
||||
namespace SockScape.Encryption {
|
||||
class Key {
|
||||
private static readonly BigInteger Secret = RNG.NextPrime(512 / 8);
|
||||
public const int KeySize = 512;
|
||||
public const int KeySizeBytes = KeySize / 8;
|
||||
|
||||
private static readonly BigInteger Secret = RNG.NextPrime(KeySizeBytes);
|
||||
public BigInteger Generator { get; } = 2;
|
||||
public BigInteger Modulus { get; }
|
||||
public BigInteger PrivateKey { get; private set; } = BigInteger.Zero;
|
||||
|
@ -17,7 +21,7 @@ namespace SockScape.Encryption {
|
|||
=> !PrivateKey.IsZero;
|
||||
|
||||
public Key() {
|
||||
Modulus = RNG.NextPrime(512 / 8);
|
||||
Modulus = RNG.NextPrime(KeySizeBytes);
|
||||
}
|
||||
|
||||
public Packet GenerateRequestPacket() {
|
||||
|
|
|
@ -7,11 +7,11 @@ using System.Numerics;
|
|||
using Glove;
|
||||
|
||||
namespace SockScape.Encryption {
|
||||
class Cipher {
|
||||
private readonly byte[] Key = new byte[512 / 8];
|
||||
class StreamCipher {
|
||||
private readonly byte[] Key = new byte[Encryption.Key.KeySizeBytes];
|
||||
private readonly byte[] State = new byte[256];
|
||||
|
||||
public Cipher(BigInteger key) {
|
||||
public StreamCipher(BigInteger key) {
|
||||
int i = 0, j = 0;
|
||||
State = State.Select(x => (byte)i++).ToArray();
|
||||
Key = Key.Select(x => (byte)0).ToArray();
|
|
@ -14,10 +14,20 @@ using MySql.Data.Entity;
|
|||
|
||||
namespace SockScape {
|
||||
static class ServerContext {
|
||||
public static Dictionary<int, Server<PlayerConnection>> Servers { get; }
|
||||
= new Dictionary<int, Server<PlayerConnection>>();
|
||||
public static Dictionary<int, Pool<PlayerConnection>> Pools { get; }
|
||||
= new Dictionary<int, Pool<PlayerConnection>>();
|
||||
public static Dictionary<ushort, Server<PlayerConnection>> Servers { get; }
|
||||
= new Dictionary<ushort, Server<PlayerConnection>>();
|
||||
public static Dictionary<ushort, Pool<PlayerConnection>> Pools { get; }
|
||||
= new Dictionary<ushort, Pool<PlayerConnection>>();
|
||||
|
||||
public static Packet StatusUpdatePacket {
|
||||
get {
|
||||
var packet = new Packet(kIntraSlaveId.StatusUpdate, (byte)Servers.Count);
|
||||
foreach(var pool in Pools)
|
||||
packet.AddRegions(pool.Key.Pack(), ((ushort)pool.Value.ConnectionCount).Pack(), Servers[pool.Key].Port.Pack());
|
||||
|
||||
return packet;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class Entrypoint {
|
||||
|
@ -33,8 +43,8 @@ namespace SockScape {
|
|||
|
||||
var serverHandle = new Server<PlayerConnection>((ushort)server["Port"], pool, server);
|
||||
|
||||
ServerContext.Pools.Add(server["Id"], pool);
|
||||
ServerContext.Servers.Add(server["Id"], serverHandle);
|
||||
ServerContext.Pools.Add((ushort)server["Id"], pool);
|
||||
ServerContext.Servers.Add((ushort)server["Id"], serverHandle);
|
||||
serverHandle.Start();
|
||||
}
|
||||
|
||||
|
|
|
@ -12,24 +12,29 @@ namespace Glove.INI {
|
|||
Raw = raw;
|
||||
}
|
||||
|
||||
public static implicit operator string(Value value) {
|
||||
return value.Raw;
|
||||
}
|
||||
public string Str
|
||||
=> this;
|
||||
|
||||
public static implicit operator bool(Value value) {
|
||||
return Boolean.TryParse(value.Raw, out bool retval) && retval;
|
||||
}
|
||||
public Int32 Int
|
||||
=> this;
|
||||
|
||||
public static implicit operator Int32(Value value) {
|
||||
return Int32.TryParse(value.Raw, out Int32 retval)
|
||||
public double Dbl
|
||||
=> this;
|
||||
|
||||
public static implicit operator string(Value value)
|
||||
=> value.Raw;
|
||||
|
||||
public static implicit operator bool(Value value)
|
||||
=> Boolean.TryParse(value.Raw, out bool retval) && retval;
|
||||
|
||||
public static implicit operator Int32(Value value)
|
||||
=> Int32.TryParse(value.Raw, out Int32 retval)
|
||||
? retval
|
||||
: 0;
|
||||
}
|
||||
|
||||
public static implicit operator double(Value value) {
|
||||
return Double.TryParse(value.Raw, out double retval)
|
||||
public static implicit operator double(Value value)
|
||||
=> Double.TryParse(value.Raw, out double retval)
|
||||
? retval
|
||||
: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -60,5 +60,23 @@ namespace Glove {
|
|||
|
||||
public static BigInteger HexStringToBigInt(this string value)
|
||||
=> BigInteger.Parse(value, NumberStyles.HexNumber);
|
||||
|
||||
public static byte[] HexStringToBytes(this string value) {
|
||||
if(value.Length % 2 == 1)
|
||||
return null;
|
||||
|
||||
var bytes = new byte[value.Length / 2];
|
||||
for(var i = 0; i < bytes.Length; ++i) {
|
||||
char upperNibble = value[2 * i],
|
||||
lowerNibble = value[2 * i + 1];
|
||||
|
||||
if(!upperNibble.IsHex() || !lowerNibble.IsHex())
|
||||
return null;
|
||||
|
||||
bytes[i] = (byte)((upperNibble.HexValue() << 4) | lowerNibble.HexValue());
|
||||
}
|
||||
|
||||
return bytes;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,6 +5,18 @@ using System.Text;
|
|||
using System.Threading.Tasks;
|
||||
|
||||
namespace Glove {
|
||||
public static class CharExtensions {
|
||||
public static bool IsHex(this char c) {
|
||||
return (c >= '0' && c <= '9')
|
||||
|| (c >= 'A' && c <= 'F')
|
||||
|| (c >= 'a' && c <= 'f');
|
||||
}
|
||||
|
||||
public static byte HexValue(this char c) {
|
||||
return (byte)(!c.IsHex() ? 0 : c - (c < 0x3A ? 0x30 : (c < 0x61 ? 0x37 : 0x57)));
|
||||
}
|
||||
}
|
||||
|
||||
public static class StringExtensions {
|
||||
public static byte[] GetBytes(this string str, bool isUtf8 = true)
|
||||
=> isUtf8 ? Encoding.UTF8.GetBytes(str)
|
||||
|
|
|
@ -29,7 +29,7 @@ namespace Kneesocks {
|
|||
Service_Unavailable = 503,
|
||||
Gateway_Timeout = 504
|
||||
}
|
||||
public kStatusCode? StatusCode { get; private set; } = null;
|
||||
public kStatusCode? StatusCode { get; } = null;
|
||||
protected string StatusCodeText
|
||||
=> Enum.GetName(typeof(kStatusCode), StatusCode).Replace('_', ' ');
|
||||
|
||||
|
|
50
server/MasterServerList.cs
Normal file
50
server/MasterServerList.cs
Normal file
|
@ -0,0 +1,50 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using Glove;
|
||||
|
||||
namespace SockScape {
|
||||
static class MasterServerList {
|
||||
public static Dictionary<UInt16, Server> Servers { get; }
|
||||
= new Dictionary<UInt16, Server>();
|
||||
|
||||
public static void Write(Server server) {
|
||||
lock(Servers) {
|
||||
if(HasId(server.Id) && !Servers[server.Id].Address.Equals(server.Address))
|
||||
Console.WriteLine($"{DateTime.Now.ToShortTimeString()} - Server {server.Id} has changed IP addresses.");
|
||||
|
||||
Servers[server.Id] = server;
|
||||
}
|
||||
}
|
||||
|
||||
public static Packet ReportPacket {
|
||||
get {
|
||||
lock(Servers) {
|
||||
var packet = new Packet(kInterMasterId.ServerListing, ((ushort)Servers.Count).Pack());
|
||||
foreach(var server in Servers)
|
||||
// TODO change this to support IPv6
|
||||
packet.AddRegions(server.Key.Pack(), server.Value.UserCount.Pack(),
|
||||
server.Value.Address.MapToIPv4().ToString(), server.Value.Port.Pack());
|
||||
|
||||
return packet;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static bool HasId(UInt16 id)
|
||||
=> Servers.ContainsKey(id);
|
||||
|
||||
public static void Clear()
|
||||
=> Servers.Clear();
|
||||
}
|
||||
|
||||
class Server {
|
||||
public ushort Id { get; set; }
|
||||
public ushort UserCount { get; set; }
|
||||
public IPAddress Address { get; set; }
|
||||
public ushort Port { get; set; }
|
||||
}
|
||||
}
|
|
@ -1,56 +0,0 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace SockScape {
|
||||
static class ServerList {
|
||||
private static ServerDictionary Servers { get; }
|
||||
= new ServerDictionary();
|
||||
|
||||
private static Dictionary<UInt16, Server> List
|
||||
=> Servers.List;
|
||||
|
||||
public static void Write(Server server) {
|
||||
lock(Servers) {
|
||||
if(HasId(server.Id) && !List[server.Id].Address.Equals(server.Address))
|
||||
Console.WriteLine($"{DateTime.Now.ToShortTimeString()} - Server {server.Id} has changed IP addresses.");
|
||||
|
||||
List[server.Id] = server;
|
||||
}
|
||||
}
|
||||
|
||||
public static Packet ReportPacket {
|
||||
get {
|
||||
var packet = new Packet(kInterMasterId.);
|
||||
|
||||
return packet;
|
||||
}
|
||||
}
|
||||
|
||||
public static bool HasId(UInt16 id)
|
||||
=> List.ContainsKey(id);
|
||||
|
||||
public static void Clear()
|
||||
=> List.Clear();
|
||||
|
||||
public class ServerDictionary {
|
||||
public Dictionary<UInt16, Server> List { get; }
|
||||
= new Dictionary<UInt16, Server>();
|
||||
|
||||
public Server this[UInt16 i] {
|
||||
get => List.ContainsKey(i) ? List[i] : null;
|
||||
set => List[i] = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class Server {
|
||||
public ushort Id { get; set; }
|
||||
public ushort UserCount { get; set; }
|
||||
public IPAddress Address { get; set; }
|
||||
public ushort Port { get; set; }
|
||||
}
|
||||
}
|
|
@ -94,17 +94,18 @@
|
|||
<Compile Include="DAL\ScapeDb.cs" />
|
||||
<Compile Include="DAL\Session.cs" />
|
||||
<Compile Include="DAL\User.cs" />
|
||||
<Compile Include="Encryption\BlockCipher.cs" />
|
||||
<Compile Include="Encryption\KeyExchange.cs" />
|
||||
<Compile Include="Encryption\Cipher.cs" />
|
||||
<Compile Include="Encryption\StreamCipher.cs" />
|
||||
<Compile Include="Migrations\201708251600325_Initial.cs" />
|
||||
<Compile Include="Migrations\201708251600325_Initial.Designer.cs">
|
||||
<DependentUpon>201708251600325_Initial.cs</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="Migrations\Configuration.cs" />
|
||||
<Compile Include="ServerList.cs" />
|
||||
<Compile Include="MasterServerList.cs" />
|
||||
<Compile Include="Socks\MasterConnection.cs" />
|
||||
<Compile Include="Socks\MasterUdpClient.cs" />
|
||||
<Compile Include="Socks\MasterUdpServer.cs" />
|
||||
<Compile Include="Socks\MasterIntraClient.cs" />
|
||||
<Compile Include="Socks\MasterIntraServer.cs" />
|
||||
<Compile Include="Socks\Protocols\ClientServerIds.cs" />
|
||||
<Compile Include="Socks\Protocols\InterMasterIds.cs" />
|
||||
<Compile Include="Socks\Protocols\IntraMasterIds.cs" />
|
||||
|
|
|
@ -10,7 +10,7 @@ using SockScape.Encryption;
|
|||
namespace SockScape {
|
||||
class MasterConnection : Connection {
|
||||
private Key Key;
|
||||
public Cipher Encryptor { get; private set; }
|
||||
public StreamCipher Encryptor { get; private set; }
|
||||
|
||||
protected override void OnOpen() {
|
||||
Key = new Key();
|
||||
|
@ -39,7 +39,7 @@ namespace SockScape {
|
|||
return;
|
||||
}
|
||||
|
||||
Encryptor = new Cipher(Key.PrivateKey);
|
||||
Encryptor = new StreamCipher(Key.PrivateKey);
|
||||
break;
|
||||
case kInterMasterId.LoginAttempt:
|
||||
|
||||
|
|
|
@ -10,9 +10,8 @@ using Glove;
|
|||
using SockScape.Encryption;
|
||||
|
||||
namespace SockScape {
|
||||
static class MasterUdpClient {
|
||||
static class MasterIntraClient {
|
||||
private static Key Key;
|
||||
private static Cipher Encryptor;
|
||||
|
||||
private static UdpClient Sock;
|
||||
private static Thread ListeningThread;
|
||||
|
@ -55,10 +54,9 @@ namespace SockScape {
|
|||
switch((kIntraMasterId)packet.Id) {
|
||||
case kIntraMasterId.KeyExchange:
|
||||
var responsePacket = Key.ParseRequestPacket(packet);
|
||||
Encryptor = new Cipher(Key.PrivateKey);
|
||||
Encryptor = new StreamCipher(Key.PrivateKey);
|
||||
if(responsePacket != null)
|
||||
Send(responsePacket);
|
||||
|
||||
else
|
||||
LastMessageIn = new DateTime(0);
|
||||
break;
|
||||
|
@ -72,6 +70,8 @@ namespace SockScape {
|
|||
break;
|
||||
|
||||
case kIntraMasterId.EncryptionError:
|
||||
NextSendId = NextRecvId = 0;
|
||||
Buffer.Clear();
|
||||
Key = new Key();
|
||||
Encryptor = null;
|
||||
LastMessageIn = new DateTime(0);
|
||||
|
@ -81,7 +81,7 @@ namespace SockScape {
|
|||
|
||||
if(LastMessageIn.Ticks != 0) {
|
||||
if(DeltaLastOut.TotalSeconds > 2)
|
||||
Send(new Packet());
|
||||
Send(Encryptor.Parse(ServerContext.StatusUpdatePacket.GetBytes()));
|
||||
} else
|
||||
if(DeltaLastOut.TotalSeconds > 10)
|
||||
Send(new Packet(kIntraSlaveId.InitiationAttempt, Configuration.General["Master Secret"]));
|
||||
|
@ -91,9 +91,14 @@ namespace SockScape {
|
|||
}
|
||||
|
||||
public static void Send(Packet packet) {
|
||||
var message = packet.GetBytes();
|
||||
Sock.Send(message, message.Length);
|
||||
Send(packet.GetBytes());
|
||||
}
|
||||
|
||||
public static void Send(byte[] bytes) {
|
||||
Sock.Send(bytes, bytes.Length);
|
||||
LastMessageOut = DateTime.Now;
|
||||
Buffer.Add(NextSendId, bytes);
|
||||
++NextSendId;
|
||||
}
|
||||
|
||||
public static void Close() {
|
|
@ -3,6 +3,7 @@ using System.Collections.Generic;
|
|||
using System.Linq;
|
||||
using System.Net;
|
||||
using System.Net.Sockets;
|
||||
using System.Security.Cryptography;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
@ -23,7 +24,7 @@ namespace SockScape {
|
|||
if(IsOpen || ListeningThread != null)
|
||||
return;
|
||||
|
||||
ServerList.Clear();
|
||||
MasterServerList.Clear();
|
||||
Prospects = new Dictionary<string, Client>();
|
||||
Clients = new Dictionary<string, Client>();
|
||||
|
||||
|
@ -49,8 +50,11 @@ namespace SockScape {
|
|||
encryptor == null ? Packet.FromBytes(data)
|
||||
: Packet.FromBytes(encryptor.Parse(data));
|
||||
|
||||
if(packet == null)
|
||||
if(packet == null) {
|
||||
if(encryptor != null)
|
||||
EncryptionError(endPoint);
|
||||
continue;
|
||||
}
|
||||
|
||||
Clients[client].LastReceive = DateTime.Now;
|
||||
switch((kIntraSlaveId)packet.Id) {
|
||||
|
@ -76,7 +80,8 @@ namespace SockScape {
|
|||
|
||||
var privateKey = Prospects[client].Key.ParseResponsePacket(packet);
|
||||
if(privateKey != -1) {
|
||||
Prospects[client].Encryptor = new Cipher(privateKey);
|
||||
Prospects[client].LastReceive = DateTime.Now;
|
||||
Prospects[client].Encryptor = new StreamCipher(privateKey);
|
||||
Clients[client] = Prospects[client];
|
||||
Prospects.Remove(client);
|
||||
} else
|
||||
|
@ -88,13 +93,13 @@ namespace SockScape {
|
|||
break;
|
||||
|
||||
if(packet.CheckRegions(0, 1)) {
|
||||
NegativeAck(endPoint, kIntraSlaveId.StatusUpdate, "Server count is malformed.");
|
||||
NegativeAck(endPoint, encryptor, kIntraSlaveId.StatusUpdate, "Server count is malformed.");
|
||||
break;
|
||||
}
|
||||
|
||||
byte serverCount = packet[0].Raw[0];
|
||||
if(packet.RegionCount != 1 + 3 * serverCount) {
|
||||
NegativeAck(endPoint, kIntraSlaveId.StatusUpdate, "Region count does not match server count");
|
||||
NegativeAck(endPoint, encryptor, kIntraSlaveId.StatusUpdate, "Region count does not match server count");
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -102,7 +107,7 @@ namespace SockScape {
|
|||
if(!packet.CheckRegions(2 + 3 * i, 2, 2, 2))
|
||||
continue;
|
||||
|
||||
ServerList.Write(new Server {
|
||||
MasterServerList.Write(new Server {
|
||||
Id = packet[2 + 3 * i].Raw.UnpackUInt16(),
|
||||
UserCount = packet[3 + 3 * i].Raw.UnpackUInt16(),
|
||||
Address = endPoint.Address,
|
||||
|
@ -110,7 +115,7 @@ namespace SockScape {
|
|||
});
|
||||
}
|
||||
|
||||
PositiveAck(endPoint, kIntraSlaveId.StatusUpdate);
|
||||
PositiveAck(endPoint, encryptor, kIntraSlaveId.StatusUpdate);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -122,8 +127,11 @@ namespace SockScape {
|
|||
}
|
||||
|
||||
private static void Send(Packet packet, IPEndPoint client) {
|
||||
var message = packet.GetBytes();
|
||||
Sock.Send(message, message.Length, client);
|
||||
Send(packet.GetBytes(), client);
|
||||
}
|
||||
|
||||
private static void Send(byte[] bytes, IPEndPoint client) {
|
||||
Sock.Send(bytes, bytes.Length, client);
|
||||
}
|
||||
|
||||
public static void Close() {
|
||||
|
@ -141,12 +149,12 @@ namespace SockScape {
|
|||
return Clients.ContainsKey(client);
|
||||
}
|
||||
|
||||
private static void PositiveAck(IPEndPoint endPoint, kIntraSlaveId id) {
|
||||
Send(new Packet(kIntraMasterId.PositiveAck, id), endPoint);
|
||||
private static void PositiveAck(IPEndPoint endPoint, StreamCipher cipher, kIntraSlaveId id) {
|
||||
Send(cipher.Parse(new Packet(kIntraMasterId.PositiveAck, id).GetBytes()), endPoint);
|
||||
}
|
||||
|
||||
private static void NegativeAck(IPEndPoint endPoint, kIntraSlaveId id, string message = "An error occurred while parsing a packet.") {
|
||||
Send(new Packet(kIntraMasterId.NegativeAck, id, message), endPoint);
|
||||
private static void NegativeAck(IPEndPoint endPoint, StreamCipher cipher, kIntraSlaveId id, string message = "An error occurred while parsing a packet.") {
|
||||
Send(cipher.Parse(new Packet(kIntraMasterId.NegativeAck, id, message).GetBytes()), endPoint);
|
||||
}
|
||||
|
||||
private static void EncryptionError(IPEndPoint endPoint, string message = "A general encryption error has occurred. Renegotiation required.") {
|
||||
|
@ -157,7 +165,7 @@ namespace SockScape {
|
|||
public IPEndPoint Address { get; set; }
|
||||
public DateTime LastReceive { get; set; }
|
||||
public TimeSpan ReceiveDelta => DateTime.Now - LastReceive;
|
||||
public Cipher Encryptor { get; set; }
|
||||
public StreamCipher Encryptor { get; set; }
|
||||
public Key Key { get; set; }
|
||||
}
|
||||
}
|
|
@ -92,6 +92,13 @@ namespace SockScape {
|
|||
return this;
|
||||
}
|
||||
|
||||
public Packet AddRegions(params object[] regions) {
|
||||
foreach(var region in regions)
|
||||
AddRegion(region);
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
public bool CheckRegions(int startIndex, params int[] lengths) {
|
||||
if(startIndex + lengths.Length > RegionCount)
|
||||
return false;
|
||||
|
@ -150,4 +157,32 @@ namespace SockScape {
|
|||
=> this;
|
||||
}
|
||||
}
|
||||
|
||||
public class PacketBuffer {
|
||||
private short MaxSize;
|
||||
private Dictionary<uint, byte[]> Buffer
|
||||
= new Dictionary<uint, byte[]>();
|
||||
|
||||
public PacketBuffer(short maxSize = 10) {
|
||||
MaxSize = maxSize;
|
||||
}
|
||||
|
||||
public void Add(uint id, byte[] packet) {
|
||||
Buffer[id] = packet;
|
||||
|
||||
if(Buffer.Count > 10)
|
||||
Buffer =
|
||||
Buffer.Where(x => x.Key >= id - 10)
|
||||
.ToDictionary(x => x.Key, x => x.Value);
|
||||
}
|
||||
|
||||
public byte[] this[uint i]
|
||||
=> Buffer[i];
|
||||
|
||||
public bool HasId(uint id)
|
||||
=> Buffer.ContainsKey(id);
|
||||
|
||||
public void Clear()
|
||||
=> Buffer.Clear();
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue