2017-04-21 21:04:03 +00:00
|
|
|
|
using System;
|
|
|
|
|
using System.Collections.Generic;
|
|
|
|
|
using System.Linq;
|
2017-04-23 04:55:29 +00:00
|
|
|
|
using System.Net.Sockets;
|
2017-04-21 21:04:03 +00:00
|
|
|
|
using System.Text;
|
|
|
|
|
using System.Threading.Tasks;
|
2017-05-09 12:22:04 +00:00
|
|
|
|
using Square;
|
2017-04-21 21:04:03 +00:00
|
|
|
|
|
2017-04-27 20:44:30 +00:00
|
|
|
|
namespace Kneesocks {
|
2017-05-04 12:21:27 +00:00
|
|
|
|
public class Connection {
|
|
|
|
|
public UInt64? _Id = null;
|
|
|
|
|
public UInt64 Id {
|
|
|
|
|
get {
|
|
|
|
|
if(_Id == null)
|
|
|
|
|
throw new ArgumentNullException();
|
|
|
|
|
else
|
|
|
|
|
return (UInt64)_Id;
|
|
|
|
|
}
|
|
|
|
|
set {
|
|
|
|
|
if(_Id == null)
|
|
|
|
|
_Id = value;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2017-04-23 04:55:29 +00:00
|
|
|
|
private TcpClient Socket;
|
2017-04-24 21:04:52 +00:00
|
|
|
|
private NetworkStream Stream;
|
2017-05-05 21:05:52 +00:00
|
|
|
|
|
|
|
|
|
ReadBuffer Buffer;
|
2017-05-09 21:08:39 +00:00
|
|
|
|
private byte[] FirstTwoBytes = null;
|
2017-05-10 21:10:42 +00:00
|
|
|
|
private int ExtraHeaderSize = 0;
|
2017-05-09 21:08:39 +00:00
|
|
|
|
private byte[] FrameHeader = null;
|
2017-05-04 21:09:38 +00:00
|
|
|
|
private List<Frame> FrameBuffer = new List<Frame>();
|
2017-04-24 21:04:52 +00:00
|
|
|
|
|
|
|
|
|
public bool Disconnected { get; private set; } = false;
|
|
|
|
|
public string DisconnectReason { get; private set; } = null;
|
|
|
|
|
|
|
|
|
|
public bool Handshaked { get; private set; } = false;
|
2017-05-08 21:06:17 +00:00
|
|
|
|
public Handshake ClientHandshake { get; private set; } = null;
|
2017-04-23 04:55:29 +00:00
|
|
|
|
|
2017-05-04 12:21:27 +00:00
|
|
|
|
public Connection(TcpClient sock) {
|
2017-04-23 04:55:29 +00:00
|
|
|
|
Socket = sock;
|
2017-04-24 21:04:52 +00:00
|
|
|
|
Socket.ReceiveTimeout = 1;
|
|
|
|
|
Stream = sock.GetStream();
|
2017-05-05 21:05:52 +00:00
|
|
|
|
Buffer = new ReadBuffer(Stream);
|
2017-04-23 04:55:29 +00:00
|
|
|
|
}
|
|
|
|
|
|
2017-05-04 12:21:27 +00:00
|
|
|
|
public Connection(UInt64 id, TcpClient sock) : this(sock) {
|
|
|
|
|
Id = id;
|
|
|
|
|
}
|
|
|
|
|
|
2017-05-05 21:05:52 +00:00
|
|
|
|
public Connection(Connection conn, bool preserveId = true) {
|
|
|
|
|
if(preserveId)
|
|
|
|
|
_Id = conn._Id;
|
|
|
|
|
|
2017-04-25 18:25:48 +00:00
|
|
|
|
Socket = conn.Socket;
|
2017-05-05 21:05:52 +00:00
|
|
|
|
Stream = conn.Stream;
|
|
|
|
|
|
|
|
|
|
Buffer = conn.Buffer;
|
2017-05-09 21:08:39 +00:00
|
|
|
|
FirstTwoBytes = conn.FirstTwoBytes;
|
|
|
|
|
ExtraHeaderSize = conn.ExtraHeaderSize;
|
|
|
|
|
FrameHeader = conn.FrameHeader;
|
2017-05-05 21:05:52 +00:00
|
|
|
|
FrameBuffer = conn.FrameBuffer;
|
2017-04-25 18:25:48 +00:00
|
|
|
|
|
|
|
|
|
Disconnected = conn.Disconnected;
|
|
|
|
|
DisconnectReason = conn.DisconnectReason;
|
|
|
|
|
|
|
|
|
|
Handshaked = conn.Handshaked;
|
2017-05-08 21:06:17 +00:00
|
|
|
|
ClientHandshake = conn.ClientHandshake;
|
2017-05-05 21:05:52 +00:00
|
|
|
|
}
|
2017-05-09 21:08:39 +00:00
|
|
|
|
|
2017-05-10 21:10:42 +00:00
|
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
|
2017-05-05 21:05:52 +00:00
|
|
|
|
byte[] readBuffer = null;
|
|
|
|
|
if(Buffer.IsReading) {
|
|
|
|
|
readBuffer = Buffer.AttemptRead();
|
2017-05-08 21:06:17 +00:00
|
|
|
|
if(readBuffer == null) {
|
2017-05-09 21:08:39 +00:00
|
|
|
|
if(Buffer.ElapsedReadTime.Seconds > (Handshaked ? 300 : 30))
|
2017-05-08 21:06:17 +00:00
|
|
|
|
Disconnect(Frame.kClosingReason.ProtocolError, "Timed out waiting for a full response");
|
|
|
|
|
|
2017-05-10 21:10:42 +00:00
|
|
|
|
return;
|
2017-05-08 21:06:17 +00:00
|
|
|
|
}
|
2017-05-05 21:05:52 +00:00
|
|
|
|
}
|
|
|
|
|
|
2017-05-04 21:09:38 +00:00
|
|
|
|
if(!Handshaked) {
|
2017-05-10 21:10:42 +00:00
|
|
|
|
ReadIfNotNull(ref readBuffer, "\r\n\r\n");
|
|
|
|
|
if(readBuffer == null)
|
|
|
|
|
return;
|
|
|
|
|
|
2017-05-08 21:06:17 +00:00
|
|
|
|
try {
|
|
|
|
|
Handshake request = new Handshake(Encoding.ASCII.GetString(readBuffer));
|
|
|
|
|
var response = Handshake.AcceptRequest(request).ToBytes();
|
|
|
|
|
Stream.Write(response, 0, response.Length);
|
|
|
|
|
ClientHandshake = request;
|
|
|
|
|
Handshaked = true;
|
|
|
|
|
} catch(Exception e) {
|
|
|
|
|
Disconnect(Frame.kClosingReason.ProtocolError, e.Message);
|
2017-05-10 21:10:42 +00:00
|
|
|
|
return;
|
2017-05-08 21:06:17 +00:00
|
|
|
|
}
|
2017-05-04 21:09:38 +00:00
|
|
|
|
|
2017-05-08 21:06:17 +00:00
|
|
|
|
OnOpen();
|
2017-05-10 21:10:42 +00:00
|
|
|
|
return;
|
2017-05-04 21:09:38 +00:00
|
|
|
|
}
|
2017-05-08 21:06:17 +00:00
|
|
|
|
|
2017-05-09 21:08:39 +00:00
|
|
|
|
OnParse();
|
|
|
|
|
|
|
|
|
|
if(FirstTwoBytes == null) {
|
2017-05-10 21:10:42 +00:00
|
|
|
|
ReadIfNotNull(ref readBuffer, 2);
|
|
|
|
|
if(readBuffer == null)
|
|
|
|
|
return;
|
2017-05-09 21:08:39 +00:00
|
|
|
|
|
|
|
|
|
FirstTwoBytes = readBuffer;
|
2017-05-10 21:10:42 +00:00
|
|
|
|
ExtraHeaderSize = Frame.HeaderLengthFromBytes(FirstTwoBytes) - 2;
|
|
|
|
|
|
2017-05-09 21:08:39 +00:00
|
|
|
|
readBuffer = null;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if(FrameHeader == null) {
|
|
|
|
|
if(ExtraHeaderSize == 0)
|
|
|
|
|
FrameHeader = FirstTwoBytes;
|
|
|
|
|
else {
|
2017-05-10 21:10:42 +00:00
|
|
|
|
ReadIfNotNull(ref readBuffer, ExtraHeaderSize);
|
|
|
|
|
if(readBuffer == null)
|
|
|
|
|
return;
|
2017-05-09 21:08:39 +00:00
|
|
|
|
|
|
|
|
|
FrameHeader = FirstTwoBytes.Concat(readBuffer).ToArray();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
readBuffer = null;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if(FrameHeader != null) {
|
2017-05-10 21:10:42 +00:00
|
|
|
|
Frame tempFrame;
|
2017-05-09 21:08:39 +00:00
|
|
|
|
|
2017-05-10 21:10:42 +00:00
|
|
|
|
if(readBuffer == null) {
|
|
|
|
|
try {
|
|
|
|
|
tempFrame = Frame.HeaderFromBytes(FrameHeader);
|
|
|
|
|
} catch(Exception e) {
|
|
|
|
|
Disconnect(Frame.kClosingReason.ProtocolError, e.Message);
|
|
|
|
|
return;
|
|
|
|
|
}
|
2017-05-09 21:08:39 +00:00
|
|
|
|
|
2017-05-10 21:10:42 +00:00
|
|
|
|
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<Frame>();
|
|
|
|
|
OnReceive(byteBuffer);
|
|
|
|
|
}
|
|
|
|
|
}
|
2017-05-08 21:06:17 +00:00
|
|
|
|
|
2017-05-10 21:10:42 +00:00
|
|
|
|
return;
|
2017-05-04 21:09:38 +00:00
|
|
|
|
}
|
|
|
|
|
|
2017-04-24 21:04:52 +00:00
|
|
|
|
public void Disconnect(string reason = null) {
|
2017-05-01 21:04:34 +00:00
|
|
|
|
Disconnect(Frame.kClosingReason.Normal, reason);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public void Disconnect(Frame.kClosingReason status, string reason = null) {
|
2017-04-24 21:04:52 +00:00
|
|
|
|
Disconnected = true;
|
|
|
|
|
DisconnectReason = reason;
|
2017-04-25 18:25:48 +00:00
|
|
|
|
|
|
|
|
|
if(Socket.Connected) {
|
|
|
|
|
Socket.SendTimeout = 1000;
|
2017-05-01 21:04:34 +00:00
|
|
|
|
var raw = Handshaked ? Frame.Closing(status, reason).GetBytes()
|
|
|
|
|
: Handshake.DenyRequest().ToString().GetBytes();
|
|
|
|
|
Stream.Write(raw, 0, raw.Length);
|
|
|
|
|
Socket.Close();
|
2017-04-25 18:25:48 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
OnClose();
|
2017-04-24 21:04:52 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// called after the client successfully handshakes
|
2017-05-05 21:05:52 +00:00
|
|
|
|
protected virtual void OnOpen() { }
|
2017-05-04 12:21:27 +00:00
|
|
|
|
|
2017-04-24 21:04:52 +00:00
|
|
|
|
// called when the thread manager iterates through
|
|
|
|
|
// the thread list and stops on this thread
|
2017-05-05 21:05:52 +00:00
|
|
|
|
protected virtual void OnParse() { }
|
2017-04-24 21:04:52 +00:00
|
|
|
|
|
|
|
|
|
// called when data has been received
|
2017-05-05 21:05:52 +00:00
|
|
|
|
protected virtual void OnReceive(byte[] data) { }
|
2017-04-23 04:55:29 +00:00
|
|
|
|
|
2017-04-24 21:04:52 +00:00
|
|
|
|
// called when the connection is disconnected
|
2017-05-05 21:05:52 +00:00
|
|
|
|
protected virtual void OnClose() { }
|
2017-04-21 21:04:03 +00:00
|
|
|
|
}
|
|
|
|
|
}
|