diff --git a/server/Libraries/Kneesocks/Connection.cs b/server/Libraries/Kneesocks/Connection.cs
index dab49b4..a61b72a 100644
--- a/server/Libraries/Kneesocks/Connection.cs
+++ b/server/Libraries/Kneesocks/Connection.cs
@@ -27,7 +27,7 @@ namespace Kneesocks {
ReadBuffer Buffer;
private byte[] FirstTwoBytes = null;
- private int ExtraHeaderSize = 2;
+ private int ExtraHeaderSize = 0;
private byte[] FrameHeader = null;
private List FrameBuffer = new List();
@@ -68,7 +68,22 @@ namespace Kneesocks {
ClientHandshake = conn.ClientHandshake;
}
- public byte[] Parse() {
+ public void ReadIfNotNull(ref byte[] buffer, int length) {
+ buffer = buffer == null ? Buffer.AttemptRead(length)
+ : buffer;
+ }
+
+ public void ReadIfNotNull(ref byte[] buffer, string terminator) {
+ buffer = buffer == null ? Buffer.AttemptRead(terminator)
+ : buffer;
+ }
+
+ public void Parse() {
+ if(!Stream.CanRead) {
+ Disconnected = true;
+ return;
+ }
+
byte[] readBuffer = null;
if(Buffer.IsReading) {
readBuffer = Buffer.AttemptRead();
@@ -76,17 +91,15 @@ namespace Kneesocks {
if(Buffer.ElapsedReadTime.Seconds > (Handshaked ? 300 : 30))
Disconnect(Frame.kClosingReason.ProtocolError, "Timed out waiting for a full response");
- return null;
+ return;
}
}
if(!Handshaked) {
- if(readBuffer == null) {
- readBuffer = Buffer.AttemptRead("\r\n\r\n");
- if(readBuffer == null)
- return null;
- }
-
+ ReadIfNotNull(ref readBuffer, "\r\n\r\n");
+ if(readBuffer == null)
+ return;
+
try {
Handshake request = new Handshake(Encoding.ASCII.GetString(readBuffer));
var response = Handshake.AcceptRequest(request).ToBytes();
@@ -95,24 +108,23 @@ namespace Kneesocks {
Handshaked = true;
} catch(Exception e) {
Disconnect(Frame.kClosingReason.ProtocolError, e.Message);
- return null;
+ return;
}
OnOpen();
- return null;
+ return;
}
OnParse();
if(FirstTwoBytes == null) {
- if(readBuffer == null) {
- readBuffer = Buffer.AttemptRead(2);
- if(readBuffer == null)
- return null;
- }
+ ReadIfNotNull(ref readBuffer, 2);
+ if(readBuffer == null)
+ return;
FirstTwoBytes = readBuffer;
- ExtraHeaderSize = Frame.HeaderSizeFromBytes(FirstTwoBytes) - 2;
+ ExtraHeaderSize = Frame.HeaderLengthFromBytes(FirstTwoBytes) - 2;
+
readBuffer = null;
}
@@ -120,11 +132,9 @@ namespace Kneesocks {
if(ExtraHeaderSize == 0)
FrameHeader = FirstTwoBytes;
else {
- if(readBuffer == null) {
- readBuffer = Buffer.AttemptRead(ExtraHeaderSize);
- if(readBuffer == null)
- return null;
- }
+ ReadIfNotNull(ref readBuffer, ExtraHeaderSize);
+ if(readBuffer == null)
+ return;
FrameHeader = FirstTwoBytes.Concat(readBuffer).ToArray();
}
@@ -133,18 +143,44 @@ namespace Kneesocks {
}
if(FrameHeader != null) {
- var check = Frame.HeaderFromBytes()
+ Frame tempFrame;
- if()
+ if(readBuffer == null) {
+ try {
+ tempFrame = Frame.HeaderFromBytes(FrameHeader);
+ } catch(Exception e) {
+ Disconnect(Frame.kClosingReason.ProtocolError, e.Message);
+ return;
+ }
+
+ readBuffer = Buffer.AttemptRead(tempFrame.BodyLength);
+ if(readBuffer == null)
+ return;
+ }
+
+ try {
+ tempFrame = Frame.FromBytes(FrameHeader.Concat(readBuffer).ToArray());
+ } catch(Exception e) {
+ Disconnect(Frame.kClosingReason.ProtocolError, e.Message);
+ return;
+ }
+
+ FrameBuffer.Add(tempFrame);
+ FirstTwoBytes = null;
+ ExtraHeaderSize = 0;
+ FrameHeader = null;
+
+ if(tempFrame.IsFinal) {
+ byte[] byteBuffer = new byte[0];
+ foreach(var frame in FrameBuffer)
+ byteBuffer = byteBuffer.Concat(frame.Content).ToArray();
+
+ FrameBuffer = new List();
+ OnReceive(byteBuffer);
+ }
}
- /*if(!Buffer.IsReading) {
- readBuffer = Buffer.AttemptRead("\r\n\r\n");
- if(readBuffer == null)
- return null;
- }*/
-
- return null;
+ return;
}
public void Disconnect(string reason = null) {
diff --git a/server/Libraries/Kneesocks/Frame.cs b/server/Libraries/Kneesocks/Frame.cs
index aea0387..11f808b 100644
--- a/server/Libraries/Kneesocks/Frame.cs
+++ b/server/Libraries/Kneesocks/Frame.cs
@@ -41,7 +41,7 @@ namespace Kneesocks {
int length = 2
+ (BodyLength >= 0x7E && BodyLength <= 0xFFFF ? 2 : 0)
- + (BodyLength > 0xFFFF ? 4 : 0)
+ + (BodyLength > 0xFFFF ? 8 : 0)
+ (IsMasked ? 4 : 0);
return (_HeaderLength = length);
@@ -99,7 +99,7 @@ namespace Kneesocks {
return returnValue;
}
- public static int HeaderSizeFromBytes(byte[] raw) {
+ public static int HeaderLengthFromBytes(byte[] raw) {
if(raw.Length < 2)
throw new FormatException("Need first two bytes to analyze");
@@ -107,7 +107,7 @@ namespace Kneesocks {
return 2
+ ((raw[1] & 0x80) != 0 ? 4: 0)
+ (lengthByte == 0x7E ? 2 : 0)
- + (lengthByte == 0x7F ? 4 : 0);
+ + (lengthByte == 0x7F ? 8 : 0);
}
public static Frame HeaderFromBytes(byte[] raw) {
@@ -131,12 +131,12 @@ namespace Kneesocks {
? 1
: (bodyLength == 0x7E ? 3 : 9);
- if(raw.Length < headerOffset + 1)
+ if(raw.Length < headerOffset + 1 + (returnFrame.IsMasked ? 4 : 0))
throw new FormatException("Websocket frame is smaller than expected header size");
- bodyLength = bodyLength < 0x7E ? 0 : bodyLength;
- for(var i = headerOffset - 1; i > 0; --i)
- bodyLength |= (ulong)raw[2 + i] << (8 * (headerOffset - 1 - i));
+ if(bodyLength >= 0x7E)
+ bodyLength = bodyLength == 0x7E ? raw.Subset(2, 2).UnpackUInt16()
+ : raw.Subset(2, 8).UnpackUInt64();
if(bodyLength > Int32.MaxValue)
throw new FormatException("Frame is too large to interpret");
@@ -153,7 +153,7 @@ namespace Kneesocks {
var returnFrame = HeaderFromBytes(raw);
uint expectedFrameLength = (uint)returnFrame.BodyLength + (uint)returnFrame.HeaderLength;
- if(expectedFrameLength < (uint)raw.Length)
+ if((uint)raw.Length < expectedFrameLength)
throw new FormatException("Raw frame length ("+ (uint)raw.Length + ") is less than described size ("+ expectedFrameLength + ")");
returnFrame.Content = new byte[returnFrame.BodyLength];
diff --git a/server/Libraries/Kneesocks/ReadBuffer.cs b/server/Libraries/Kneesocks/ReadBuffer.cs
index 5cbc3d5..bfae2f1 100644
--- a/server/Libraries/Kneesocks/ReadBuffer.cs
+++ b/server/Libraries/Kneesocks/ReadBuffer.cs
@@ -7,6 +7,8 @@ using System.Threading.Tasks;
namespace Kneesocks {
class ReadBuffer {
+ private const int BufferSize = 1024;
+
private List Buffer;
private int ExpectedLength;
private string ExpectedString;
@@ -52,21 +54,21 @@ namespace Kneesocks {
if(!IsReading)
return null;
+ if(!Source.CanRead)
+ return null;
+
byte[] returnValue;
if((returnValue = CheckBuffer()) != null)
return returnValue;
- var buffer = new byte[1024];
+ var buffer = new byte[BufferSize];
while(Source.DataAvailable) {
var readAmount = ExpectedString == null
- ? Math.Min(1024, ExpectedLength - Buffer.Count)
- : 1024;
+ ? Math.Min(BufferSize, ExpectedLength - Buffer.Count)
+ : BufferSize;
var bytesRead = Source.Read(buffer, 0, readAmount);
- if(bytesRead == readAmount)
- Buffer.AddRange(buffer);
- else
- Buffer.AddRange(buffer.Take(readAmount));
+ Buffer.AddRange(bytesRead == BufferSize ? buffer : buffer.Take(bytesRead));
if((returnValue = CheckBuffer()) != null)
return returnValue;
diff --git a/server/Libraries/Kneesocks/Stack.cs b/server/Libraries/Kneesocks/Stack.cs
index b36e3bc..df9fac6 100644
--- a/server/Libraries/Kneesocks/Stack.cs
+++ b/server/Libraries/Kneesocks/Stack.cs
@@ -11,7 +11,6 @@ namespace Kneesocks {
private List Clients = new List();
private bool RunWithNoClients = false;
private bool Running = true;
- private bool _finished = false;
public Stack(Pool poolRef, Connection initialConnection = null) {
PoolRef = poolRef;
@@ -48,7 +47,13 @@ namespace Kneesocks {
while(Running && (Count > 0 || RunWithNoClients)) {
for(var i = Count - 1; i >= 0 && Running; --i) {
var client = Clients[i];
- client.Parse();
+ if(!client.Disconnected)
+ client.Parse();
+ else {
+ lock(Clients) {
+ Clients.RemoveAt(i);
+ }
+ }
}
}