From 583182e81b3dd3c7d4740d38d06763ff434ca5f4 Mon Sep 17 00:00:00 2001 From: Malloc of Kuzkycyziklistan Date: Fri, 5 May 2017 16:05:52 -0500 Subject: [PATCH] thigh highs running out of sock names --- server/Kneesocks/Connection.cs | 41 +++++++++--- server/Kneesocks/Frame.cs | 87 +++++++++++++++++++------- server/Kneesocks/Kneesocks.csproj | 1 + server/Kneesocks/ReadBuffer.cs | 100 ++++++++++++++++++++++++++++++ server/Kneesocks/Stack.cs | 13 ++-- 5 files changed, 202 insertions(+), 40 deletions(-) create mode 100644 server/Kneesocks/ReadBuffer.cs diff --git a/server/Kneesocks/Connection.cs b/server/Kneesocks/Connection.cs index 365b651..81a56e0 100644 --- a/server/Kneesocks/Connection.cs +++ b/server/Kneesocks/Connection.cs @@ -23,7 +23,9 @@ namespace Kneesocks { private TcpClient Socket; private NetworkStream Stream; - private string RawBuffer = ""; + + ReadBuffer Buffer; + private Frame PartialFrame = null; private List FrameBuffer = new List(); public bool Disconnected { get; private set; } = false; @@ -38,16 +40,23 @@ namespace Kneesocks { Socket = sock; Socket.ReceiveTimeout = 1; Stream = sock.GetStream(); + Buffer = new ReadBuffer(Stream); } public Connection(UInt64 id, TcpClient sock) : this(sock) { Id = id; } - public Connection(Connection conn) { - Id = conn.Id; + public Connection(Connection conn, bool preserveId = true) { + if(preserveId) + _Id = conn._Id; + Socket = conn.Socket; - Stream = Socket.GetStream(); + Stream = conn.Stream; + + Buffer = conn.Buffer; + PartialFrame = conn.PartialFrame; + FrameBuffer = conn.FrameBuffer; Disconnected = conn.Disconnected; DisconnectReason = conn.DisconnectReason; @@ -57,11 +66,25 @@ namespace Kneesocks { Headers = conn.Headers; } + private void StartRead(ulong length) { + + } + public byte[] Parse() { + byte[] readBuffer = null; + if(Buffer.IsReading) { + readBuffer = Buffer.AttemptRead(); + if(readBuffer == null) + return null; + } + if(!Handshaked) { + if(Stream.) + return null; } else { - + + OnParse(); } } @@ -85,16 +108,16 @@ namespace Kneesocks { } // called after the client successfully handshakes - public virtual void OnOpen() { } + protected virtual void OnOpen() { } // called when the thread manager iterates through // the thread list and stops on this thread - public virtual void OnParse() { } + protected virtual void OnParse() { } // called when data has been received - public virtual void OnReceive(byte[] data) { } + protected virtual void OnReceive(byte[] data) { } // called when the connection is disconnected - public virtual void OnClose() { } + protected virtual void OnClose() { } } } diff --git a/server/Kneesocks/Frame.cs b/server/Kneesocks/Frame.cs index ccc54ea..c05d97a 100644 --- a/server/Kneesocks/Frame.cs +++ b/server/Kneesocks/Frame.cs @@ -32,7 +32,29 @@ namespace Kneesocks { public byte[] Mask { get; set; } = new byte[] { 0, 0, 0, 0 }; public byte Reserved { get; set; } = 0; - public byte[] Content { get; set; } + private int _HeaderLength = 0; + public int HeaderLength { + get { + if(_HeaderLength != 0) + return _HeaderLength; + + int length = 2 + + (BodyLength >= 0x7E && BodyLength <= 0xFFFF ? 2 : 0) + + (BodyLength > 0xFFFF ? 4 : 0) + + (IsMasked ? 4 : 0); + + return (_HeaderLength = length); + } + } + + private int _BodyLength = 0; + public int BodyLength { + get { + return Content == null ? _BodyLength : Content.Length; + } + } + + public byte[] Content { get; set; } = null; public byte[] MaskedContent { get { long counter = 0; @@ -41,8 +63,8 @@ namespace Kneesocks { } public byte[] GetBytes() { - var headerSize = 2L; - var bodySize = Content.LongLength; + var headerSize = 2; + var bodySize = (UInt64)Content.LongLength; var headerLengthFirstByte = (byte)Content.Length; if(bodySize >= 0x7E && bodySize <= 0xFFFF) { headerSize += 2; @@ -55,7 +77,7 @@ namespace Kneesocks { if(IsMasked) headerSize += 4; - var returnValue = new byte[headerSize + bodySize]; + var returnValue = new byte[(UInt64)headerSize + bodySize]; returnValue[0] = (byte)(((byte)Opcode % 0x10) | ((Reserved % 8) << 4) | (IsFinal ? 0x80 : 0x0)); @@ -76,44 +98,65 @@ namespace Kneesocks { return returnValue; } - public static Frame FromBytes(byte[] raw) { + public static int HeaderSizeFromBytes(byte[] raw) { + if(raw.Length < 2) + throw new FormatException("Need first two bytes to analyze"); + + var lengthByte = raw[1] & 0x7F; + return 2 + + ((raw[1] & 0x80) != 0 ? 4: 0) + + (lengthByte == 0x7E ? 2 : 0) + + (lengthByte == 0x7F ? 4 : 0); + } + + public static Frame HeaderFromBytes(byte[] raw) { if(raw.Length < 2) throw new FormatException("Websocket frame cannot be less than two bytes long"); var rawOpcode = raw[0] & 0x0F; if(!Enum.IsDefined(typeof(kOpcode), rawOpcode)) - throw new FormatException("Opcode '0x"+ rawOpcode.ToString("X") +"' not understood"); - + throw new ArgumentException("Opcode '0x" + rawOpcode.ToString("X") + "' not understood"); + var returnFrame = new Frame { - IsFinal = (raw[0] & 0x80) != 0, - Opcode = (kOpcode)rawOpcode, + IsFinal = (raw[0] & 0x80) != 0, + Opcode = (kOpcode)rawOpcode, IsMasked = (raw[1] & 0x80) != 0, Reserved = (byte)((raw[0] & 0x70) >> 4) }; ulong bodyLength = raw[1] & 0x7Ful; - int headerOffset = - bodyLength < 0x7E - ? 1 + int headerOffset = + bodyLength < 0x7E + ? 1 : (bodyLength == 0x7E ? 3 : 9); - + if(raw.Length < headerOffset + 1) 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)); + bodyLength |= (ulong)raw[2 + i] << (8 * (headerOffset - 1 - i)); - if(returnFrame.IsMasked) { + if(bodyLength > Int32.MaxValue) + throw new FormatException("Frame is too large to interpret"); + + returnFrame._BodyLength = (int)bodyLength; + + if(returnFrame.IsMasked) Array.Copy(raw, headerOffset + 1, returnFrame.Mask, 0, 4); - headerOffset += 4; - } - ulong expectedFrameLength = bodyLength + (uint)headerOffset + 1; - if(expectedFrameLength < (ulong)raw.LongLength) - throw new FormatException("Raw frame length ("+ (ulong)raw.LongLength + ") is less than described size ("+ expectedFrameLength + ")"); - - Array.Copy(raw, headerOffset + 1, returnFrame.Content, 0L, (long)bodyLength); + return returnFrame; + } + + public static Frame FromBytes(byte[] raw) { + var returnFrame = HeaderFromBytes(raw); + + uint expectedFrameLength = (uint)returnFrame.BodyLength + (uint)returnFrame.HeaderLength; + if(expectedFrameLength < (uint)raw.Length) + throw new FormatException("Raw frame length ("+ (uint)raw.Length + ") is less than described size ("+ expectedFrameLength + ")"); + + returnFrame.Content = new byte[returnFrame.BodyLength]; + Array.Copy(raw, returnFrame.HeaderLength, returnFrame.Content, 0L, (long)returnFrame.BodyLength); if(returnFrame.IsMasked) returnFrame.Content = returnFrame.MaskedContent; diff --git a/server/Kneesocks/Kneesocks.csproj b/server/Kneesocks/Kneesocks.csproj index 8d4f9a5..ffa0fec 100644 --- a/server/Kneesocks/Kneesocks.csproj +++ b/server/Kneesocks/Kneesocks.csproj @@ -45,6 +45,7 @@ + diff --git a/server/Kneesocks/ReadBuffer.cs b/server/Kneesocks/ReadBuffer.cs new file mode 100644 index 0000000..a2d33ee --- /dev/null +++ b/server/Kneesocks/ReadBuffer.cs @@ -0,0 +1,100 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Net.Sockets; +using System.Text; +using System.Threading.Tasks; + +namespace Kneesocks { + class ReadBuffer { + private List Buffer; + private int ExpectedLength; + private string ExpectedString; + private NetworkStream Source; + private DateTime StartTime; + + public bool IsReading { get; private set; } = false; + + public ReadBuffer(NetworkStream source) { + Source = source; + } + + public TimeSpan ElapsedReadTime { + get { + return DateTime.Now - StartTime; + } + } + + private byte[] CheckBuffer() { + byte[] returnValue = null; + + if(ExpectedString != null) { + var location = Encoding.ASCII.GetString(Buffer.ToArray()).IndexOf(ExpectedString); + if(location != -1) { + var fullJump = location + ExpectedString.Length; + returnValue = Buffer.Take(fullJump).ToArray(); + Buffer = Buffer.Skip(fullJump).ToList(); + IsReading = false; + } + } else { + if(Buffer.Count >= ExpectedLength) { + returnValue = Buffer.Take(ExpectedLength).ToArray(); + Buffer = Buffer.Skip(ExpectedLength).ToList(); + IsReading = false; + } + } + + return returnValue; + } + + public byte[] AttemptRead() { + if(!IsReading) + return null; + + byte[] returnValue; + if((returnValue = CheckBuffer()) != null) + return returnValue; + + var buffer = new byte[1024]; + while(Source.DataAvailable) { + var readAmount = ExpectedString == null + ? Math.Min(1024, ExpectedLength - Buffer.Count) + : 1024; + + var bytesRead = Source.Read(buffer, 0, readAmount); + if(bytesRead == readAmount) + Buffer.AddRange(buffer); + else + Buffer.AddRange(buffer.Take(readAmount)); + + if((returnValue = CheckBuffer()) != null) + return returnValue; + } + + return null; + } + + public byte[] AttemptRead(int length) { + if(IsReading) + return null; + + IsReading = true; + ExpectedLength = length; + ExpectedString = null; + StartTime = DateTime.Now; + + return AttemptRead(); + } + + public byte[] AttemptRead(string terminator) { + if(IsReading) + return null; + + IsReading = true; + ExpectedString = terminator; + StartTime = DateTime.Now; + + return AttemptRead(); + } + } +} diff --git a/server/Kneesocks/Stack.cs b/server/Kneesocks/Stack.cs index d9d7d65..55fba2b 100644 --- a/server/Kneesocks/Stack.cs +++ b/server/Kneesocks/Stack.cs @@ -9,7 +9,6 @@ namespace Kneesocks { public class Stack where T : Connection { private Pool PoolRef = null; private List Clients = new List(); - private Mutex ClientsMutex = new Mutex(); private bool RunWithNoClients = false; private bool Running = true; private bool _finished = false; @@ -26,14 +25,10 @@ namespace Kneesocks { RunWithNoClients = runWithNoClients; } - public bool AddClient(Connection client) { - if(!ClientsMutex.WaitOne(5000)) - return false; - - Clients.Add(client); - - ClientsMutex.ReleaseMutex(); - return true; + public void AddClient(Connection client) { + lock(Clients) { + Clients.Add(client); + } } public int Count {