예제 #1
0
        /// <summary>
        /// Processes the packet within the context. Returns true whether the packet was processed or throttled.
        /// </summary>
        /// <param name="channel">The through which the packet is coming/going out.</param>
        /// <param name="context">The packet context for this operation.</param>
        /// <returns>True whether the packet was processed or throttled, false otherwise.</returns>
        public static ProcessingState Process(Emitter.Connection channel, ProcessingContext context)
        {
            // Only process precompiled buffer
            var inputBuffer = context.Buffer;

            if (inputBuffer == null)
            {
                return(ProcessingState.Failure);
            }

            // Get the length & reserve new buffer
            var length = inputBuffer.Length;
            var buffer = context.BufferReserve(length + 2);

            // Wrap in between 0 and 255
            buffer.Array[buffer.Offset] = Start;
            Memory.Copy(inputBuffer.Array, inputBuffer.Offset, buffer.Array, buffer.Offset + 1, length);
            buffer.Array[buffer.Offset + length + 1] = End;

            // Switch to the new buffer
            context.SwitchBuffer(buffer);

            // Trace a websocket event
            NetTrace.WriteLine("Draft76 frame [" + buffer.Length + "] encoded", channel, NetTraceCategory.WebSocket);

            return(ProcessingState.Success);
        }
예제 #2
0
        /// <summary>
        /// Processes the packet within the context. Returns true whether the packet was processed or throttled.
        /// </summary>
        /// <param name="channel">The through which the packet is coming/going out.</param>
        /// <param name="context">The packet context for this operation.</param>
        /// <returns>True whether the packet was processed or throttled, false otherwise.</returns>
        public static ProcessingState Process(Emitter.Connection channel, ProcessingContext context)
        {
            // It can only process StringPacket objects
            var response = context.Packet as HttpResponse;

            if (response == null)
            {
                return(ProcessingState.Failure);
            }

            // If we explicitely disabled the response, don't send it
            if (!response.ShouldSend)
            {
                return(ProcessingState.Failure);
            }

            // Get the client
            var client = context.Client;
            var stream = response.GetUnderlyingStream();

            // Flush the writer, ensuring we have the correct compiled buffer here.
            response.Flush();

            // Compile the headers
            var headers = HttpHeaders.Compile(response);

            // Create the buffer
            var buffer = context.BufferReserve(headers.Length + (int)stream.Length);

            Memory.Copy(headers, 0, buffer.Array, buffer.Offset, headers.Length);
            Memory.Copy(stream.GetBuffer(), 0, buffer.Array, buffer.Offset + headers.Length, (int)stream.Length);

            // Trace HTTP request
            NetTrace.WriteLine(response.Status + " " + response.ContentType + " Length: " + stream.Length, channel, NetTraceCategory.Http);

            // Write to the buffer
            context.SwitchBuffer(buffer);

            return(ProcessingState.Success);
        }
예제 #3
0
        /// <summary>
        /// Processes the packet within the context. Returns true whether the packet was processed or throttled.
        /// </summary>
        /// <param name="channel">The through which the packet is coming/going out.</param>
        /// <param name="context">The packet context for this operation.</param>
        /// <returns>True whether the packet was processed or throttled, false otherwise.</returns>
        public static ProcessingState Process(Emitter.Connection channel, ProcessingContext context)
        {
            // Only process precompiled buffer
            var inputBuffer = context.Buffer;

            if (inputBuffer == null)
            {
                return(ProcessingState.Failure);
            }

            // Get the length & the final length
            var length      = inputBuffer.Length;
            var finalLength = length > UInt16.MaxValue
                ? length + 10
                : length > 125
                    ? length + 4
                    : length + 2;

            // Reserve the buffer
            var buffer = context.BufferReserve(finalLength);

            // Get the frame type

            /*var frameType = channel.TransportEncoding == TransportEncoding.Binary
             *      ? WebSocketFrameType.Binary
             *      : WebSocketFrameType.Text;*/
            var frameType = WebSocketFrameType.Binary;

            // Is it a pong request? change the frame type
            if (context.Packet is WebSocketPong)
            {
                frameType = WebSocketFrameType.Pong;
            }

            // Get the operation byte
            var op      = (byte)((byte)frameType + 128);
            var segment = buffer.AsSegment();
            var offset  = segment.Offset;

            // Write the operation first
            segment.Array[offset] = op;
            ++offset;

            if (length > UInt16.MaxValue)
            {
                // Length flag
                segment.Array[offset] = (byte)127;
                ++offset;

                // Length value
                var lengthBytes = length.ToBigEndianBytes <ulong>();
                Memory.Copy(lengthBytes, 0, segment.Array, offset, lengthBytes.Length);
                offset += lengthBytes.Length;
            }
            else if (length > 125)
            {
                // Length flag
                segment.Array[offset] = (byte)126;
                ++offset;

                // Length value
                var lengthBytes = length.ToBigEndianBytes <ushort>();
                Memory.Copy(lengthBytes, 0, segment.Array, offset, lengthBytes.Length);
                offset += lengthBytes.Length;
            }
            else
            {
                // Length value
                segment.Array[offset] = (byte)length;
                ++offset;
            }

            // Write the payload
            Memory.Copy(inputBuffer.Array, inputBuffer.Offset, segment.Array, offset, inputBuffer.Length);
            offset += length;

            // Switch to the new buffer
            context.SwitchBuffer(buffer);

            // Trace a websocket event
            NetTrace.WriteLine("Hybi13 frame [" + buffer.Length + "] encoded", channel, NetTraceCategory.WebSocket);

            return(ProcessingState.Success);
        }
