udplease go away
woomy
This commit is contained in:
parent
b11b9957ac
commit
8867c3051a
7 changed files with 222 additions and 241 deletions
|
@ -5,6 +5,8 @@ const enum kPacketId {
|
|||
}
|
||||
|
||||
class Packet {
|
||||
private static magicNumber: Uint8Array = new Uint8Array([0xF0, 0x9F, 0xA6, 0x91]);
|
||||
|
||||
private _id: kPacketId;
|
||||
public get id(): kPacketId {
|
||||
return this._id;
|
||||
|
@ -47,10 +49,14 @@ class Packet {
|
|||
|
||||
public static fromBytes(bytes: Uint8Array): Packet {
|
||||
var packet = new Packet;
|
||||
packet._id = bytes[0];
|
||||
var regionCount = bytes[1];
|
||||
|
||||
if(!bytes.subarray(0, 4).every((v, i) => v === Packet.magicNumber[i]))
|
||||
return null;
|
||||
|
||||
packet._id = bytes[4];
|
||||
var regionCount = bytes[5];
|
||||
var regionLengths = [];
|
||||
var ptr = 2;
|
||||
var ptr = 6;
|
||||
for(var i = 0; i < regionCount; ++i) {
|
||||
if(bytes[ptr] < 0xFE)
|
||||
regionLengths.push(bytes[ptr]);
|
||||
|
@ -74,7 +80,7 @@ class Packet {
|
|||
}
|
||||
|
||||
public getBytes(): Uint8Array {
|
||||
var headerSize = 2, bodySize = 0;
|
||||
var headerSize = 6, bodySize = 0;
|
||||
this._regions.forEach(region => {
|
||||
bodySize += region.byteLength;
|
||||
|
||||
|
@ -86,9 +92,10 @@ class Packet {
|
|||
});
|
||||
|
||||
var buffer = new Uint8Array(headerSize + bodySize);
|
||||
var headerPtr = 2, bodyPtr = headerSize;
|
||||
buffer[0] = this._id % 256;
|
||||
buffer[1] = this._regions.length;
|
||||
var headerPtr = 6, bodyPtr = headerSize;
|
||||
buffer.set(Packet.magicNumber, 0);
|
||||
buffer[4] = this._id % 256;
|
||||
buffer[5] = this._regions.length;
|
||||
this._regions.forEach(region => {
|
||||
var regionLength = region.byteLength;
|
||||
if(regionLength < 0xFE)
|
||||
|
|
386
protocol.md
386
protocol.md
|
@ -10,9 +10,10 @@ All references to the 'byte' in this document refers to individual 8-bit octets,
|
|||
|
||||
Because the body of the packet is a sequence of many different regions of byte data that is not delimited, it is necessary for the header of the packet to determine boundaries for the regions of data.
|
||||
|
||||
* The first byte is the packet id, the meanings of which are defined in the [_Packet IDs_](#packet-ids) section.
|
||||
* The second byte is the number of byte regions in the packet.
|
||||
* The bytes following the second byte are a list of binary length segments, each of which correspond to the number of bytes in its respective region. They each follow this format:
|
||||
* The first four bytes will always be 0xF0, 0x9F, 0xA6, 0x91. If this is not set properly, the endpoint must close the connection.
|
||||
* The fifth byte is the packet id, the meanings of which are defined in the [_Packet IDs_](#packet-ids) section.
|
||||
* The sixth byte is the number of byte regions in the packet.
|
||||
* The bytes following the sixth byte are a list of binary length segments, each of which correspond to the number of bytes in its respective region. They each follow this format:
|
||||
* If length is less than 254, the length of the region is stored in a single byte.
|
||||
* If length is greater than or equal to 254 but less than 65,536, the first byte of the lenght segment should be 254 and the following two bytes is the length of the region.
|
||||
* If length is greater than or equal to 65,536, the first byte of the length segment should be 255 and the following four bytes is the length of the region.
|
||||
|
@ -37,219 +38,180 @@ A packet ID may have a specific "direction" of communication, in that an endpoin
|
|||
|
||||
#### Server to Client
|
||||
|
||||
<div style="display: flex; flex-wrap: wrap;">
|
||||
<!--
|
||||
<table class="float">
|
||||
<thead>
|
||||
<th colspan="100" class="center">
|
||||
ID 0: Key Exchange<br />
|
||||
Requester
|
||||
</th>
|
||||
</thead>
|
||||
<thead>
|
||||
<th colspan="2" class="right">#</th>
|
||||
<th>Region</th>
|
||||
<th>Type</th>
|
||||
</thead>
|
||||
<tr>
|
||||
<td><i>s ∈ [0, 2]</i></td>
|
||||
<td class="right">1</td>
|
||||
<td>Step</td>
|
||||
<td>Uint8</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><i>s = 0</i></td>
|
||||
<td class="right">2</td>
|
||||
<td>Generator</td>
|
||||
<td>Big Int</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><i>s = 0</i></td>
|
||||
<td class="right">3</td>
|
||||
<td>Modulus</td>
|
||||
<td>Big Int</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><i>s = 1</i></td>
|
||||
<td class="right">2</td>
|
||||
<td>Server Key</td>
|
||||
<td>Big Int</td>
|
||||
</tr>
|
||||
</table>
|
||||
-->
|
||||
<table style="margin-right: 8px; margin-bottom: 8px;">
|
||||
<thead>
|
||||
<th colspan="100" class="center">
|
||||
ID 0: Key Exchange<br />
|
||||
Requester
|
||||
</th>
|
||||
</thead>
|
||||
<thead>
|
||||
<th>#</th>
|
||||
<th>Region</th>
|
||||
<th>Type</th>
|
||||
</thead>
|
||||
<tr>
|
||||
<td>1</td>
|
||||
<td>Generator</td>
|
||||
<td>Big Int</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>2</td>
|
||||
<td>Modulus</td>
|
||||
<td>Big Int</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>3</td>
|
||||
<td>Server Key</td>
|
||||
<td>Big Int</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<table style="margin-right: 8px; margin-bottom: 8px;">
|
||||
<thead>
|
||||
<th colspan="100" class="center">
|
||||
ID 1: Login Attempt<br />
|
||||
[Encrypted] Responder
|
||||
</th>
|
||||
</thead>
|
||||
<thead>
|
||||
<th>#</th>
|
||||
<th>Region</th>
|
||||
<th>Type</th>
|
||||
</thead>
|
||||
<tr>
|
||||
<td class="center">1</td>
|
||||
<td>Check Const</td>
|
||||
<td>String</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="center">2</td>
|
||||
<td>Succeeded</td>
|
||||
<td>Boolean</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="center">3</td>
|
||||
<td>Message</td>
|
||||
<td>String</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<table style="margin-right: 8px; margin-bottom: 8px;">
|
||||
<thead>
|
||||
<th colspan="100" class="center">
|
||||
ID 2: Registration Attempt<br />
|
||||
[Encrypted] Responder
|
||||
</th>
|
||||
</thead>
|
||||
<thead>
|
||||
<th>#</th>
|
||||
<th>Region</th>
|
||||
<th>Type</th>
|
||||
</thead>
|
||||
<tr>
|
||||
<td class="center">1</td>
|
||||
<td>Check Const</td>
|
||||
<td>String</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="center">2</td>
|
||||
<td>Succeeded</td>
|
||||
<td>Boolean</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="center">3</td>
|
||||
<td>Message</td>
|
||||
<td>String</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
TODO: populate
|
||||
|
||||
#### Client to Server
|
||||
|
||||
<div style="display: flex; flex-wrap: wrap;">
|
||||
<table style="margin-right: 8px; margin-bottom: 8px;">
|
||||
<thead>
|
||||
<th colspan="100" class="center">
|
||||
ID 0: Key Exchange<br />
|
||||
Responder
|
||||
</th>
|
||||
</thead>
|
||||
<thead>
|
||||
<th>#</th>
|
||||
<th>Region</th>
|
||||
<th>Type</th>
|
||||
</thead>
|
||||
<tr>
|
||||
<td class="center">1</td>
|
||||
<td>Client Key</td>
|
||||
<td>Big Int</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<table style="margin-right: 8px; margin-bottom: 8px;">
|
||||
<thead>
|
||||
<th colspan="100" class="center">
|
||||
ID 1: Login Attempt<br />
|
||||
[Encrypted] Requester
|
||||
</th>
|
||||
</thead>
|
||||
<thead>
|
||||
<th>#</th>
|
||||
<th>Region</th>
|
||||
<th>Type</th>
|
||||
</thead>
|
||||
<tr>
|
||||
<td class="center">1</td>
|
||||
<td>Check Const</td>
|
||||
<td>String</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="center">2</td>
|
||||
<td>Username</td>
|
||||
<td>String</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="center">3</td>
|
||||
<td>Password</td>
|
||||
<td>String</td>
|
||||
</tr>
|
||||
</table>
|
||||
TODO: populate
|
||||
|
||||
<table style="margin-right: 8px; margin-bottom: 8px;">
|
||||
<thead>
|
||||
<th colspan="100" class="center">
|
||||
ID 2: Registration Attempt<br />
|
||||
[Encrypted] Requester
|
||||
</th>
|
||||
</thead>
|
||||
<thead>
|
||||
<th>#</th>
|
||||
<th>Region</th>
|
||||
<th>Type</th>
|
||||
</thead>
|
||||
<tr>
|
||||
<td class="center">1</td>
|
||||
<td>Check Const</td>
|
||||
<td>String</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="center">2</td>
|
||||
<td>Username</td>
|
||||
<td>String</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="center">3</td>
|
||||
<td>Password</td>
|
||||
<td>String</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="center">4</td>
|
||||
<td>Email</td>
|
||||
<td>String</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
## Master/Slave Servers
|
||||
|
||||
To keep track of the status of multiple servers from a centralized point that the client may query, each server must be able to communicate with a "master" server that will record and dispense information regarding all servers to clients. All servers that report to the master server will hereby be refered to as "slave" servers.
|
||||
|
||||
Communication between master and slave servers will be done over a UDP connection on a port that is defined by the master server's configuration. The protocol used for this communication is identical to the protocol defined for standard client/server communication; however, the [_Packet IDs_](#TODO) are defined differently.
|
||||
|
||||
Communication between the master server and clients will be done over a WebSocket connection on a port that is defined by the master server's configuration. The protocol used for this communication is identical to the protocol defined for standard client/server communication; however, the [_Packet IDs_](#TODO) are defined differently.
|
||||
|
||||
### Master/Slave Packet IDs
|
||||
|
||||
#### Master to Slave
|
||||
|
||||
<table style="margin-right: 8px; margin-bottom: 8px;">
|
||||
<thead>
|
||||
<th colspan="100" class="center">
|
||||
ID 0: Key Exchange<br />
|
||||
Requester
|
||||
</th>
|
||||
</thead>
|
||||
<thead>
|
||||
<th>#</th>
|
||||
<th>Region</th>
|
||||
<th>Type</th>
|
||||
</thead>
|
||||
<tr>
|
||||
<td>1</td>
|
||||
<td>Generator</td>
|
||||
<td>Big Int</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>2</td>
|
||||
<td>Modulus</td>
|
||||
<td>Big Int</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>3</td>
|
||||
<td>Server Key</td>
|
||||
<td>Big Int</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<table style="margin-right: 8px; margin-bottom: 8px;">
|
||||
<thead>
|
||||
<th colspan="100" class="center">
|
||||
ID 1: Login Attempt<br />
|
||||
[Encrypted] Responder
|
||||
</th>
|
||||
</thead>
|
||||
<thead>
|
||||
<th>#</th>
|
||||
<th>Region</th>
|
||||
<th>Type</th>
|
||||
</thead>
|
||||
<tr>
|
||||
<td class="center">1</td>
|
||||
<td>Succeeded</td>
|
||||
<td>Boolean</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="center">2</td>
|
||||
<td>Message</td>
|
||||
<td>String</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<table style="margin-right: 8px; margin-bottom: 8px;">
|
||||
<thead>
|
||||
<th colspan="100" class="center">
|
||||
ID 2: Registration Attempt<br />
|
||||
[Encrypted] Responder
|
||||
</th>
|
||||
</thead>
|
||||
<thead>
|
||||
<th>#</th>
|
||||
<th>Region</th>
|
||||
<th>Type</th>
|
||||
</thead>
|
||||
<tr>
|
||||
<td class="center">1</td>
|
||||
<td>Succeeded</td>
|
||||
<td>Boolean</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="center">2</td>
|
||||
<td>Message</td>
|
||||
<td>String</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
#### Slave to Master
|
||||
|
||||
<table style="margin-right: 8px; margin-bottom: 8px;">
|
||||
<thead>
|
||||
<th colspan="100" class="center">
|
||||
ID 0: Key Exchange<br />
|
||||
Responder
|
||||
</th>
|
||||
</thead>
|
||||
<thead>
|
||||
<th>#</th>
|
||||
<th>Region</th>
|
||||
<th>Type</th>
|
||||
</thead>
|
||||
<tr>
|
||||
<td class="center">1</td>
|
||||
<td>Client Key</td>
|
||||
<td>Big Int</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<table style="margin-right: 8px; margin-bottom: 8px;">
|
||||
<thead>
|
||||
<th colspan="100" class="center">
|
||||
ID 1: Login Attempt<br />
|
||||
[Encrypted] Requester
|
||||
</th>
|
||||
</thead>
|
||||
<thead>
|
||||
<th>#</th>
|
||||
<th>Region</th>
|
||||
<th>Type</th>
|
||||
</thead>
|
||||
<tr>
|
||||
<td class="center">1</td>
|
||||
<td>Username</td>
|
||||
<td>String</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="center">2</td>
|
||||
<td>Password</td>
|
||||
<td>String</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<table style="margin-right: 8px; margin-bottom: 8px;">
|
||||
<thead>
|
||||
<th colspan="100" class="center">
|
||||
ID 2: Registration Attempt<br />
|
||||
[Encrypted] Requester
|
||||
</th>
|
||||
</thead>
|
||||
<thead>
|
||||
<th>#</th>
|
||||
<th>Region</th>
|
||||
<th>Type</th>
|
||||
</thead>
|
||||
<tr>
|
||||
<td class="center">1</td>
|
||||
<td>Username</td>
|
||||
<td>String</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="center">2</td>
|
||||
<td>Password</td>
|
||||
<td>String</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="center">3</td>
|
||||
<td>Email</td>
|
||||
<td>String</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
### Master/Client Packet IDs
|
||||
|
||||
#### Master to Client
|
||||
|
||||
#### Client to Master
|
||||
|
||||
## Sockstamps
|
||||
|
||||
|
|
|
@ -23,7 +23,8 @@ namespace SockScape {
|
|||
InitialCount = 3,
|
||||
InitialSize = 3,
|
||||
SizeGrowth = 3,
|
||||
MaxSize = 100
|
||||
MaxSize = 100,
|
||||
MaxTotal = server["Max Users"] ?? Configuration.General["Max Users"]
|
||||
};
|
||||
|
||||
pools.Add(server["Id"], pool);
|
||||
|
|
|
@ -20,6 +20,9 @@ namespace Kneesocks {
|
|||
// maximum number of threads that will be spawned
|
||||
// 0 means no limit
|
||||
public int MaxCount { get; set; } = 0;
|
||||
// maximum amount of total connections in the pool
|
||||
// 0 means no limit
|
||||
public int MaxTotal { get; set; } = 0;
|
||||
// maximum number of connections in a thread that exceeds the calculated
|
||||
// amount for the pool's thread count before the connection redistribution
|
||||
// function is called
|
||||
|
@ -81,6 +84,9 @@ namespace Kneesocks {
|
|||
if(Disposed)
|
||||
return false;
|
||||
|
||||
if(MaxTotal != 0 && Connections.Count >= MaxTotal)
|
||||
return false;
|
||||
|
||||
lock(Threads) {
|
||||
foreach(var thread in Threads) {
|
||||
if(thread.Stack.Count < FullThreadSize) {
|
||||
|
|
|
@ -49,7 +49,9 @@ namespace Kneesocks {
|
|||
Server = this
|
||||
};
|
||||
templatedConnection.Initialize(Socket.AcceptTcpClient());
|
||||
ConnectionPool.AddConnection(templatedConnection);
|
||||
|
||||
if(!ConnectionPool.AddConnection(templatedConnection))
|
||||
templatedConnection.Disconnect("Connection pooler rejected connection.");
|
||||
}
|
||||
|
||||
Thread.Sleep(100);
|
||||
|
|
|
@ -7,27 +7,29 @@ using Glove;
|
|||
|
||||
namespace SockScape {
|
||||
class Packet {
|
||||
private static readonly byte[] MagicNumber = { 0xF0, 0x9F, 0xA6, 0x91 };
|
||||
|
||||
public enum kId {
|
||||
KeyExchange = 0,
|
||||
LoginAttempt,
|
||||
RegistrationAttempt
|
||||
}
|
||||
|
||||
private static Packet ErrorPacket {
|
||||
get => new Packet { IsLegal = false };
|
||||
}
|
||||
|
||||
public static Packet FromBytes(byte[] raw) {
|
||||
if(raw.Length < 3)
|
||||
return ErrorPacket;
|
||||
if(raw.Length < 7)
|
||||
return null;
|
||||
|
||||
Packet packet = new Packet();
|
||||
if(!Enum.IsDefined(typeof(kId), (int)raw[0]))
|
||||
return ErrorPacket;
|
||||
packet.Id = (kId)raw[0];
|
||||
var regionCount = raw[1];
|
||||
if(!Enum.IsDefined(typeof(kId), (int)raw[4]))
|
||||
return null;
|
||||
|
||||
if(!raw.Subset(0, 4).SequenceEqual(MagicNumber))
|
||||
return null;
|
||||
|
||||
packet.Id = (kId)raw[4];
|
||||
var regionCount = raw[5];
|
||||
var regionLengths = new List<uint>();
|
||||
var headerPtr = 2;
|
||||
var headerPtr = 6;
|
||||
for(var i = 0; i < regionCount; ++i) {
|
||||
regionLengths.Add(0);
|
||||
var first = raw[headerPtr];
|
||||
|
@ -36,22 +38,22 @@ namespace SockScape {
|
|||
++headerPtr;
|
||||
} else if(first == 254) {
|
||||
if(headerPtr + 3 < raw.Length)
|
||||
return ErrorPacket;
|
||||
return null;
|
||||
regionLengths[i] = raw.Subset(headerPtr + 1, 2).UnpackUInt16();
|
||||
headerPtr += 3;
|
||||
} else {
|
||||
if(headerPtr + 5 < raw.Length)
|
||||
return ErrorPacket;
|
||||
return null;
|
||||
regionLengths[i] = raw.Subset(headerPtr + 1, 4).UnpackUInt32();
|
||||
headerPtr += 5;
|
||||
}
|
||||
|
||||
if(headerPtr > raw.Length)
|
||||
return ErrorPacket;
|
||||
return null;
|
||||
}
|
||||
|
||||
if(headerPtr + regionLengths.Sum(x => x) > raw.Length)
|
||||
return ErrorPacket;
|
||||
return null;
|
||||
|
||||
long bodyPtr = headerPtr;
|
||||
foreach(var regionLength in regionLengths) {
|
||||
|
@ -96,10 +98,11 @@ namespace SockScape {
|
|||
if(!IsLegal)
|
||||
return null;
|
||||
|
||||
var header = new List<byte> {
|
||||
(byte)Id,
|
||||
(byte)RegionCount
|
||||
};
|
||||
var header = new List<byte>();
|
||||
header.AddRange(MagicNumber);
|
||||
header.Add((byte)Id);
|
||||
header.Add((byte)RegionCount);
|
||||
|
||||
IEnumerable<byte> body = new byte[0];
|
||||
foreach(var region in Regions) {
|
||||
if(region.Length < 0xFE)
|
||||
|
|
|
@ -32,7 +32,7 @@ namespace SockScape {
|
|||
Encryptor == null ? Packet.FromBytes(data)
|
||||
: Packet.FromBytes(Encryptor.Parse(data));
|
||||
|
||||
if(!packet.IsLegal) {
|
||||
if(packet == null) {
|
||||
Disconnect(Frame.kClosingReason.ProtocolError, "Packet received was not legal.");
|
||||
return;
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue