sockscape/server/Kneesocks/Frame.cs
2017-04-29 16:07:17 -05:00

74 lines
2.5 KiB
C#

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Kneesocks {
public class Frame {
public enum kOpcode {
Continuation = 0x0,
TextFrame = 0x1,
BinaryFrame = 0x2,
Close = 0x8,
Ping = 0x9,
Pong = 0xA
};
public kOpcode Opcode { get; set; }
public bool IsFinal { get; set; }
public bool IsMasked { get; set; }
public byte[] Mask { get; set; } = new byte[] { 0, 0, 0, 0 };
public byte Reserved { get; set; }
public byte[] Content { get; set; }
public byte[] MaskedContent {
get {
byte[] returnValue = new byte[Content.Length];
for(long i = 0; i < Content.LongLength; ++i)
returnValue[i] = (byte)(Content[i] ^ Mask[i % 4]);
return returnValue;
}
}
public static Frame FromRaw(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 '"+ rawOpcode.ToString("0x{0:X}") +"' not understood");
var returnFrame = new Frame {
IsFinal = (raw[0] & 0x80) != 0,
Opcode = (kOpcode)rawOpcode,
IsMasked = (raw[1] & 0x80) != 0,
Reserved = (byte)((raw[0] & 0x70) >> 4)
};
ulong frameLength = raw[1] & 0x7Ful;
int lengthOffset =
frameLength < 126
? 1
: (frameLength == 126 ? 3 : 9);
for(var i = lengthOffset - 1; i > 0; --i) {
var bytePos = lengthOffset - 1 - i;
frameLength &= 0xFFul << bytePos;
frameLength |= (ulong)raw[2 + i] << bytePos;
}
if(returnFrame.IsMasked) {
for(var i = 0; i < 4; ++i)
returnFrame.Mask[i] = raw[i + 1 + lengthOffset];
lengthOffset += 4;
}
if(raw.LongLength + lengthOffset + 1 < frameLength)
throw new FormatException("Raw frame length passed in is undersized ")
return returnFrame;
}
}
}