예제 #4
0
        /// <summary>
        /// Decodes a single hybi13 frame.
        /// </summary>
        /// <param name="context">The context for decoding.</param>
        /// <param name="pBuffer">The byte pointer to start decoding process.</param>
        /// <param name="length">The length of the buffer, starting at pBuffer offset.</param>
        /// <param name="index">The amount of procesed bytes.</param>
        /// <param name="isFinal">Whether the frame is final or not.</param>
        /// <param name="decoded">The frame decoded.</param>
        /// <returns>Processing state.</returns>
        private static ProcessingState DecodeFrame(ProcessingContext context, byte *pBuffer, int length, out int index, out bool isFinal, out BufferSegment decoded)
        {
            // Default values
            index   = 0;
            decoded = null;

            // Check if we have a buffer for the mask
            if (MaskBuffer == null)
            {
                MaskBuffer = new byte[4];
            }

            // Get the first part of the header
            var frameType = (WebSocketFrameType)(*pBuffer & 15);

            isFinal = (*pBuffer & 128) != 0;

            // Must have at least some bytes
            if (length == 0)
            {
                return(ProcessingState.InsufficientData);
            }

            // We only got one byte, kthx iOS
            if (length == 1 && (frameType == WebSocketFrameType.Text || frameType == WebSocketFrameType.Binary))
            {
                return(ProcessingState.InsufficientData);
            }

            // Get the second part of the header
            var isMasked   = (*(pBuffer + 1) & 128) != 0;
            var dataLength = (*(pBuffer + 1) & 127);

            // Close the connection if requested
            if (frameType == WebSocketFrameType.Close)
            {
                // Client sent us a close frame, we should close the connection
                context.Channel.Close();
                return(ProcessingState.Stop);
            }

            // We got some weird shit
            if (!isMasked)
            {
                throw new WebSocketException("Incorrect incoming Hybi13 data format.");
            }

            // Validate the frame type
            switch (frameType)
            {
            // Frames with a payload
            case WebSocketFrameType.Text:
            case WebSocketFrameType.Binary:
            case WebSocketFrameType.Continuation:
            case WebSocketFrameType.Ping:
            case WebSocketFrameType.Pong:
                break;

            // Unrecognized frame type
            default: throw new WebSocketException("Unsupported Huby13 frame (" + frameType + ") received.");
            }

            index = 2;
            int payloadLength;

            if (dataLength == 127)
            {
                if (length < index + 8)
                {
                    return(ProcessingState.InsufficientData);
                }

                // TODO: Support little endian too
                payloadLength = *(pBuffer + 2) << 56
                                | *(pBuffer + 3) << 48
                                | *(pBuffer + 4) << 40
                                | *(pBuffer + 5) << 32
                                | *(pBuffer + 6) << 24
                                | *(pBuffer + 7) << 16
                                | *(pBuffer + 8) << 8
                                | *(pBuffer + 9);

                index += 8;
            }
            else if (dataLength == 126)
            {
                if (length < index + 2)
                {
                    return(ProcessingState.InsufficientData);
                }

                // TODO: Support little endian too
                payloadLength = *(pBuffer + 2) << 8
                                | *(pBuffer + 3);

                index += 2;
            }
            else
            {
                payloadLength = dataLength;
            }

            // Check if we have the whole frame here
            if (length < index + payloadLength + 4)
            {
                return(ProcessingState.InsufficientData);
            }

            // Get the mask bytes
            MaskBuffer[0] = *(pBuffer + index);
            MaskBuffer[1] = *(pBuffer + index + 1);
            MaskBuffer[2] = *(pBuffer + index + 2);
            MaskBuffer[3] = *(pBuffer + index + 3);
            index        += 4;

            // Reserve a decode buffer to decode into
            decoded = context.BufferReserve(payloadLength);

            // Decode the body
            byte *pTo   = decoded.AsBytePointer();
            byte *pFrom = pBuffer + index;

            for (int i = 0; i < payloadLength; ++i, ++pTo, ++pFrom)
            {
                *pTo = (byte)((*pFrom) ^ MaskBuffer[i % 4]);
            }

            // Set the new index
            index += payloadLength;
            switch (frameType)
            {
            // We need to reply to the ping
            case WebSocketFrameType.Ping:
            {
                // Send the websocket with the copy of the body (as per RFC)
                context.Channel.Send(WebSocketPong.Acquire(decoded));
                decoded.TryRelease();
                return(ProcessingState.Stop);
            }

            // Pong is just used for the heartbeat
            case WebSocketFrameType.Pong: return(ProcessingState.Stop);
            }

            // Trace a websocket event
            return(ProcessingState.Success);
        }