thigh highs
running out of sock names
This commit is contained in:
parent
2393f94339
commit
583182e81b
5 changed files with 202 additions and 40 deletions
|
@ -23,7 +23,9 @@ namespace Kneesocks {
|
||||||
|
|
||||||
private TcpClient Socket;
|
private TcpClient Socket;
|
||||||
private NetworkStream Stream;
|
private NetworkStream Stream;
|
||||||
private string RawBuffer = "";
|
|
||||||
|
ReadBuffer Buffer;
|
||||||
|
private Frame PartialFrame = null;
|
||||||
private List<Frame> FrameBuffer = new List<Frame>();
|
private List<Frame> FrameBuffer = new List<Frame>();
|
||||||
|
|
||||||
public bool Disconnected { get; private set; } = false;
|
public bool Disconnected { get; private set; } = false;
|
||||||
|
@ -38,16 +40,23 @@ namespace Kneesocks {
|
||||||
Socket = sock;
|
Socket = sock;
|
||||||
Socket.ReceiveTimeout = 1;
|
Socket.ReceiveTimeout = 1;
|
||||||
Stream = sock.GetStream();
|
Stream = sock.GetStream();
|
||||||
|
Buffer = new ReadBuffer(Stream);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Connection(UInt64 id, TcpClient sock) : this(sock) {
|
public Connection(UInt64 id, TcpClient sock) : this(sock) {
|
||||||
Id = id;
|
Id = id;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Connection(Connection conn) {
|
public Connection(Connection conn, bool preserveId = true) {
|
||||||
Id = conn.Id;
|
if(preserveId)
|
||||||
|
_Id = conn._Id;
|
||||||
|
|
||||||
Socket = conn.Socket;
|
Socket = conn.Socket;
|
||||||
Stream = Socket.GetStream();
|
Stream = conn.Stream;
|
||||||
|
|
||||||
|
Buffer = conn.Buffer;
|
||||||
|
PartialFrame = conn.PartialFrame;
|
||||||
|
FrameBuffer = conn.FrameBuffer;
|
||||||
|
|
||||||
Disconnected = conn.Disconnected;
|
Disconnected = conn.Disconnected;
|
||||||
DisconnectReason = conn.DisconnectReason;
|
DisconnectReason = conn.DisconnectReason;
|
||||||
|
@ -57,11 +66,25 @@ namespace Kneesocks {
|
||||||
Headers = conn.Headers;
|
Headers = conn.Headers;
|
||||||
}
|
}
|
||||||
|
|
||||||
public byte[] Parse() {
|
private void StartRead(ulong length) {
|
||||||
if(!Handshaked) {
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public byte[] Parse() {
|
||||||
|
byte[] readBuffer = null;
|
||||||
|
if(Buffer.IsReading) {
|
||||||
|
readBuffer = Buffer.AttemptRead();
|
||||||
|
if(readBuffer == null)
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!Handshaked) {
|
||||||
|
if(Stream.)
|
||||||
|
|
||||||
|
return null;
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
|
OnParse();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -85,16 +108,16 @@ namespace Kneesocks {
|
||||||
}
|
}
|
||||||
|
|
||||||
// called after the client successfully handshakes
|
// called after the client successfully handshakes
|
||||||
public virtual void OnOpen() { }
|
protected virtual void OnOpen() { }
|
||||||
|
|
||||||
// called when the thread manager iterates through
|
// called when the thread manager iterates through
|
||||||
// the thread list and stops on this thread
|
// the thread list and stops on this thread
|
||||||
public virtual void OnParse() { }
|
protected virtual void OnParse() { }
|
||||||
|
|
||||||
// called when data has been received
|
// called when data has been received
|
||||||
public virtual void OnReceive(byte[] data) { }
|
protected virtual void OnReceive(byte[] data) { }
|
||||||
|
|
||||||
// called when the connection is disconnected
|
// called when the connection is disconnected
|
||||||
public virtual void OnClose() { }
|
protected virtual void OnClose() { }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -32,7 +32,29 @@ namespace Kneesocks {
|
||||||
public byte[] Mask { get; set; } = new byte[] { 0, 0, 0, 0 };
|
public byte[] Mask { get; set; } = new byte[] { 0, 0, 0, 0 };
|
||||||
public byte Reserved { get; set; } = 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 {
|
public byte[] MaskedContent {
|
||||||
get {
|
get {
|
||||||
long counter = 0;
|
long counter = 0;
|
||||||
|
@ -41,8 +63,8 @@ namespace Kneesocks {
|
||||||
}
|
}
|
||||||
|
|
||||||
public byte[] GetBytes() {
|
public byte[] GetBytes() {
|
||||||
var headerSize = 2L;
|
var headerSize = 2;
|
||||||
var bodySize = Content.LongLength;
|
var bodySize = (UInt64)Content.LongLength;
|
||||||
var headerLengthFirstByte = (byte)Content.Length;
|
var headerLengthFirstByte = (byte)Content.Length;
|
||||||
if(bodySize >= 0x7E && bodySize <= 0xFFFF) {
|
if(bodySize >= 0x7E && bodySize <= 0xFFFF) {
|
||||||
headerSize += 2;
|
headerSize += 2;
|
||||||
|
@ -55,7 +77,7 @@ namespace Kneesocks {
|
||||||
if(IsMasked)
|
if(IsMasked)
|
||||||
headerSize += 4;
|
headerSize += 4;
|
||||||
|
|
||||||
var returnValue = new byte[headerSize + bodySize];
|
var returnValue = new byte[(UInt64)headerSize + bodySize];
|
||||||
returnValue[0] = (byte)(((byte)Opcode % 0x10)
|
returnValue[0] = (byte)(((byte)Opcode % 0x10)
|
||||||
| ((Reserved % 8) << 4)
|
| ((Reserved % 8) << 4)
|
||||||
| (IsFinal ? 0x80 : 0x0));
|
| (IsFinal ? 0x80 : 0x0));
|
||||||
|
@ -76,13 +98,24 @@ namespace Kneesocks {
|
||||||
return returnValue;
|
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)
|
if(raw.Length < 2)
|
||||||
throw new FormatException("Websocket frame cannot be less than two bytes long");
|
throw new FormatException("Websocket frame cannot be less than two bytes long");
|
||||||
|
|
||||||
var rawOpcode = raw[0] & 0x0F;
|
var rawOpcode = raw[0] & 0x0F;
|
||||||
if(!Enum.IsDefined(typeof(kOpcode), rawOpcode))
|
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 {
|
var returnFrame = new Frame {
|
||||||
IsFinal = (raw[0] & 0x80) != 0,
|
IsFinal = (raw[0] & 0x80) != 0,
|
||||||
|
@ -102,18 +135,28 @@ namespace Kneesocks {
|
||||||
|
|
||||||
bodyLength = bodyLength < 0x7E ? 0 : bodyLength;
|
bodyLength = bodyLength < 0x7E ? 0 : bodyLength;
|
||||||
for(var i = headerOffset - 1; i > 0; --i)
|
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);
|
Array.Copy(raw, headerOffset + 1, returnFrame.Mask, 0, 4);
|
||||||
headerOffset += 4;
|
|
||||||
|
return returnFrame;
|
||||||
}
|
}
|
||||||
|
|
||||||
ulong expectedFrameLength = bodyLength + (uint)headerOffset + 1;
|
public static Frame FromBytes(byte[] raw) {
|
||||||
if(expectedFrameLength < (ulong)raw.LongLength)
|
var returnFrame = HeaderFromBytes(raw);
|
||||||
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);
|
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)
|
if(returnFrame.IsMasked)
|
||||||
returnFrame.Content = returnFrame.MaskedContent;
|
returnFrame.Content = returnFrame.MaskedContent;
|
||||||
|
|
||||||
|
|
|
@ -45,6 +45,7 @@
|
||||||
<Compile Include="Handshake.cs" />
|
<Compile Include="Handshake.cs" />
|
||||||
<Compile Include="Pool.cs" />
|
<Compile Include="Pool.cs" />
|
||||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||||
|
<Compile Include="ReadBuffer.cs" />
|
||||||
<Compile Include="Server.cs" />
|
<Compile Include="Server.cs" />
|
||||||
<Compile Include="Stack.cs" />
|
<Compile Include="Stack.cs" />
|
||||||
<Compile Include="Utilities.cs" />
|
<Compile Include="Utilities.cs" />
|
||||||
|
|
100
server/Kneesocks/ReadBuffer.cs
Normal file
100
server/Kneesocks/ReadBuffer.cs
Normal file
|
@ -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<byte> 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();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -9,7 +9,6 @@ namespace Kneesocks {
|
||||||
public class Stack<T> where T : Connection {
|
public class Stack<T> where T : Connection {
|
||||||
private Pool<T> PoolRef = null;
|
private Pool<T> PoolRef = null;
|
||||||
private List<Connection> Clients = new List<Connection>();
|
private List<Connection> Clients = new List<Connection>();
|
||||||
private Mutex ClientsMutex = new Mutex();
|
|
||||||
private bool RunWithNoClients = false;
|
private bool RunWithNoClients = false;
|
||||||
private bool Running = true;
|
private bool Running = true;
|
||||||
private bool _finished = false;
|
private bool _finished = false;
|
||||||
|
@ -26,14 +25,10 @@ namespace Kneesocks {
|
||||||
RunWithNoClients = runWithNoClients;
|
RunWithNoClients = runWithNoClients;
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool AddClient(Connection client) {
|
public void AddClient(Connection client) {
|
||||||
if(!ClientsMutex.WaitOne(5000))
|
lock(Clients) {
|
||||||
return false;
|
|
||||||
|
|
||||||
Clients.Add(client);
|
Clients.Add(client);
|
||||||
|
}
|
||||||
ClientsMutex.ReleaseMutex();
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public int Count {
|
public int Count {
|
||||||
|
|
Loading…
Reference in a new issue