예제 #1
0
        internal static PayloadHeader Decode(List <byte> buffer, int startPosition)
        {
            var header = new PayloadHeader();

            // Decode the first byte
            var position = startPosition;

            if (position >= buffer.Count)
            {
                return(null);
            }
            header.FinishedBit = (buffer[position] & 128) == 128;
            header.OpCode      = (WebSocketOpCode)(buffer[position] & 15);
            position++;

            // Decode the second byte
            if (position >= buffer.Count)
            {
                return(null);
            }
            header.Masked        = (buffer[position] & 128) == 128;
            header.PayloadLength = buffer[position] & 127;
            position++;

            // Calculate the real length of the payload (but exit if we don't have enough bytes)
            if (header.PayloadLength == 126)
            {
                if (position + 1 >= buffer.Count)
                {
                    return(null);
                }
                header.PayloadLength = (buffer[position++] << 8) | buffer[position++];
            }
            else if (header.PayloadLength == 127)
            {
                if (position + 7 >= buffer.Count)
                {
                    return(null);
                }
                header.PayloadLength = (buffer[position++] << 56) | (buffer[position++] << 48) | (buffer[position++] << 40) | (buffer[position++] << 32) | (buffer[position++] << 24) | (buffer[position++] << 16) | (buffer[position++] << 8) | buffer[position++];
            }

            // Get the mask key bytes
            if (header.Masked)
            {
                if (position + 3 >= buffer.Count)
                {
                    return(null);
                }
                header.MaskKey = new byte[4];
                buffer.CopyTo(position, header.MaskKey, 0, 4);
                position += 4;
            }

            // Return decoded payload header
            header.Size = position - startPosition;
            return(header);
        }
예제 #2
0
        private Packet DecodeBuffer()
        {
            var position = 0;
            var header   = PayloadHeader.Decode(largeBuffer, position);

            if (header == null)
            {
                return(null);
            }
            position += header.Size;

            // Confirm that we have retrieved enough bytes, otherwise we need to wait for more data to come in
            var totalExpectedSize = header.Size + header.PayloadLength;

            if (largeBuffer.Count < totalExpectedSize)
            {
                return(null);
            }

            // Copy the payload into its own array, unmasking it if necessary into a readable form
            var payloadBytes = new byte[header.PayloadLength];

            if (header.Masked)
            {
                for (var i = 0; i < header.PayloadLength; i++)
                {
                    payloadBytes[i] = (byte)(largeBuffer[position + i] ^ header.MaskKey[i % 4]);
                }
            }
            else
            {
                largeBuffer.CopyTo(position, payloadBytes, 0, header.PayloadLength);
            }

            // Advance the position
            position += header.PayloadLength;

            // We only accept these types of opcode
            switch (header.OpCode)
            {
            case WebSocketOpCode.Close:
                largeBuffer.RemoveRange(0, position);
                return(new Packet(RemoteEndPoint, WebSocketAction.Disconnect, "Intentional client disconnection."));

            case WebSocketOpCode.Text:
            case WebSocketOpCode.Continuation:
            case WebSocketOpCode.Ping:

                // Add to the payload
                largeBuffer.RemoveRange(0, position);
                incompletePayload.AddRange(payloadBytes);

                // Do we have a complete payload?
                if (!header.FinishedBit)
                {
                    return(DecodeBuffer());
                }

                // Convert the completed payload into a string
                var payloadText = Encoding.UTF8.GetString(incompletePayload.ToArray());
                incompletePayload.Clear();

                // Raise a text packet for processing
                if (header.OpCode != WebSocketOpCode.Ping)
                {
                    return(new Packet(RemoteEndPoint, WebSocketAction.SendText, payloadText));
                }

                // Send a pong and get the next packet
                Send(WebSocketOpCode.Pong, payloadText);
                return(DecodeBuffer());

            case WebSocketOpCode.Pong:

                // Simply get the next packet
                largeBuffer.RemoveRange(0, position);
                return(DecodeBuffer());

            default:
                throw new NotImplementedException("Web socket opcode " + header.OpCode + " is currently not supported.");
            }
        }