bool TryDecodeNextMessage(out OpCode opCode, out byte[] messagePayload)
{
while (true)
{
switch (decodeState)
{
case DecodeState.DecodeHeader:
if (FrameDecoder.TryDecodeHeader(readBuffer, ref dataStart, readBufferOffset, out isFin, out frameOpCode, out isMasked, out framePayloadLength, mask))
{
decodeState = DecodeState.DecodePayload;
switch (frameOpCode)
{
case OpCode.Continuation:
if (framePayloadLength > 0)
{
BufferUtils.Expand(ref messageBuffer, framePayloadLength); //TODO: limit, sanity guard
}
break;
case OpCode.Text:
case OpCode.Binary:
messageOpCode = frameOpCode;
messageBuffer = new byte[framePayloadLength];
messageBufferOffset = 0;
break;
case OpCode.Close:
case OpCode.Ping:
case OpCode.Pong:
if (!isFin)
{
throw new WebSocketException("Control frame cannot be fragmented");
}
break;
}
continue;
}
break;
case DecodeState.DecodePayload:
var decodeStart = dataStart;
if (FrameDecoder.TryDecodePayload(readBuffer, ref dataStart, readBufferOffset, framePayloadLength, isMasked, mask))
{
decodeState = DecodeState.DecodeHeader;
switch (frameOpCode)
{
case OpCode.Continuation:
case OpCode.Text:
case OpCode.Binary:
Array.Copy(readBuffer, decodeStart, messageBuffer, messageBufferOffset, framePayloadLength);
CompactReadBuffer(ref dataStart);
if (isFin)
{
opCode = messageOpCode;
messagePayload = messageBuffer;
messageBuffer = null;
messageBufferOffset = 0;
return true;
}
else
{
messageBufferOffset += framePayloadLength;
continue;
}
case OpCode.Close:
case OpCode.Ping:
case OpCode.Pong:
opCode = frameOpCode;
messagePayload = new byte[framePayloadLength];
Array.Copy(readBuffer, decodeStart, messagePayload, 0, framePayloadLength);
CompactReadBuffer(ref dataStart);
return true; // must be Fin
}
}
break;
}
opCode = OpCode.Continuation;
messagePayload = null;
return false;
}
}